0
0
mirror of https://github.com/vim/vim.git synced 2025-10-23 08:44:20 -04:00

patch 9.1.1408: not easily possible to complete from register content

Problem:  not easily possible to complete from register content
Solution: add register-completion submode using i_CTRL-X_CTRL-R
          (glepnir)

closes: #17354

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
glepnir
2025-05-26 18:23:27 +02:00
committed by Christian Brabandt
parent 69c3493adc
commit 0546068aae
13 changed files with 218 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
*index.txt* For Vim version 9.1. Last change: 2025 May 14 *index.txt* For Vim version 9.1. Last change: 2025 May 26
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -163,6 +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-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

View File

@@ -1,4 +1,4 @@
*insert.txt* For Vim version 9.1. Last change: 2025 May 08 *insert.txt* For Vim version 9.1. Last change: 2025 May 26
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -649,6 +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|
Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text. Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text.
@@ -1019,6 +1020,21 @@ CTRL-X CTRL-V Guess what kind of item is in front of the cursor and
completion, for example: > completion, for example: >
:imap <Tab> <C-X><C-V> :imap <Tab> <C-X><C-V>
Completing words 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.
Further use of CTRL-R (without CTRL-X) will insert the
register content, see |i_CTRL-R|.
'ignorecase' applies to the matching.
CTRL-N Search forwards for next match. This match replaces
the previous one.
CTRL-P Search backwards for previous match. This match
replaces the previous one.
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

View File

@@ -1,4 +1,4 @@
*options.txt* For Vim version 9.1. Last change: 2025 May 16 *options.txt* For Vim version 9.1. Last change: 2025 May 26
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4658,7 +4658,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'ignorecase' 'ic' boolean (default off) 'ignorecase' 'ic' boolean (default off)
global global
Ignore case in search patterns, |cmdline-completion|, when Ignore case in search patterns, |cmdline-completion|, when
searching in the tags file, and non-|Vim9| |expr-==|. searching in the tags file, non-|Vim9| |expr-==| and for Insert-mode
completion |ins-completion|.
Also see 'smartcase' and 'tagcase'. Also see 'smartcase' and 'tagcase'.
Can be overruled by using "\c" or "\C" in the pattern, see Can be overruled by using "\c" or "\C" in the pattern, see
|/ignorecase|. |/ignorecase|.

View File

