Skip to content

Commit e9b8bb5

Browse files
authored
Merge pull request #211 from tlaplus/lsp-rename-step-v2
Small fixes in LSP step rename command.
2 parents f919bcc + 139c5d5 commit e9b8bb5

File tree

7 files changed

+113
-77
lines changed

7 files changed

+113
-77
lines changed

lsp/doc/proof_step_rename.gif

893 KB
Loading

lsp/doc/proof_step_renumber.gif

99.3 KB
Loading

lsp/lib/analysis/step_rename.ml

Lines changed: 75 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,49 @@
22
open Tlapm_lib
33
module StepMap = Map.Make (String)
44

5-
exception Found_the_step of string * int * Range.t list
5+
module StepInfo = struct
6+
type t = { name : string; label_offset : int; step_ranges : Range.t list }
7+
8+
let make level suffix step_loc =
9+
let prefix_str = Printf.sprintf "<%d>" level in
10+
let step_str = Printf.sprintf "<%d>%s" level suffix in
11+
let range = Range.of_locus_must step_loc in
12+
let range = Range.of_len range (String.length step_str) in
13+
{
14+
name = step_str;
15+
label_offset = String.length prefix_str;
16+
step_ranges = [ range ];
17+
}
18+
19+
let with_range si range = { si with step_ranges = range :: si.step_ranges }
20+
21+
let matching_range si range =
22+
List.find_opt
23+
(fun r -> Range.intersect range r || Range.touches range r)
24+
si.step_ranges
25+
26+
let step_label si =
27+
String.sub si.name si.label_offset (String.length si.name - si.label_offset)
28+
29+
let step_label_range si range = Range.crop_line_prefix range si.label_offset
30+
end
31+
32+
exception Found_the_step of StepInfo.t
633

