mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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: #17395
Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
			
			
This commit is contained in:
		
				
					committed by
					
						 Christian Brabandt
						Christian Brabandt
					
				
			
			
				
	
			
			
			
						parent
						
							3993cd619a
						
					
				
				
					commit
					d5fdfa5c9c
				
			| @@ -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 | 		  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-N|	CTRL-X CTRL-N	next completion | ||||||
| |i_CTRL-X_CTRL-O|	CTRL-X CTRL-O	omni 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-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-S|	CTRL-X CTRL-S	spelling suggestions | ||||||
| |i_CTRL-X_CTRL-T|	CTRL-X CTRL-T	complete identifiers from thesaurus | |i_CTRL-X_CTRL-T|	CTRL-X CTRL-T	complete identifiers from thesaurus | ||||||
| |i_CTRL-X_CTRL-Y|	CTRL-X CTRL-Y	scroll down | |i_CTRL-X_CTRL-Y|	CTRL-X CTRL-Y	scroll down | ||||||
|   | |||||||
| @@ -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 | 		  VIM REFERENCE MANUAL    by Bram Moolenaar | ||||||
| @@ -649,7 +649,7 @@ Completion can be done for: | |||||||
| 11. omni completion					|i_CTRL-X_CTRL-O| | 11. omni completion					|i_CTRL-X_CTRL-O| | ||||||
| 12. Spelling suggestions				|i_CTRL-X_s| | 12. Spelling suggestions				|i_CTRL-X_s| | ||||||
| 13. keywords in 'complete'				|i_CTRL-N| |i_CTRL-P| | 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. | 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> | 				: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* | 							*i_CTRL-X_CTRL-R* | ||||||
| CTRL-X CTRL-R		Guess what kind of item is in front of the cursor from | 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. | 			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 | 	CTRL-P		Search backwards for previous match.  This match | ||||||
| 			replaces the previous one. | 			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* | User defined completion					*compl-function* | ||||||
|  |  | ||||||
| Completion is done by a function that can be defined by the user with the | Completion is done by a function that can be defined by the user with the | ||||||
|   | |||||||
| @@ -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 | 		     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-D		macro definitions (also in included files) | ||||||
| 	CTRL-X CTRL-I		current and included files | 	CTRL-X CTRL-I		current and included files | ||||||
| 	CTRL-X CTRL-K		words from a dictionary | 	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-T		words from a thesaurus | ||||||
| 	CTRL-X CTRL-]		tags | 	CTRL-X CTRL-]		tags | ||||||
| 	CTRL-X CTRL-V		Vim command line | 	CTRL-X CTRL-V		Vim command line | ||||||
|   | |||||||
| @@ -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 | 		  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-D|	definitions or macros | ||||||
| 	|i_CTRL-X_CTRL-O|	Omni completion: clever completion | 	|i_CTRL-X_CTRL-O|	Omni completion: clever completion | ||||||
| 				specifically for a file type | 				specifically for a file type | ||||||
| 	|i_CTRL-X_CTRL-R|	words from registers | 	|i_CTRL-X_CTRL-R|	contents from registers | ||||||
| 	etc. | 	etc. | ||||||
|  |  | ||||||
| Long line support.					|'wrap'| |'linebreak'| | Long line support.					|'wrap'| |'linebreak'| | ||||||
|   | |||||||
| @@ -4935,35 +4935,83 @@ get_register_completion(void) | |||||||
|  |  | ||||||
| 	reg = (yankreg_T *)reg_ptr; | 	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; | 	    for (int j = 0; j < reg->y_size; j++) | ||||||
| 	    if (str == NULL) |  | ||||||
| 		continue; |  | ||||||
|  |  | ||||||
| 	    char_u *p = str; |  | ||||||
| 	    while (*p != NUL) |  | ||||||
| 	    { | 	    { | ||||||
| 		p = find_word_start(p); | 		char_u *str = reg->y_array[j].string; | ||||||
| 		if (*p == NUL) | 		if (str == NULL) | ||||||
| 		    break; | 		    continue; | ||||||
|  |  | ||||||
| 		char_u *word_end = find_word_end(p); | 		int str_len = (int)STRLEN(str); | ||||||
|  | 		if (str_len == 0) | ||||||
|  | 		    continue; | ||||||
|  |  | ||||||
| 		// Add the word to the completion list | 		if (!compl_orig_text.string | ||||||
| 		int len = (int)(word_end - p); | 			|| (p_ic ? STRNICMP(str, compl_orig_text.string, | ||||||
| 		if (len > 0 && (!compl_orig_text.string | 					    compl_orig_text.length) == 0 | ||||||
| 			    || (p_ic ? STRNICMP(p, compl_orig_text.string, | 				: STRNCMP(str, compl_orig_text.string, | ||||||
| 						compl_orig_text.length) == 0 | 					    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, | 		    if (ins_compl_add_infercase(str, str_len, p_ic, NULL, dir, FALSE, 0) == OK) | ||||||
| 							dir, FALSE, 0) == OK) |  | ||||||
| 			dir = FORWARD; | 			dir = FORWARD; | ||||||
| 		} | 		} | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 	    for (int j = 0; j < reg->y_size; j++) | ||||||
|  | 	    { | ||||||
|  | 		char_u *str = reg->y_array[j].string; | ||||||
|  | 		if (str == NULL) | ||||||
|  | 		    continue; | ||||||
|  |  | ||||||
| 		p = word_end; | 		// 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; | ||||||
|  |  | ||||||
|  | 		    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 |     static int | ||||||
| compl_get_info(char_u *line, int startcol, colnr_T curs_col, int *line_invalid) | 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 | 	    || (ctrl_x_mode & CTRL_X_WANT_IDENT | ||||||
| 		&& !thesaurus_func_complete(ctrl_x_mode))) | 		&& !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; | 	    return FAIL; | ||||||
| 	*line_invalid = TRUE;	// "line" may have become invalid | 	*line_invalid = TRUE;	// "line" may have become invalid | ||||||
|     } |     } | ||||||
|     else if (ctrl_x_mode_register()) |  | ||||||
|     { |  | ||||||
| 	return get_normal_compl_info(line, startcol, curs_col); |  | ||||||
|     } |  | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
| 	internal_error("ins_complete()"); | 	internal_error("ins_complete()"); | ||||||
| @@ -6480,7 +6524,7 @@ ins_compl_continue_search(char_u *line) | |||||||
| 	if (compl_length < 1) | 	if (compl_length < 1) | ||||||
| 	    compl_cont_status &= CONT_LOCAL; | 	    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; | 	compl_cont_status = CONT_ADDING | CONT_N_ADDS; | ||||||
|     else |     else | ||||||
| 	compl_cont_status = 0; | 	compl_cont_status = 0; | ||||||
|   | |||||||
| @@ -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 feedkeys("Sze\<C-X>\<C-R>\<C-R>=string(complete_info(['mode']))\<CR>\<ESC>", "tx") | ||||||
|   call assert_equal("zero{'mode': 'register'}", getline(1)) |   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 |   " Clean up | ||||||
|   bwipe! |   bwipe! | ||||||
|   delfunc GetItems |   delfunc GetItems | ||||||
|   | |||||||
| @@ -709,6 +709,8 @@ static char *(features[]) = | |||||||
|  |  | ||||||
| static int included_patches[] = | static int included_patches[] = | ||||||
| {   /* Add new patch number below this line */ | {   /* Add new patch number below this line */ | ||||||
|  | /**/ | ||||||
|  |     1426, | ||||||
| /**/ | /**/ | ||||||
|     1425, |     1425, | ||||||
| /**/ | /**/ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user