vim-patch:9.1.0936: cannot highlight completed text

Problem:  cannot highlight completed text
Solution: (optionally) highlight auto-completed text using the
          ComplMatchIns highlight group (glepnir)

closes: vim/vim#16173

6a38aff218

Co-authored-by: glepnir <glephunter@gmail.com>
This commit is contained in:
zeertzjq 2024-12-17 12:40:30 +08:00
parent 0dd933265f
commit c830901e8c
7 changed files with 101 additions and 13 deletions

View File

@ -60,6 +60,7 @@ hi('PmenuMatch', { link = 'Pmenu' })
hi('PmenuMatchSel', { link = 'PmenuSel' }) hi('PmenuMatchSel', { link = 'PmenuSel' })
hi('PmenuExtra', { link = 'Pmenu' }) hi('PmenuExtra', { link = 'Pmenu' })
hi('PmenuExtraSel', { link = 'PmenuSel' }) hi('PmenuExtraSel', { link = 'PmenuSel' })
hi('ComplMatchIns', { link = 'Normal' })
hi('Substitute', { link = 'Search' }) hi('Substitute', { link = 'Search' })
hi('Whitespace', { link = 'NonText' }) hi('Whitespace', { link = 'NonText' })
hi('MsgSeparator', { link = 'StatusLine' }) hi('MsgSeparator', { link = 'StatusLine' })

View File

@ -216,6 +216,7 @@ EDITOR
• On Windows, filename arguments on the command-line prefixed with "~\" or • On Windows, filename arguments on the command-line prefixed with "~\" or
"~/" are now expanded to the user's profile directory, not a relative path "~/" are now expanded to the user's profile directory, not a relative path
to a literal "~" directory. to a literal "~" directory.
• |hl-ComplMatchIns| shows matched text of the currently inserted completion.
• |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup. • |hl-PmenuMatch| and |hl-PmenuMatchSel| show matched text in completion popup.
EVENTS EVENTS

View File

@ -5243,6 +5243,8 @@ PmenuMatch Popup menu: Matched text in normal item. Combined with
*hl-PmenuMatchSel* *hl-PmenuMatchSel*
PmenuMatchSel Popup menu: Matched text in selected item. Combined with PmenuMatchSel Popup menu: Matched text in selected item. Combined with
|hl-PmenuMatch| and |hl-PmenuSel|. |hl-PmenuMatch| and |hl-PmenuSel|.
*hl-ComplMatchIns*
ComplMatchIns Matched text of the currently inserted completion.
*hl-Question* *hl-Question*
Question |hit-enter| prompt and yes/no questions. Question |hit-enter| prompt and yes/no questions.
*hl-QuickFixLine* *hl-QuickFixLine*

View File

