From e91e48354750d28a76f65966443a8fa4f098d72d Mon Sep 17 00:00:00 2001 From: Andreas Kupries Date: Wed, 20 Feb 2013 16:12:35 -0800 Subject: [PATCH] New feature: Maintain a cut/paste buffer. The existing bindings for Ctrl+k, Ctrl+u, and Ctrl+w are modified to fill the cut buffer with the characters they deleted. The new binding for Ctrl+y inserts the contents of the cut buffer at the current position. --- linenoise.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/linenoise.c b/linenoise.c index 11e82fe..c06d88e 100644 --- a/linenoise.c +++ b/linenoise.c @@ -168,6 +168,7 @@ struct current { int pos; /* Cursor position, measured in chars */ int cols; /* Size of the window, in chars */ const char *prompt; + char *capture; /* Allocated capture buffer, or NULL for none. Always null terminated */ #if defined(USE_TERMIOS) int fd; /* Terminal fd */ #elif defined(USE_WINCONSOLE) @@ -939,16 +940,64 @@ static int insert_char(struct current *current, int pos, int ch) } /** + * Captures up to 'n' characters starting at 'pos' for the cut buffer. + * + * This replaces any existing characters in the cut buffer. + */ +static void capture_chars(struct current *current, int pos, int n) +{ + if (pos >= 0 && (pos + n - 1) < current->chars) { + int p1 = utf8_index(current->buf, pos); + int nbytes = utf8_index(current->buf + p1, n); + + if (nbytes) { + free(current->capture); + /* Include space for the null terminator */ + current->capture = (char *)malloc(nbytes + 1); + memcpy(current->capture, current->buf + p1, nbytes); + current->capture[nbytes] = '\0'; + } + } +} + +/** + * Removes up to 'n' characters at cursor position 'pos'. + * * Returns 0 if no chars were removed or non-zero otherwise. */ static int remove_chars(struct current *current, int pos, int n) { int removed = 0; + + /* First save any chars which will be removed */ + capture_chars(current, pos, n); + while (n-- && remove_char(current, pos)) { removed++; } return removed; } +/** + * Inserts the characters (string) 'chars' at the cursor position 'pos'. + * + * Returns 0 if no chars were inserted or non-zero otherwise. + */ +static int insert_chars(struct current *current, int pos, const char *chars) +{ + int inserted = 0; + + while (*chars) { + int ch; + int n = utf8_tounicode(chars, &ch); + if (insert_char(current, pos, ch) == 0) { + break; + } + inserted++; + pos++; + chars += n; + } + return inserted; +} #ifndef NO_COMPLETION static linenoiseCompletionCallback *completionCallback = NULL; @@ -1099,7 +1148,7 @@ process_char: * Future possibility: Toggle Insert/Overwrite Modes */ break; - case ctrl('W'): /* ctrl-w */ + case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */ /* eat any spaces on the left */ { int pos = current->pos; @@ -1301,16 +1350,21 @@ history_navigation: current->pos = current->chars; refreshLine(current->prompt, current); break; - case ctrl('U'): /* Ctrl+u, delete to beginning of line. */ + case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */ if (remove_chars(current, 0, current->pos)) { refreshLine(current->prompt, current); } break; - case ctrl('K'): /* Ctrl+k, delete from current to end of line. */ + case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */ if (remove_chars(current, current->pos, current->chars - current->pos)) { refreshLine(current->prompt, current); } break; + case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */ + if (current->capture && insert_chars(current, current->pos, current->capture)) { + refreshLine(current->prompt, current); + } + break; case ctrl('L'): /* Ctrl+L, clear screen */ clearScreen(current); /* Force recalc of window size for serial terminals */ @@ -1365,10 +1419,14 @@ char *linenoise(const char *prompt) current.chars = 0; current.pos = 0; current.prompt = prompt; + current.capture = NULL; count = linenoisePrompt(¤t); + disableRawMode(¤t); printf("\n"); + + free(current.capture); if (count == -1) { return NULL; } -- 2.44.0