#1097

Feature request: raw mode that leaves output post-processing (OPOST) on, for line editors sharing a terminal

Openjames-kassabianopened 3mo ago

Is your feature request related to a problem? Please describe.

enable_raw_mode() goes through cfmakeraw() / Termios::make_raw(), which clears OPOST along with everything else. This is documented and, for a full-screen application, correct:

New line character will not be processed therefore println! can't be used, use write! instead

It is a problem for a program that puts a line editor on the terminal rather than taking the whole screen over, because such a program does not own the terminal exclusively — other writers share it. Once OPOST is off, a bare \n moves down a row without returning to column 0, so anything writing to that terminal that isn't the crossterm application staircases:

AAA
   BBB
      CCC

The application's own output is fine, since it writes \r\n deliberately. The output that breaks belongs to whatever else has the same tty — for a shell, a background job and every process it spawns.

I hit this writing a shell. ( sleep 3; echo AAA; echo BBB; echo CCC ) & staircases exactly as above while the prompt is up. GNU readline has the same problem to solve and solves it by leaving output processing alone: it turns off echo and canonical input (ECHO, ICANON, ISIG, and input flags), but does not touch c_oflag. That's why background output under bash lands flush left.

Describe the solution you'd like

An opt-in raw mode that leaves output post-processing on — the input half of raw mode without the output half. Something like:

crossterm::terminal::enable_raw_mode_with(RawModeOptions { output_processing: true })

or a separate enable_line_editing_mode(), whichever fits crossterm's API taste better. Concretely it is cfmakeraw() followed by restoring OPOST | ONLCR:

fn raw_terminal_attr(termios: &mut Termios) {
    unsafe { cfmakeraw(termios) }
    if keep_output_processing {
        termios.c_oflag |= libc::OPOST | libc::ONLCR;
    }
}

with the equivalent on the rustix path (termios.output_modes |= OutputModes::OPOST | OutputModes::ONLCR). Windows needs nothing: ENABLE_VIRTUAL_TERMINAL_PROCESSING already handles \n as CR-LF, which is why this is a Unix-only difference.

Describe alternatives you've considered

  • Translating in the application. Doesn't work — the output isn't the application's. It comes from unrelated processes writing to the shared tty.
  • Setting termios directly around crossterm. Possible, but it means duplicating the raw-mode logic and fighting enable_raw_mode's saved-state bookkeeping, and it is exactly the sort of thing #931 asks crossterm to make unnecessary.
  • Patching crossterm locally. What I'm doing now, which is why I'm raising it.

Additional context

Related to #931 in spirit: both are cases where a downstream program needs raw mode with one specific flag left alone, and currently has to go around crossterm to get it. If a general "raw mode with these termios adjustments" facility were preferable to a one-flag option, that would cover both.

I'm happy to open a PR for whichever shape you'd prefer.

Activity

0

No activity yet.