sindresorhus / ansi-escapes

ANSI escape codes for manipulating the terminal
MIT License
494 stars 44 forks source link

Make cursor position a little more cross platform #1

Closed jamestalmage closed 7 years ago

jamestalmage commented 8 years ago

cursorSavePosition, and cursorRestorePosition to not work at all on OSX.

The following appears to:

var ESC = '\u001b';
var STORE = ESC + '7';
var RESTORE = ESC + '8';

Source: http://stackoverflow.com/questions/25879183/can-terminal-app-be-made-to-respect-ansi-escape-codes

I am not sure what the differences are, but it's worth exploring.

sindresorhus commented 8 years ago

By OS X, I assume you mean Terminal.app? Wonder if it works on iTerm.

For reference, current code: https://github.com/sindresorhus/ansi-escapes/blob/3dff027c48a59a377ed44b6d942b1b4f007c326f/index.js#L52-L53

Looks like other modern terminals supports both, so I guess we could just switch to 7/8?

@Qix- Thoughts?

jamestalmage commented 8 years ago

Note that ESC in this case doesn't have the trailing [. I think the trailing [ technically makes it a CSI character sequence. (My entire education on the topic comes from wikipedia, so take with a grain of salt).

Qix- commented 8 years ago

Firstly, not entirely sure where 7 and 8 come from; I don't see them documented anywhere on any of my go-to lists (at least, not clearly). See bottom for edit.

However, iTerm correctly performs the escape.

$ printf "first\n\x1b7second\n\x1b8third"
first
third

as does Terminal.app.

screen shot 2016-01-10 at 19 15 42

The escapes I've seen officially documented in lieu of 7 and 8 are s and u, respectively.

$ printf "first\n\x1b[ssecond\n\x1b[uthird"
first
third

However these do not work in Terminal.app. This is probably because (and I'm speculating here) Apple has hinted at being pretty starchy with their terminal additions and seem to try to keep things pretty aligned with the VT100, which IIRC doesn't support [s and [u.

screen shot 2016-01-10 at 19 17 19

@jamestalmage what version of OS X are you running?


Something that is worth mentioning is the dated-ness of ANSI escapes. Color stuff works fine because it is needed far more often in terminal output. It's solid and commonly accepted (though IMO weakly standardized) and color output is generated progressively, meaning there's no rewrites of existing buffers.

Cursor manipulation, as you can tell, is hairy and not at all implemented fairly across all terminals. Using cursor operations, in my humble opinion, should only ever consist of in-line modifications in practice. This is because cursor positions are absolute to the window and not to the buffer itself (I'm sure, though, there is an emulator out there somewhere that does otherwise. Poor standardization!).

This means if a window is resized or is much smaller (I commonly get some terminals down to 2 lines in a paned layout just to see the tail of logging, etc.) your out-of-line cursor manipulation escapes are going to cause undesirable effects the vast majority of the time (unless you're counting on process.stdout.rows, which... don't :dancer:).

In the cases where you need to jump between lines, use a technology much better suited, such as the curses or even better the ncurses library. There are quite1high a2mid few3low libraries that help with such things, depending on how high/low level you want to go. However using the termcap library in some capacity is definitely the Right Way™ to do more robust cursor manipulation.


In the end, I'd be inclined to say something is up with your Terminal.app configuration or that these particular OOB escapes were added in a newer version of OS X (I'm currently at El Capitan and seeing them correctly).

Any more docs on them would be appreciated.


EDIT: Aha, that's why. They're individual escape values derived from the Termcap database for some particular TERM. What's your TERM environment variable set to?

Long explanation: Termcap databases were created for the curses library IIRC and basically define all of the capabilities of all of the possible TERM values. A lot of shells/emulators won't let you set TERM to something not in the Termcap database for this reason.

screen shot 2016-01-10 at 19 42 28

Each entry in the database has a list of capabilities and, in the event the TERM is capable of doing something, the provides the associated escape codes for each capability. 7 and 8 seem to be the associated escapes for save/restore for at least xterm-256color. Speculation, but I would imagine a large percentage of users use xterm-256color as a default, hence why this has gone unnoticed for as long as it has.

@sindresorhus while these might work for a lot of users, using hard-coded values derived from Termcap info is definitely not the Right Way™. Depending on how complete we want this to be, it might be time to start looking at Termcap parsing like we've entertained before.

Hopefully this sheds a little bit of light!

jamestalmage commented 8 years ago
$ echo $TERM
xterm-256color

OSX Yosemite 10.10.5

Qix- commented 8 years ago

OSX Yosemite

Must be an OS X version thing, then. That's the only explanation I can muster up.

Can you confirm the output of the following command, just to humor me? :tada:

$ printf "first\n\x1b7second\n\x1b8third\n"
jamestalmage commented 8 years ago
first
second
third
Qix- commented 8 years ago

Yeah, my guess is it's an OS X versioning thing. Let me dig really quick.

Qix- commented 8 years ago

what does this output?

$ infocmp $TERM | grep -Eo '( sc=\\E..)|( rc=\\E..)'
jamestalmage commented 8 years ago
 rc=\E8,
 sc=\E7,
Qix- commented 8 years ago

Interesting. Your Terminfo is indicating it's correct, but Terminal.app doesn't seem to like it. Still pretty convinced this is an OS X versioning thing.

I don't know what else to suggest other than to not use Terminal.app if you absolutely need this functionality. Or, upgrade OS X :P

Sorry I'm not more helpful >.<

jamestalmage commented 8 years ago

You said not to count on process.stdout.rows. I'm assuming the same applies for columns?

Is there a better to reliably detect column width?

Qix- commented 8 years ago

Eh, in my experience neither of them have been reliable. They're both obtained by the same mechanism, tput (tput rows and tput cols), but for similar reasons as cursor positioning (age of terminal technology, etc.) I don't put a whole lot of trust into those values. I've had cases where they both return 0. I know multiplexers such as tmux have historically caused all sorts of trouble with positioning within TTY sessions.

However I don't know of any other way to get those values.

Side note: In all honesty I bet Windows has more reliable results simply because their ConsoleXXX functions work directly with their proprietary command prompt. Again, purely speculation.

sindresorhus commented 8 years ago

So the gist of this is that everything is broken, unreliable, and inconsistent...

Depending on how complete we want this to be, it might be time to start looking at Termcap parsing like we've entertained before.

I would really prefer not having to go down that route.

Your Terminfo is indicating it's correct, but Terminal.app doesn't seem to like it.

So much for depending on termcap :p

Could we just output both? (7 and s) It seems terminals will pick either, not both.

Another solution would be to just use 7/8 when it's Terminal.app.

Qix- commented 8 years ago

I would really prefer not having to go down that route.

Agreed. I mean yeah it would be 'complete' but I think one of the upper-hands we have with the Chalk family is that we're pretty dern lightweight. Termcap parsing would introduce a considerable overhead.

So much for depending on termcap

Termcap isn't wrong here; termcap goes off of whatever is in TERM. It's Apple's fault they allow TERM to be set to something they don't fully support.

At least it's been fixed, but I mean... Apple has had almost 40 years to figure this stuff out (Apple ][, looking at you. You could have fixed this. :facepunch:)

Could we just output both?

I mean, I don't see anything wrong with it at face value but I'd put money on the probability of some wacky terminal treating it weird. Could be useful to investigate.

Another solution would be to just use 7/8 when it's Terminal.app.

That wouldn't make any difference in this particular case.

sindresorhus commented 8 years ago

That wouldn't make any difference in this particular case.

Why not? According to James it works in Terminal.app. Or did I miss something in the discussion?

Qix- commented 8 years ago

Actually I don't think @jamestalmage ever definitively specified if this was a Terminal.app problem. I assumed it was because you mentioned it.

jamestalmage commented 8 years ago

Yep my problem was Terminal.app.

Based on your comments here, I've abandoned cursor positioning for what I was trying to do.