@ -31,6 +31,7 @@
#include "nvim/highlight_defs.h" #include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h" #include "nvim/highlight_group.h"
#include "nvim/indent.h" #include "nvim/indent.h"
#include "nvim/insexpand.h"
#include "nvim/mark_defs.h" #include "nvim/mark_defs.h"
#include "nvim/marktree_defs.h" #include "nvim/marktree_defs.h"
#include "nvim/match.h" #include "nvim/match.h"
@ -934,6 +935,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
colnr_T vcol_prev = -1; // "wlv.vcol" of previous character colnr_T vcol_prev = -1; // "wlv.vcol" of previous character
ScreenGrid *grid = &wp->w_grid; // grid specific to the window ScreenGrid *grid = &wp->w_grid; // grid specific to the window
const bool in_curline = wp == curwin && lnum == curwin->w_cursor.lnum;
const bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0; const bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0;
const bool has_foldtext = has_fold && *wp->w_p_fdt != NUL; const bool has_foldtext = has_fold && *wp->w_p_fdt != NUL;
@ -954,6 +956,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
int vi_attr = 0; // attributes for Visual and incsearch highlighting int vi_attr = 0; // attributes for Visual and incsearch highlighting
int area_attr = 0; // attributes desired by highlighting int area_attr = 0; // attributes desired by highlighting
int search_attr = 0; // attributes desired by 'hlsearch' int search_attr = 0; // attributes desired by 'hlsearch'
int ins_match_attr = 0; // attributes desired by PmenuMatch
int vcol_save_attr = 0; // saved attr for 'cursorcolumn' int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
int decor_attr = 0; // attributes desired by syntax and extmarks int decor_attr = 0; // attributes desired by syntax and extmarks
bool has_syntax = false; // this buffer has syntax highl. bool has_syntax = false; // this buffer has syntax highl.
@ -1117,7 +1120,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
} }
// Check if the char under the cursor should be inverted (highlighted). // Check if the char under the cursor should be inverted (highlighted).
if (!highlight_match && lnum == curwin->w_cursor.lnum && wp == curwin if (!highlight_match && in_curline
&& cursor_is_block_during_visual(*p_sel == 'e')) { && cursor_is_block_during_visual(*p_sel == 'e')) {
noinvcur = true; noinvcur = true;
} }
@ -2704,6 +2707,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
vcol_prev = wlv.vcol; vcol_prev = wlv.vcol;
} }
if (wlv.filler_todo <= 0
&& (State & MODE_INSERT) && in_curline && ins_compl_active()) {
ins_match_attr = ins_compl_col_range_attr(wlv.col);
if (ins_match_attr > 0) {
wlv.char_attr = hl_combine_attr(wlv.char_attr, ins_match_attr);
}
}
// Store character to be displayed. // Store character to be displayed.
// Skip characters that are left of the screen for 'nowrap'. // Skip characters that are left of the screen for 'nowrap'.
if (wlv.filler_todo > 0) { if (wlv.filler_todo > 0) {

View File

@ -173,6 +173,7 @@ static const char *highlight_init_both[] = {
"default link PmenuKind Pmenu", "default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel", "default link PmenuKindSel PmenuSel",
"default link PmenuSbar Pmenu", "default link PmenuSbar Pmenu",
"default link ComplMatchIns Normal",
"default link Substitute Search", "default link Substitute Search",
"default link StatusLineTerm StatusLine", "default link StatusLineTerm StatusLine",
"default link StatusLineTermNC StatusLineNC", "default link StatusLineTermNC StatusLineNC",

View File

@ -256,6 +256,7 @@ static pos_T compl_startpos;
static int compl_length = 0; static int compl_length = 0;
static colnr_T compl_col = 0; ///< column where the text starts static colnr_T compl_col = 0; ///< column where the text starts
///< that is being completed ///< that is being completed
static colnr_T compl_ins_end_col = 0;
static char *compl_orig_text = NULL; ///< text as it was before static char *compl_orig_text = NULL; ///< text as it was before
///< completion started ///< completion started
/// Undo information to restore extmarks for original text. /// Undo information to restore extmarks for original text.
@ -282,6 +283,11 @@ static size_t spell_bad_len = 0; // length of located bad word
static int compl_selected_item = -1; static int compl_selected_item = -1;
// "compl_match_array" points the currently displayed list of entries in the
// popup menu. It is NULL when there is no popup menu.
static pumitem_T *compl_match_array = NULL;
static int compl_match_arraysize;
/// CTRL-X pressed in Insert mode. /// CTRL-X pressed in Insert mode.
void ins_ctrl_x(void) void ins_ctrl_x(void)
{ {
@ -943,6 +949,30 @@ static bool ins_compl_equal(compl_T *match, char *str, size_t len)
return strncmp(match->cp_str, str, len) == 0; return strncmp(match->cp_str, str, len) == 0;
} }
/// when len is -1 mean use whole length of p otherwise part of p
static void ins_compl_insert_bytes(char *p, int len)
FUNC_ATTR_NONNULL_ALL
{
if (len == -1) {
len = (int)strlen(p);
}
assert(len >= 0);
ins_bytes_len(p, (size_t)len);
compl_ins_end_col = curwin->w_cursor.col - 1;
}
/// Checks if the column is within the currently inserted completion text
/// column range. If it is, it returns a special highlight attribute.
/// -1 mean normal item.
int ins_compl_col_range_attr(int col)
{
if (col >= compl_col && col < compl_ins_end_col) {
return syn_name2attr("ComplMatchIns");
}
return -1;
}
/// Reduce the longest common string for match "match". /// Reduce the longest common string for match "match".
static void ins_compl_longest_match(compl_T *match) static void ins_compl_longest_match(compl_T *match)
{ {
@ -952,7 +982,7 @@ static void ins_compl_longest_match(compl_T *match)
bool had_match = (curwin->w_cursor.col > compl_col); bool had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete(false); ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len()); ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
ins_redraw(false); ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it // When the match isn't there (to avoid matching itself) remove it
@ -986,7 +1016,7 @@ static void ins_compl_longest_match(compl_T *match)
*p = NUL; *p = NUL;
bool had_match = (curwin->w_cursor.col > compl_col); bool had_match = (curwin->w_cursor.col > compl_col);
ins_compl_delete(false); ins_compl_delete(false);
ins_bytes(compl_leader + get_compl_len()); ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
ins_redraw(false); ins_redraw(false);
// When the match isn't there (to avoid matching itself) remove it // When the match isn't there (to avoid matching itself) remove it
@ -1058,11 +1088,6 @@ unsigned get_cot_flags(void)
return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags; return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags;
} }
/// "compl_match_array" points the currently displayed list of entries in the
/// popup menu. It is NULL when there is no popup menu.
static pumitem_T *compl_match_array = NULL;
static int compl_match_arraysize;
/// Remove any popup menu. /// Remove any popup menu.
static void ins_compl_del_pum(void) static void ins_compl_del_pum(void)
{ {
@ -1678,6 +1703,7 @@ void ins_compl_clear(void)
compl_cont_status = 0; compl_cont_status = 0;
compl_started = false; compl_started = false;
compl_matches = 0; compl_matches = 0;
compl_ins_end_col = 0;
XFREE_CLEAR(compl_pattern); XFREE_CLEAR(compl_pattern);
compl_patternlen = 0; compl_patternlen = 0;
XFREE_CLEAR(compl_leader); XFREE_CLEAR(compl_leader);
@ -1802,7 +1828,7 @@ static void ins_compl_new_leader(void)
{ {
ins_compl_del_pum(); ins_compl_del_pum();
ins_compl_delete(true); ins_compl_delete(true);
ins_bytes(compl_leader + get_compl_len()); ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
compl_used_match = false; compl_used_match = false;
if (compl_started) { if (compl_started) {
@ -2137,7 +2163,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
const int compl_len = get_compl_len(); const int compl_len = get_compl_len();
const int len = (int)strlen(p); const int len = (int)strlen(p);
if (len > compl_len) { if (len > compl_len) {
ins_bytes_len(p + compl_len, (size_t)(len - compl_len)); ins_compl_insert_bytes(p + compl_len, len - compl_len);
} }
} }
restore_orig_extmarks(); restore_orig_extmarks();
@ -3639,7 +3665,7 @@ void ins_compl_insert(bool in_compl_func)
// Make sure we don't go over the end of the string, this can happen with // Make sure we don't go over the end of the string, this can happen with
// illegal bytes. // illegal bytes.
if (compl_len < (int)strlen(compl_shown_match->cp_str)) { if (compl_len < (int)strlen(compl_shown_match->cp_str)) {
ins_bytes(compl_shown_match->cp_str + compl_len); ins_compl_insert_bytes(compl_shown_match->cp_str + compl_len, -1);
} }
compl_used_match = !match_at_original_text(compl_shown_match); compl_used_match = !match_at_original_text(compl_shown_match);
@ -3888,14 +3914,15 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match
// Insert the text of the new completion, or the compl_leader. // Insert the text of the new completion, or the compl_leader.
if (compl_no_insert && !started) { if (compl_no_insert && !started) {
ins_bytes(compl_orig_text + get_compl_len()); ins_compl_insert_bytes(compl_orig_text + get_compl_len(), -1);
compl_used_match = false; compl_used_match = false;
restore_orig_extmarks(); restore_orig_extmarks();
} else if (insert_match) { } else if (insert_match) {
if (!compl_get_longest || compl_used_match) { if (!compl_get_longest || compl_used_match) {
ins_compl_insert(in_compl_func); ins_compl_insert(in_compl_func);
} else { } else {
ins_bytes(compl_leader + get_compl_len()); assert(compl_leader != NULL);
ins_compl_insert_bytes(compl_leader + get_compl_len(), -1);
} }
if (!strcmp(compl_curr_match->cp_str, compl_orig_text)) { if (!strcmp(compl_curr_match->cp_str, compl_orig_text)) {
restore_orig_extmarks(); restore_orig_extmarks();

View File

@ -1713,4 +1713,49 @@ func Test_pum_keep_select()
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
func Test_pum_matchins_higlight()
CheckScreendump
let lines =<< trim END
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi ComplMatchIns ctermfg=red
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
call TermWait(buf)
call term_sendkeys(buf, "S\<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_01', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call TermWait(buf)
call term_sendkeys(buf, "S\<C-X>\<C-O>\<C-N>")
call VerifyScreenDump(buf, 'Test_pum_matchins_02', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call TermWait(buf)
call term_sendkeys(buf, "S\<C-X>\<C-O>\<C-N>\<C-N>")
call VerifyScreenDump(buf, 'Test_pum_matchins_03', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" restore after accept
call TermWait(buf)
call term_sendkeys(buf, "S\<C-X>\<C-O>\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
" restore after cancel completion
call TermWait(buf)
call term_sendkeys(buf, "S\<C-X>\<C-O>\<Space>")
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
call StopVimInTerminal(buf)
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab