Skip to content

missing x,y for current cursor position on process.stdout #49

Closed

Description

@coolaj86

I'm a very experienced node.js developer, but not very experienced ANSI terminal developer.

How do I determine the current location of the cursor?

I see that I can determine the window size with process.stdout.columns, process.stdout.rows, and there's a nifty resize event. Awesome.

But there isn't a process.stdout.column and process.stdout.row or process.stdeout.x, process.stdeout.y to tell me where I currently am, which kind of stinks.

Is there a technical reason as to why this isn't available? Or is it just not documented? Or does it need some love and a pull request?

Practical Use Case

I've got a websocket checking on some stuff in the background. Every few seconds it updates a status message in known location the upper right corner. The function should check to see where the cursor is, make the update, and put the cursor back where it was.

Activity

  1. changed the title [-]missing info for current cursor position on process.stdout[/-] [+]missing x,y for current cursor position on process.stdout[/+] on Dec 14, 2015
  2. bnoordhuis commented on Dec 15, 2015

    @bnoordhuis
    Member

    https://gist.github.com/lancejpollard/3765464 is an example of how you can query the tty for the cursor position. The key part is the '\x1b[6n' scan code.

    I think the reason node.js doesn't support it natively is that it's not very portable.

  3. maltekosian commented on Feb 3, 2018

    @maltekosian

    Why this issue is closed? sh scripts do not work on windows and it is not a build-in method of node.

  4. gibfahn commented on Feb 5, 2018

    @gibfahn
    Member

    I think the reason node.js doesn't support it natively is that it's not very portable.

    As Ben said:

    I think the reason node.js doesn't support it natively is that it's not very portable.

    Not sure if there is a way to do it in Windows, cc/ @nodejs/platform-windows

  5. joaocgreis commented on Feb 5, 2018

    @joaocgreis
    Member
  6. alshdavid commented on Nov 25, 2021

    @alshdavid

    Is this available in nodejs yet?

  7. UnluckyNinja commented on Mar 22, 2025

    @UnluckyNinja

    In case someone come across this issue like me:
    Just like bnoordhuis pointed out, write \x1b[6n (or \u001b[6n) to stdout will have the cursor position returned in stdin. And it's doable with only js.

    There are js examples on stackoverflow:
    https://stackoverflow.com/questions/70033207/how-do-i-get-the-current-cursor-position-relative-to-the-output-with-nodejs-read
    Tested in win10 with cmd, powershell 5.1 & 7.4.7 in Windows Terminal. All of them can return cursor position with \x1b[6n.

    The only problem I currently have is that when using it with createInterface from node:readline, if the input buffer is long enough (>= 4 chars on my machine), an additional 'R' will be appended to current cursor position.

    (EDIT: turns out when the cursor is at column >=10 the input sequence received by keypress event is {"sequence":"\u001b[27;10","name":"undefined","ctrl":false,"meta":false,"shift":false,"code":"[27;10"} where the "R" at the sequence's end is left out.)
    (EDIT2: I think I found the cause, it's simply that in the code it doesn't take such sequence into account. It only parse 2 more characters after ";" (1 digit and 1 any char): https://github.com/nodejs/node/blob/3861eccc05751eea2a0915316c16b86caea531ba/lib/internal/readline/utils.js#L182-L188)

    And a reproduction, modified from above.

    import * as readline from 'node:readline';
    
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    const getCursorPos = () => new Promise((resolve) => {
      const termcodes = { cursorGetPosition: '\u001b[6n' };
    
      process.stdin.setEncoding('utf8');
      process.stdin.setRawMode(true);
    
      const readfx = function () {
          const buf = process.stdin.read();
          const str = JSON.stringify(buf); // "\u001b[9;1R"
          const regex = /\[(.*)/g;
          const xy = regex.exec(str)[0].replace(/\[|R"/g, '').split(';');
          const pos = { rows: xy[0], cols: xy[1] };
          process.stdin.setRawMode(false);
          resolve(pos);
      }
    
      process.stdin.once('readable', readfx);
      process.stdout.write(termcodes.cursorGetPosition);
    })
    
    const AppMain = async function () {
      process.stdout.write('HELLO');
      const pos = await getCursorPos();
      process.stdout.write("\n");
      console.log({ pos });
      process.stdin.unref()
    }
    
    console.log('Type some text >= 4 chars')
    setTimeout(()=>{
      setImmediate(AppMain);
    }, 2000)

    It would be convenient if we can have a builtin function that provides such feature and avoid conflicts/mistakes with readline or any custom interactive console.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions