neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit eb108528044d310c994b967a64375c1b5c4ee770
parent ee84518b94a4159c230ff11436f465bcbedd3c06
Author: glepnir <glephunter@gmail.com>
Date:   Tue,  3 Jun 2025 14:48:53 +0800

vim-patch:9.1.1426: completion: register contents not completed

Problem:  CTRL-X CTRL-R only completes individual words from registers,
          making it difficult to insert complete register content.
Solution: Add consecutive CTRL-X CTRL-R support - first press completes
          words, second press completes full register lines, similar to
          CTRL-X CTRL-L and CTRL-X CTRL-P behavior (glepnir).

closes: vim/vim#17395

https://github.com/vim/vim/commit/d5fdfa5c9cf00790cf720e15c580a591a09fa906

Co-authored-by: glepnir <glephunter@gmail.com>

Diffstat:
Mruntime/doc/index.txt | 2+-
Mruntime/doc/insert.txt | 9+++++++--
Mruntime/doc/usr_24.txt | 2+-
Mruntime/doc/vi_diff.txt | 2+-
Msrc/nvim/insexpand.c | 74++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mtest/old/testdir/test_ins_complete.vim | 21+++++++++++++++++++++
6 files changed, 79 insertions(+), 31 deletions(-)

diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt @@ -146,7 +146,7 @@ commands in CTRL-X submode *i_CTRL-X_index* |i_CTRL-X_CTRL-N| CTRL-X CTRL-N next completion |i_CTRL-X_CTRL-O| CTRL-X CTRL-O omni completion |i_CTRL-X_CTRL-P| CTRL-X CTRL-P previous completion -|i_CTRL-X_CTRL-R| CTRL-X CTRL-R complete words from registers +|i_CTRL-X_CTRL-R| CTRL-X CTRL-R complete contents from registers |i_CTRL-X_CTRL-S| CTRL-X CTRL-S spelling suggestions |i_CTRL-X_CTRL-T| CTRL-X CTRL-T complete identifiers from thesaurus |i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt @@ -629,7 +629,7 @@ Completion can be done for: 11. omni completion |i_CTRL-X_CTRL-O| 12. Spelling suggestions |i_CTRL-X_s| 13. keywords in 'complete' |i_CTRL-N| |i_CTRL-P| -14. words from registers |i_CTRL-X_CTRL-R| +14. contents from registers |i_CTRL-X_CTRL-R| Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text. @@ -1000,7 +1000,7 @@ CTRL-X CTRL-V Guess what kind of item is in front of the cursor and completion, for example: > :imap <Tab> <C-X><C-V> -Completing words from registers *compl-register-words* +Completing contents from registers *compl-register-words* *i_CTRL-X_CTRL-R* CTRL-X CTRL-R Guess what kind of item is in front of the cursor from all registers and find the first match for it. @@ -1014,6 +1014,11 @@ CTRL-X CTRL-R Guess what kind of item is in front of the cursor from CTRL-P Search backwards for previous match. This match replaces the previous one. + CTRL-X CTRL-R Further use of CTRL-X CTRL-R will copy the line + following the previous expansion in other contexts + unless a double CTRL-X is used (e.g. this switches + from completing register words to register contents). + User defined completion *compl-function* Completion is done by a function that can be defined by the user with the diff --git a/runtime/doc/usr_24.txt b/runtime/doc/usr_24.txt @@ -187,7 +187,7 @@ with a certain type of item: CTRL-X CTRL-D macro definitions (also in included files) CTRL-X CTRL-I current and included files CTRL-X CTRL-K words from a dictionary - CTRL-X CTRL-R words from registers + CTRL-X CTRL-R contents from registers CTRL-X CTRL-T words from a thesaurus CTRL-X CTRL-] tags CTRL-X CTRL-V Vim command line diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt @@ -230,7 +230,7 @@ Insert-mode completion. |ins-completion| |i_CTRL-X_CTRL-D| definitions or macros |i_CTRL-X_CTRL-O| Omni completion: clever completion specifically for a file type - |i_CTRL-X_CTRL-R| words from registers + |i_CTRL-X_CTRL-R| contents from registers etc. Long line support. |'wrap'| |'linebreak'| diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c @@ -4209,34 +4209,58 @@ static void get_register_completion(void) continue; } - for (size_t j = 0; j < reg->y_size; j++) { - char *str = reg->y_array[j].data; - if (str == NULL) { - continue; - } + if (compl_status_adding()) { + for (size_t j = 0; j < reg->y_size; j++) { + char *str = reg->y_array[j].data; + if (str == NULL) { + continue; + } - char *p = str; - while (*p != NUL) { - p = find_word_start(p); - if (*p == NUL) { - break; + int str_len = (int)strlen(str); + if (str_len == 0) { + continue; } - char *word_end = find_word_end(p); - int len = (int)(word_end - p); - - // Add the word to the completion list - if (len > 0 && (!compl_orig_text.data - || (p_ic ? STRNICMP(p, compl_orig_text.data, - compl_orig_text.size) == 0 - : strncmp(p, compl_orig_text.data, - compl_orig_text.size) == 0))) { - if (ins_compl_add_infercase(p, len, p_ic, NULL, - dir, false, 0) == OK) { + if (!compl_orig_text.data + || (p_ic ? STRNICMP(str, compl_orig_text.data, + compl_orig_text.size) == 0 + : strncmp(str, compl_orig_text.data, + compl_orig_text.size) == 0)) { + if (ins_compl_add_infercase(str, str_len, p_ic, NULL, dir, false, 0) == OK) { dir = FORWARD; } } - p = word_end; + } + } else { + for (size_t j = 0; j < reg->y_size; j++) { + char *str = reg->y_array[j].data; + if (str == NULL) { + continue; + } + + char *p = str; + while (*p != NUL) { + p = find_word_start(p); + if (*p == NUL) { + break; + } + + char *word_end = find_word_end(p); + int len = (int)(word_end - p); + + // Add the word to the completion list + if (len > 0 && (!compl_orig_text.data + || (p_ic ? STRNICMP(p, compl_orig_text.data, + compl_orig_text.size) == 0 + : strncmp(p, compl_orig_text.data, + compl_orig_text.size) == 0))) { + if (ins_compl_add_infercase(p, len, p_ic, NULL, + dir, false, 0) == OK) { + dir = FORWARD; + } + } + p = word_end; + } } } @@ -5468,7 +5492,7 @@ static int get_spell_compl_info(int startcol, colnr_T curs_col) /// @return OK on success. static int compl_get_info(char *line, int startcol, colnr_T curs_col, bool *line_invalid) { - if (ctrl_x_mode_normal() + if (ctrl_x_mode_normal() || ctrl_x_mode_register() || ((ctrl_x_mode & CTRL_X_WANT_IDENT) && !thesaurus_func_complete(ctrl_x_mode))) { return get_normal_compl_info(line, startcol, curs_col); @@ -5489,8 +5513,6 @@ static int compl_get_info(char *line, int startcol, colnr_T curs_col, bool *line return FAIL; } *line_invalid = true; // "line" may have become invalid - } else if (ctrl_x_mode_register()) { - return get_normal_compl_info(line, startcol, curs_col); } else { internal_error("ins_complete()"); return FAIL; @@ -5546,7 +5568,7 @@ static void ins_compl_continue_search(char *line) if (compl_length < 1) { compl_cont_status &= CONT_LOCAL; } - } else if (ctrl_x_mode_line_or_eval()) { + } else if (ctrl_x_mode_line_or_eval() || ctrl_x_mode_register()) { compl_cont_status = CONT_ADDING | CONT_N_ADDS; } else { compl_cont_status = 0; diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim @@ -4751,6 +4751,27 @@ func Test_register_completion() call feedkeys("Sze\<C-X>\<C-R>\<C-R>=string(complete_info(['mode']))\<CR>\<ESC>", "tx") call assert_equal("zero{'mode': 'register'}", getline(1)) + " Test consecutive CTRL-X CTRL-R (adding mode)Add commentMore actions + " First CTRL-X CTRL-R should split into words, second should use full content + let @f = "hello world test complete" + call setline(1, "hel") + call cursor(1, 3) + call feedkeys("a\<C-X>\<C-R>\<C-N>\<Esc>", 'tx') + call assert_equal("hello", getline(1)) + + " Second consecutive CTRL-X CTRL-R should complete with full content + call setline(1, "hello") + call cursor(1, 5) + call feedkeys("a\<C-X>\<C-R>\<C-X>\<C-R>\<Esc>", 'tx') + call assert_equal("hello world test complete", getline(1)) + + " Test consecutive completion with multi-line register + let @g = "first line content\nsecond line here\nthird line data" + call setline(1, "first") + call cursor(1, 5) + call feedkeys("a\<C-X>\<C-R>\<C-X>\<C-R>\<Esc>", 'tx') + call assert_equal("first line content", getline(1)) + " Clean up bwipe! delfunc GetItems