Finding current cursor position in the terminal

I'd like to be able to get the current x,y (or row, column) position of the cursor in a terminal. This is for a Bash or ZSH prompt, and my intention is to calculate how far across the terminal we've printed and then decide if we should wrap the prompt from one to two lines. There's a terminal escape sequence to do this: echo -e '\033[6n' or: tput u7 These output the desired information in some form of extremely difficult-to-parse code (works on Mac or any Linux, I think). The output looks like this: ^[[24;1R The numbers are line and column respectively. If you search the web, you can find various code (usually using the builtin 'read' command) to parse this. And some of the answers work fine ... in this context, ie. running it as a stand-alone command. But wrap it in a prompt and things go straight to hell. export PS1="--\$(echo -en '\e[6n')-- " You'll find that some of the output appears after the prompt, as part of the input line. Any attempt to 'read' and parse the value within the prompt hangs or returns empty, or does something else weird. My guess (uneducated and wild as it is) is that the escape sequence doesn't complete until AFTER the prompt is displayed. Because it's waiting for some magical code the prompt provides? I have no clue. One or two of the pieces of code I've found do parse the result and return properly ... but then they always return "1" for the column ... (they usually get the row right). And I'm primarily looking for the column. I've spent a lot of time searching for a solution, and trying all kinds of weird Bash coding tricks, with no particular luck. Does anyone have any idea how this might be handled? This is just one of many, many half-complete examples I've tracked down. The questioner eventually provided his own answer: https://stackoverflow.com/questions/43911175/get-current-cursor-position-whi... but what I found was that it always returns 1 for the column ... The author didn't care because they were only interested in the line number. Any help appreciated. -- Giles https://www.gilesorr.com/ gilesorr@gmail.com

| From: Giles Orr via talk <talk@gtalug.org> | I'd like to be able to get the current x,y (or row, column) position | of the cursor in a terminal. This is for a Bash or ZSH prompt, and my | intention is to calculate how far across the terminal we've printed | and then decide if we should wrap the prompt from one to two lines. | | There's a terminal escape sequence to do this: | | echo -e '\033[6n' TL;DR: I suspect you need a ? after the ESC [. Among other things, there is probably clashes of levels of abstraction here. This is querying your terminal / terminal emulator. Every one is free to support different encodings. ANSI 3.67 (from my faulty memory) is the relevant of standard, I would think (it cost money so I never got a copy). It looks as if ECMA-48 is similar and available: <http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-48,%202nd%20Edition,%20August%201979.pdf> ESC [ is a 7-bit sequence that stands for the eight-bit code CSI (Control Sequence Introducer). That's why you see that a lot. There is a grammar to these commands A characters is eight bits (or actually, 7 bits). The "column" of a character is the most significant hex digit (if 7 bits, the column is only 3 bits). The row is the least significant hex digit. control sequence: CSI parameters intermediates function # a parameter is typically empty or a sequence of digits parameter: | parameter digit # list separated by ; parameters: parameter | parameters ; parameter intermediate: character from column 2 intermediates: | intermediates intermediate function: character from column 4, 5, 6, or 7, excluding 7/15 If the CSI is followed by ?, I think that is some extension that isn't part of the standard. (Anything from column 3 that isn't a digit, :, or : is an extension). What you want ought use CPR (CURSOR POSITION REPORT). This seems to be row 2 column 5 in table 2. I think that that means (char) (2 + 5*16) which is R What you have is function n (column 6 row 15) which should be DAQ (Define Area Qualification). With the parameter 6, it means "fill with ZEROs". Just what this function does is pretty unclear to me. SO: maybe you are using an xterm control sequence. <https://xfree86.org/4.7.0/ctlseqs.html> CSI ? Ps n, where P is 6, means Report Cursor Position (CPR). Note the ? (which you didn't have). This is a DEC extension. I hope the standard form would work. Without the ?, it looks like a Set Scrolling Region (a DEC thing). I have to stop here due to a higher priority interrupt.

On Mon, Feb 10, 2020 at 02:54:43PM -0500, Giles Orr via talk wrote:
I'd like to be able to get the current x,y (or row, column) position of the cursor in a terminal. This is for a Bash or ZSH prompt, and my intention is to calculate how far across the terminal we've printed and then decide if we should wrap the prompt from one to two lines.
There's a terminal escape sequence to do this:
echo -e '\033[6n'
or:
tput u7
These output the desired information in some form of extremely difficult-to-parse code (works on Mac or any Linux, I think). The output looks like this:
^[[24;1R
The numbers are line and column respectively.
If you search the web, you can find various code (usually using the builtin 'read' command) to parse this. And some of the answers work fine ... in this context, ie. running it as a stand-alone command. But wrap it in a prompt and things go straight to hell.
export PS1="--\$(echo -en '\e[6n')-- "
You'll find that some of the output appears after the prompt, as part of the input line. Any attempt to 'read' and parse the value within the prompt hangs or returns empty, or does something else weird. My guess (uneducated and wild as it is) is that the escape sequence doesn't complete until AFTER the prompt is displayed. Because it's waiting for some magical code the prompt provides? I have no clue. One or two of the pieces of code I've found do parse the result and return properly ... but then they always return "1" for the column ... (they usually get the row right). And I'm primarily looking for the column.
I've spent a lot of time searching for a solution, and trying all kinds of weird Bash coding tricks, with no particular luck. Does anyone have any idea how this might be handled?
This is just one of many, many half-complete examples I've tracked down. The questioner eventually provided his own answer:
https://stackoverflow.com/questions/43911175/get-current-cursor-position-whi...
but what I found was that it always returns 1 for the column ... The author didn't care because they were only interested in the line number.
Any help appreciated.
What would you like the prompt to look like? Could you give an example? Since the command expansion of your echo command happens before PS1 is evaluated and printed, there is no way to do it by that method. You would need to figure out the length of PS1 before it is printed and make the decision based on that. -- Len Sorensen

On Tue, 18 Feb 2020 at 12:41, Lennart Sorensen via talk <talk@gtalug.org> wrote:
On Mon, Feb 10, 2020 at 02:54:43PM -0500, Giles Orr via talk wrote:
I'd like to be able to get the current x,y (or row, column) position of the cursor in a terminal. This is for a Bash or ZSH prompt, and my intention is to calculate how far across the terminal we've printed and then decide if we should wrap the prompt from one to two lines.
There's a terminal escape sequence to do this:
echo -e '\033[6n'
or:
tput u7
These output the desired information in some form of extremely difficult-to-parse code (works on Mac or any Linux, I think). The output looks like this:
^[[24;1R
The numbers are line and column respectively.
If you search the web, you can find various code (usually using the builtin 'read' command) to parse this. And some of the answers work fine ... in this context, ie. running it as a stand-alone command. But wrap it in a prompt and things go straight to hell.
export PS1="--\$(echo -en '\e[6n')-- "
You'll find that some of the output appears after the prompt, as part of the input line. Any attempt to 'read' and parse the value within the prompt hangs or returns empty, or does something else weird. My guess (uneducated and wild as it is) is that the escape sequence doesn't complete until AFTER the prompt is displayed. Because it's waiting for some magical code the prompt provides? I have no clue. One or two of the pieces of code I've found do parse the result and return properly ... but then they always return "1" for the column ... (they usually get the row right). And I'm primarily looking for the column.
I've spent a lot of time searching for a solution, and trying all kinds of weird Bash coding tricks, with no particular luck. Does anyone have any idea how this might be handled?
This is just one of many, many half-complete examples I've tracked down. The questioner eventually provided his own answer:
https://stackoverflow.com/questions/43911175/get-current-cursor-position-whi...
but what I found was that it always returns 1 for the column ... The author didn't care because they were only interested in the line number.
Any help appreciated.
What would you like the prompt to look like? Could you give an example?
Since the command expansion of your echo command happens before PS1 is evaluated and printed, there is no way to do it by that method. You would need to figure out the length of PS1 before it is printed and make the decision based on that.
And ... I think you just nailed my misunderstanding. In my head, I was thinking of the part of PS1 before the escape sequence as already being printed ... except it isn't. So yes, I'll always get the right ROW and COLUMN=1 if I embed in an existing PS1. Yeah, I've done the math calculations to figure out how big a prompt will be. This escape sequence seemed like a better way to do it. I'll take a look at using the PROMPT_COMMAND in Bash (or precmd() in ZSH) to print something before the prompt (the directory name, which can vary significantly in length if you don't apply some form of truncation), then run the escape sequence. I'll see if that will work. Thanks! -- Giles https://www.gilesorr.com/ gilesorr@gmail.com
participants (3)
-
D. Hugh Redelmeier
-
Giles Orr
-
lsorense@csclub.uwaterloo.ca