diff options
| author | Maxime Dénès | 2020-05-16 17:07:37 +0200 |
|---|---|---|
| committer | Maxime Dénès | 2020-06-02 18:53:33 +0200 |
| commit | 33021618a06a94563d28691940f02a55bd9d358d (patch) | |
| tree | 9d0cab0e9ffc2f1499ec1d49b142a758d7f80fee /ide/wg_ScriptView.ml | |
| parent | db768e6828af62e06eb03d36509be6f8fc1efbf3 (diff) | |
Move CoqIDE to its own folder
The will make it possible to put a VsCoq toplevel in `ide/vscoq`.
Diffstat (limited to 'ide/wg_ScriptView.ml')
| -rw-r--r-- | ide/wg_ScriptView.ml | 555 |
1 files changed, 0 insertions, 555 deletions
diff --git a/ide/wg_ScriptView.ml b/ide/wg_ScriptView.ml deleted file mode 100644 index 62d58a5f23..0000000000 --- a/ide/wg_ScriptView.ml +++ /dev/null @@ -1,555 +0,0 @@ -(************************************************************************) -(* * The Coq Proof Assistant / The Coq Development Team *) -(* v * Copyright INRIA, CNRS and contributors *) -(* <O___,, * (see version control and CREDITS file for authors & dates) *) -(* \VV/ **************************************************************) -(* // * This file is distributed under the terms of the *) -(* * GNU Lesser General Public License Version 2.1 *) -(* * (see LICENSE file for the text of the license) *) -(************************************************************************) - -open Preferences - -exception Abort - -type insert_action = { - ins_val : string; - ins_off : int; - ins_len : int; - ins_mrg : bool; -} - -type delete_action = { - del_val : string; (** Contents *) - del_off : int; (** Absolute offset of the modification *) - del_len : int; (** Length *) - del_mrg : bool; (** Is the modification mergeable? *) -} - -type action = - | Insert of insert_action - | Delete of delete_action - | Action of action list - | EndGrp (** pending begin_user_action *) - -let merge_insert ins = function -| Insert ins' :: rem -> - if ins.ins_mrg && ins'.ins_mrg && - (ins'.ins_off + ins'.ins_len = ins.ins_off) then - let nins = { - ins_val = ins'.ins_val ^ ins.ins_val; - ins_off = ins'.ins_off; - ins_len = ins'.ins_len + ins.ins_len; - ins_mrg = true; - } in - Insert nins :: rem - else - Insert ins :: Insert ins' :: rem -| l -> - Insert ins :: l - -let merge_delete del = function -| Delete del' :: rem -> - if del.del_mrg && del'.del_mrg && - (del.del_off + del.del_len = del'.del_off) then - let ndel = { - del_val = del.del_val ^ del'.del_val; - del_off = del.del_off; - del_len = del.del_len + del'.del_len; - del_mrg = true; - } in - Delete ndel :: rem - else - Delete del :: Delete del' :: rem -| l -> - Delete del :: l - -let rec negate_action act = match act with - | Insert act -> - let act = { - del_len = act.ins_len; - del_off = act.ins_off; - del_val = act.ins_val; - del_mrg = act.ins_mrg; - } in - Delete act - | Delete act -> - let act = { - ins_len = act.del_len; - ins_off = act.del_off; - ins_val = act.del_val; - ins_mrg = act.del_mrg; - } in - Insert act - | Action acts -> - Action (List.rev_map negate_action acts) - | EndGrp -> assert false - -type source_view = [ Gtk.text_view | `sourceview ] Gtk.obj - -class undo_manager (buffer : GText.buffer) = -object(self) - val mutable lock_undo = true - val mutable history = [] - val mutable redo = [] - - method with_lock_undo : 'a. ('a -> unit) -> 'a -> unit = - fun f x -> - if lock_undo then - let () = lock_undo <- false in - try (f x; lock_undo <- true) - with e -> (lock_undo <- true; raise e) - else () - - method private dump_debug () = - let rec iter = function - | Insert act -> - Printf.eprintf "Insert of '%s' at %d (length %d, mergeable %b)\n%!" - act.ins_val act.ins_off act.ins_len act.ins_mrg - | Delete act -> - Printf.eprintf "Delete '%s' from %d (length %d, mergeable %b)\n%!" - act.del_val act.del_off act.del_len act.del_mrg - | Action l -> - Printf.eprintf "Action\n%!"; - List.iter iter l; - Printf.eprintf "//Action\n%!"; - | EndGrp -> - Printf.eprintf "End Group\n%!" - in - if false (* !debug *) then begin - Printf.eprintf "+++++++++++++++++++++++++++++++++++++\n%!"; - Printf.eprintf "==========Undo Stack top=============\n%!"; - List.iter iter history; - Printf.eprintf "Stack size %d\n" (List.length history); - Printf.eprintf "==========Undo Stack Bottom==========\n%!"; - Printf.eprintf "==========Redo Stack start===========\n%!"; - List.iter iter redo; - Printf.eprintf "Stack size %d\n" (List.length redo); - Printf.eprintf "==========Redo Stack End=============\n%!"; - Printf.eprintf "+++++++++++++++++++++++++++++++++++++\n%!"; - end - - method clear_undo () = - history <- []; - redo <- [] - - (** Warning: processing actually undo the action *) - method private process_insert_action ins = - let start = buffer#get_iter (`OFFSET ins.ins_off) in - let stop = start#forward_chars ins.ins_len in - buffer#delete_interactive ~start ~stop () - - method private process_delete_action del = - let iter = buffer#get_iter (`OFFSET del.del_off) in - buffer#insert_interactive ~iter del.del_val - - (** We don't care about atomicity. Return: - 1. `OK when there was no error, `FAIL otherwise - 2. `NOOP if no write occurred, `WRITE otherwise - *) - method private process_action = function - | Insert ins -> - if self#process_insert_action ins then (`OK, `WRITE) else (`FAIL, `NOOP) - | Delete del -> - if self#process_delete_action del then (`OK, `WRITE) else (`FAIL, `NOOP) - | Action lst -> - let fold accu action = match accu with - | (`FAIL, _) -> accu (* we stop now! *) - | (`OK, status) -> - let (res, nstatus) = self#process_action action in - let merge op1 op2 = match op1, op2 with - | `NOOP, `NOOP -> `NOOP (* only a noop when both are *) - | _ -> `WRITE - in - (res, merge status nstatus) - in - List.fold_left fold (`OK, `NOOP) lst - | EndGrp -> assert false - - method perform_undo () = match history with - | [] -> () - | action :: rem -> - let ans = self#process_action action in - begin match ans with - | (`OK, _) -> - history <- rem; - redo <- (negate_action action) :: redo - | (`FAIL, `NOOP) -> () (* we do nothing *) - | (`FAIL, `WRITE) -> self#clear_undo () (* we don't know how we failed, so start off *) - end - - method perform_redo () = match redo with - | [] -> () - | action :: rem -> - let ans = self#process_action action in - begin match ans with - | (`OK, _) -> - redo <- rem; - history <- (negate_action action) :: history; - | (`FAIL, `NOOP) -> () (* we do nothing *) - | (`FAIL, `WRITE) -> self#clear_undo () (* we don't know how we failed *) - end - - method undo () = - Minilib.log "UNDO"; - self#with_lock_undo begin fun () -> - buffer#begin_user_action (); - self#perform_undo (); - buffer#end_user_action () - end () - - method redo () = - Minilib.log "REDO"; - self#with_lock_undo begin fun () -> - buffer#begin_user_action (); - self#perform_redo (); - buffer#end_user_action () - end () - - method process_begin_user_action () = - (* Push a new level of event on history stack *) - history <- EndGrp :: history - - method begin_user_action () = - self#with_lock_undo self#process_begin_user_action () - - method process_end_user_action () = - (* Search for the pending action *) - let rec split accu = function - | [] -> raise Not_found (* no pending begin action! *) - | EndGrp :: rem -> - let grp = List.rev accu in - let rec flatten = function - | [] -> rem - | [Insert ins] -> merge_insert ins rem - | [Delete del] -> merge_delete del rem - | [Action l] -> flatten l - | _ -> Action grp :: rem - in - flatten grp - | action :: rem -> - split (action :: accu) rem - in - try (history <- split [] history; self#dump_debug ()) - with Not_found -> - Minilib.log "Error: Badly parenthezised user action"; - self#clear_undo () - - method end_user_action () = - self#with_lock_undo self#process_end_user_action () - - method private process_handle_insert iter s = - (* Save the insert action *) - let len = Glib.Utf8.length s in - let mergeable = - (* heuristic: split at newline and atomic pastes *) - len = 1 && (s <> "\n") - in - let ins = { - ins_val = s; - ins_off = iter#offset; - ins_len = len; - ins_mrg = mergeable; - } in - let () = history <- Insert ins :: history in - () - - method private handle_insert iter s = - self#with_lock_undo (self#process_handle_insert iter) s - - method private process_handle_delete start stop = - (* Save the delete action *) - let text = buffer#get_text ~start ~stop () in - let len = Glib.Utf8.length text in - let mergeable = len = 1 && (text <> "\n") in - let del = { - del_val = text; - del_off = start#offset; - del_len = stop#offset - start#offset; - del_mrg = mergeable; - } in - let action = Delete del in - history <- action :: history; - redo <- []; - - method private handle_delete ~start ~stop = - self#with_lock_undo (self#process_handle_delete start) stop - - initializer - let _ = buffer#connect#after#begin_user_action ~callback:self#begin_user_action in - let _ = buffer#connect#after#end_user_action ~callback:self#end_user_action in - let _ = buffer#connect#insert_text ~callback:self#handle_insert in - let _ = buffer#connect#delete_range ~callback:self#handle_delete in - () - -end - -class script_view (tv : source_view) (ct : Coq.coqtop) = - -let view = new GSourceView3.source_view (Gobject.unsafe_cast tv) in -let provider = new Wg_Completion.completion_provider view#buffer ct in - -object (self) - inherit GSourceView3.source_view (Gobject.unsafe_cast tv) - - val undo_manager = new undo_manager view#buffer - - method auto_complete = provider#active - - method set_auto_complete flag = - provider#set_active flag - - method recenter_insert = - self#scroll_to_mark - ~use_align:false ~yalign:0.75 ~within_margin:0.25 `INSERT - - (* HACK: missing gtksourceview features *) - method! right_margin_position = - let prop = { - Gobject.name = "right-margin-position"; - conv = Gobject.Data.int; - } in - Gobject.get prop obj - - method! set_right_margin_position pos = - let prop = { - Gobject.name = "right-margin-position"; - conv = Gobject.Data.int; - } in - Gobject.set prop obj pos - - method! show_right_margin = - let prop = { - Gobject.name = "show-right-margin"; - conv = Gobject.Data.boolean; - } in - Gobject.get prop obj - - method! set_show_right_margin show = - let prop = { - Gobject.name = "show-right-margin"; - conv = Gobject.Data.boolean; - } in - Gobject.set prop obj show - - method comment () = - let rec get_line_start iter = - if iter#starts_line then iter - else get_line_start iter#backward_char - in - let (start, stop) = - if self#buffer#has_selection then - self#buffer#selection_bounds - else - let insert = self#buffer#get_iter `INSERT in - (get_line_start insert, insert#forward_to_line_end) - in - let stop_mark = self#buffer#create_mark ~left_gravity:false stop in - let () = self#buffer#begin_user_action () in - let was_inserted = self#buffer#insert_interactive ~iter:start "(* " in - let stop = self#buffer#get_iter_at_mark (`MARK stop_mark) in - let () = if was_inserted then ignore (self#buffer#insert_interactive ~iter:stop " *)") in - let () = self#buffer#end_user_action () in - self#buffer#delete_mark (`MARK stop_mark) - - method uncomment () = - let rec get_left_iter depth (iter : GText.iter) = - let prev_close = iter#backward_search "*)" in - let prev_open = iter#backward_search "(*" in - let prev_object = match prev_close, prev_open with - | None, None | Some _, None -> `NONE - | None, Some (po, _) -> `OPEN po - | Some (co, _), Some (po, _) -> if co#compare po < 0 then `OPEN po else `CLOSE co - in - match prev_object with - | `NONE -> None - | `OPEN po -> - if depth <= 0 then Some po - else get_left_iter (pred depth) po - | `CLOSE co -> - get_left_iter (succ depth) co - in - let rec get_right_iter depth (iter : GText.iter) = - let next_close = iter#forward_search "*)" in - let next_open = iter#forward_search "(*" in - let next_object = match next_close, next_open with - | None, None | None, Some _ -> `NONE - | Some (_, co), None -> `CLOSE co - | Some (_, co), Some (_, po) -> - if co#compare po > 0 then `OPEN po else `CLOSE co - in - match next_object with - | `NONE -> None - | `OPEN po -> - get_right_iter (succ depth) po - | `CLOSE co -> - if depth <= 0 then Some co - else get_right_iter (pred depth) co - in - let insert = self#buffer#get_iter `INSERT in - let left_elt = get_left_iter 0 insert in - let right_elt = get_right_iter 0 insert in - match left_elt, right_elt with - | Some liter, Some riter -> - let stop_mark = self#buffer#create_mark ~left_gravity:false riter in - (* We remove one trailing/leading space if it exists *) - let lcontent = self#buffer#get_text ~start:liter ~stop:(liter#forward_chars 3) () in - let rcontent = self#buffer#get_text ~start:(riter#backward_chars 3) ~stop:riter () in - let llen = if lcontent = "(* " then 3 else 2 in - let rlen = if rcontent = " *)" then 3 else 2 in - (* Atomic operation for the user *) - let () = self#buffer#begin_user_action () in - let was_deleted = self#buffer#delete_interactive ~start:liter ~stop:(liter#forward_chars llen) () in - let riter = self#buffer#get_iter_at_mark (`MARK stop_mark) in - if was_deleted then ignore (self#buffer#delete_interactive ~start:(riter#backward_chars rlen) ~stop:riter ()); - let () = self#buffer#end_user_action () in - self#buffer#delete_mark (`MARK stop_mark) - | _ -> () - - method apply_unicode_binding () = - let rec get_line_start iter = - if iter#starts_line then iter - else get_line_start iter#backward_char - in - (* Main action *) - let buffer = self#buffer in - let insert = buffer#get_iter `INSERT in - let insert_mark = buffer#create_mark ~left_gravity:false insert in - let () = buffer#begin_user_action () in - let word_to_insert = - try - let line_start = get_line_start insert in - let prev_backslash_search = insert#backward_search ~limit:line_start "\\" in - let backslash = - match prev_backslash_search with - | None -> raise Abort - | Some (backslash_start,backslash_stop) -> backslash_start - in - let prefix = backslash#get_text ~stop:insert in - let word = - match Unicode_bindings.lookup prefix with - | None -> raise Abort - | Some word -> word - in - let was_deleted = buffer#delete_interactive ~start:backslash ~stop:insert () in - if not was_deleted then raise Abort; - word - with Abort -> " " - (* Insert a space if no binding applies. This is to make sure that the user - gets some visual feedback that the keystroke was taken into account. - And also avoid slowing down users who press "Shift" for capitalizing the - first letter of a sentence just before typing the "Space" that comes in - front of that first letter. *) - in - let insert2 = buffer#get_iter_at_mark (`MARK insert_mark) in - let _was_inserted = buffer#insert_interactive ~iter:insert2 word_to_insert in - let () = self#buffer#end_user_action () in - self#buffer#delete_mark (`MARK insert_mark) - - - method proposal : string option = None (* FIXME *) - - method undo = undo_manager#undo - method redo = undo_manager#redo - method clear_undo = undo_manager#clear_undo - - method private paste () = - let cb = GData.clipboard Gdk.Atom.clipboard in - match cb#text with - | None -> () - | Some text -> - let () = self#buffer#begin_user_action () in - let _ = self#buffer#delete_selection () in - let _ = self#buffer#insert_interactive text in - self#buffer#end_user_action () - - initializer - let () = Gtk_parsing.fix_double_click self in - let supersed cb _ = - let _ = cb () in - GtkSignal.stop_emit() - in - (* HACK: Redirect the undo/redo signals of the underlying GtkSourceView *) - let _ = self#connect#undo ~callback:(supersed self#undo) in - let _ = self#connect#redo ~callback:(supersed self#redo) in - (* HACK: Redirect the paste signal *) - let _ = self#connect#paste_clipboard ~callback:(supersed self#paste) in - (* HACK: Redirect the move_line signal of the underlying GtkSourceView *) - let move_line_marshal = GtkSignal.marshal2 - Gobject.Data.boolean Gobject.Data.int "move_line_marshal" - in - let move_line_signal = { - GtkSignal.name = "move-lines"; - classe = Obj.magic 0; - marshaller = move_line_marshal; } - in - let callback b i = - let rec start_line iter = - if iter#starts_line then iter - else start_line iter#backward_char - in - let iter = start_line (self#buffer#get_iter `INSERT) in - (* do we forward the signal? *) - let proceed = - if not b && i = 1 then - iter#editable ~default:true && - iter#forward_line#editable ~default:true - else if not b && i = -1 then - iter#editable ~default:true && - iter#backward_line#editable ~default:true - else false - in - if not proceed then GtkSignal.stop_emit () - in - let _ = GtkSignal.connect ~sgn:move_line_signal ~callback obj in - (* Plug on preferences *) -(* FIXME: handle this using CSS *) -(* let cb clr = self#misc#modify_bg [`NORMAL, `NAME clr] in *) -(* let _ = background_color#connect#changed ~callback:cb in *) -(* let _ = self#misc#connect#realize ~callback:(fun () -> cb background_color#get) in *) - - let cb b = self#set_wrap_mode (if b then `WORD else `NONE) in - stick dynamic_word_wrap self cb; - stick show_line_number self self#set_show_line_numbers; - stick auto_indent self self#set_auto_indent; - stick highlight_current_line self self#set_highlight_current_line; - - (* Hack to handle missing binding in lablgtk *) - let cb b = - let flag = if b then 0b1001011 (* SPACE, TAB, NBSP, TRAILING *) else 0 in - let conv = Gobject.({ name = "draw-spaces"; conv = Data.int }) in - Gobject.set conv self#as_widget flag - in - stick show_spaces self cb; - - stick show_right_margin self self#set_show_right_margin; - stick spaces_instead_of_tabs self self#set_insert_spaces_instead_of_tabs; - stick tab_length self self#set_tab_width; - stick auto_complete self self#set_auto_complete; - stick auto_complete_delay self (fun d -> self#completion#set_auto_complete_delay d); - - let cb ft = self#misc#modify_font (GPango.font_description_from_string ft) in - stick text_font self cb; - - let () = self#completion#set_accelerators 0 in - let () = self#completion#set_show_headers false in - let _ = self#completion#add_provider (provider :> GSourceView3.source_completion_provider) in - - () - -end - -let script_view ct ?(source_buffer:GSourceView3.source_buffer option) ?draw_spaces = - GtkSourceView3.SourceView.make_params [] ~cont:( - GtkText.View.make_params ~cont:( - GContainer.pack_container ~create: - (fun pl -> - let w = match source_buffer with - | None -> GtkSourceView3.SourceView.new_ () - | Some buf -> GtkSourceView3.SourceView.new_with_buffer - (Gobject.try_cast buf#as_buffer "GtkSourceBuffer") - in - let w = Gobject.unsafe_cast w in - Gobject.set_params (Gobject.try_cast w "GtkSourceView") pl; - Gaux.may ~f:(GtkSourceView3.SourceView.set_draw_spaces w) draw_spaces; - ((new script_view w ct) : script_view)))) |
