]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.1426: completion: register contents not completed v9.1.1426
authorglepnir <glephunter@gmail.com>
Mon, 2 Jun 2025 17:45:41 +0000 (19:45 +0200)
committerChristian Brabandt <cb@256bit.org>
Mon, 2 Jun 2025 17:45:41 +0000 (19:45 +0200)
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: #17395

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/index.txt
runtime/doc/insert.txt
runtime/doc/usr_24.txt
runtime/doc/vi_diff.txt
src/insexpand.c
src/testdir/test_ins_complete.vim
src/version.c

index d03d81effac88755b6c53b99bebbd6443f3b9201..ff2799470683486f6d7f5a3f538c8277b7ab2bb3 100644 (file)
@@ -1,4 +1,4 @@
-*index.txt*     For Vim version 9.1.  Last change: 2025 May 26
+*index.txt*     For Vim version 9.1.  Last change: 2025 Jun 02
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -163,7 +163,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
index 553183d74dad58d7e8a44f17132f8d3de885d3f7..9ec46825e4c1fa46bc0c1f7f08dd5a5f6f1a8807 100644 (file)
@@ -1,4 +1,4 @@
-*insert.txt*    For Vim version 9.1.  Last change: 2025 May 26
+*insert.txt*    For Vim version 9.1.  Last change: 2025 Jun 02
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -649,7 +649,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.
 
@@ -1021,7 +1021,7 @@ CTRL-X CTRL-V             Guess what kind of item is in front of the cursor and
                                :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.
@@ -1035,6 +1035,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
index 250bd17ea6ffb5f82c160eee82dd3683b93ce9ca..0f724957474c534016664f451fcb7c7457ef643d 100644 (file)
@@ -1,4 +1,4 @@
-*usr_24.txt*   For Vim version 9.1.  Last change: 2018 Mar 18
+*usr_24.txt*   For Vim version 9.1.  Last change: 2025 Jun 02
 
                     VIM USER MANUAL - by Bram Moolenaar
 
@@ -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
index ae14968bbe185a130bf44487b344642e9ed098a2..b35fe77c7809b78909b87d2343da9973943b2267 100644 (file)
@@ -1,4 +1,4 @@
-*vi_diff.txt*   For Vim version 9.1.  Last change: 2025 Mar 28
+*vi_diff.txt*   For Vim version 9.1.  Last change: 2025 Jun 02
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -338,7 +338,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'|
index 51dd675b1379f7e28477afc4dfece18fe9c4dce0..9b5eec500df21ed70057783a67f6ff32c81ae3b5 100644 (file)
@@ -4935,35 +4935,83 @@ get_register_completion(void)
 
        reg = (yankreg_T *)reg_ptr;
 
-       for (int j = 0; j < reg->y_size; j++)
+       if (compl_status_adding())
        {
-           char_u *str = reg->y_array[j].string;
-           if (str == NULL)
-               continue;
-
-           char_u *p = str;
-           while (*p != NUL)
+           for (int j = 0; j < reg->y_size; j++)
            {
-               p = find_word_start(p);
-               if (*p == NUL)
-                   break;
-
-               char_u *word_end = find_word_end(p);
-
-               // Add the word to the completion list
-               int len = (int)(word_end - p);
-               if (len > 0 && (!compl_orig_text.string
-                           || (p_ic ? STRNICMP(p, compl_orig_text.string,
-                                               compl_orig_text.length) == 0
-                               : STRNCMP(p, compl_orig_text.string,
-                                           compl_orig_text.length) == 0)))
+               char_u *str = reg->y_array[j].string;
+               if (str == NULL)
+                   continue;
+
+               int str_len = (int)STRLEN(str);
+               if (str_len == 0)
+                   continue;
+
+               if (!compl_orig_text.string
+                       || (p_ic ? STRNICMP(str, compl_orig_text.string,
+                                           compl_orig_text.length) == 0
+                               : STRNCMP(str, compl_orig_text.string,
+                                           compl_orig_text.length) == 0))
                {
-                   if (ins_compl_add_infercase(p, len, p_ic, NULL,
-                                                       dir, FALSE, 0) == OK)
+                   if (ins_compl_add_infercase(str, str_len, p_ic, NULL, dir, FALSE, 0) == OK)
                        dir = FORWARD;
                }
+           }
+       }
+       else
+       {
+           for (int j = 0; j < reg->y_size; j++)
+           {
+               char_u *str = reg->y_array[j].string;
+               if (str == NULL)
+                   continue;
+
+               // Calculate the safe end of string to avoid null byte issues
+               char_u *str_end = str + STRLEN(str);
+               char_u *p = str;
+
+               // Safely iterate through the string
+               while (p < str_end && *p != NUL)
+               {
+                   char_u *old_p = p;
+                   p = find_word_start(p);
+                   if (p >= str_end || *p == NUL)
+                       break;
 
-               p = word_end;
+                   char_u *word_end = find_word_end(p);
+
+                   if (word_end <= p)
+                   {
+                       if (has_mbyte)
+                           word_end = p + (*mb_ptr2len)(p);
+                       else
+                           word_end = p + 1;
+                   }
+
+                   if (word_end > str_end)
+                       word_end = str_end;
+
+                   int len = (int)(word_end - p);
+                   if (len > 0 && (!compl_orig_text.string
+                               || (p_ic ? STRNICMP(p, compl_orig_text.string,
+                                                   compl_orig_text.length) == 0
+                                       : STRNCMP(p, compl_orig_text.string,
+                                                   compl_orig_text.length) == 0)))
+                   {
+                       if (ins_compl_add_infercase(p, len, p_ic, NULL,
+                                                   dir, FALSE, 0) == OK)
+                           dir = FORWARD;
+                   }
+
+                   p = word_end;
+
+                   if (p <= old_p)
+                   {
+                       p = old_p + 1;
+                       if (has_mbyte && p < str_end)
+                           p = old_p + (*mb_ptr2len)(old_p);
+                   }
+               }
            }
        }
 
@@ -6379,7 +6427,7 @@ get_spell_compl_info(int startcol UNUSED, colnr_T curs_col UNUSED)
     static int
 compl_get_info(char_u *line, int startcol, colnr_T curs_col, int *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)))
     {
@@ -6410,10 +6458,6 @@ compl_get_info(char_u *line, int startcol, colnr_T curs_col, int *line_invalid)
            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()");
@@ -6480,7 +6524,7 @@ ins_compl_continue_search(char_u *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;
index f3c29d1e76fc7ec60ac4144fed6f17796935e98f..7d67e9f057c3e2d205b9ce1b0dab4b7eaa6bbad1 100644 (file)
@@ -4670,6 +4670,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)
+  " 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
index df6eb585cefce6216fee4cc1023d70d5f5b6547d..3160bdfeca7f30c295fc30dbc19bdc606a03286c 100644 (file)
@@ -709,6 +709,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1426,
 /**/
     1425,
 /**/