Skip to content

In new version, for some input, keys need Enter #834

Closed

Description

@agguser

On Arch Linux, less v710, but not v704, with input from some programs (e.g. js-beautify -h | less), needs to press Enter after hotkeys (e.g. qEnter to quit).

Activity

  1. gwsw commented on Sep 30, 2026

    @gwsw
    Owner

    Are you trying to quit less before js-beautify has produced any output? This is a deliberate change to fix issue #807. We now avoid putting the terminal into raw mode until the piping program has produced at least one byte of output. This allows the piping program to use the terminal in normal, not raw, mode.

  2. agguser commented on Oct 1, 2026

    @agguser
    Author

    js-beautify -h | less shows all its output before I press q, which must be followed by Enter, for less to quit. (You may try it yourself, by installing https://github.com/beautifier/js-beautify.) This is unlike, says, ls --help | less (no need for Enter). So I'm not sure if it should be fixed in js-beautify or less, but less v704 works fine, so less should have an option to use the new/old behavior, to not break things.

  3. avih commented on Oct 1, 2026

    @avih
    Contributor

    js-beautify -h | less shows all its output before I press q

    If you save this output to a file, like so: js-beautify -h > beautify.out, does the issue also happpen if you do this? cat beautify.out | less

    If yes, does it also happen when you do this? cat becautify.out | LESSNOCONFIG=1 less

    Could you please attach this beautify.out file here? (zip it if you have to)

  4. agguser commented on Oct 1, 2026

    @agguser
    Author

    js-beautify -h > beautify.out; cat beautify.out | less works fine (no need for Enter).

    beautify.out.txt

  5. avih commented on Oct 1, 2026

    @avih
    Contributor

    js-beautify -h > beautify.out; cat beautify.out | less works fine (no need for Enter).

    That's interesting. So this appears to be specifically related to the fact that js-beautify -h is piping this output to less, and not related to the actual content or content size.

    Other than the fact that with cat you don't have to press Enter after q, are there some visible differences in the content in less between the cat method and without it?

    Are you sometimes piping other programs (not js-beautify) into less? if yes, do they work as expected, and the issue is only with js-beautify? or does that also happen with other programs? (if it happens also with other programs, please share an example or two)

    I'll let @gwsw take it from here, but that's useful info, thanks.

  6. agguser commented on Oct 1, 2026

    @agguser
    Author

    No differences between both outputs.

    It seems to be Node.js specific (js-beautify uses it); these commands have this issue: node -h | less, node -e 'console.log(123)' | less.

    No such issue if non-node, e.g.: deno eval 'console.log(123)' | less

  7. avih commented on Oct 1, 2026

    @avih
    Contributor

    Thanks. Good find.

    One last question if you don't mind, before I let @gwsw take over, what happens with this? node -h | LESSNOCONFIG=1 less

  8. agguser commented on Oct 1, 2026

    @agguser
    Author

    node -h | LESSNOCONFIG=1 less needs Enter too.

  9. avih commented on Oct 1, 2026

    @avih
    Contributor

    Thanks.

  10. gwsw commented on Oct 1, 2026

    @gwsw
    Owner

    I can't get js_beautify to build, but I can reproduce the problem with node. The issue seems to be that node is doing a weird thing where it reads the terminal settings at startup, then prints its output, then resets the terminal to the startup settings. It doesn't actually change the settings except for the final reset, so the whole process is pointless. It does however break less, since the sequence is:

    1. node reads settings (normal cooked mode)
    2. node prints output
    3. less sees start of output and sets terminal to raw mode
    4. node finishes printing output
    5. node sets terminal back to cooked mode
    6. less is now running with the terminal in cooked mode

    I could fix this by resetting the terminal to raw mode before every prompt but this is very ugly. An even worse "solution" is to have less delay for a little while at startup:

    node -h | ( sleep 2; less )
    

    This fixes this particular case but obviously can't work in general because we don't know how much to delay.

    Another non-solution is to redirect node's file descriptors so it doesn't have access to the terminal:

    node -h 0</dev/null 2>/dev/null | less
    

    I'm trying to come up with a better solution.

  11. avih commented on Oct 1, 2026

    @avih
    Contributor

    I'm trying to come up with a better solution.

    I'd think the correct solution is to report to node.js that they shouldn't touch the terminal settings if stdout (or whatever stream they print to) is not a tty.

    Less can't really workaround other applications which change the terminal settings while it runs...

  12. gwsw commented on Oct 1, 2026

    @gwsw
    Owner

    Yeah, it does seem to be misbehavior on node's part. There has always been a problem with node doing this, but previously it usually worked because less set the terminal setting on startup fast enough that it was usually already in raw mode by the time node queried it. But it has always been a race.

  13. avih commented on Oct 1, 2026

    @avih
    Contributor

    @agguser do you think you'll be able to report it to node.js, and add a link to this issue?

  14. agguser commented on Oct 1, 2026

    @agguser
    Author

    Another workaround is to fully read node's output first, e.g. node -h | sponge | less. (Or if less has an option to fully read its input first.)

  15. gwsw commented on Oct 4, 2026

    @gwsw
    Owner

    The --file-size option will cause less to read the full input at startup, if the input is a pipe. That's not really the primary purpose of this option, but it's a side effect of its intended purpose.

    @agguser do you agree that this is a problem in node and not in less? As avih says, node should not be changing the terminal settings if its output is not the terminal.

  16. 15 remaining items

  17. avih commented on Oct 7, 2026

    @avih
    Contributor

    When you pipe f to cat or sponge then neither of them is interactive.

    This is incorrect

    It is absolutely correct. Neither cat nor sponge are interactive (in the example cases above).

    Creating a pipeline of two interactive applications just can't work reasonably.

    It can work if ...

    Yes, there are conditions to make it work, which is why generally it doesn't work. You can't pipe less into vim or vice versa and have any reasonable expectation about it. The best case scenario here is that one of them decides to become non-interactive because its stdout is not a tty.

    Piping ssh or svn when it's is interactive and asks for password (and disable terminal echo while at it), into less, is a recipe for trouble, and has been an endless source of pain for less over the years. People want it to work, and less might even jump through some hoops to try and make it work if the stars align, but that doesn't mean this expectation is valid.

    Unless the user understands the "rules" absolutely and can control the applications to fit these rules, two or more interactive applications in a single pipeline is simply a recipe for trouble. It's really as simple as that.

  18. vinc17fr commented on Oct 7, 2026

    @vinc17fr
    Contributor

    When you pipe f to cat or sponge then neither of them is interactive.

    This is incorrect

    It is absolutely correct. Neither cat nor sponge are interactive (in the example cases above).

    But f is interactive (you said "neither of them").

    Piping ssh or svn when it's is interactive and asks for password (and disable terminal echo while at it), into less, is a recipe for trouble, and has been an endless source of pain for less over the years. People want it to work, and less might even jump through some hoops to try and make it work if the stars align, but that doesn't mean this expectation is valid.

    What matters is that this is very useful, and it is reasonable to ask the pager not to read from the terminal while it hasn't received any data yet.

  19. avih commented on Oct 7, 2026

    @avih
    Contributor

    But f is interactive (you said "neither of them").

    I was referring to cat and sponge.

    The point is that's not a pipeline of two interactive applications. In both the examples above, neither cat nor sponge are interactive, which is why it's not the same as f | less which is a pipeline of two interactive applications.

    What matters is that this is very useful, and it is reasonable to ask the pager not to read from the terminal while it hasn't received any data yet.

    It already does that, as part of the hoops it tries to jump through in order to make it work.

    The problem here is that this user doesn't know the "rules" to make two interactive applications in a pipeline sort-of work, and f is used interactively even after it started its output into "less".

    As I said, two or more interactive applications in a pipeline require the starts to align, and by default they're typically not aligned, which is why it's a recipe for trouble.

  20. vinc17fr commented on Oct 7, 2026

    @vinc17fr
    Contributor

    The problem here is that this user doesn't know the "rules" to make two interactive applications in a pipeline sort-of work, and f is used interactively even after it started its output into "less".

    Note, however, that the use of an intermediate sponge (last example: f | sponge | less) is expected to work for the given f (but not for a general f, e.g. which would close or redirect stdout before reading from the terminal, in which case both f and less would read from the terminal at the same time).

  21. avih commented on Oct 7, 2026

    @avih
    Contributor

    Note, however, that the use of an intermediate sponge (last example: f | sponge | less) is expected to work

    Sure. That's one reason (of several) for utilities like sponge to exist.

    But OP didn't ask for a solution. They were stating that there's a difference between f|cat or f|sponge to f|less, and this difference exists because it's generally inadvisable to combine two interactive applications in a single pipeline.

    It doesn't mean "never do it", and if they know what they're doing and how to control it - for instance using sponge, then it can work sometimes. But it's still very inadvisable to try such things.

  22. gwsw commented on Oct 7, 2026

    @gwsw
    Owner

    It's an ugly problem. Less does avoid using the terminal until the first byte of data has been received, but this causes other issues. For example, if the piping program takes a long time to produce the first byte, less will display the "waiting for data" message. At that point, the user can't interrupt the wait by just typing ctrl-X as usual, because the terminal is not yet in raw mode. They would have to type ctrl-X followed by RETURN, which is unexpected and nonintuitive. I wish there were some well defined protocol for simultaneously running programs to gain access to the terminal.

  23. vinc17fr commented on Oct 7, 2026

    @vinc17fr
    Contributor

    When there is no output yet, I don't see any real use for Ctrl-X, except for interrupting the program and quitting less, in which case the user can already do Ctrl-C. If some users really need Ctrl-X in this case, the behavior could be chosen with a new option.

    To share terminal input between the program and less, I think that the solution would be to make less run the program and do something like what GNU Screen or tmux does (in a simpler way); this implies creating a pseudo-tty for the program. There might also be drawbacks I'm not aware of.

  24. gwsw commented on Oct 7, 2026

    @gwsw
    Owner

    Yes, ctrl-C is probably sufficient in this particular case, but if the user is accustomed to using ctrl-X, they may type it and then be puzzled as to why it just echoes ^X and does nothing. It's just unexpected and inconsistent behavior.

    Also, ^C kills the piping process while ^X does not. Perhaps the user wants to run a shell command via the ! command while continuing to wait for the piped data, or something like that.

  25. vinc17fr commented on Oct 7, 2026

    @vinc17fr
    Contributor

    I'd say that this case is rather uncommon.

  26. gwsw commented on Oct 7, 2026

    @gwsw
    Owner

    I don't dispute that the shell command example is uncommon. But I don't think it's uncommon to type ctrl-X while waiting for the initial data. I've done it myself and been momentarily puzzled as to why it didn't interrupt the read until I remembered the implementation. I don't think that an average user is going to understand why ctrl-X works sometimes and not others.

  27. vinc17fr commented on Oct 7, 2026

    @vinc17fr
    Contributor

    This is something that is rather easy to learn, much less an issue than wondering what happens when two concurrent programs read terminal input at the same time.

  28. gwsw commented on Oct 7, 2026

    @gwsw
    Owner

    I guess my point is that it would be BETTER if ctrl-X worked consistently, and it's unfortunate that it's impossible to make it do so because of the competing requirement to support initially-interactive programs.

  29. agguser commented on Oct 8, 2026

    @agguser
    Author

    Seems that a good way to view the output of an interactive app is to use tee to capture the output first, e.g.

    $ f() { echo 1; read x; echo 2 $x 3; }
    
    $ t=$(mktemp); f | tee $t; less $t; rm $t
    1
    0   # this input line is not shown in `less`
    2 0 3
    
    $ tless() (t=$(mktemp) && trap 'rm -f $t' EXIT && tee $t && less $t)   # define function for reuse
    
    $ f | tless
    1
    0
    2 0 3
    
    # But it shows output 2 times: to stdout and to less
    $ f | tless | cat
    1
    0
    2 0 3
    1
    2 0 3

    Alternatively, script may be used, e.g.

    $ t=$(mktemp)
    
    $ script -q $t -- 'echo 1; read x; echo 2 $x 3'; less $t
    1
    0
    2 0 3
    
    # to not show/echo input, use `-Enever`
    $ script -q -Enever $t -- 'echo 1; read x; echo 2 $x 3'; less $t
    1
    2 0 3
    
    $ rm $t
  30. gwsw commented on Oct 12, 2026

    @gwsw
    Owner

    As far as I can tell, this is not a less issue, and the issue related to node is currently being discussed at nodejs/node#66440.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions