Skip to content

Commit 47ad43b

Browse files
Merge PR #15772: Correctly prevent editable status of text when CoqIDE is busy.
Reviewed-by: herbelin Co-authored-by: herbelin <[email protected]>
2 parents 76075ca + 99b9080 commit 47ad43b

File tree

7 files changed

+132
-178
lines changed

7 files changed

+132
-178
lines changed

ide/coqide/coqide.ml

Lines changed: 17 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,6 @@ let on_current_term f =
7070
| None -> ()
7171
| Some t -> ignore (f t)
7272

73-
let on_current_term_val default f =
74-
let term = try Some notebook#current_term with Invalid_argument _ -> None in
75-
match term with
76-
| None -> default
77-
| Some t -> f t
78-
7973
let cb_on_current_term f _ = on_current_term f
8074

8175
(** Nota: using && here has the advantage of working both under win32 and unix.
@@ -1295,17 +1289,6 @@ let toggle_items menu_name l =
12951289

12961290
let no_under = Util.String.map (fun x -> if x = '_' then '-' else x)
12971291

1298-
(* workaround: GTKSourceView3 ignores editable *)
1299-
1300-
(* allowed in script panel, if editable, and elsewhere *)
1301-
let can_paste () =
1302-
on_current_term_val true (fun t ->
1303-
(t.script#is_focus && t.script#editable2) || not t.script#is_focus)
1304-
1305-
(* template insert only allowed in script panel *)
1306-
let can_template () =
1307-
on_current_term_val false (fun t -> t.script#is_focus && t.script#editable2)
1308-
13091292
(** Create alphabetical menu items with elements in sub-items.
13101293
[l] is a list of lists, one per initial letter *)
13111294

@@ -1328,9 +1311,7 @@ let alpha_items menu_name item_name l =
13281311
Buffer.contents buf
13291312
in
13301313
let callback _ =
1331-
on_current_term (fun sn ->
1332-
let text' = if can_template () then text' else "" in
1333-
sn.buffer#insert_interactive text')
1314+
on_current_term (fun sn -> sn.buffer#insert_interactive text')
13341315
in
13351316
item (item_name^" "^(no_under text)) ~label:text ~callback menu_name
13361317
in
@@ -1357,17 +1338,16 @@ let template_item (text, offset, len, key) =
13571338
let label = "_"^name^" __" in
13581339
let negoffset = String.length text - offset - len in
13591340
let callback sn =
1360-
if can_paste () then
1361-
let b = sn.buffer in
1362-
if b#insert_interactive text then begin
1363-
let iter = b#get_iter_at_mark `INSERT in
1364-
ignore (iter#nocopy#backward_chars negoffset);
1365-
b#move_mark `INSERT ~where:iter;
1366-
ignore (iter#nocopy#backward_chars len);
1367-
b#move_mark `SEL_BOUND ~where:iter;
1368-
end
1369-
in
1370-
item name ~label ~callback:(cb_on_current_term callback) ~accel:(modifier^key)
1341+
let b = sn.buffer in
1342+
if b#insert_interactive text then begin
1343+
let iter = b#get_iter_at_mark `INSERT in
1344+
ignore (iter#nocopy#backward_chars negoffset);
1345+
b#move_mark `INSERT ~where:iter;
1346+
ignore (iter#nocopy#backward_chars len);
1347+
b#move_mark `SEL_BOUND ~where:iter;
1348+
end
1349+
in
1350+
item name ~label ~callback:(cb_on_current_term callback) ~accel:(modifier^key)
13711351

13721352
(** Create menu items for pairs (query, shortcut key). *)
13731353
let user_queries_items menu_name item_name l =
@@ -1448,19 +1428,15 @@ let build_ui () =
14481428
menu edit_menu [
14491429
item "Edit" ~label:"_Edit";
14501430
item "Undo" ~accel:"<Primary>u" ~stock:`UNDO
1451-
~callback:(cb_on_current_term (fun t -> if can_paste () then
1452-
t.script#undo ()));
1431+
~callback:(cb_on_current_term (fun t -> t.script#undo ()));
14531432
item "Redo" ~stock:`REDO
1454-
~callback:(cb_on_current_term (fun t -> if can_paste () then
1455-
t.script#redo ()));
1433+
~callback:(cb_on_current_term (fun t -> t.script#redo ()));
14561434
item "Cut" ~stock:`CUT
1457-
~callback:(fun _ -> if can_paste () then
1458-
emit_to_focus w GtkText.View.S.cut_clipboard);
1435+
~callback:(fun _ -> emit_to_focus w GtkText.View.S.cut_clipboard);
14591436
item "Copy" ~stock:`COPY
14601437
~callback:(fun _ -> emit_to_focus w GtkText.View.S.copy_clipboard);
14611438
item "Paste" ~stock:`PASTE
1462-
~callback:(fun _ -> if can_paste () then
1463-
emit_to_focus w GtkText.View.S.paste_clipboard);
1439+
~callback:(fun _ -> emit_to_focus w GtkText.View.S.paste_clipboard);
14641440
item "Find" ~stock:`FIND ~label:"Find / Replace"
14651441
~callback:(cb_on_current_term (fun t -> t.finder#show ()));
14661442
item "Find Next" ~label:"Find _Next" ~stock:`GO_DOWN ~accel:"F3"
@@ -1590,11 +1566,9 @@ let build_ui () =
15901566
menu tools_menu [
15911567
item "Tools" ~label:"_Tools";
15921568
item "Comment" ~label:"_Comment" ~accel:"<CTRL>D"
1593-
~callback:(cb_on_current_term (fun t -> if can_paste () then
1594-
t.script#comment ()));
1569+
~callback:(cb_on_current_term (fun t -> t.script#comment ()));
15951570
item "Uncomment" ~label:"_Uncomment" ~accel:"<CTRL><SHIFT>D"
1596-
~callback:(cb_on_current_term (fun t -> if can_paste () then
1597-
t.script#uncomment ()));
1571+
~callback:(cb_on_current_term (fun t -> t.script#uncomment ()));
15981572
item "Coqtop arguments" ~label:"Coqtop _arguments"
15991573
~callback:MiscMenu.coqtop_arguments;
16001574
item "LaTeX-to-unicode" ~label:"_LaTeX-to-unicode" ~accel:"<Shift>space"

ide/coqide/session.ml

Lines changed: 74 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -118,34 +118,40 @@ let create_script coqtop source_buffer =
118118

119119
let misc () = CDebug.(get_flag misc)
120120

121+
type action_stack = Gtk.text_mark list option
122+
123+
let call_coq_or_cancel_action coqtop coqops (buffer : GText.buffer) it =
124+
let () = try buffer#delete_mark (`NAME "target") with GText.No_such_mark _ -> () in
125+
let mark = buffer#create_mark ~name:"target" it in
126+
let action = coqops#go_to_mark (`MARK mark) in
127+
ignore @@ Coq.try_grab coqtop action (fun () -> ())
128+
129+
let init_user_action (stack : action_stack ref) = match !stack with
130+
| None -> stack := Some []
131+
| Some _ -> assert false
132+
133+
let close_user_action (stack : action_stack ref) = match !stack with
134+
| None -> assert false
135+
| Some marks ->
136+
let () = stack := None in
137+
marks
138+
139+
let handle_iter coqtop coqops (buffer : GText.buffer) it stack = match it with
140+
| None -> ()
141+
| Some it ->
142+
match !stack with
143+
| Some marks ->
144+
(* We are inside an user action, deferring to its end *)
145+
let mark = buffer#create_mark it in
146+
stack := Some (mark :: marks)
147+
| None ->
148+
(* Otherwise we move to the mark now *)
149+
call_coq_or_cancel_action coqtop coqops buffer it
150+
121151
let set_buffer_handlers
122152
(buffer : GText.buffer) script (coqops : CoqOps.ops) coqtop
123153
=
124-
let action_was_cancelled = ref true in
125-
let no_coq_action_required = ref true in
126-
let cur_action = ref 0 in
127-
let new_action_id =
128-
let id = ref 0 in
129-
fun () -> incr id; !id in
130-
let running_action = ref None in
131-
let cancel_signal ?(stop_emit=true) reason =
132-
Minilib.log ("user_action cancelled: "^reason);
133-
action_was_cancelled := true;
134-
if stop_emit then GtkSignal.stop_emit () in
135-
let del_mark () =
136-
try buffer#delete_mark (`NAME "target")
137-
with GText.No_such_mark _ -> () in
138-
let add_mark it = del_mark (); buffer#create_mark ~name:"target" it in
139-
let call_coq_or_cancel_action f =
140-
no_coq_action_required := false;
141-
let action = !cur_action in
142-
let action, fallback =
143-
Coq.seq (Coq.lift (fun () -> running_action := Some action)) f,
144-
fun () -> (* If Coq is busy due to the current action, we don't cancel *)
145-
match !running_action with
146-
| Some aid when aid = action -> ()
147-
| _ -> cancel_signal ~stop_emit:false "Coq busy" in
148-
ignore @@ Coq.try_grab coqtop action fallback in
154+
let action_stack = ref None in
149155
let get_start () = buffer#get_iter_at_mark (`NAME "start_of_input") in
150156
let get_stop () = buffer#get_iter_at_mark (`NAME "stop_of_input") in
151157
let ensure_marks_exist () =
@@ -172,63 +178,55 @@ let set_buffer_handlers
172178
aux it it#copy in
173179
let insert_cb it s = if String.length s = 0 then () else begin
174180
if misc () then Minilib.log ("insert_cb " ^ string_of_int it#offset);
175-
let text_mark = add_mark it in
176181
let () = update_prev it in
177-
if it#has_tag Tags.Script.to_process ||
178-
it#has_tag Tags.Script.incomplete then
179-
cancel_signal "Altering the script being processed is not implemented"
180-
else if it#has_tag Tags.Script.processed then
181-
(* note code in Wg_scriptview.keypress_cb *)
182-
call_coq_or_cancel_action (coqops#go_to_mark (`MARK text_mark))
183-
else if it#has_tag Tags.Script.error_bg then begin
184-
match processed_sentence_just_before_error it with
185-
| None -> ()
186-
| Some prev_sentence_end ->
187-
let text_mark = add_mark prev_sentence_end in
188-
call_coq_or_cancel_action (coqops#go_to_mark (`MARK text_mark))
189-
end end in
182+
let iter =
183+
if it#has_tag Tags.Script.processed then Some it
184+
else if it#has_tag Tags.Script.error_bg then
185+
processed_sentence_just_before_error it
186+
else None
187+
in
188+
handle_iter coqtop coqops buffer iter action_stack
189+
end
190+
in
190191
let delete_cb ~start ~stop =
191192
if misc () then Minilib.log (Printf.sprintf "delete_cb %d %d" start#offset stop#offset);
192193
let min_iter, max_iter =
193194
if start#compare stop < 0 then start, stop else stop, start in
194195
let () = update_prev min_iter in
195-
let text_mark = add_mark min_iter in
196-
let rec aux min_iter =
197-
if min_iter#equal max_iter then ()
198-
else if min_iter#has_tag Tags.Script.to_process ||
199-
min_iter#has_tag Tags.Script.incomplete then
200-
cancel_signal "Altering the script being processed is not implemented"
201-
else if min_iter#has_tag Tags.Script.processed then
202-
call_coq_or_cancel_action (coqops#go_to_mark (`MARK text_mark))
203-
else if min_iter#has_tag Tags.Script.error_bg then
204-
match processed_sentence_just_before_error min_iter with
205-
| None -> ()
206-
| Some prev_sentence_end ->
207-
let text_mark = add_mark prev_sentence_end in
208-
call_coq_or_cancel_action (coqops#go_to_mark (`MARK text_mark))
209-
else aux min_iter#forward_char in
210-
aux min_iter in
196+
let rec aux iter =
197+
if iter#equal max_iter then None
198+
else if iter#has_tag Tags.Script.processed then
199+
Some min_iter
200+
else if iter#has_tag Tags.Script.error_bg then
201+
processed_sentence_just_before_error iter
202+
else aux iter#forward_char
203+
in
204+
let iter = aux min_iter in
205+
handle_iter coqtop coqops buffer iter action_stack
206+
in
211207
let begin_action_cb () =
212-
if misc () then Minilib.log "begin_action_cb";
213-
action_was_cancelled := false;
214-
no_coq_action_required := true;
215-
cur_action := new_action_id ();
208+
let () = if misc () then Minilib.log "begin_action_cb" in
209+
let () = init_user_action action_stack in
216210
let where = get_insert () in
217-
buffer#move_mark (`NAME "prev_insert") ~where in
211+
buffer#move_mark (`NAME "prev_insert") ~where
212+
in
218213
let end_action_cb () =
219-
if misc () then Minilib.log "end_action_cb";
220-
ensure_marks_exist ();
221-
if not !action_was_cancelled then begin
214+
let () = if misc () then Minilib.log "end_action_cb" in
215+
let marks = close_user_action action_stack in
216+
let () = ensure_marks_exist () in
217+
if CList.is_empty marks then
218+
let start, stop = get_start (), get_stop () in
219+
let () = List.iter (fun tag -> buffer#remove_tag tag ~start ~stop) Tags.Script.ephemere in
220+
Sentence.tag_on_insert buffer
221+
else
222222
(* If coq was asked to backtrack, the cleanup must be done by the
223223
backtrack_until function, since it may move the stop_of_input
224224
to a point indicated by coq. *)
225-
if !no_coq_action_required then begin
226-
let start, stop = get_start (), get_stop () in
227-
List.iter (fun tag -> buffer#remove_tag tag ~start ~stop)
228-
Tags.Script.ephemere;
229-
Sentence.tag_on_insert buffer
230-
end;
231-
end in
225+
let iters = List.map (fun mark -> buffer#get_iter_at_mark (`MARK mark)) marks in
226+
let iter = List.hd @@ List.sort (fun it1 it2 -> it1#compare it2) iters in
227+
let () = List.iter (fun mark -> try buffer#delete_mark (`MARK mark) with GText.No_such_mark _ -> ()) marks in
228+
call_coq_or_cancel_action coqtop coqops buffer iter
229+
in
232230
let mark_deleted_cb m =
233231
match GtkText.Mark.get_name m with
234232
| Some "insert" -> ()
@@ -244,7 +242,13 @@ let set_buffer_handlers
244242
| Some s -> if misc () then Minilib.log (s^" moved")
245243
| None -> ()
246244
in
245+
let set_busy b =
246+
let prop = `EDITABLE b in
247+
let tags = [Tags.Script.processed] in
248+
List.iter (fun tag -> tag#set_property prop) tags
249+
in
247250
(* Pluging callbacks *)
251+
let () = Coq.setup_script_editable coqtop set_busy in
248252
let _ = buffer#connect#insert_text ~callback:insert_cb in
249253
let _ = buffer#connect#delete_range ~callback:delete_cb in
250254
let _ = buffer#connect#begin_user_action ~callback:begin_action_cb in
@@ -409,7 +413,6 @@ let create file coqtop_args =
409413
let reset () = Coq.reset_coqtop coqtop in
410414
let buffer = create_buffer () in
411415
let script = create_script coqtop buffer in
412-
Coq.setup_script_editable coqtop (fun v -> script#set_editable2 v);
413416
let proof = create_proof () in
414417
incr next_sid;
415418
let sid = !next_sid in
@@ -421,7 +424,6 @@ let create file coqtop_args =
421424
let messages = create_messages () in
422425
let segment = new Wg_Segment.segment () in
423426
let finder = new Wg_Find.finder basename (script :> GText.view) in
424-
finder#setup_is_script_editable (fun _ -> script#editable2);
425427
let debugger = Wg_Debugger.debugger (Printf.sprintf "Debugger (%s)" basename) sid in
426428
let fops = new FileOps.fileops (buffer :> GText.buffer) file reset in
427429
let _ = fops#update_stats in

ide/coqide/tags.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ struct
2222
let warning = make_tag table ~name:"warning" [`UNDERLINE `SINGLE; `FOREGROUND "blue"]
2323
let error = make_tag table ~name:"error" [`UNDERLINE `SINGLE]
2424
let error_bg = make_tag table ~name:"error_bg" []
25-
let to_process = make_tag table ~name:"to_process" []
25+
let to_process = make_tag table ~name:"to_process" [`EDITABLE false]
2626
let processed = make_tag table ~name:"processed" []
2727
let debugging = make_tag table ~name:"debugging" []
28-
let incomplete = make_tag table ~name:"incomplete" []
28+
let incomplete = make_tag table ~name:"incomplete" [`EDITABLE false]
2929
let unjustified = make_tag table ~name:"unjustified" [`BACKGROUND "gold"]
3030
let tooltip = make_tag table ~name:"tooltip" [] (* debug:`BACKGROUND "blue" *)
3131
let ephemere =

ide/coqide/wg_Find.ml

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,7 @@ class finder name (view : GText.view) =
5656
let stop = view#buffer#get_iter `SEL_BOUND in
5757
view#buffer#get_text ~start ~stop ()
5858

59-
val mutable is_script_editable = ((fun _ -> failwith "is_script_editable") : unit -> bool)
60-
61-
method setup_is_script_editable (f : unit -> bool) = is_script_editable <- f
62-
6359
method private may_replace () =
64-
(is_script_editable ()) &&
6560
(self#search_text <> "") &&
6661
(Str.string_match self#regex (self#get_selected_word ()) 0)
6762

@@ -135,11 +130,9 @@ class finder name (view : GText.view) =
135130
let next_ct = if edited then ct + 1 else ct in
136131
replace_at next next_ct (tot + 1)
137132
in
138-
if is_script_editable () then begin
139-
let () = view#buffer#begin_user_action () in
140-
let () = replace_at view#buffer#start_iter 0 0 in
141-
view#buffer#end_user_action ()
142-
end
133+
let () = view#buffer#begin_user_action () in
134+
let () = replace_at view#buffer#start_iter 0 0 in
135+
view#buffer#end_user_action ()
143136

144137
method private set_not_found () =
145138
find_entry#misc#modify_bg [`NORMAL, `NAME "#F7E6E6"];

ide/coqide/wg_Find.mli

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,4 @@ class finder : string -> GText.view ->
1717
method replace_all : unit -> unit
1818
method find_backward : unit -> unit
1919
method find_forward : unit -> unit
20-
method setup_is_script_editable : (unit -> bool) -> unit
2120
end

0 commit comments

Comments
 (0)