37
38:- module('$history',
39 [ read_term_with_history/2 40 ]). 41
42:- multifile
43 prolog:history/2. 44
49
50read_term_with_history(Term, Options) :-
51 '$option'(prompt(Prompt), Options, '~! ?-'),
52 '$option'(input(Input), Options, user_input),
53 repeat,
54 prompt_history(Prompt),
55 '$toplevel':read_query_line(Input, Raw),
56 read_history_(Raw, Term, Options),
57 !.
58
59read_history_(Raw, _Term, Options) :-
60 '$option'(show(Raw), Options, history),
61 list_history,
62 !,
63 fail.
64read_history_(Raw, _Term, Options) :-
65 '$option'(help(Raw), Options, '!help'),
66 '$option'(show(Show), Options, '!history'),
67 print_message(help, history(help(Show, Raw))),
68 !,
69 fail.
70read_history_(Raw, Term, Options) :-
71 expand_history(Raw, Expanded, Changed),
72 add_to_history(Expanded, Options),
73 '$option'(module(Module), Options, Var),
74 ( Module == Var
75 -> '$current_typein_module'(Module)
76 ; true
77 ),
78 '$option'(variable_names(Bindings), Options, Bindings0),
79 history_blob_mode(Changed, BlobMode),
80 catch(read_term_from_atom(Expanded, Term0,
81 [ module(Module),
82 variable_names(Bindings0),
83 blob(BlobMode)
84 ]),
85 E,
86 ( print_message(error, E),
87 fail
88 )),
89 ( var(Term0)
90 -> Term = Term0,
91 Bindings = Bindings0
92 ; ( Changed == true
93 -> print_message(query, history(expanded(Expanded)))
94 ; true
95 ),
96 Term = Term0,
97 Bindings = Bindings0
98 ).
99
107
108history_blob_mode(true, dead) :- !. 109history_blob_mode(_, resolve).
110
114
115list_history :-
116 prolog:history(current_input, events(Events0)),
117 !,
118 '$reverse'(Events0, Events),
119 print_message(query, history(history(Events))).
120list_history :-
121 print_message(query, history(no_history)).
122
127
128prompt_history('') :-
129 !,
130 ttyflush.
131prompt_history(Prompt) :-
132 ( prolog:history(current_input, curr(Curr, _))
133 -> This is Curr + 1
134 ; This = 1
135 ),
136 atom_codes(Prompt, SP),
137 atom_codes(This, ST),
138 ( atom_codes('~!', Repl),
139 substitute(Repl, ST, SP, String)
140 -> prompt1(String)
141 ; prompt1(Prompt)
142 ),
143 ttyflush.
144
148
149substitute(Old, New, String, Substituted) :-
150 '$append'(Head, OldAndTail, String),
151 '$append'(Old, Tail, OldAndTail),
152 !,
153 '$append'(Head, New, HeadAndNew),
154 '$append'(HeadAndNew, Tail, Substituted).
155
160
161add_to_history(end_of_file, _) :- !.
162add_to_history(Line, Options) :-
163 '$option'(no_save(NoSave), Options),
164 catch(term_string(Query, Line), error(_,_), fail),
165 nonvar(Query),
166 memberchk(Query, NoSave),
167 !.
168add_to_history(Line, _Options) :-
169 format(string(CompleteLine), '~W~W',
170 [ Line, [partial(true)],
171 '.', [partial(true)]
172 ]),
173 catch(prolog:history(user_input, add(CompleteLine)), _, fail),
174 !.
175add_to_history(_, _).
176
187
188expand_history(Raw, Expanded, Changed) :-
189 atom_chars(Raw, RawString),
190 expand_history2(RawString, ExpandedString, Changed),
191 atom_chars(Expanded, ExpandedString),
192 !.
193
194expand_history2([!], [!], false) :- !.
195expand_history2([!, C|Rest], [!|Expanded], Changed) :-
196 not_event_char(C),
197 !,
198 expand_history2([C|Rest], Expanded, Changed).
199expand_history2([!|Rest], Expanded, true) :-
200 !,
201 match_event(Rest, Event, NewRest),
202 '$append'(Event, RestExpanded, Expanded),
203 !,
204 expand_history2(NewRest, RestExpanded, _).
205expand_history2(['\''|In], ['\''|Out], Changed) :-
206 !,
207 skip_quoted(In, '\'', Out, Tin, Tout),
208 expand_history2(Tin, Tout, Changed).
209expand_history2(['"'|In], ['"'|Out], Changed) :-
210 !,
211 skip_quoted(In, '"', Out, Tin, Tout),
212 expand_history2(Tin, Tout, Changed).
213expand_history2([H|T], [H|R], Changed) :-
214 !,
215 expand_history2(T, R, Changed).
216expand_history2([], [], false).
217
218skip_quoted([Q|T],Q,[Q|R], T, R) :- !.
219skip_quoted([\,Q|T0],Q,[\,Q|T], In, Out) :-
220 !,
221 skip_quoted(T0, Q, T, In, Out).
222skip_quoted([Q,Q|T0],Q,[Q,Q|T], In, Out) :-
223 !,
224 skip_quoted(T0, Q, T, In, Out).
225skip_quoted([C|T0],Q,[C|T], In, Out) :-
226 !,
227 skip_quoted(T0, Q, T, In, Out).
228skip_quoted([], _, [], [], []).
229
234
235get_last_event(Event) :-
236 prolog:history(current_input, first(_Num, String)),
237 string_chars(String, Event0),
238 remove_full_stop(Event0, Event),
239 !.
240get_last_event(_) :-
241 print_message(query, history(no_event)),
242 fail.
243
244remove_full_stop(In, Out) :-
245 phrase(remove_full_stop(Out), In).
246
247remove_full_stop([]) -->
248 spaces, ['.'], spaces, eos,
249 !.
250remove_full_stop([H|T]) -->
251 [H], !,
252 remove_full_stop(T).
253remove_full_stop([]) -->
254 [].
255
256spaces --> space, !, spaces.
257spaces --> [].
258
259space -->
260 [C],
261 { char_type(C, space) }.
262
263eos([], []).
264
268
269match_event(Spec, Event, Rest) :-
270 find_event(Spec, Event, Rest),
271 !.
272match_event(_, _, _) :-
273 print_message(query, history(no_event)),
274 fail.
275
276not_event_char(C) :- event_char(C), !, fail.
277not_event_char(!) :- !, fail.
278not_event_char(_).
279
285
286event_char(C) :- code_type(C, alnum), !.
287event_char(0'_).
288
289find_event([!|Left], Event, Left) :-
290 !,
291 get_last_event(Event).
292find_event([N|Rest], Event, Left) :-
293 code_type(N, digit),
294 !,
295 take_number([N|Rest], NumCodes, Left),
296 number_codes(Number, NumCodes),
297 prolog:history(current_input, event(Number, String)),
298 string_chars(String, Event0),
299 remove_full_stop(Event0, Event).
300find_event(Spec, Event, Left) :-
301 take_string(Spec, String, Left),
302 matching_event(String, Event).
303
304take_string([C|Rest], [C|String], Left) :-
305 event_char(C),
306 !,
307 take_string(Rest, String, Left).
308take_string([C|Rest], [], [C|Rest]) :- !.
309take_string([], [], []).
310
311take_number([C|Rest], [C|String], Left) :-
312 code_type(C, digit),
313 !,
314 take_string(Rest, String, Left).
315take_number([C|Rest], [], [C|Rest]) :- !.
316take_number([], [], []).
317
322
323matching_event(String, Chars) :-
324 prolog:history(current_input, prev_str(String, _Num, String)),
325 string_chars(String, Chars0),
326 remove_full_stop(Chars0, Chars)