Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

whenever a terminal special character is bound in .inputrc, clear it from the terminals c_cc[] #111

Open
hanslub42 opened this issue Jan 12, 2021 · 3 comments

Comments

@hanslub42
Copy link
Owner

hanslub42 commented Jan 12, 2021

Some users are surprised that binding a terminal special key like CTRL+C in .inputrc doesn't work. Of course, rlwrap never sees the special key because it is always caught by the terminal driver. An easy remedy would be to issue a stty intr undef before launching rlwrap, but in many (most?) cases, the rlwrapped command will re-instate the special key, which will make rlwrap do the same (rlwrap mirrors the wrapped command's terminal settings), putting us back at square one.

To prevent this unpleasant surprise, rlwrap could (should?) take notice and clear the special key from c_cc[], which clearly is what the user expects.

Examples (probably): #101, #106

@hanslub42
Copy link
Owner Author

Is there any other readline program that does this? If not, why not?

@hanslub42
Copy link
Owner Author

hanslub42 commented Feb 15, 2021

cf this StackOverflow question. There are a few programs (mit-scheme, clojure) that manipulate their interrupt characters (i.e. their terminal's c_cc[VINTR]) inside their REPL:

To see why this can be problematic, consider that there are two ways keypresses like CTRL+C can reach the client when rlwrap is editing your input:

  • If that key is the client's c_cc[VINTR], it will also be rlwraps c_cc[VINTR] as rlwrap continually mirrors the client terminal setttings . The signal (SIGINT) that rlwrap receives when the key is pressed is then forwarded to the client, which will receive it just as it would have without rlwrap (it would never have seen the keypress anyway)
    • Problem: rlwrap may lag behind the client when it is blocked on select() in its main loop, as the client changing its c_cc[VINTR] will not make select() return). In that case, rlwrap may have the "wrong" c_cc[VINTR] until the next keypress, and the signal never gets sent. This lagging behind can be mitigated by using the --polling option, which will reduce the select) timeout, so that rlwrap will mirror the terminal settings before the next user input. This is a bit of a kludge, however: rlwrap waking up 25 times a second is not good news for your laptop battery
  • If that key is not the client's c_cc[VINTR], it will not reach the client unless it is bound to rlwrap-direct-keypress.
    • but, in that case, there is no lag: a direct keypress goes "straight through", having exactly the same effect as it would have had without rlwrap (except in the improbable case that its meaning depends on the state of the client's input line, like CTRL+D does: this input line will always be empty when the client is running within rlwrap

In short: forwarding keypresses directly is more transparent and reliable than "translating" them into signals and forwarding those. A drawback is that it needs a few lines in .inputrc (or an extra rlwrap option)

But forwarding only works if those keypresses are not caught by rlwraps terminal. This is what the current proposal proposes:

  • Keep watching the client's c_cc[VINTR], as rlwrap does now
  • But if this changes into a key that is bound to rlwrap-direct-keypress (and/or specified in some new option --interrupt-characters), disable (i.e. don't mirror, as happens now) rlwraps interrupt character by zeroing c_cc[VINTR].

kill $rlwrap_PID -INT will still be forwarded to the client, of course. --polling will still work (and eat your battery). In other words: this proposed change is entirely backwards compatible.

Finally:

  • The same can be done for c_cc[VQUIT] (but not c_cc[VSUSP] as rlwrap is not a shell: it only ever has one client)
  • rlwrap could even always bind the client's special keys to rlwrap-direct-keypress. This would not solve the "delay problem" however, as this binding may occur one keypress too late.
  • since version 0.45, rlwrap allows multi-key keybindings. This can be used to accomodate programs with interrupt character sequences (also: tio)

@hanslub42
Copy link
Owner Author

The same can be done for c_cc[VQUIT] (but not c_cc[VSUSP] as rlwrap is not a shell: it only ever has one client)

Even for VSUSP: see: https://unix.stackexchange.com/questions/683932/proper-way-to-wrap-dash-using-rlwrap. In that case, the rlwrapped command (dash) will receive the CTRL+Z keypress (instead of the TSUSP signal) and do its thing

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

No branches or pull requests

1 participant