How to turn off "|:" prompt for reading from user_input?

When I use get_code/2 with user_input, I always get a prompt “|: ”, even when input isn’t from a tty. Is there a way to turn off the prompt (or a way to add a check for isatty to get_code/2)?

"Don’t use read_codes/2" is not a solution; I’m getting this from json_read_dict/3, which uses read_codes/2.

Example:

$ (echo abc; echo def; echo fgh) | swipl --no-tty -g doit -t halt /tmp/z.pl
|: |: ***
abc
def
fgh

***
peter@wistaria5b:~/src/pykythe$ cat /tmp/z.pl
doit :-
    read_codes(Codes),
    format('***~n~s~n***~n', [Codes]).

read_codes(Codes) :-
    get_code(user_input, Code),
    (  Code == -1
    -> Codes = []
    ;  Codes = [Code|Codes2],
       read_codes(Codes2)
    ).
1 Like

Found this

?- prompt(Old,Old).
Old = '|: '.

?- get_code(C).
|: 1

C = 49.

?- prompt(_,'').
true.

?- get_code(C).
1

C = 49.

?- 

See: prompt/2

HTH


It also works with backspace, e.g.

?- prompt(_,'\b').
true.

which may be useful for what you need but not very useful with a user at the terminal.

Also when I was peeking around in the source code changing the encoding might also be of use.

See: set_stream/2 and Wide character encodings on streams

1 Like

Perfect!

@jan - the documentation for prompt/2 seems to have a bug – read/1 is for reading terms, but prompt/2 also affects get_code/2 (and perhaps other predicates).
Also, shouldn’t the prompt be output only if user_input is a tty (according to isatty(3))? (It seems that the isatty information is available in the stream, as it’s an option to set_stream/2 and can be checked with stream_property/2.)

You don’t need to change the prompt or use --no-tty. If the prompt is annoying you just use cat. This is what you see at the moment:

$ (echo abc; echo def; echo fgh) | swipl -g doit -g halt z.pl
|: |: ***
abc
def
fgh

***

and this is what happens when you pipe it through cat:

$ (echo abc; echo def; echo fgh) | swipl -g doit -g halt z.pl | cat
***
abc
def
fgh

***

Of course you can forget about cat if the swipl process is not the last one in your pipe:

$ (echo abc; echo def; echo fgh) | swipl -g doit -g halt z.pl | grep -v '*'
abc
def
fgh

Disclaimer: I like to cite my sources. I am almost certain that this tip was handed down to me by Ulrich Neumerkel aka “false” years ago on Stackoverflow. It was a comment to a comment or something like this because I cannot find it. Back then I tried to read the code to figure out what is this magic but I must have given up. Maybe someone who knows their stuff can explain.

1 Like

It was a bit of a mess. Cleared up the docs and avoid prompting if user_input does not have the tty property. I’m not entirely sure about the latter. The rule now is that you have use prompt/2 and prompt1/1 to control the prompt, but the prompt is ignored if user_input is not a tty. The alternative would be to set the prompt to '' if user_input is not a tty. That sounds simpler (and thus better), but there is also some value that you can disable prompting globally, even if an application using different prompt defines in different locations.

P.s. --no-tty doesn’t make Prolog think there is no tty. It prevents it from changing the tty properties to achieve raw input and/or do line editing.

BTW, the reason I didn’t find prompt/2 is that I expected to find it within current_prolog_flag/2.

@jan - based on Boris’s comment, it seems you need a bit more of doc change … it needs to mention the conditions of user_output that turn off prompting. [At first, I thought that this was crazy, but then I realized that redirected output wouldn’t be seen, so a prompt would be pointless … however, a case could be made that if input is from /dev/tty, then the prompt should go to /dev/tty, regardless of output redirection – that’s what the MTS operating system did IIRC.]

Could have been, I guess. AFAIK, prompt/2 originates from Edinburgh C Prolog :slight_smile: In fact, there is a flag toplevel_prompt that determines the ?- prompt.

I think that is all a bit over the top. As is, the rule is now quite simple: prompt only if user_input is a terminal. As you can control whether Prolog should consider user_input a terminal, this gives you full control. Just tested with bash. cat -u | bash doesn’t prompt, while bash | cat -u does, which is consistent with what we do now.

Finally, if you want Prolog to run some goals inside a (shell) script, it might be easier to use -g goal. Note that you can repeat this option. If you combine this with -t halt you should have pretty much what you typically want: run some goals and exit with status 0 if all went right and stop with status not 0 on a failure or exception.

2 Likes

I just tested with cat -u and swipl does not prompt. (Using 8.1.20 on Ubuntu 18.0.4, with gnome-terminal and also with an emacs shell.)

I have no strong opinion either way on the behavior of swipl when it’s outputting to a non-tty; but in the meantime it’d be nice if the documentation mentions that prompting only occurs if user_output is a tty. [The code has this, which I assume means a check for user_output being a tty: if ( Soutput && true(Soutput, SIO_ISATTY) )

(You can ignore my comments about prompting from /dev/tty – that was merely to show an alternative philosophy from an operating system that I admire.)

Please checkout the current head. Prompting now only depends on user_input and docx are updated. If it is still incorrect, please report.

It seems that if the output isn’t a tty, then the prompt is suppressed. Which I agree with, but the documentation doesn’t mention that.

The following is after doing git pull origin master and a clean build.

~/src/swipl-devel/build$ ./src/swipl -g doit -t halt /tmp/z.pl
|: hello
|: sailor
|: ***
hello
sailor

***
~/src/swipl-devel/build$ ./src/swipl -g doit -t halt /tmp/z.pl | cat
hello 
sailor
***
hello
sailor

***
~/src/swipl-devel/build$ cat /tmp/z.pl
doit :-
    read_codes(Codes),
    format('***~n~s~n***~n', [Codes]).

read_codes(Codes) :-
    get_code(user_input, Code),
    (  Code == -1
    -> Codes = []
    ;  Codes = [Code|Codes2],
       read_codes(Codes2)
    ).

Oops. That is not what the new docs say and not what bash does. Pushed a fix. The rule is (now) simple: pompting is active is user_input has the tty property set to true. The prompt itself is defined by prompt/2. The toplevel ?- is defined by the Prolog flag toplevel_prompt.

So, if you want to suppress the prompt in case you read from a tty, call set_stream(user_input, tty(false)). In a similar way you can force a prompt using set_stream(user_input, tty(true)) even if Prolog is reading from something else than a tty.

Most likely something with the Qt based console. Source is in packages/swipl-win :slight_smile: