35
36:- module(prolog_console_input,
37 [
38 ]). 39:- autoload(library(lists), [reverse/2, append/2]). 40:- autoload(library(dcg/basics), [remainder/3]). 41:- autoload(library(apply), [maplist/3, convlist/3]).
52:- multifile
53 prolog:complete_input/4.
96prolog:complete_input(Before, After, Delete, Completions) :-
97 string_codes(Before, Chars),
98 reverse(Chars, BeforeRev),
99 complete(BeforeRev, After, Delete, Completions).
100
101complete(BeforeRev, _After, Prefix, Files) :- 102 phrase(file_prefix(Prefix, Type), BeforeRev),
103 !,
104 ( Type = library(Close)
105 -> complete_library(Prefix, Close, Files)
106 ; atom_concat(Prefix, '*', Pattern),
107 expand_file_name(Pattern, Files0),
108 finish_file_name(Files0, Type, Files)
109 ).
110complete(BeforeRev, After, Prefix, Completions) :- 111 phrase(identifier_prefix_r(Prefix, Type), BeforeRev, BeforeRev1),
112 !,
113 identifier_completions(Type, Prefix, BeforeRev1, After, Completions).
114
115identifier_completions(atom, Prefix, _, _, Atoms) :-
116 '$atom_completions'(Prefix, Atoms).
117identifier_completions(var, Prefix, BeforeRev, After, Vars) :-
118 findall(Var, var_starts(Prefix, BeforeRev, After, Var), Vars0),
119 sort(Vars0, Vars).
120
121var_starts(Prefix, [0'$|_], _After, Var) :- 122 !,
123 recorded('$topvar', Var = _),
124 sub_atom(Var, 0, _, _, Prefix).
125var_starts(Prefix, BeforeRev, _After, Var) :- 126 phrase((..., nonid_char, identifier_prefix_r(Var, var)),
127 BeforeRev, _),
128 sub_string(Var, 0, _, _, Prefix).
129var_starts(Prefix, _BeforeRev, AfterString, Var) :- 130 string_codes(AfterString, After),
131 phrase((..., nonid_char, identifier_prefix(Var, var)),
132 After, _),
133 sub_string(Var, 0, _, _, Prefix).
134
135... --> [] ; [_], ... .
136
137nonid_char -->
138 [C],
139 { \+ code_type(C, prolog_identifier_continue) }.
144identifier_prefix(Prefix, Type) -->
145 atom_chars(String),
146 { String = [H|_],
147 ( code_type(H, prolog_var_start)
148 -> Type = var
149 ; Type = atom
150 ),
151 string_codes(Prefix, String) 152 }.
153
154identifier_prefix_r(Prefix, Type) -->
155 atom_chars(RevString),
156 { reverse(RevString, String),
157 String = [H|_],
158 ( code_type(H, prolog_var_start)
159 -> Type = var
160 ; Type = atom
161 ),
162 string_codes(Prefix, String) 163 }.
164
165atom_chars([H|T]) --> atom_char(H), !, atom_chars(T).
166atom_chars([]) --> [].
167
168atom_char(C) --> [C], { atom_char(C) }.
169
170atom_char(C) :- code_type(C, prolog_identifier_continue).
176file_prefix(Prefix, file) -->
177 file_chars(RevString, quoted('\'')), "'",
178 !,
179 remainder(_),
180 { reverse(RevString, String),
181 atom_codes(Prefix, String)
182 }.
183file_prefix(Prefix, consult(']')) -->
184 file_chars(RevString, unquoted), "[",
185 !,
186 { reverse(RevString, String),
187 atom_codes(Prefix, String)
188 }.
189file_prefix(Prefix, library(')')) -->
190 file_chars(RevString, unquoted), "(yrarbil",
191 !,
192 remainder(_),
193 { reverse(RevString, String),
194 atom_codes(Prefix, String)
195 }.
196
197file_chars([H|T], Style) --> file_char(H, Style), !, file_chars(T, Style).
198file_chars([], _) --> [].
199
200file_char(C, Style) --> [C], { file_char(C, Style) }.
201
202file_char(C, _) :- code_type(C, alnum). 203file_char(0'_, _). 204file_char(0'/, _).
205file_char(C, quoted(_)) :-
206 file_char(C).
207
208file_char(0'.).
209file_char(0'-).
210file_char(0'~).
211:- if(current_prolog_flag(windows,true)). 212file_char(0':).
213file_char(0'\s).
214:- endif.
220finish_file_name([Dir0], _, [Dir]) :-
221 exists_directory(Dir0),
222 !,
223 atom_concat(Dir0, '/', Dir).
224finish_file_name([File0], Close, [File]) :-
225 exists_file(File0),
226 close_file_name(File0, Close, File),
227 !.
228finish_file_name(Files0, _, Files) :-
229 maplist(tag_dir, Files0, Files).
230
231tag_dir(Dir, DirS) :-
232 exists_directory(Dir),
233 !,
234 atom_concat(Dir, /, DirS).
235tag_dir(File, File).
236
237close_file_name(File0, consult(Close), File) :-
238 file_name_extension(Base, Ext, File0),
239 user:prolog_file_type(Ext, prolog),
240 atom_concat(Base, Close, File).
241close_file_name(File0, quoted(Close), File) :-
242 atom_concat(File0, Close, File).
249complete_library(Prefix, Close, Libraries) :-
250 findall(Pairs, complete_one_libdir(Prefix, Pairs), DirPairs),
251 ( DirPairs = [LibDir-[f(File)]]
252 -> atom_concat(LibDir, Local, File),
253 atom_concat(Local, Close, Completion),
254 Libraries = [Completion]
255 ; DirPairs = [LibDir-[d(Dir)]]
256 -> atom_concat(LibDir, Local, Dir),
257 atom_concat(Local, '/', Completion),
258 Libraries = [Completion]
259 ; maplist(local_libs, DirPairs, FilesLists),
260 append(FilesLists, Libraries0),
261 sort(Libraries0, Libraries)
262 ).
263
264complete_one_libdir(Prefix, LibdirS-Files) :-
265 absolute_file_name(library(.), LibDir,
266 [ file_type(directory),
267 solutions(all)
268 ]),
269 atom_concat(LibDir, /, LibdirS),
270 atomic_list_concat([LibdirS, Prefix, '*'], Pattern),
271 expand_file_name(Pattern, Entries),
272 convlist(dir_or_source, Entries, Files0),
273 sort(Files0, Files),
274 Files \== [].
275
276local_libs(LibDir-Members, Locals) :-
277 maplist(local_file_name(LibDir), Members, Locals).
278
279local_file_name(LibDir, f(File), Local) :-
280 atom_concat(LibDir, Local, File).
281local_file_name(LibDir, d(Dir), Local) :-
282 atom_concat(LibDir, Local0, Dir),
283 atom_concat(Local0, /, Local).
284
285dir_or_source(Entry, f(Plain)) :-
286 file_name_extension(Plain, Ext, Entry),
287 user:prolog_file_type(Ext, prolog),
288 !.
289dir_or_source(Entry, d(Entry)) :-
290 exists_directory(Entry)
Support entering toplevel queries
This module implements prolog:complete_input/4, which is used notably by the command line editor library(edit) to perform context aware TAB completion. It is a seperate library such that other input scenarios can reuse this code.