From 5629979536e869062991136ecf96197c4f5a6668 Mon Sep 17 00:00:00 2001 From: ziyi chen Date: Wed, 22 Mar 2023 11:39:25 +0800 Subject: [PATCH] Fix CTRL-D in CLI --- tools/shell/linenoise.cpp | 144 ++++++++++++++------------------------ 1 file changed, 54 insertions(+), 90 deletions(-) diff --git a/tools/shell/linenoise.cpp b/tools/shell/linenoise.cpp index c8c33cc516..8a63432400 100644 --- a/tools/shell/linenoise.cpp +++ b/tools/shell/linenoise.cpp @@ -155,7 +155,7 @@ struct linenoiseState { size_t pos; /* Current cursor position. */ size_t oldpos; /* Previous refresh cursor position. */ size_t len; /* Current edited line length. */ - size_t chars; /* Number of utf-8 chars in buffer. */ + size_t totalUTF8Chars; /* Number of utf-8 chars in buffer. */ size_t cols; /* Number of columns in terminal. */ size_t maxrows; /* Maximum num of rows used so far (multiline mode) */ int history_index; /* The history index we are currently editing. */ @@ -190,8 +190,6 @@ static void refreshLine(struct linenoiseState* l); std::string oldInput = ""; bool inputLeft; -std::string utf8store = ""; - /* Debugging macro. */ #if 0 FILE *lndebug_fp = NULL; @@ -569,19 +567,6 @@ uint32_t linenoiseComputeRenderWidth(const char* buf, size_t len) { return renderWidth; } -int getBufCharPos(struct linenoiseState* l) { - if (l->pos == l->chars) { - return l->len; - } - size_t idx = 0; - size_t ctr = 0; - while (ctr < l->pos) { - idx = utf8proc_next_grapheme(l->buf, l->len, idx); - ctr++; - } - return idx; -} - /* Single line low level line refresh. * * Rewrite the currently edited line accordingly to the buffer content, @@ -593,7 +578,7 @@ static void refreshSingleLine(struct linenoiseState* l) { char buf[LINENOISE_MAX_LINE]; size_t len = l->len; size_t pos = l->pos; - size_t chars = l->chars; + size_t chars = l->totalUTF8Chars; struct abuf ab; uint32_t renderWidth = 0; uint32_t renderPos = 0; @@ -613,7 +598,7 @@ static void refreshSingleLine(struct linenoiseState* l) { posCounter++; totalRenderWidth += charRenderWidth; if (totalRenderWidth >= remainingRenderWidth) { - if (prevPos >= getBufCharPos(l)) { + if (prevPos >= pos) { // We passed the cursor: break, we no longer need to render. charPos = prevPos; break; @@ -791,91 +776,68 @@ bool pastedInput(int ifd) { * On error writing to the terminal -1 is returned, otherwise 0. */ int linenoiseEditInsert(struct linenoiseState* l, char c) { if (l->len < l->buflen) { - if (l->chars == l->pos) { - l->buf[l->len] = c; + if (l->len == l->pos) { + l->buf[l->pos] = c; + l->pos++; l->len++; l->buf[l->len] = '\0'; - - if ((!mlmode && !hintsCallback)) { - char d = (maskmode == 1) ? '*' : c; - if (!Utf8Proc::isValid(&d, 1)) { - utf8store += d; - if (Utf8Proc::isValid(utf8store.c_str(), utf8store.length())) { - utf8store = ""; - l->chars++; - l->pos++; - } - } else { - if (l->plen + l->chars < l->cols) { - if (write(l->ofd, &d, 1) == -1) - return -1; - } - l->chars++; - l->pos++; - } - } - if (!pastedInput(l->ifd) && !inputLeft) { + if ((!mlmode && l->plen + l->len < l->cols && !hintsCallback)) { + /* Avoid a full update of the line in the + * trivial case. */ + if (write(l->ofd, &c, 1) == -1) + return -1; + } else { refreshLine(l); } } else { - if (!Utf8Proc::isValid(&c, 1)) { - utf8store += c; - l->len++; - } - if (Utf8Proc::isValid(utf8store.c_str(), utf8store.length())) { - uint32_t charLoc = getBufCharPos(l); - uint32_t charWidth = std::max((uint32_t)utf8store.length(), 1u); - memmove(l->buf + charLoc + charWidth, l->buf + charLoc, l->len - charLoc); - if (utf8store != "") { - for (auto i = 0u; i < utf8store.length(); i++) { - l->buf[charLoc + i] = utf8store[i]; - } - utf8store = ""; - l->pos++; - l->chars++; - l->buf[l->len] = '\0'; - refreshLine(l); - } else { - l->buf[l->pos] = c; - l->len++; - l->pos++; - l->chars++; - l->buf[l->len] = '\0'; - refreshLine(l); - } - } + memmove(l->buf + l->pos + 1, l->buf + l->pos, l->len - l->pos); + l->buf[l->pos] = c; + l->len++; + l->pos++; + l->buf[l->len] = '\0'; + refreshLine(l); } } + refreshLine(l); return 0; } static uint32_t prevChar(struct linenoiseState* l) { - return Utf8Proc::previousGraphemeCluster(l->buf, l->len, getBufCharPos(l)); + return Utf8Proc::previousGraphemeCluster(l->buf, l->len, l->pos); } static uint32_t nextChar(struct linenoiseState* l) { - return utf8proc_next_grapheme(l->buf, l->len, getBufCharPos(l)); + return utf8proc_next_grapheme(l->buf, l->len, l->pos); } /* Move cursor on the left. */ void linenoiseEditMoveLeft(struct linenoiseState* l) { if (l->pos > 0) { - l->pos--; + l->pos = prevChar(l); refreshLine(l); } } /* Move cursor on the right. */ void linenoiseEditMoveRight(struct linenoiseState* l) { - if (l->pos != l->chars) { - l->pos++; + if (l->pos != l->len) { + l->pos = nextChar(l); refreshLine(l); } } /* Checks to see if character defines a separation between words */ bool isWordSeparator(char c) { - return (c == 0x20); + if (c >= 'a' && c <= 'z') { + return false; + } + if (c >= 'A' && c <= 'Z') { + return false; + } + if (c >= '0' && c <= '9') { + return false; + } + return true; } /* Move cursor one word to the left */ @@ -884,19 +846,19 @@ void linenoiseEditMoveWordLeft(struct linenoiseState* l) { return; } do { - l->pos--; - } while (l->pos > 0 && !isWordSeparator(l->buf[getBufCharPos(l)])); + l->pos = prevChar(l); + } while (l->pos > 0 && !isWordSeparator(l->buf[l->pos])); refreshLine(l); } /* Move cursor one word to the right */ void linenoiseEditMoveWordRight(struct linenoiseState* l) { - if (l->pos == l->chars) { + if (l->pos == l->len) { return; } do { - l->pos++; - } while (l->pos != l->chars && !isWordSeparator(l->buf[getBufCharPos(l)])); + l->pos = nextChar(l); + } while (l->pos != l->len && !isWordSeparator(l->buf[l->pos])); refreshLine(l); } @@ -910,8 +872,8 @@ void linenoiseEditMoveHome(struct linenoiseState* l) { /* Move cursor to the end of the line. */ void linenoiseEditMoveEnd(struct linenoiseState* l) { - if (l->pos != l->chars) { - l->pos = l->chars; + if (l->pos != l->len) { + l->pos = l->len; refreshLine(l); } } @@ -945,13 +907,14 @@ void linenoiseEditHistoryNext(struct linenoiseState* l, int dir) { /* Delete the character at the right of the cursor without altering the cursor * position. Basically this is what happens with the "Delete" keyboard key. */ void linenoiseEditDelete(struct linenoiseState* l) { - if (l->len > 0 && l->pos < l->chars) { + if (l->len > 0 && l->pos < l->len) { uint32_t newPos = nextChar(l); - uint32_t oldPos = getBufCharPos(l); - uint32_t charSize = newPos - oldPos; - memmove(l->buf + oldPos, l->buf + newPos, l->len - oldPos); + uint32_t charSize = newPos - l->pos; + memmove(l->buf + l->pos, l->buf + newPos, l->len - newPos); l->len -= charSize; - l->chars--; + if(charSize > 1) { + l->totalUTF8Chars--; + } l->buf[l->len] = '\0'; refreshLine(l); } @@ -961,12 +924,13 @@ void linenoiseEditDelete(struct linenoiseState* l) { void linenoiseEditBackspace(struct linenoiseState* l) { if (l->pos > 0 && l->len > 0) { uint32_t newPos = prevChar(l); - uint32_t oldPos = getBufCharPos(l); - uint32_t charSize = oldPos - newPos; - memmove(l->buf + newPos, l->buf + oldPos, l->len - newPos); + uint32_t charSize = l->pos - newPos; + memmove(l->buf + newPos, l->buf + l->pos, l->len - l->pos); l->len -= charSize; - l->pos--; - l->chars--; + l->pos = newPos; + if(charSize > 1) { + l->totalUTF8Chars--; + } l->buf[l->len] = '\0'; refreshLine(l); } @@ -1010,7 +974,7 @@ static int linenoiseEdit( l.plen = strlen(prompt); l.oldpos = l.pos = 0; l.len = 0; - l.chars = 0; + l.totalUTF8Chars = 0; l.cols = getColumns(stdin_fd, stdout_fd); l.maxrows = 0; l.history_index = 0;