diff options
author | Steve Bennett <steveb@workware.net.au> | 2011-04-05 12:40:39 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2011-04-05 12:47:47 +1000 |
commit | a76b3913552b0204b02cbd64567c00a7b3aff8eb (patch) | |
tree | ce9650bd3ead7eeff01807752f66ef5349c65de8 /linenoise.c | |
parent | abd0fa0c9dfde1e4895bcfe488b24c0ab9ad69f8 (diff) | |
download | jimtcl-a76b3913552b0204b02cbd64567c00a7b3aff8eb.zip jimtcl-a76b3913552b0204b02cbd64567c00a7b3aff8eb.tar.gz jimtcl-a76b3913552b0204b02cbd64567c00a7b3aff8eb.tar.bz2 |
Better line editing on serial terminals
If TIOCGWINSZ doesn't work, try to query the window width
with escape sequences.
Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'linenoise.c')
-rw-r--r-- | linenoise.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/linenoise.c b/linenoise.c index 0612219..cf3e3f7 100644 --- a/linenoise.c +++ b/linenoise.c @@ -47,7 +47,7 @@ * - Completion? * * List of escape sequences used by this program, we do everything just - * with three sequences. In order to be so cheap we may have some + * a few sequences. In order to be so cheap we may have some * flickering effect with some slow terminal, but the lesser sequences * the more compatible. * @@ -64,6 +64,11 @@ * CUF (CUrsor Forward) * Sequence: ESC [ n C * Effect: moves cursor forward of n chars + * + * DSR/CPR (Report cursor position) + * Sequence: ESC [ 6 n + * Effect: reports current cursor position as ESC [ NNN ; MMM R + * * * For highlighting control characters, we also use: * SO (enter StandOut) @@ -103,6 +108,7 @@ static int history_len = 0; static char **history = NULL; static void linenoiseAtExit(void); +static int getColumns(int fd); static int isUnsupportedTerm(void) { char *term = getenv("TERM"); @@ -171,13 +177,6 @@ static void linenoiseAtExit(void) { freeHistory(); } -static int getColumns(void) { - struct winsize ws; - - if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) return 80; - return ws.ws_col; -} - /* Structure to contain the status of the current (being edited) line */ struct current { int fd; /* Terminal fd */ @@ -232,7 +231,7 @@ static int get_char(struct current *current, int pos) } return -1; } - + static void refreshLine(const char *prompt, struct current *current) { size_t plen; int pchars; @@ -246,7 +245,7 @@ static void refreshLine(const char *prompt, struct current *current) { int n; /* Should intercept SIGWINCH. For now, just get the size every time */ - current->cols = getColumns(); + current->cols = getColumns(current->fd); plen = strlen(prompt); pchars = utf8_strlen(prompt, plen); @@ -446,6 +445,53 @@ static int fd_read(int fd) #endif } +static int getColumns(int fd) { + struct winsize ws; + + if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { + static int queried_cols = 0; + + if (queried_cols == 0) { + queried_cols = 80; + + /* Failed to query the window size. Perhaps we are on a serial terminal. + * Try to query the width by sending the cursor as far to the right + * and reading back the cursor position. + * Note that this is only done once. + */ + /* Move cursor far right and report cursor position */ + fd_printf(fd, "\x1b[999G" "\x1b[6n"); + + /* Parse the response: ESC [ rows ; cols R */ + if (fd_read_char(fd, 100) == 0x1b && fd_read_char(fd, 100) == '[') { + int n = 0; + while (1) { + int ch = fd_read_char(fd, 100); + if (ch == ';') { + /* Ignore rows */ + n = 0; + } + else if (ch == 'R') { + /* Got cols */ + if (n != 0 && n < 1000) { + queried_cols = n; + } + break; + } + else if (ch >= 0 && ch <= '9') { + n = n * 10 + ch - '0'; + } + else { + break; + } + } + } + } + return queried_cols; + } + return ws.ws_col; +} + /* Use -ve numbers here to co-exist with normal unicode chars */ enum { SPECIAL_NONE, |