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 = alias(Alias, Close)
105 -> complete_alias(Alias, 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, alias(Alias, Close)) -->
190 file_chars(RevString, unquoted),
191 file_search_alias(Alias),
192 ( "["
193 -> {Close = ')]'}
194 ; {Alias == library,
195 Close = ')'
196 }
197 ),
198 !,
199 remainder(_),
200 { reverse(RevString, String),
201 atom_codes(Prefix, String)
202 }.
203
204file_chars([H|T], Style) --> file_char(H, Style), !, file_chars(T, Style).
205file_chars([], _) --> [].
206
207file_char(C, Style) --> [C], { file_char(C, Style) }.
208
209file_char(C, _) :- code_type(C, alnum). 210file_char(0'_, _). 211file_char(0'/, _).
212file_char(C, quoted(_)) :-
213 file_char(C).
214
215file_char(0'.).
216file_char(0'-).
217file_char(0'~).
218:- if(current_prolog_flag(windows,true)). 219file_char(0':).
220file_char(0'\s).
221:- endif. 222
223file_search_alias(Alias) -->
224 "(", alias_chars(RevCodes),
225 { reverse(RevCodes, Codes),
226 atom_codes(Alias, Codes),
227 user:file_search_path(Alias, _)
228 },
229 !.
230
231alias_chars([H|T]) --> [H], { code_type(H, csym) }, !, alias_chars(T).
232alias_chars([]) --> [].
239finish_file_name([Dir0], _, [Dir]) :-
240 exists_directory(Dir0),
241 !,
242 atom_concat(Dir0, '/', Dir).
243finish_file_name([File0], Close, [File]) :-
244 exists_file(File0),
245 close_file_name(File0, Close, File),
246 !.
247finish_file_name(Files0, _, Files) :-
248 maplist(tag_dir, Files0, Files).
249
250tag_dir(Dir, DirS) :-
251 exists_directory(Dir),
252 !,
253 atom_concat(Dir, /, DirS).
254tag_dir(File, File).
255
256close_file_name(File0, consult(Close), File) :-
257 file_name_extension(Base, Ext, File0),
258 user:prolog_file_type(Ext, prolog),
259 atom_concat(Base, Close, File).
260close_file_name(File0, quoted(Close), File) :-
261 atom_concat(File0, Close, File).
268complete_alias(Alias, Prefix, Close, Libraries) :-
269 findall(Pairs, complete_one_alias(Alias, Prefix, Pairs), DirPairs),
270 ( DirPairs = [LibDir-[f(File)]]
271 -> atom_concat(LibDir, Local, File),
272 atom_concat(Local, Close, Completion),
273 Libraries = [Completion]
274 ; DirPairs = [LibDir-[d(Dir)]]
275 -> atom_concat(LibDir, Local, Dir),
276 atom_concat(Local, '/', Completion),
277 Libraries = [Completion]
278 ; maplist(local_libs, DirPairs, FilesLists),
279 append(FilesLists, Libraries0),
280 sort(Libraries0, Libraries)
281 ).
282
283complete_one_alias(Alias, Prefix, LibdirS-Files) :-
284 DirTerm =.. [Alias, '.'],
285 absolute_file_name(DirTerm, LibDir,
286 [ file_type(directory),
287 solutions(all)
288 ]),
289 atom_concat(LibDir, /, LibdirS),
290 atomic_list_concat([LibdirS, Prefix, '*'], Pattern),
291 expand_file_name(Pattern, Entries),
292 convlist(dir_or_source, Entries, Files0),
293 sort(Files0, Files),
294 Files \== [].
295
296local_libs(LibDir-Members, Locals) :-
297 maplist(local_file_name(LibDir), Members, Locals).
298
299local_file_name(LibDir, f(File), Local) :-
300 atom_concat(LibDir, Local, File).
301local_file_name(LibDir, d(Dir), Local) :-
302 atom_concat(LibDir, Local0, Dir),
303 atom_concat(Local0, /, Local).
304
305dir_or_source(Entry, f(Plain)) :-
306 file_name_extension(Plain, Ext, Entry),
307 user:prolog_file_type(Ext, prolog),
308 !.
309dir_or_source(Entry, d(Entry)) :-
310 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.