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, csym).
203file_char(0'/, _).
204file_char(C, quoted(_)) :-
205 file_char(C).
206
207file_char(0'.).
208file_char(0'-).
209file_char(0'~).
210:- if(current_prolog_flag(windows,true)). 211file_char(0':).
212file_char(0'\s).
213:- endif.
219finish_file_name([Dir0], _, [Dir]) :-
220 exists_directory(Dir0),
221 !,
222 atom_concat(Dir0, '/', Dir).
223finish_file_name([File0], Close, [File]) :-
224 exists_file(File0),
225 close_file_name(File0, Close, File),
226 !.
227finish_file_name(Files0, _, Files) :-
228 maplist(tag_dir, Files0, Files).
229
230tag_dir(Dir, DirS) :-
231 exists_directory(Dir),
232 !,
233 atom_concat(Dir, /, DirS).
234tag_dir(File, File).
235
236close_file_name(File0, consult(Close), File) :-
237 file_name_extension(Base, Ext, File0),
238 user:prolog_file_type(Ext, prolog),
239 atom_concat(Base, Close, File).
240close_file_name(File0, quoted(Close), File) :-
241 atom_concat(File0, Close, File).
248complete_library(Prefix, Close, Libraries) :-
249 findall(Pairs, complete_one_libdir(Prefix, Pairs), DirPairs),
250 ( DirPairs = [LibDir-[f(File)]]
251 -> atom_concat(LibDir, Local, File),
252 atom_concat(Local, Close, Completion),
253 Libraries = [Completion]
254 ; DirPairs = [LibDir-[d(Dir)]]
255 -> atom_concat(LibDir, Local, Dir),
256 atom_concat(Local, '/', Completion),
257 Libraries = [Completion]
258 ; maplist(local_libs, DirPairs, FilesLists),
259 append(FilesLists, Libraries0),
260 sort(Libraries0, Libraries)
261 ).
262
263complete_one_libdir(Prefix, LibdirS-Files) :-
264 absolute_file_name(library(.), LibDir,
265 [ file_type(directory),
266 solutions(all)
267 ]),
268 atom_concat(LibDir, /, LibdirS),
269 atomic_list_concat([LibdirS, Prefix, '*'], Pattern),
270 expand_file_name(Pattern, Entries),
271 convlist(dir_or_source, Entries, Files0),
272 sort(Files0, Files),
273 Files \== [].
274
275local_libs(LibDir-Members, Locals) :-
276 maplist(local_file_name(LibDir), Members, Locals).
277
278local_file_name(LibDir, f(File), Local) :-
279 atom_concat(LibDir, Local, File).
280local_file_name(LibDir, d(Dir), Local) :-
281 atom_concat(LibDir, Local0, Dir),
282 atom_concat(Local0, /, Local).
283
284dir_or_source(Entry, f(Plain)) :-
285 file_name_extension(Plain, Ext, Entry),
286 user:prolog_file_type(Ext, prolog),
287 !.
288dir_or_source(Entry, d(Entry)) :-
289 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. */