Compare commits

...

5 Commits

Author SHA1 Message Date
Justin M. Keyes
a427cf8361
Merge f40f4c7d8a into 02bc40c194 2024-12-19 13:11:26 +09:00
zeertzjq
02bc40c194
vim-patch:9.1.0945: ComplMatchIns highlight doesn't end after inserted text (#31628)
Problem:  ComplMatchIns highlight doesn't end after inserted text.
Solution: Handle ComplMatchIns highlight more like search highlight.
          Fix off-by-one error. Handle deleting text properly.
          (zeertzjq)

closes: vim/vim#16244

f25d8f9312
2024-12-18 23:59:03 +00:00
luukvbaal
160cbd0ef4
test(cursor_spec): global highlight definitions (#31613) 2024-12-18 19:06:16 +00:00
Gregory Anders
3db3947b0e
fix(terminal): restore cursor from 'guicursor' on TermLeave (#31620)
Fixes: https://github.com/neovim/neovim/issues/31612
2024-12-18 11:41:05 -06:00
Justin M. Keyes
f40f4c7d8a docs: misc
todo

- https://github.com/neovim/neovim/pull/30085#discussion_r1741869280
2024-12-17 16:12:32 +01:00
20 changed files with 308 additions and 129 deletions

View File

@ -60,7 +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('ComplMatchIns', {})
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

@ -17,10 +17,14 @@ TUI and GUI (assuming the UI supports the given feature). See |TUI| for notes
specific to the terminal UI. Help tags with the "gui-" prefix refer to UI specific to the terminal UI. Help tags with the "gui-" prefix refer to UI
features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|. features, whereas help tags with the "ui-" prefix refer to the |ui-protocol|.
Nvim provides a default, builtin UI (the |TUI|), but there are many other ==============================================================================
(third-party) GUIs that you can use instead: Third-party GUIs *third-party-guis* *vscode*
Nvim provides a builtin "terminal UI" (|TUI|), but also works with many
(third-party) GUIs which may provide a fresh look or extra features on top of
Nvim. For example, "vscode-neovim" essentally allows you to use VSCode as
a Nvim GUI.
*vscode*
- vscode-neovim (Nvim in VSCode!) https://github.com/vscode-neovim/vscode-neovim - vscode-neovim (Nvim in VSCode!) https://github.com/vscode-neovim/vscode-neovim
- Firenvim (Nvim in your web browser!) https://github.com/glacambre/firenvim - Firenvim (Nvim in your web browser!) https://github.com/glacambre/firenvim
- Neovide https://neovide.dev/ - Neovide https://neovide.dev/

View File

@ -32,8 +32,9 @@ and |user-manual|.
Resources *resources* Resources *resources*
*internet* *www* *distribution* *internet* *www* *distribution*
- Nvim home page: https://neovim.io/ Nvim home page:
- Vim FAQ: https://vimhelp.org/vim_faq.txt.html
https://neovim.io/
*book* *book*
There are many resources to learn Vi, Vim, and Nvim. We recommend: There are many resources to learn Vi, Vim, and Nvim. We recommend:
@ -48,6 +49,7 @@ There are many resources to learn Vi, Vim, and Nvim. We recommend:
- For more information try one of these: - For more information try one of these:
- https://iccf-holland.org/click5.html - https://iccf-holland.org/click5.html
- https://www.vim.org/iccf/click5.html - https://www.vim.org/iccf/click5.html
- Vim FAQ: https://vimhelp.org/vim_faq.txt.html
*bugs* *bug-report* *feature-request* *bugs* *bug-report* *feature-request*
Report bugs and request features here: https://github.com/neovim/neovim/issues Report bugs and request features here: https://github.com/neovim/neovim/issues
@ -67,18 +69,24 @@ To install or upgrade Nvim, you can...
- Build from source: - Build from source:
https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-source https://github.com/neovim/neovim/blob/master/INSTALL.md#install-from-source
*uninstall* ------------------------------------------------------------------------------
Un-installing Nvim *uninstall*
To uninstall Nvim: To uninstall Nvim:
- If you downloaded a pre-built archive or built Nvim from source (e.g. `make - If you downloaded a pre-built archive or built Nvim from source (e.g.
install`), just delete its files, typically located in: > `make install`), just delete its files, typically located in: >
/usr/local/bin/nvim /usr/local/bin/nvim
/usr/local/share/nvim /usr/local/share/nvim
<
- To find where Nvim is installed, run these commands: >
:echo v:progpath
:echo $VIMRUNTIME
< <
- If you installed via package manager, read your package manager's - If you installed via package manager, read your package manager's
documentation. Common examples: documentation. Common examples:
- APT (Debian, Ubuntu, …): `apt-get remove neovim` - APT (Debian, Ubuntu, …): `apt-get remove neovim`
- Homebrew (macOS): `brew install neovim` - Homebrew (macOS): `brew uninstall neovim`
- Scoop (Windows): `scoop install neovim` - Scoop (Windows): `scoop uninstall neovim`
============================================================================== ==============================================================================
Sponsor Vim/Nvim development *sponsor* *register* Sponsor Vim/Nvim development *sponsor* *register*

View File

@ -348,22 +348,17 @@ Each response handler has this signature: >
*lsp-handler-resolution* *lsp-handler-resolution*
Handlers can be set by (in increasing priority): Handlers can be set by (in increasing priority):
- Setting a field in vim.lsp.handlers. *vim.lsp.handlers* *vim.lsp.handlers*
`vim.lsp.handlers` is a global table that contains the default mapping of - Setting a field in `vim.lsp.handlers`. The `vim.lsp.handlers` global table
|lsp-method| names to lsp-handlers. contains the default mappings of |lsp-method| names to handlers. (Note: only
for server-to-client requests/notifications, not client-to-server.)
Example: >lua Example: >lua
vim.lsp.handlers['textDocument/publishDiagnostics'] = my_custom_diagnostics_handler vim.lsp.handlers['textDocument/publishDiagnostics'] = my_custom_diagnostics_handler
< <
Note: this only applies for requests/notifications made by the - Passing a {handlers} parameter to |vim.lsp.start()|. This sets the default
server to the client. |lsp-handler| for a specific server. (Note: only for server-to-client
requests/notifications, not client-to-server.)
- The {handlers} parameter of |vim.lsp.start()|. This sets the default
|lsp-handler| for a specific server.
Example: >lua Example: >lua
vim.lsp.start { vim.lsp.start {
..., -- Other configuration omitted. ..., -- Other configuration omitted.
handlers = { handlers = {
@ -371,14 +366,9 @@ Handlers can be set by (in increasing priority):
}, },
} }
< <
Note: this only applies for requests/notifications made by the - Passing a {handler} parameter to |vim.lsp.buf_request_all()|. This sets the
server to the client. |lsp-handler| ONLY for the given request(s).
- The {handler} parameter of |vim.lsp.buf_request_all()|. This sets
the |lsp-handler| ONLY for the given request(s).
Example: >lua Example: >lua
vim.lsp.buf_request_all( vim.lsp.buf_request_all(
0, 0,
'textDocument/publishDiagnostics', 'textDocument/publishDiagnostics',

View File

@ -817,8 +817,8 @@ vim.json.encode({obj}, {opts}) *vim.json.encode()*
Parameters: ~ Parameters: ~
• {obj} (`any`) • {obj} (`any`)
• {opts} (`table<string,any>?`) Options table with keys: • {opts} (`table<string,any>?`) Options table with keys:
• escape_slash: (boolean) (default false) When true, escapes • escape_slash: (boolean) (default false) Escape slash
`/` character in JSON strings characters "/" in string values.
Return: ~ Return: ~
(`string`) (`string`)

View File

@ -12,7 +12,7 @@ manual.
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
============================================================================== ==============================================================================
1. Key mapping *keybind* *key-mapping* *mapping* *macro* 1. Key mapping *keybind* *key-mapping* *mapping*
Key mapping is used to change the meaning of typed keys. The most common use Key mapping is used to change the meaning of typed keys. The most common use
is to define a sequence of commands for a function key. Example: > is to define a sequence of commands for a function key. Example: >

View File

@ -61,7 +61,6 @@ DEFAULTS
current buffer, respectively. current buffer, respectively.
• 'number', 'relativenumber', 'signcolumn', and 'foldcolumn' are disabled in • 'number', 'relativenumber', 'signcolumn', and 'foldcolumn' are disabled in
|terminal| buffers. See |terminal-config| for an example of changing these defaults. |terminal| buffers. See |terminal-config| for an example of changing these defaults.
• |vim.json.encode()| no longer escapes the forward slash symbol by default
DIAGNOSTICS DIAGNOSTICS
@ -124,6 +123,7 @@ LUA
• Command-line completions for: `vim.g`, `vim.t`, `vim.w`, `vim.b`, `vim.v`, • Command-line completions for: `vim.g`, `vim.t`, `vim.w`, `vim.b`, `vim.v`,
`vim.o`, `vim.wo`, `vim.bo`, `vim.opt`, `vim.opt_local`, `vim.opt_global`, `vim.o`, `vim.wo`, `vim.bo`, `vim.opt`, `vim.opt_local`, `vim.opt_global`,
and `vim.fn`. and `vim.fn`.
• |vim.json.encode()| no longer escapes forward slashes "/" by default
OPTIONS OPTIONS
@ -177,7 +177,6 @@ The following new features were added.
API API
• |nvim__ns_set()| can set properties for a namespace • |nvim__ns_set()| can set properties for a namespace
• |vim.json.encode()| has an option to enable forward slash escaping
DEFAULTS DEFAULTS
@ -255,6 +254,7 @@ LUA
is more performant and easier to read. is more performant and easier to read.
• |vim.str_byteindex()| and |vim.str_utfindex()| gained overload signatures • |vim.str_byteindex()| and |vim.str_utfindex()| gained overload signatures
supporting two new parameters, `encoding` and `strict_indexing`. supporting two new parameters, `encoding` and `strict_indexing`.
• |vim.json.encode()| has an option to enable forward slash escaping
OPTIONS OPTIONS
@ -266,6 +266,8 @@ PERFORMANCE
• Significantly reduced redraw time for long lines with treesitter • Significantly reduced redraw time for long lines with treesitter
highlighting. highlighting.
• LSP diagnostics and inlay hints are de-duplicated (new requests cancel
inflight requests). This greatly improves performance with slow LSP servers.
PLUGINS PLUGINS

View File

@ -111,7 +111,7 @@ To abort this type CTRL-C twice.
============================================================================== ==============================================================================
Complex repeats *complex-repeat* Complex repeats *complex-repeat*
*q* *recording* *q* *recording* *macro*
q{0-9a-zA-Z"} Record typed characters into register {0-9a-zA-Z"} q{0-9a-zA-Z"} Record typed characters into register {0-9a-zA-Z"}
(uppercase to append). The 'q' command is disabled (uppercase to append). The 'q' command is disabled
while executing a register, and it doesn't work inside while executing a register, and it doesn't work inside

View File

@ -24,7 +24,7 @@ User configuration and data files are found in standard |base-directories|
session information. |shada| session information. |shada|
============================================================================== ==============================================================================
Defaults *nvim-defaults* Defaults *defaults* *nvim-defaults*
- Filetype detection is enabled by default. This can be disabled by adding - Filetype detection is enabled by default. This can be disabled by adding
":filetype off" to |init.vim|. ":filetype off" to |init.vim|.
@ -291,7 +291,8 @@ Commands:
User commands can support |:command-preview| to show results as you type User commands can support |:command-preview| to show results as you type
- |:write| with "++p" flag creates parent directories. - |:write| with "++p" flag creates parent directories.
Events: Events (autocommands):
- Fixed inconsistent behavior in execution of nested autocommands #23368
- |RecordingEnter| - |RecordingEnter|
- |RecordingLeave| - |RecordingLeave|
- |SearchWrapped| - |SearchWrapped|
@ -299,6 +300,8 @@ Events:
- |TabNewEntered| - |TabNewEntered|
- |TermClose| - |TermClose|
- |TermOpen| - |TermOpen|
- |TermResponse| is fired for any OSC sequence received from the terminal,
instead of the Primary Device Attributes response. |v:termresponse|
- |UIEnter| - |UIEnter|
- |UILeave| - |UILeave|
@ -366,7 +369,7 @@ Options:
- 'shortmess' - 'shortmess'
- "F" flag does not affect output from autocommands. - "F" flag does not affect output from autocommands.
- "q" flag fully hides macro recording message. - "q" flag fully hides macro recording message.
- 'signcolumn' supports up to 9 dynamic/fixed columns - 'signcolumn' can show multiple signs (dynamic or fixed columns)
- 'statuscolumn' full control of columns using 'statusline' format - 'statuscolumn' full control of columns using 'statusline' format
- 'tabline' middle-click on tabpage label closes tabpage, - 'tabline' middle-click on tabpage label closes tabpage,
and %@Func@foo%X can call any function on mouse-click and %@Func@foo%X can call any function on mouse-click
@ -375,6 +378,10 @@ Options:
- 'winblend' pseudo-transparency in floating windows |api-floatwin| - 'winblend' pseudo-transparency in floating windows |api-floatwin|
- 'winhighlight' window-local highlights - 'winhighlight' window-local highlights
Performance:
- Signs are implemented using Nvim's internal "marktree" (btree) structure.
- Folds are not updated during insert-mode.
Providers: Providers:
- If a Python interpreter is available on your `$PATH`, |:python| and - If a Python interpreter is available on your `$PATH`, |:python| and
|:python3| are always available. See |provider-python|. |:python3| are always available. See |provider-python|.
@ -392,6 +399,7 @@ Shell:
- |system()| does not support writing/reading "backgrounded" commands. |E5677| - |system()| does not support writing/reading "backgrounded" commands. |E5677|
Signs: Signs:
- 'signcolumn' can show multiple signs.
- Signs are removed if the associated line is deleted. - Signs are removed if the associated line is deleted.
- Signs placed twice with the same identifier in the same group are moved. - Signs placed twice with the same identifier in the same group are moved.
@ -584,9 +592,6 @@ Mappings:
Motion: Motion:
- The |jumplist| avoids useless/phantom jumps. - The |jumplist| avoids useless/phantom jumps.
Performance:
- Folds are not updated during insert-mode.
Syntax highlighting: Syntax highlighting:
- syncolor.vim has been removed. Nvim now sets up default highlighting groups - syncolor.vim has been removed. Nvim now sets up default highlighting groups
automatically for both light and dark backgrounds, regardless of whether or automatically for both light and dark backgrounds, regardless of whether or
@ -611,12 +616,6 @@ Working directory (Vim implemented some of these after Nvim):
- `getcwd(-1)` is equivalent to `getcwd(-1, 0)` instead of returning the global - `getcwd(-1)` is equivalent to `getcwd(-1, 0)` instead of returning the global
working directory. Use `getcwd(-1, -1)` to get the global working directory. working directory. Use `getcwd(-1, -1)` to get the global working directory.
Autocommands:
- Fixed inconsistent behavior in execution of nested autocommands:
https://github.com/neovim/neovim/issues/23368
- |TermResponse| is fired for any OSC sequence received from the terminal,
instead of the Primary Device Attributes response. |v:termresponse|
Options: Options:
- 'titlestring' uses printf-style '%' items (see: 'statusline') to implement - 'titlestring' uses printf-style '%' items (see: 'statusline') to implement
the default behaviour. The implementation is equivalent to setting the default behaviour. The implementation is equivalent to setting

View File

@ -25,18 +25,18 @@ vim.json = {}
--- ---
---@param str string Stringified JSON data. ---@param str string Stringified JSON data.
---@param opts? table<string,any> Options table with keys: ---@param opts? table<string,any> Options table with keys:
--- - luanil: (table) Table with keys: --- - luanil: (table) Table with keys:
--- * object: (boolean) When true, converts `null` in JSON objects --- - object: (boolean) When true, converts `null` in JSON objects
--- to Lua `nil` instead of |vim.NIL|. --- to Lua `nil` instead of |vim.NIL|.
--- * array: (boolean) When true, converts `null` in JSON arrays --- - array: (boolean) When true, converts `null` in JSON arrays
--- to Lua `nil` instead of |vim.NIL|. --- to Lua `nil` instead of |vim.NIL|.
---@return any ---@return any
function vim.json.decode(str, opts) end function vim.json.decode(str, opts) end
--- Encodes (or "packs") Lua object {obj} as JSON in a Lua string. --- Encodes (or "packs") Lua object {obj} as JSON in a Lua string.
---@param obj any ---@param obj any
---@param opts? table<string,any> Options table with keys: ---@param opts? table<string,any> Options table with keys:
--- - escape_slash: (boolean) (default false) When true, escapes `/` --- - escape_slash: (boolean) (default false) Escape slash
--- character in JSON strings --- characters "/" in string values.
---@return string ---@return string
function vim.json.encode(obj, opts) end function vim.json.encode(obj, opts) end

View File

@ -955,7 +955,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
bool area_highlighting = false; // Visual or incsearch highlighting in this line bool area_highlighting = false; // Visual or incsearch highlighting in this line
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' or ComplMatchIns
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.
@ -969,7 +969,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
int spell_attr = 0; // attributes desired by spelling int spell_attr = 0; // attributes desired by spelling
int word_end = 0; // last byte with same spell_attr int word_end = 0; // last byte with same spell_attr
int cur_checked_col = 0; // checked column for current line int cur_checked_col = 0; // checked column for current line
bool extra_check = 0; // has syntax or linebreak bool extra_check = false; // has extra highlighting
int multi_attr = 0; // attributes desired by multibyte int multi_attr = 0; // attributes desired by multibyte
int mb_l = 1; // multi-byte byte length int mb_l = 1; // multi-byte byte length
int mb_c = 0; // decoded multi-byte character int mb_c = 0; // decoded multi-byte character
@ -1495,6 +1495,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
ptr = line + v; // "line" may have been updated ptr = line + v; // "line" may have been updated
} }
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
area_highlighting = true;
}
win_line_start(wp, &wlv); win_line_start(wp, &wlv);
bool draw_cols = true; bool draw_cols = true;
int leftcols_width = 0; int leftcols_width = 0;
@ -1740,6 +1744,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
if (*ptr == NUL) { if (*ptr == NUL) {
has_match_conc = 0; has_match_conc = 0;
} }
// Check if ComplMatchIns highlight is needed.
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
if (ins_match_attr > 0) {
search_attr = hl_combine_attr(search_attr, ins_match_attr);
}
}
} }
if (wlv.diff_hlf != (hlf_T)0) { if (wlv.diff_hlf != (hlf_T)0) {
@ -1787,16 +1799,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri); wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
} }
// Apply ComplMatchIns highlight if needed.
if (wlv.filler_todo <= 0
&& (State & MODE_INSERT) && in_curline && ins_compl_active()) {
int ins_match_attr = ins_compl_col_range_attr((int)(ptr - line));
if (ins_match_attr > 0) {
char_attr_pri = hl_combine_attr(char_attr_pri, ins_match_attr);
wlv.char_attr = hl_combine_attr(char_attr_base, char_attr_pri);
}
}
if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) { if (draw_folded && has_foldtext && wlv.n_extra == 0 && wlv.col == win_col_offset) {
const int v = (int)(ptr - line); const int v = (int)(ptr - line);
linenr_T lnume = lnum + foldinfo.fi_lines - 1; linenr_T lnume = lnum + foldinfo.fi_lines - 1;

View File

@ -173,7 +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 ComplMatchIns NONE",
"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

@ -958,7 +958,7 @@ static void ins_compl_insert_bytes(char *p, int len)
} }
assert(len >= 0); assert(len >= 0);
ins_bytes_len(p, (size_t)len); ins_bytes_len(p, (size_t)len);
compl_ins_end_col = curwin->w_cursor.col - 1; compl_ins_end_col = curwin->w_cursor.col;
} }
/// Checks if the column is within the currently inserted completion text /// Checks if the column is within the currently inserted completion text
@ -2147,6 +2147,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
&& pum_visible()) { && pum_visible()) {
word = xstrdup(compl_shown_match->cp_str); word = xstrdup(compl_shown_match->cp_str);
retval = true; retval = true;
// May need to remove ComplMatchIns highlight.
redrawWinline(curwin, curwin->w_cursor.lnum);
} }
// CTRL-E means completion is Ended, go back to the typed text. // CTRL-E means completion is Ended, go back to the typed text.
@ -3648,6 +3650,7 @@ void ins_compl_delete(bool new_leader)
return; return;
} }
backspace_until_column(col); backspace_until_column(col);
compl_ins_end_col = curwin->w_cursor.col;
} }
// TODO(vim): is this sufficient for redrawing? Redrawing everything // TODO(vim): is this sufficient for redrawing? Redrawing everything

