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

Provide DEC sequences for save & restore cursor position operations #226

Closed
pmonks opened this issue Nov 13, 2021 · 5 comments
Closed

Provide DEC sequences for save & restore cursor position operations #226

pmonks opened this issue Nov 13, 2021 · 5 comments
Milestone

Comments

@pmonks
Copy link

pmonks commented Nov 13, 2021

Background

The escape sequences for "save cursor position" and "restore cursor position" were never standardised as part of the ANSI (or subsequent) specs, resulting in two different sequences known in some circles as "DEC" and "SCO":

  • DEC: ESC7 (save) and ESC8 (restore)
  • SCO: ESC[s (save) and ESC[u (restore)

Different terminals (and OSes) support different combinations of these sequences (one, the other, neither or both); for example the iTerm2 terminal on macOS supports both, while the built-in macOS Terminal.app only supports the DEC sequences.

Problem

From the source I see that jansi's saveCursorPosition and restoreCursorPosition methods use the SCO sequences for these operations, meaning that they won't work by default on some terminals (including, notably, macOS' built-in Terminal.app).

Proposed Solution

Add support for both variants, so that jansi consumers can determine the correct one to use (itself a thorny problem, but one that feels appropriate to punt out of the library).

@gnodet
Copy link
Member

gnodet commented Jan 21, 2022

What's your use case exactly ? It's a bad idea to depend on those cursor movements if the terminal can not use it and Jansi is somewhat limited when it comes to mimic ansi sequences. The original goal is to allow rendering colors and strip them on unsupported terminal and emulate on windows.
Anything more advanced should really use a better suited library and I would recommend looking at JLine3 (on top of jansi) which has full terminal support.

@pmonks
Copy link
Author

pmonks commented Jan 21, 2022

The project is here, but in a nutshell the use case is a text-mode "spinner" for long-running command line processes, which involves these steps:

  1. save the current cursor position (since the cursor could be anywhere on the screen, depending on what has already been written to it - this is nondeterministic)
  2. write some text (the next "frame" in the set of frames making up the spinner animation)
  3. short sleep (default is 250ms)
  4. restore the cursor position saved in step 1
  5. erase to end of line

This is done in a loop that spins through the frames in the caller's chosen spinner animation.

From a quick evaluation it appears that JLine3 is unsuitable for my use case given that:

  • my use case doesn't require the input or rich text UI capabilities that JLine3 offers
  • my library is small/simple/narrowly-focused, and keeping dependencies (and their runtime impacts) to a minimum is an explicit design goal
  • jansi already provides these APIs - it's just that it only provides one variant of what ended up (for historical reasons) as two distinct ANSI escape sequences. Modern programs need to be able to use either or both, since some modern terminals (including, notably, the default Terminal.app on macOS) lack support for the SCO sequences that jansi currently emits.

And just to be crystal clear, I'm not asking for termcap/terminfo capabilities. I personally think that's well beyond the scope of jansi. Instead I'm simply asking for two new APIs that will (unconditionally) emit the DEC sequences for cursor save & restore when called (while maintaining the existing saveCursorPosition and restoreCursorPosition APIs that emit the SCO sequences). Leaving terminal capability detection to the jansi client (in this case my library) is absolutely fine by me (in fact I encourage that).

@pmonks
Copy link
Author

pmonks commented Jul 14, 2022

Here's my workaround, which I've tested in various terminal emulators on both macOS and Linux.

As previously mentioned, it would be ideal if jansi added new APIs to emit the DEC sequences for save cursor position and restore cursor position, as it's highly implausible that my library is the only one that has run into this problem.

@gnodet
Copy link
Member

gnodet commented Sep 28, 2023

@pmonks would the #262 PR fix your problem ?

@gnodet gnodet added this to the 2.5.0 milestone Sep 28, 2023
@pmonks
Copy link
Author

pmonks commented Sep 28, 2023

@gnodet I believe it would - that's the approach I took in my own code. However there may be folks who need finer-grained control over which sequences(s) are sent, so I'd probably suggest splitting this into multiple methods, perhaps something like:

    public Ansi saveCursorPosition() {
        saveCursorPositionSCO();
        return saveCursorPositionDEC();
    }

    // SCO command
    public Ansi saveCursorPositionSCO() {
        return appendEscapeSequence('s');
    }

    // DEC command
    public Ansi saveCursorPositionDEC {
        builder.append(FIRST_ESC_CHAR);
        builder.append('7');
        return this;
    }

    public Ansi restoreCursorPosition() {
        restoreCursorPositionSCO();
        return restoreCursorPositionDEC();
    }

    // SCO command
    public Ansi restoreCursorPositionSCO() {
        return appendEscapeSequence('u');
    }

    // DEC command
    public Ansi restoreCursorPositionDEC() {
        builder.append(FIRST_ESC_CHAR);
        builder.append('8');
        return this;
    }

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

No branches or pull requests

2 participants