As per another thread, I’m trying to write an extension for Visual Studio Code which makes use of the Integrated Terminal feature of the IDE to provide the user with a running prolog instance.
I thought about using the wasm library initially for ease of use and interoperation, and for the ability to issue queries unknowingly to the user, but I faced two main issues:
- I would have had to reproduce most of the ordinary behavior of the top level from scratch;
- the swipl version provided by the wasm library is still not on par with the normal one (as reminded me by Jan).
So I got back to using the ordinary swipl terminal.
For user interaction this is perfect, as everything is as the developer expects it to be, but now I cannot issue “hidden queries” to the prolog instance anymore (these queries are used by the extension to get up-to-date information about loaded prolog code).
Regarding communication of such queries (i.e. retrieving their result), I’m currently writing the results’ bindings (either through message_hook/3 or expand_answer/2) to a temporary json file, which is subsequently read by the extension.
I didn’t really like the idea of communicating through a file initially, but in the end it seemed to me the cleanest and most platform-independent way to do it. I knew about the MQI library, but I discarded that because of overhead complexity and because I would like to keep the swipl instance as pristine as possible regarding the developer’s loaded/run code (i.e. no threads created apart from those specifically created by the developer etc).
There remained the issue of sending these queries unknowingly to the user, and this basically translates to:
- not showing the query in the terminal or - better said - removing it as soon as it’s read (possibly staying on the same line, not generating another prompt);
- not saving the query as a history entry (preventing it from showing up with the up-key feature), and
- not updating the history counter (the number shown before the prompt).
By studying the source code (namely toplevel.pl
and history.pl
) and by testing with some system predicate redefinitions I could achieve some of the objectives above, but obviously this is not ideal as the source code is not fixed in time and I would have to warn the user that some lines of code were added or altered for core modules of the swipl instance loaded in the VSC terminal.
While reading the code, I found kind of a minor feature that seems to (partially) suit my needs.
This is the '$silent'(Goal)
interception in history.pl
(made for the GNU Emacs, as said in the predicate’s comment), which on finding such a goal executes Goal
once and then proceeds. This possibly was to cope with a similar need as mine (issuing utility queries for an IDE).
'$silent'/1
seems to solve automatically requirements 2) and 3), but I’m still faced with 1), i.e. I don’t want the query to show up in the terminal, or better said I wish that once one of such queries is issued (and read) its line gets removed (up to the prompt) as if the query was never written.
I don’t even know if that’s possible, as the final predicate used for reading queries seems to be read_term_from_atom/3
and the logic behind “erasing” the read input is or should be there I guess.
So, I don’t know whether this could even be made into a “feature request”, i.e. having certain queries read by swipl being “swallowed up”, not updating the terminal in any way (history, prompt and such).
I don’t think this requirement would be that unique (maybe the very existence of '$silent'/1
is proof of that), and I’m sure its implementation would not interfere with anything of importance.
Maybe something like silent_query_hook/2
, so that one might say:
silent_query_hook(foo(Goal), [bindings(Bindings)]) :-
call(Goal),
write_bindings_to_json(Bindings). % This is from my use case
“Silent queries” would not update query history and would be removed from the current line once read.
As it is now, with '$silent'/1
:
1 ?- '$silent'(A=2).
1 ?- % Still getting a new line; up key showing the query
As I would like to have it:
1 ?- foo(A=2). % Before
---
1 ?- % After (same line, up-key not showing the query); meanwhile, stuff defined by the user executed