1:- module(lsp_refactor, [ rename_at_location/4 ]). 2
3:- include('_lsp_path_add.pl'). 4
5:- use_module(library(apply_macros)). 6:- use_module(library(yall)). 7
8:- use_module(lsp(lsp_highlights)). 9:- use_module(lsp(lsp_source), [loaded_source/1]). 10:- use_module(lsp(lsp_reading_source)). 11:- use_module(lsp(lsp_utils)). 12
13rename_at_location(Uri, line_char(Line1, Char0), NewName, Edits) :-
14 url_path(Uri, Path),
15 16 17 lsp_highlights:highlights_at_position(Path, line_char(Line1, Char0), '$var'(_),
18 Positions), !,
19 maplist({NewName}/[P0, P1]>>put_dict(newText, P0, NewName, P1), Positions, Edits),
20 atom_string(AUri, Uri), 21 dict_create(Edits, _, [AUri=Edits]).
22rename_at_location(Uri, line_char(Line1, Char0), NewName, Edits) :-
23 url_path(Uri, Path),
24 clause_in_file_at_position(Clause, Path, line_char(Line1, Char0)),
25 clause_references(Clause, RefLocations),
26 clause_definitions(Clause, DefLocations),
27 clause_exports(Clause, ExportLocations),
28 clause_imports(Clause, ImportLocations),
29 30 append([RefLocations, DefLocations, ExportLocations, ImportLocations], Locations),
31 maplist({NewName}/[P0, P1]>>put_dict(newText, P0, NewName, P1), Locations, Edits0),
32 setof(
33 RefUri=DocEdits,
34 setof(
35 DocEdit,
36 Edit^(
37 member(Edit, Edits0),
38 del_dict(uri, Edit, RefUri, DocEdit)
39 ),
40 DocEdits
41 ),
42 EditsList
43 ),
44 dict_create(Edits, @, EditsList).
45
46clause_references(Clause, LLocations) :-
47 findall(
48 Locations,
49 ( loaded_source(Doc),
50 url_path(DocUri, Doc),
51 called_at(Doc, Clause, Locs0),
52 53 maplist({DocUri}/[D0, D]>>put_dict(uri, D0, DocUri, D), Locs0, Locations)
54 ),
55 LLocations0),
56 append(LLocations0, LLocations).
57
58clause_definitions(Clause, Locations) :-
59 name_callable(Clause, Callable),
60 findall(
61 Location,
62 ( loaded_source(Doc),
63 xref_source(Doc),
64 xref_defined(Doc, Callable, local(_)),
65 definition_location_in(Doc, Callable, Location)
66 ),
67 Locations).
68
69definition_location_in(Doc, Callable, Location) :-
70 file_lines_start_end(Doc, LineCharRange),
71 read_term_positions(Doc, TermPositions),
72 url_path(DocUri, Doc),
73 member(TermPos, TermPositions),
74 ( ( get_dict(term, TermPos, (Callable :- _)),
75 get_dict(subterm, TermPos, SubTermPos0),
76 SubTermPos0 = term_position(_, _, _, _, [term_position(_, _, FFrom, FTo, _)|_])
77 ) ; (
78 get_dict(term, TermPos, Callable),
79 get_dict(subterm, TermPos, SubTermPos0),
80 SubTermPos0 = term_position(_, _, FFrom, FTo, _)
81 ) ),
82 file_offset_line_position(LineCharRange, FFrom, StartLine1, StartChar),
83 succ(StartLine0, StartLine1),
84 file_offset_line_position(LineCharRange, FTo, EndLine1, EndChar),
85 succ(EndLine0, EndLine1),
86 Location = @{uri: DocUri,
87 range: @{start: @{line: StartLine0, character: StartChar},
88 end: @{line: EndLine0, character: EndChar}}}.
89
90clause_exports(Clause, Locations) :-
91 name_callable(Clause, Callable),
92 findall(
93 Location,
94 ( loaded_source(Doc),
95 xref_source(Doc),
96 xref_defined(Doc, Callable, local(_)),
97 export_location_in(Doc, Clause, Location)
98 ),
99 Locations).
100
101export_location_in(Doc, Clause, Location) :-
102 file_lines_start_end(Doc, LineCharRange),
103 read_term_positions(Doc, TermPositions),
104 member(TermPos, TermPositions),
105 get_dict(term, TermPos, (:- module(_, Exports))),
106 member(Clause, Exports), !,
107 find_in_term_with_positions(
108 {Clause}/[X, _]>>( nonvar(X), X = Clause ),
109 TermPos.term, TermPos.subterm,
110 Matches, []),
111 112 maplist([found_at(Name/_Arity, term_position(_F, _T, _FF, _FT, [Start-End|_]))]>>(
113 position_to_match(LineCharRange, found_at(Name, Start-End))
114 ),
115 Matches, Locations),
116 member(Location0, Locations),
117 url_path(Uri, Doc),
118 put_dict(uri, Location0, Uri, Location).
119
120clause_imports(Clause, Locations) :-
121 name_callable(Clause, Callable),
122 findall(
123 Location,
124 ( loaded_source(Doc),
125 xref_source(Doc),
126 127 xref_defined(Doc, Callable, imported(_)),
128 import_location_in(Doc, Clause, Location)
129 ),
130 Locations).
131
132import_location_in(Doc, Clause, Location) :-
133 file_lines_start_end(Doc, LineCharRange),
134 read_term_positions(Doc, TermPositions),
135 member(TermPos, TermPositions),
136 get_dict(term, TermPos, (:- use_module(_, Imports))),
137 member(Clause, Imports), !,
138 find_in_term_with_positions(
139 {Clause}/[X, _]>>( nonvar(X), X = Clause ),
140 TermPos.term, TermPos.subterm,
141 Matches, []),
142 143 maplist([found_at(Name/_Arity, term_position(_F, _T, _FF, _FT, [Start-End|_]))]>>(
144 position_to_match(LineCharRange, found_at(Name, Start-End))
145 ),
146 Matches, Locations),
147 member(Location0, Locations),
148 url_path(Uri, Doc),
149 put_dict(uri, Location0, Uri, Location)