734
class step_rename_visitor (at_loc : Range.t) =
835
object (self : 'self)
936
inherit Module.Visit.map as m_super
1037
inherit [unit] Proof.Visit.iter as p_super
11-
val mutable step_map : (int * Range.t list) StepMap.t = StepMap.empty
38+
val mutable step_map : StepInfo.t StepMap.t = StepMap.empty
1239

13-
(* Leaf at the `Proof.Visit.iter as p_super`.
40+
(* Leaf at the `Module.Visit.map as m_super`.
1441
We will look at `orig_pf`, it is closer to the initial source code. *)
15-
method! theorem cx name sq naxs _pf orig_pf summ =
16-
let pf = orig_pf in
17-
let ctx = Expr.Visit.empty () in
18-
self#proof ctx pf;
42+
method! theorem cx name sq naxs pf orig_pf summ =
43+
(if Range.lines_intersect at_loc (Range.of_wrapped_must orig_pf) then
44+
(* Only look for steps in proofs that intersects with the user selection. *)
45+
let pf = orig_pf in
46+
let ctx = Expr.Visit.empty () in
47+
self#proof ctx pf);
1948
m_super#theorem cx name sq naxs pf orig_pf summ
2049

2150
(* After each proof drop new step names that were defined within the proof.
@@ -33,14 +62,13 @@ class step_rename_visitor (at_loc : Range.t) =
3362
| _ -> ());
3463
(* If we are removing some step from the context, all its references
3564
are collected already. Check maybe we found what we were looking for. *)
36-
let matches range = Range.intersect range at_loc in
3765
step_map <-
3866
StepMap.filter
39-
(fun step_str (label_offset, step_ranges) ->
40-
if not (StepMap.mem step_str step_map_before) then (
41-
if List.exists matches step_ranges then
42-
raise (Found_the_step (step_str, label_offset, step_ranges));
43-
false)
67+
(fun step_str step_info ->
68+
if not (StepMap.mem step_str step_map_before) then
69+
match StepInfo.matching_range step_info at_loc with
70+
| None -> false
71+
| Some _ -> raise (Found_the_step step_info)
4472
else true)
4573
step_map
4674

@@ -63,32 +91,26 @@ class step_rename_visitor (at_loc : Range.t) =
6391
method add_step_opt stepno_opt (step_loc : Loc.locus) =
6492
match stepno_opt with
6593
| Proof.T.Named (level, suffix, false) ->
66-
let prefix_str = Printf.sprintf "<%d>" level in
67-
let step_str = Printf.sprintf "<%d>%s" level suffix in
68-
let range = Range.of_locus_must step_loc in
69-
let range = Range.of_len range (String.length step_str) in
70-
let step_info = (String.length prefix_str, [ range ]) in
71-
step_map <- StepMap.add step_str step_info step_map
94+
let si = StepInfo.make level suffix step_loc in
95+
step_map <- StepMap.add si.name si step_map
7296
| Proof.T.Named (_level, _suffix, true) -> ()
7397
| Proof.T.Unnamed (_, _) -> ()
7498

7599
(* Private helper. *)
76100
method add_step_range_opt (step_name : string) (locus : Loc.locus) =
77101
match StepMap.find_opt step_name step_map with
78102
| None -> ()
79-
| Some (label_offset, ranges) ->
80-
let new_info = (label_offset, Range.of_locus_must locus :: ranges) in
81-
step_map <- StepMap.add step_name new_info step_map
103+
| Some si ->
104+
let si = StepInfo.with_range si (Range.of_locus_must locus) in
105+
step_map <- StepMap.add step_name si step_map
82106
end
83107

84-
let find_ranges (at_loc : Range.t) (mule : Module.T.mule) :
85-
(string * int * Range.t list) option =
108+
let find_ranges (at_loc : Range.t) (mule : Module.T.mule) : StepInfo.t option =
86109
let visitor = new step_rename_visitor at_loc in
87110
try
88111
let _ = visitor#tla_module_root mule in
89112
None
90-
with Found_the_step (step_str, label_offset, step_ranges) ->
91-
Some (step_str, label_offset, step_ranges)
113+
with Found_the_step si -> Some si
92114

93115
let%test_module "poc renames" =
94116
(module struct
@@ -111,47 +133,47 @@ let%test_module "poc renames" =
111133
let%test_unit "find <1>1 by step name" =
112134
match find_ranges (Range.of_ints ~lf:3 ~cf:6 ~lt:3 ~ct:6) mule with
113135
| None -> assert false
114-
| Some (st_name, st_lb_o, st_ranges) ->
115-
assert (st_name = "<1>1");
116-
assert (st_lb_o = 3);
117-
assert (List.length st_ranges = 3);
118-
()
136+
| Some si ->
137+
assert (si.name = "<1>1");
138+
assert (si.label_offset = 3);
139+
assert (List.length si.step_ranges = 3)
119140

120141
let%test_unit "find <1>1 by step use" =
121142
match find_ranges (Range.of_ints ~lf:5 ~cf:18 ~lt:5 ~ct:18) mule with
122143
| None -> assert false
123-
| Some (st_name, st_lb_o, st_ranges) ->
124-
assert (st_name = "<1>1");
125-
assert (st_lb_o = 3);
126-
assert (List.length st_ranges = 3);
127-
()
144+
| Some si ->
145+
assert (si.name = "<1>1");
146+
assert (si.label_offset = 3);
147+
assert (List.length si.step_ranges = 3)
128148

129149
let%test_unit "find <1>2" =
130150
match find_ranges (Range.of_ints ~lf:4 ~cf:6 ~lt:4 ~ct:6) mule with
131151
| None -> assert false
132-
| Some (st_name, st_lb_o, st_ranges) ->
133-
assert (st_name = "<1>2");
134-
assert (st_lb_o = 3);
135-
assert (List.length st_ranges = 2);
136-
()
152+
| Some si ->
153+
assert (si.name = "<1>2");
154+
assert (si.label_offset = 3);
155+
assert (List.length si.step_ranges = 2)
156+
157+
let%test_unit "find <1>2 - start col" =
158+
match find_ranges (Range.of_ints ~lf:4 ~cf:5 ~lt:4 ~ct:5) mule with
159+
| None -> assert false
160+
| Some si -> assert (si.name = "<1>2")
161+
162+
let%test_unit "find <1>2 - end col" =
163+
match find_ranges (Range.of_ints ~lf:4 ~cf:9 ~lt:4 ~ct:9) mule with
164+
| None -> assert false
165+
| Some si -> assert (si.name = "<1>2")
137166

138167
let%test_unit "find <1>1 -- qed" =
139168
match find_ranges (Range.of_ints ~lf:5 ~cf:6 ~lt:5 ~ct:6) mule with
140169
| None -> assert false
141-
| Some (st_name, st_lb_o, st_ranges) ->
142-
assert (st_name = "<1>q");
143-
assert (st_lb_o = 3);
144-
assert (List.length st_ranges = 1);
145-
()
170+
| Some si ->
171+
assert (si.name = "<1>q");
172+
assert (si.label_offset = 3);
173+
assert (List.length si.step_ranges = 1)
146174

147175
let%test_unit "not found" =
148176
match find_ranges (Range.of_ints ~lf:2 ~cf:6 ~lt:2 ~ct:6) mule with
149177
| None -> ()
150-
| Some (_st_name, _st_lb_o, _st_ranges) -> assert false
178+
| Some _si -> assert false
151179
end)
152-
153-
let step_label step_name label_offset =
154-
String.sub step_name label_offset (String.length step_name - label_offset)
155-
156-
let step_label_range range label_offset =
157-
Range.crop_line_prefix range label_offset

lsp/lib/analysis/step_rename.mli

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
val find_ranges :
2-
Range.t -> Tlapm_lib.Module.T.mule -> (string * int * Range.t list) option
3-
(** Find ranges related to the step at the cursor position. *)
1+
module StepInfo : sig
2+
type t = { name : string; label_offset : int; step_ranges : Range.t list }
3+
4+
val matching_range : t -> Range.t -> Range.t option
5+
(** Returns a range where the step was mentioned and matches the specified
6+
range. *)
7+
8+
val step_label : t -> string
9+
(** Returns the label part of the step. *)
410

5-
val step_label : string -> int -> string
6-
val step_label_range : Range.t -> int -> Range.t
11+
val step_label_range : t -> Range.t -> Range.t
12+
(** Returns a label part range of a step. The range must be one of the step
13+
ranges. *)
14+
end
15+
16+
val find_ranges : Range.t -> Tlapm_lib.Module.T.mule -> StepInfo.t option
17+
(** Find ranges related to the step at the cursor position. *)

lsp/lib/range.ml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,7 @@ let of_lsp_range (range : LspT.Range.t) =
6868
R (f, t)
6969

7070
let of_lsp_position (pos : LspT.Position.t) =
71-
let p = (pos.line + 1, pos.character + 1) in
72-
R (p, p)
71+
R ((pos.line + 1, pos.character + 1), (pos.line + 1, pos.character))
7372

7473
let of_string_opt s =
7574
match String.split_on_char ':' s with
@@ -117,6 +116,12 @@ let of_all = R ((0, 0), (0, 0))
117116
(** [before p r] means range [r] is before point [p]. *)
118117
let before p r = Position.less (till r) p
119118

119+
(** [touches a b] is true, if ranges [a] and [b] touches with their endpoints.
120+
Consider here that the ranges here are with the end character inclusive.
121+
I.e. "..-x:10" touches with "x:11-.." *)
122+
let touches (R ((alf, acf), (alt, act))) (R ((blf, bcf), (blt, bct))) =
123+
(alt = blf && act + 1 = bcf) || (blt = alf && bct + 1 = acf)
124+
120125
(** [intersect a b] is true, if ranges [a] and [b] overlaps. *)
121126
let intersect a b =
122127
Position.leq (from a) (till b) && Position.leq (from b) (till a)

lsp/lib/range.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ val string_of_range : t -> string
3333
val string_of_pos : Position.t -> string
3434
val compare : t -> t -> int
3535
val before : Position.t -> t -> bool
36+
val touches : t -> t -> bool
3637
val intersect : t -> t -> bool
3738
val lines_intersect : t -> t -> bool
3839
val line_covered : t -> Position.t -> bool

lsp/lib/server/handlers.ml

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,14 @@ module Make (CB : Callbacks) = struct
237237
let uri = params.textDocument.uri in
238238
let pos = Range.of_lsp_position params.position in
239239
CB.with_docs cb_state @@ fun cb_st docs ->
240-
let f _vsn mule = Analysis.Step_rename.find_ranges pos mule in
240+
let open Analysis.Step_rename in
241+
let f _vsn mule = find_ranges pos mule in
241242
let docs, res = Docs.on_parsed_mule_latest docs uri f in
242243
let cb_st =
243244
match res with
244245
| None -> reply_ok jsonrpc_req `Null cb_st
245-
| Some (step_name, label_offset, step_ranges) -> (
246-
match List.find_opt (Range.intersect pos) step_ranges with
246+
| Some si -> (
247+
match StepInfo.matching_range si pos with
247248
| None -> reply_ok jsonrpc_req `Null cb_st
248249
| Some step_range ->
249250
reply_ok jsonrpc_req
@@ -252,12 +253,8 @@ module Make (CB : Callbacks) = struct
252253
( "range",
253254
LspT.Range.yojson_of_t
254255
(Range.as_lsp_range
255-
(Analysis.Step_rename.step_label_range step_range
256-
label_offset)) );
257-
( "placeholder",
258-
`String
259-
(Analysis.Step_rename.step_label step_name label_offset)
260-
);
256+
(StepInfo.step_label_range si step_range)) );
257+
("placeholder", `String (StepInfo.step_label si));
261258
])
262259
cb_st)
263260
in
@@ -267,27 +264,27 @@ module Make (CB : Callbacks) = struct
267264
(params : LspT.RenameParams.t) cb_state =
268265
let uri = params.textDocument.uri in
269266
let pos = Range.of_lsp_position params.position in
270-
let new_text = params.newName in
267+
let newText = params.newName in
271268
CB.with_docs cb_state @@ fun cb_st docs ->
272-
let f _vsn mule = Analysis.Step_rename.find_ranges pos mule in
269+
let open Analysis.Step_rename in
270+
let f _vsn mule = find_ranges pos mule in
273271
let docs, res = Docs.on_parsed_mule_latest docs uri f in
274272
let cb_st =
275273
match res with
276274
| None -> reply_ok jsonrpc_req `Null cb_st
277-
| Some (_step_name, label_offset, step_ranges) -> (
278-
match List.find_opt (Range.intersect pos) step_ranges with
275+
| Some si -> (
276+
match StepInfo.matching_range si pos with
279277
| None -> reply_ok jsonrpc_req `Null cb_st
280278
| Some _step_range ->
281279
let edits =
282280
List.map
283281
(fun step_range ->
284282
let range =
285283
Range.as_lsp_range
286-
(Analysis.Step_rename.step_label_range step_range
287-
label_offset)
284+
(StepInfo.step_label_range si step_range)
288285
in
289-
LspT.TextEdit.create ~newText:new_text ~range)
290-
step_ranges
286+
LspT.TextEdit.create ~newText ~range)
287+
si.step_ranges
291288
in
292289
let workspace_edit =
293290
LspT.WorkspaceEdit.create ~changes:[ (uri, edits) ] ()

0 commit comments

Comments
 (0)