View File

@ -641,9 +641,6 @@ bool terminal_enter(void)
curwin->w_p_so = 0; curwin->w_p_so = 0;
curwin->w_p_siso = 0; curwin->w_p_siso = 0;
// Save the existing cursor entry since it may be modified by the application
cursorentry_T save_cursorentry = shape_table[SHAPE_IDX_TERM];
// Update the cursor shape table and flush changes to the UI // Update the cursor shape table and flush changes to the UI
s->term->pending.cursor = true; s->term->pending.cursor = true;
refresh_cursor(s->term); refresh_cursor(s->term);
@ -674,8 +671,8 @@ bool terminal_enter(void)
RedrawingDisabled = s->save_rd; RedrawingDisabled = s->save_rd;
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf); apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
shape_table[SHAPE_IDX_TERM] = save_cursorentry; // Restore the terminal cursor to what is set in 'guicursor'
ui_mode_info_set(); (void)parse_shape_opt(SHAPE_CURSOR);
if (save_curwin == curwin->handle) { // Else: window was closed. if (save_curwin == curwin->handle) { // Else: window was closed.
curwin->w_p_cul = save_w_p_cul; curwin->w_p_cul = save_w_p_cul;

View File

@ -152,7 +152,7 @@ describe('vim.json.encode()', function()
clear() clear()
end) end)
it('dumps strings with & without escaped slash', function() it('escape_slash', function()
-- With slash -- With slash
eq('"Test\\/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = true })]])) eq('"Test\\/"', exec_lua([[return vim.json.encode('Test/', { escape_slash = true })]]))
eq( eq(

View File

@ -15,9 +15,20 @@ local skip = t.skip
describe(':terminal cursor', function() describe(':terminal cursor', function()
local screen local screen
local terminal_mode_idx ---@type number
before_each(function() before_each(function()
clear() clear()
screen = tt.setup_screen() screen = tt.setup_screen()
if terminal_mode_idx == nil then
for i, v in ipairs(screen._mode_info) do
if v.name == 'terminal' then
terminal_mode_idx = i
end
end
assert(terminal_mode_idx)
end
end) end)
it('moves the screen cursor when focused', function() it('moves the screen cursor when focused', function()
@ -143,13 +154,6 @@ describe(':terminal cursor', function()
it('can be modified by application #3681', function() it('can be modified by application #3681', function()
skip(is_os('win'), '#31587') skip(is_os('win'), '#31587')
local idx ---@type number
for i, v in ipairs(screen._mode_info) do
if v.name == 'terminal' then
idx = i
end
end
assert(idx)
local states = { local states = {
[1] = { blink = true, shape = 'block' }, [1] = { blink = true, shape = 'block' },
@ -171,13 +175,13 @@ describe(':terminal cursor', function()
]], ]],
condition = function() condition = function()
if v.blink then if v.blink then
eq(500, screen._mode_info[idx].blinkon) eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff) eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
else else
eq(0, screen._mode_info[idx].blinkon) eq(0, screen._mode_info[terminal_mode_idx].blinkon)
eq(0, screen._mode_info[idx].blinkoff) eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
end end
eq(v.shape, screen._mode_info[idx].cursor_shape) eq(v.shape, screen._mode_info[terminal_mode_idx].cursor_shape)
end, end,
}) })
end end
@ -191,20 +195,13 @@ describe(':terminal cursor', function()
]]) ]])
-- Cursor returns to default on TermLeave -- Cursor returns to default on TermLeave
eq(500, screen._mode_info[idx].blinkon) eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff) eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('block', screen._mode_info[idx].cursor_shape) eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
end) end)
it('can be modified per terminal', function() it('can be modified per terminal', function()
skip(is_os('win'), '#31587') skip(is_os('win'), '#31587')
local idx ---@type number
for i, v in ipairs(screen._mode_info) do
if v.name == 'terminal' then
idx = i
end
end
assert(idx)
-- Set cursor to vertical bar with blink -- Set cursor to vertical bar with blink
tt.feed_csi('5 q') tt.feed_csi('5 q')
@ -216,9 +213,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]],
condition = function() condition = function()
eq(500, screen._mode_info[idx].blinkon) eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff) eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape) eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
end, end,
}) })
@ -231,9 +228,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]],
condition = function() condition = function()
eq(500, screen._mode_info[idx].blinkon) eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff) eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape) eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
end, end,
}) })
@ -256,9 +253,9 @@ describe(':terminal cursor', function()
]], ]],
condition = function() condition = function()
-- New terminal, cursor resets to defaults -- New terminal, cursor resets to defaults
eq(500, screen._mode_info[idx].blinkon) eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff) eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('block', screen._mode_info[idx].cursor_shape) eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
end, end,
}) })
@ -275,9 +272,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]],
condition = function() condition = function()
eq(0, screen._mode_info[idx].blinkon) eq(0, screen._mode_info[terminal_mode_idx].blinkon)
eq(0, screen._mode_info[idx].blinkoff) eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
eq('horizontal', screen._mode_info[idx].cursor_shape) eq('horizontal', screen._mode_info[terminal_mode_idx].cursor_shape)
end, end,
}) })
@ -294,9 +291,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]], ]],
condition = function() condition = function()
eq(500, screen._mode_info[idx].blinkon) eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff) eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape) eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
end, end,
}) })
end) end)
@ -326,6 +323,32 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
end) end)
it('preserves guicursor value on TermLeave #31612', function()
eq(3, screen._mode_info[terminal_mode_idx].hl_id)
-- Change 'guicursor' while terminal mode is active
command('set guicursor+=t:Error')
local error_hl_id = call('hlID', 'Error')
screen:expect({
condition = function()
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
end,
})
-- Exit terminal mode
feed([[<C-\><C-N>]])
screen:expect([[
tty ready |
^ |
|*5
]])
eq(error_hl_id, screen._mode_info[terminal_mode_idx].hl_id)
end)
end) end)
describe('buffer cursor position is correct in terminal without number column', function() describe('buffer cursor position is correct in terminal without number column', function()
@ -350,12 +373,6 @@ describe('buffer cursor position is correct in terminal without number column',
}, { }, {
cols = 70, cols = 70,
}) })
screen:set_default_attr_ids({
[1] = { foreground = 253, background = 11 },
[2] = { reverse = true },
[3] = { bold = true },
[4] = { background = 11 },
})
-- Also check for real cursor position, as it is used for stuff like input methods -- Also check for real cursor position, as it is used for stuff like input methods
screen._handle_busy_start = function() end screen._handle_busy_start = function() end
screen._handle_busy_stop = function() end screen._handle_busy_stop = function() end
@ -667,13 +684,6 @@ describe('buffer cursor position is correct in terminal with number column', fun
}, { }, {
cols = 70, cols = 70,
}) })
screen:set_default_attr_ids({
[1] = { foreground = 253, background = 11 },
[2] = { reverse = true },
[3] = { bold = true },
[4] = { background = 11 },
[7] = { foreground = 130 },
})
-- Also check for real cursor position, as it is used for stuff like input methods -- Also check for real cursor position, as it is used for stuff like input methods
screen._handle_busy_start = function() end screen._handle_busy_start = function() end
screen._handle_busy_stop = function() end screen._handle_busy_stop = function() end