@@ -6654,6 +6654,7 @@ compl-generic insert.txt /*compl-generic*
compl-keyword insert.txt /*compl-keyword* compl-keyword insert.txt /*compl-keyword*
compl-omni insert.txt /*compl-omni* compl-omni insert.txt /*compl-omni*
compl-omni-filetypes insert.txt /*compl-omni-filetypes* compl-omni-filetypes insert.txt /*compl-omni-filetypes*
compl-register-words insert.txt /*compl-register-words*
compl-spelling insert.txt /*compl-spelling* compl-spelling insert.txt /*compl-spelling*
compl-states insert.txt /*compl-states* compl-states insert.txt /*compl-states*
compl-stop insert.txt /*compl-stop* compl-stop insert.txt /*compl-stop*
@@ -8425,6 +8426,7 @@ i_CTRL-X_CTRL-L insert.txt /*i_CTRL-X_CTRL-L*
i_CTRL-X_CTRL-N insert.txt /*i_CTRL-X_CTRL-N* i_CTRL-X_CTRL-N insert.txt /*i_CTRL-X_CTRL-N*
i_CTRL-X_CTRL-O insert.txt /*i_CTRL-X_CTRL-O* i_CTRL-X_CTRL-O insert.txt /*i_CTRL-X_CTRL-O*
i_CTRL-X_CTRL-P insert.txt /*i_CTRL-X_CTRL-P* i_CTRL-X_CTRL-P insert.txt /*i_CTRL-X_CTRL-P*
i_CTRL-X_CTRL-R insert.txt /*i_CTRL-X_CTRL-R*
i_CTRL-X_CTRL-S insert.txt /*i_CTRL-X_CTRL-S* i_CTRL-X_CTRL-S insert.txt /*i_CTRL-X_CTRL-S*
i_CTRL-X_CTRL-T insert.txt /*i_CTRL-X_CTRL-T* i_CTRL-X_CTRL-T insert.txt /*i_CTRL-X_CTRL-T*
i_CTRL-X_CTRL-U insert.txt /*i_CTRL-X_CTRL-U* i_CTRL-X_CTRL-U insert.txt /*i_CTRL-X_CTRL-U*

View File

@@ -1,4 +1,4 @@
*todo.txt* For Vim version 9.1. Last change: 2025 Apr 24 *todo.txt* For Vim version 9.1. Last change: 2025 May 26
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4764,7 +4764,6 @@ Insert mode completion/expansion:
7 When expanding $HOME/dir with ^X^F keep the $HOME (with an option?). 7 When expanding $HOME/dir with ^X^F keep the $HOME (with an option?).
7 Add CTRL-X command in Insert mode like CTRL-X CTRL-N, that completes WORDS 7 Add CTRL-X command in Insert mode like CTRL-X CTRL-N, that completes WORDS
instead of words. instead of words.
8 Add CTRL-X CTRL-R: complete words from register contents.
8 Add completion of previously inserted texts (like what CTRL-A does). 8 Add completion of previously inserted texts (like what CTRL-A does).
Requires remembering a number of insertions. Requires remembering a number of insertions.
8 Add 'f' flag to 'complete': Expand file names. 8 Add 'f' flag to 'complete': Expand file names.

View File

@@ -187,6 +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-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

View File

@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.1. Last change: 2025 May 16 *version9.txt* For Vim version 9.1. Last change: 2025 May 26
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41586,6 +41586,9 @@ Support for the |Tuple| data type in Vim script and Vim9 script.
Support for a vertical |tabpanel| window similar to the 'tabline'. Support for a vertical |tabpanel| window similar to the 'tabline'.
New Insert-mode completion: |i_CTRL-X_CTRL-R| to complete words from
registers.
*changed-9.2* *changed-9.2*
Changed~ Changed~
------- -------

View File

@@ -338,6 +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
etc. etc.
Long line support. |'wrap'| |'linebreak'| Long line support. |'wrap'| |'linebreak'|

View File

@@ -929,6 +929,8 @@ doESCkey:
break; break;
case Ctrl_R: // insert the contents of a register case Ctrl_R: // insert the contents of a register
if (ctrl_x_mode_register() && !ins_compl_active())
goto docomplete;
ins_reg(); ins_reg();
auto_format(FALSE, TRUE); auto_format(FALSE, TRUE);
inserted_space = FALSE; inserted_space = FALSE;

View File

@@ -38,6 +38,7 @@
# define CTRL_X_LOCAL_MSG 15 // only used in "ctrl_x_msgs" # define CTRL_X_LOCAL_MSG 15 // only used in "ctrl_x_msgs"
# define CTRL_X_EVAL 16 // for builtin function complete() # define CTRL_X_EVAL 16 // for builtin function complete()
# define CTRL_X_CMDLINE_CTRL_X 17 // CTRL-X typed in CTRL_X_CMDLINE # define CTRL_X_CMDLINE_CTRL_X 17 // CTRL-X typed in CTRL_X_CMDLINE
# define CTRL_X_REGISTER 18 // complete words from registers
# define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT] # define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
@@ -45,7 +46,7 @@
static char *ctrl_x_msgs[] = static char *ctrl_x_msgs[] =
{ {
N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl. N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"), N_(" ^X mode (^]^D^E^F^I^K^L^N^O^P^Rs^U^V^Y)"),
NULL, // CTRL_X_SCROLL: depends on state NULL, // CTRL_X_SCROLL: depends on state
N_(" Whole line completion (^L^N^P)"), N_(" Whole line completion (^L^N^P)"),
N_(" File name completion (^F^N^P)"), N_(" File name completion (^F^N^P)"),
@@ -62,6 +63,7 @@ static char *ctrl_x_msgs[] =
N_(" Keyword Local completion (^N^P)"), N_(" Keyword Local completion (^N^P)"),
NULL, // CTRL_X_EVAL doesn't use msg. NULL, // CTRL_X_EVAL doesn't use msg.
N_(" Command-line completion (^V^N^P)"), N_(" Command-line completion (^V^N^P)"),
N_(" Register completion (^N^P)"),
}; };
#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) #if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
@@ -84,6 +86,7 @@ static char *ctrl_x_mode_names[] = {
NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs" NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
"eval", "eval",
"cmdline", "cmdline",
"register",
}; };
#endif #endif
@@ -330,6 +333,8 @@ static int ctrl_x_mode_eval(void)
{ return ctrl_x_mode == CTRL_X_EVAL; } { return ctrl_x_mode == CTRL_X_EVAL; }
int ctrl_x_mode_line_or_eval(void) int ctrl_x_mode_line_or_eval(void)
{ return ctrl_x_mode == CTRL_X_WHOLE_LINE || ctrl_x_mode == CTRL_X_EVAL; } { return ctrl_x_mode == CTRL_X_WHOLE_LINE || ctrl_x_mode == CTRL_X_EVAL; }
int ctrl_x_mode_register(void)
{ return ctrl_x_mode == CTRL_X_REGISTER; }
/* /*
* Whether other than default completion has been selected. * Whether other than default completion has been selected.
@@ -460,7 +465,7 @@ has_compl_option(int dict_opt)
vim_is_ctrl_x_key(int c) vim_is_ctrl_x_key(int c)
{ {
// Always allow ^R - let its results then be checked // Always allow ^R - let its results then be checked
if (c == Ctrl_R) if (c == Ctrl_R && ctrl_x_mode != CTRL_X_REGISTER)
return TRUE; return TRUE;
// Accept <PageUp> and <PageDown> if the popup menu is visible. // Accept <PageUp> and <PageDown> if the popup menu is visible.
@@ -479,7 +484,7 @@ vim_is_ctrl_x_key(int c)
|| c == Ctrl_N || c == Ctrl_T || c == Ctrl_V || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
|| c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
|| c == Ctrl_S || c == Ctrl_K || c == 's' || c == Ctrl_S || c == Ctrl_K || c == 's'
|| c == Ctrl_Z); || c == Ctrl_Z || c == Ctrl_R);
case CTRL_X_SCROLL: case CTRL_X_SCROLL:
return (c == Ctrl_Y || c == Ctrl_E); return (c == Ctrl_Y || c == Ctrl_E);
case CTRL_X_WHOLE_LINE: case CTRL_X_WHOLE_LINE:
@@ -511,6 +516,8 @@ vim_is_ctrl_x_key(int c)
return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N); return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
case CTRL_X_EVAL: case CTRL_X_EVAL:
return (c == Ctrl_P || c == Ctrl_N); return (c == Ctrl_P || c == Ctrl_N);
case CTRL_X_REGISTER:
return (c == Ctrl_R || c == Ctrl_P || c == Ctrl_N);
} }
internal_error("vim_is_ctrl_x_key()"); internal_error("vim_is_ctrl_x_key()");
return FALSE; return FALSE;
@@ -2535,7 +2542,7 @@ ins_compl_addfrommatch(void)
static int static int
set_ctrl_x_mode(int c) set_ctrl_x_mode(int c)
{ {
int retval = FALSE; int retval = FALSE;
switch (c) switch (c)
{ {
@@ -2563,8 +2570,11 @@ set_ctrl_x_mode(int c)
ctrl_x_mode = CTRL_X_DICTIONARY; ctrl_x_mode = CTRL_X_DICTIONARY;
break; break;
case Ctrl_R: case Ctrl_R:
// Register insertion without exiting CTRL-X mode // When CTRL-R is followed by '=', don't trigger register completion
// Simply allow ^R to happen without affecting ^X mode // This allows expressions like <C-R>=func()<CR> to work normally
if (vpeekc() == '=')
break;
ctrl_x_mode = CTRL_X_REGISTER;
break; break;
case Ctrl_T: case Ctrl_T:
// complete words from a thesaurus // complete words from a thesaurus
@@ -4783,6 +4793,83 @@ expand_cpt_function(callback_T *cb)
} }
#endif #endif
/*
* Get completion matches from register contents.
* Extracts words from all available registers and adds them to the completion list.
*/
static void
get_register_completion(void)
{
int dir = compl_direction;
yankreg_T *reg = NULL;
void *reg_ptr = NULL;
for (int i = 0; i < NUM_REGISTERS; i++)
{
int regname = 0;
if (i == 0)
regname = '"'; // unnamed register
else if (i < 10)
regname = '0' + i;
else if (i == DELETION_REGISTER)
regname = '-';
#ifdef FEAT_CLIPBOARD
else if (i == STAR_REGISTER)
regname = '*';
else if (i == PLUS_REGISTER)
regname = '+';
#endif
else
regname = 'a' + i - 10;
// Skip invalid or black hole register
if (!valid_yank_reg(regname, FALSE) || regname == '_')
continue;
reg_ptr = get_register(regname, FALSE);
if (reg_ptr == NULL)
continue;
reg = (yankreg_T *)reg_ptr;
for (int j = 0; j < reg->y_size; j++)
{
char_u *str = reg->y_array[j].string;
if (str == NULL)
continue;
char_u *p = str;
while (*p != NUL)
{
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)))
{
if (ins_compl_add_infercase(p, len, p_ic, NULL,
dir, FALSE, 0) == OK)
dir = FORWARD;
}
p = word_end;
}
}
// Free the register copy
put_register(regname, reg_ptr);
}
}
/* /*
* get the next set of completion matches for "type". * get the next set of completion matches for "type".
* Returns TRUE if a new match is found. Otherwise returns FALSE. * Returns TRUE if a new match is found. Otherwise returns FALSE.
@@ -4838,6 +4925,10 @@ get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini)
get_next_spell_completion(st->first_match_pos.lnum); get_next_spell_completion(st->first_match_pos.lnum);
break; break;
case CTRL_X_REGISTER:
get_register_completion();
break;
default: // normal ^P/^N and ^X^L default: // normal ^P/^N and ^X^L
found_new_match = get_next_default_completion(st, ini); found_new_match = get_next_default_completion(st, ini);
if (found_new_match == FAIL && st->ins_buf == curbuf) if (found_new_match == FAIL && st->ins_buf == curbuf)
@@ -6125,6 +6216,10 @@ 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()");

View File

@@ -17,6 +17,7 @@ int ctrl_x_mode_spell(void);
int ctrl_x_mode_line_or_eval(void); int ctrl_x_mode_line_or_eval(void);
int ctrl_x_mode_not_default(void); int ctrl_x_mode_not_default(void);
int ctrl_x_mode_not_defined_yet(void); int ctrl_x_mode_not_defined_yet(void);
int ctrl_x_mode_register(void);
int compl_status_adding(void); int compl_status_adding(void);
int compl_status_sol(void); int compl_status_sol(void);
int compl_status_local(void); int compl_status_local(void);

View File

@@ -4521,4 +4521,85 @@ func Test_complete_match()
delfunc TestComplete delfunc TestComplete
endfunc endfunc
func Test_register_completion()
let @a = "completion test apple application"
let @b = "banana behavior better best"
let @c = "complete completion compliment computer"
let g:save_reg = ''
func GetItems()
let g:result = complete_info(['pum_visible'])
endfunc
new
call setline(1, "comp")
call cursor(1, 4)
call feedkeys("a\<C-X>\<C-R>\<C-N>\<C-N>\<Esc>", 'tx')
call assert_equal("compliment", getline(1))
inoremap <buffer><F2> <C-R>=GetItems()<CR>
call feedkeys("S\<C-X>\<C-R>\<F2>\<ESC>", 'tx')
call assert_equal(1, g:result['pum_visible'])
call setline(1, "app")
call cursor(1, 3)
call feedkeys("a\<C-X>\<C-R>\<C-N>\<Esc>", 'tx')
call assert_equal("application", getline(1))
" Test completion with case differences
set ignorecase
let @e = "TestCase UPPERCASE lowercase"
call setline(1, "testc")
call cursor(1, 5)
call feedkeys("a\<C-X>\<C-R>\<Esc>", 'tx')
call assert_equal("TestCase", getline(1))
" Test clipboard registers if available
if has('clipboard_working')
let g:save_reg = getreg('*')
call setreg('*', "clipboard selection unique words")
call setline(1, "uni")
call cursor(1, 3)
call feedkeys("a\<C-X>\<C-R>\<Esc>", 'tx')
call assert_equal("unique", getline(1))
call setreg('*', g:save_reg)
let g:save_reg = getreg('+')
call setreg('+', "system clipboard special content")
call setline(1, "spe")
call cursor(1, 3)
call feedkeys("a\<C-X>\<C-R>\<Esc>", 'tx')
call assert_equal("special", getline(1))
call setreg('+', g:save_reg)
call setreg('*', g:save_reg)
call setreg('a', "normal register")
call setreg('*', "clipboard mixed content")
call setline(1, "mix")
call cursor(1, 3)
call feedkeys("a\<C-X>\<C-R>\<Esc>", 'tx')
call assert_equal("mixed", getline(1))
call setreg('*', g:save_reg)
endif
" Test black hole register should be skipped
let @_ = "blackhole content should not appear"
call setline(1, "black")
call cursor(1, 5)
call feedkeys("a\<C-X>\<C-R>\<Esc>", 'tx')
call assert_equal("black", getline(1))
let @1 = "recent yank zero"
call setline(1, "ze")
call cursor(1, 2)
call feedkeys("a\<C-X>\<C-R>\<Esc>", 'tx')
call assert_equal("zero", getline(1))
" Clean up
bwipe!
delfunc GetItems
unlet g:result
unlet g:save_reg
set ignorecase&
endfunc
" vim: shiftwidth=2 sts=2 expandtab nofoldenable " vim: shiftwidth=2 sts=2 expandtab nofoldenable

View File

@@ -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 */
/**/
1408,
/**/ /**/
1407, 1407,
/**/ /**/