View File

@ -94,7 +94,7 @@ describe('ui mode_change event', function()
} }
end) end)
-- oldtest: Test_indent_norm_with_gq() -- oldtest: Test_mouse_shape_indent_norm_with_gq()
it('is restored to Normal mode after "gq" indents using :normal #12309', function() it('is restored to Normal mode after "gq" indents using :normal #12309', function()
screen:try_resize(60, 6) screen:try_resize(60, 6)
n.exec([[ n.exec([[

View File

@ -1162,6 +1162,8 @@ describe('builtin popupmenu', function()
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red }, [6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search [7] = { background = Screen.colors.Yellow }, -- Search
[8] = { foreground = Screen.colors.Red }, [8] = { foreground = Screen.colors.Red },
[9] = { foreground = Screen.colors.Yellow, background = Screen.colors.Green },
[10] = { foreground = Screen.colors.White, background = Screen.colors.Green },
ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey }, ks = { foreground = Screen.colors.Red, background = Screen.colors.Grey },
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 }, kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey }, xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
@ -5625,6 +5627,114 @@ describe('builtin popupmenu', function()
{2:-- INSERT --} | {2:-- INSERT --} |
]]) ]])
feed('<Esc>') feed('<Esc>')
-- text after the inserted text shouldn't be highlighted
feed('0ea <C-X><C-O>')
screen:expect([[
αβγ {8:foo}^ foo |
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-P>')
screen:expect([[
αβγ ^ foo |
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{8:Back at original} |
]])
feed('<C-P>')
screen:expect([[
αβγ {8:}^ foo |
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{s: }{1: }|
{1:~ }|*15
{2:-- }{5:match 3 of 3} |
]])
feed('<C-Y>')
screen:expect([[
αβγ ^ foo |
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<Esc>')
end)
-- oldtest: Test_pum_matchins_highlight_combine()
it('with ComplMatchIns, Normal and CursorLine highlights', function()
exec([[
func Omni_test(findstart, base)
if a:findstart
return col(".")
endif
return [#{word: "foo"}, #{word: "bar"}, #{word: "你好"}]
endfunc
set omnifunc=Omni_test
hi Normal guibg=blue
hi CursorLine guibg=green guifg=white
set cursorline
call setline(1, 'aaa bbb')
]])
-- when ComplMatchIns is not set, CursorLine applies normally
feed('0ea <C-X><C-O>')
screen:expect([[
{10:aaa foo^ bbb }|
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-E>')
screen:expect([[
{10:aaa ^ bbb }|
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<BS><Esc>')
-- when ComplMatchIns is set, it is applied over CursorLine
command('hi ComplMatchIns guifg=Yellow')
feed('0ea <C-X><C-O>')
screen:expect([[
{10:aaa }{9:foo}{10:^ bbb }|
{1:~ }{s: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{5:match 1 of 3} |
]])
feed('<C-P>')
screen:expect([[
{10:aaa ^ bbb }|
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{n: }{1: }|
{1:~ }|*15
{2:-- }{8:Back at original} |
]])
feed('<C-P>')
screen:expect([[
{10:aaa }{9:}{10:^ bbb }|
{1:~ }{n: foo }{1: }|
{1:~ }{n: bar }{1: }|
{1:~ }{s: }{1: }|
{1:~ }|*15
{2:-- }{5:match 3 of 3} |
]])
feed('<C-E>')
screen:expect([[
{10:aaa ^ bbb }|
{1:~ }|*18
{2:-- INSERT --} |
]])
feed('<Esc>')
end) end)
end end
end end

View File

@ -308,7 +308,7 @@ endfunc
" Test that mouse shape is restored to Normal mode after using "gq" when " Test that mouse shape is restored to Normal mode after using "gq" when
" 'indentexpr' executes :normal. " 'indentexpr' executes :normal.
func Test_indent_norm_with_gq() func Test_mouse_shape_indent_norm_with_gq()
CheckFeature mouseshape CheckFeature mouseshape
CheckCanRunGui CheckCanRunGui

View File

@ -1747,13 +1747,67 @@ func Test_pum_matchins_highlight()
call TermWait(buf) call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>") call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_04', {}) call VerifyScreenDump(buf, 'Test_pum_matchins_04', {})
call term_sendkeys(buf, "\<C-E>\<Esc>") call term_sendkeys(buf, "\<Esc>")
" restore after cancel completion " restore after cancel completion
call TermWait(buf) call TermWait(buf)
call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>") call term_sendkeys(buf, "Sαβγ \<C-X>\<C-O>\<Space>")
call VerifyScreenDump(buf, 'Test_pum_matchins_05', {}) call VerifyScreenDump(buf, 'Test_pum_matchins_05', {})
call term_sendkeys(buf, "\<C-E>\<Esc>") call term_sendkeys(buf, "\<Esc>")
" text after the inserted text shouldn't be highlighted
call TermWait(buf)
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_07', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_08', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_09', {})
call term_sendkeys(buf, "\<C-Y>")
call VerifyScreenDump(buf, 'Test_pum_matchins_10', {})
call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf)
endfunc
func Test_pum_matchins_highlight_combine()
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 Normal ctermbg=blue
hi CursorLine cterm=underline ctermbg=green
set cursorline
call setline(1, 'aaa bbb')
END
call writefile(lines, 'Xscript', 'D')
let buf = RunVimInTerminal('-S Xscript', {})
" when ComplMatchIns is not set, CursorLine applies normally
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_01', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_02', {})
call term_sendkeys(buf, "\<BS>\<Esc>")
" when ComplMatchIns is set, it is applied over CursorLine
call TermWait(buf)
call term_sendkeys(buf, ":hi ComplMatchIns ctermbg=red ctermfg=yellow\<CR>")
call TermWait(buf)
call term_sendkeys(buf, "0ea \<C-X>\<C-O>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_03', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_04', {})
call term_sendkeys(buf, "\<C-P>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_05', {})
call term_sendkeys(buf, "\<C-E>")
call VerifyScreenDump(buf, 'Test_pum_matchins_combine_06', {})
call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc