Compare commits

...

9 Commits

Author SHA1 Message Date
glepnir
f8e8f93d36
Merge c14954a840 into 02bc40c194 2024-12-18 17:45:12 -07: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
Lewis Russell
7121983c45 refactor(man.lua): various changes
- Replace all uses of vim.regex with simpler Lua patterns.
- Replace all uses of vim.fn.substitute with string.gsub.
- Rework error handling so expected errors are passed back via a return.
  - These get routed up an passed to `vim.notify()`
  - Any other errors will cause a stack trace.
- Reworked the module initialization of `localfile_arg`
- Updated all type annotations.
- Refactored CLI completion by introduction a parse_cmdline()
  function.
- Simplified `show_toc()`
- Refactor highlighting
- Inline some functions
- Fix completion on MacOS 13 and earlier.
  - Prefer `manpath -q` over `man -w`
- Make completion more efficient by avoiding vim.fn.sort and vim.fn.uniq
  - Reimplement using a single loop
2024-12-18 14:40:36 +00:00
phanium
888a803755
fix(lsp): vim.lsp.start fails if existing client has no workspace_folders #31608
Problem:
regression since https://github.com/neovim/neovim/pull/31340

`nvim -l repro.lua`:
```lua
vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls' }
vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls', root_dir = 'foo' }

-- swapped case will be ok:
-- vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls', root_dir = 'foo' }
-- vim.lsp.start { cmd = { 'lua-language-server' }, name = 'lua_ls' }
```

Failure:
```
E5113: Error while calling lua chunk: /…/lua/vim/lsp.lua:214: bad argument #1 to
'ipairs' (table expected, got nil)
stack traceback:
        [C]: in function 'ipairs'
        /…/lua/vim/lsp.lua:214: in function 'reuse_client'
        /…/lua/vim/lsp.lua:629: in function 'start'
        repro.lua:34: in main chunk
```
2024-12-18 06:37:12 -08:00
Peter Lithammer
07d5dc8938
feat(lsp): show server version in :checkhealth #31611
Problem:
Language server version information missing from `:checkhealth vim.lsp`.

Solution:
Store `InitializeResult.serverInfo.version` from the `initialize`
response and display for each client in `:checkhealth vim.lsp`.
2024-12-18 06:31:25 -08:00
Justin M. Keyes
f9eb68f340
fix(coverity): error handling CHECKED_RETURN #31618
CID 516406:  Error handling issues  (CHECKED_RETURN)
    /src/nvim/api/vimscript.c: 284 in nvim_call_dict_function()
    278       Object rv = OBJECT_INIT;
    279
    280       typval_T rettv;
    281       bool mustfree = false;
    282       switch (dict.type) {
    283       case kObjectTypeString:
    >>>     CID 516406:  Error handling issues  (CHECKED_RETURN)
    >>>     Calling "eval0" without checking return value (as is done elsewhere 10 out of 12 times).
    284         TRY_WRAP(err, {
    285           eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE);
    286           clear_evalarg(&EVALARG_EVALUATE, NULL);
    287         });
    288         if (ERROR_SET(err)) {
    289           return rv;
2024-12-18 06:05:37 -08:00
glepnir
c14954a840 feat(option): add winborder option
Problem:
There is currently no global option to define the default border style for floating windows. This leads to repetitive code when developers need consistent styling across multiple floating windows.

Solution:
Introduce a global option winborder to specify the default border style for floating windows. When a floating window is created without explicitly specifying a border style, the value of the winborder option will be used. This simplifies configuration and ensures consistency in floating window appearance.
2024-12-10 15:05:01 +08:00
30 changed files with 842 additions and 510 deletions

View File

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

View File

@ -3236,28 +3236,20 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
`eob` flag of 'fillchars' to a space char, and clearing
the |hl-EndOfBuffer| region in 'winhighlight'.
• border: Style of (optional) window border. This can either
be a string or an array. The string values are
• "none": No border (default).
• "single": A single line box.
• "double": A double line box.
• "rounded": Like "single", but with rounded corners
("╭" etc.).
• "solid": Adds padding by a single whitespace cell.
• "shadow": A drop shadow effect by blending with the
background.
• If it is an array, it should have a length of eight or
any divisor of eight. The array will specify the eight
chars building up the border in a clockwise fashion
starting with the top-left corner. As an example, the
double box style could be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
be a string or an array. The string values are the same as
those described in 'winborder'. If it is an array, it
should have a length of eight or any divisor of eight. The
array will specify the eight chars building up the border
in a clockwise fashion starting with the top-left corner.
As an example, the double box style could be specified as: >
[ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
<
If the number of chars are less than eight, they will be
repeated. Thus an ASCII border could be specified as >
[ "/", "-", \"\\\\\", "|" ],
If the number of chars are less than eight, they will be
repeated. Thus an ASCII border could be specified as >
[ "/", "-", \"\\\\\", "|" ],
<
or all chars the same as >
[ "x" ].
or all chars the same as >
[ "x" ].
<
An empty string can be used to turn off a specific border,
for instance, >

View File

@ -1126,6 +1126,9 @@ Lua module: vim.lsp.client *lsp-client*
• {server_capabilities} (`lsp.ServerCapabilities?`) Response from the
server sent on `initialize` describing the
server's capabilities.
• {server_info} (`lsp.ServerInfo?`) Response from the server
sent on `initialize` describing information
about the server.
• {progress} (`vim.lsp.Client.Progress`) A ring buffer
(|vim.ringbuf()|) containing progress messages
sent by the server. See

View File

@ -115,6 +115,7 @@ LSP
• |vim.lsp.util.make_position_params()|, |vim.lsp.util.make_range_params()|
and |vim.lsp.util.make_given_range_params()| now require the `position_encoding`
parameter.
• `:checkhealth vim.lsp` displays the server version (if available).
LUA

View File

@ -7125,6 +7125,18 @@ A jump table for the options with a short description can be found at |Q_op|.
UI-dependent. Works best with RGB colors. 'termguicolors'
*'winborder'*
'winborder' string (default "")
global
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("╭" etc.).
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
*'window'* *'wi'*
'window' 'wi' number (default screen height - 1)
global

File diff suppressed because it is too large Load Diff

View File

@ -1804,17 +1804,11 @@ function vim.api.nvim_open_term(buffer, opts) end
--- 'fillchars' to a space char, and clearing the
--- `hl-EndOfBuffer` region in 'winhighlight'.
--- - border: Style of (optional) window border. This can either be a string
--- or an array. The string values are
--- - "none": No border (default).
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
--- - If it is an array, it should have a length of eight or any divisor of
--- eight. The array will specify the eight chars building up the border
--- in a clockwise fashion starting with the top-left corner. As an
--- example, the double box style could be specified as:
--- or an array. The string values are the same as those described in 'winborder'.
--- If it is an array, it should have a length of eight or any divisor of
--- eight. The array will specify the eight chars building up the border
--- in a clockwise fashion starting with the top-left corner. As an
--- example, the double box style could be specified as:
--- ```
--- [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
--- ```

View File

@ -7798,6 +7798,19 @@ vim.o.winbl = vim.o.winblend
vim.wo.winblend = vim.o.winblend
vim.wo.winbl = vim.wo.winblend
--- Defines the default border style of floating windows. The default value
--- is empty, which is equivalent to "none". Valid values include:
--- - "none": No border.
--- - "single": A single line box.
--- - "double": A double line box.
--- - "rounded": Like "single", but with rounded corners ("╭" etc.).
--- - "solid": Adds padding by a single whitespace cell.
--- - "shadow": A drop shadow effect by blending with the background.
---
--- @type string
vim.o.winborder = ""
vim.go.winborder = vim.o.winborder
--- Window height used for `CTRL-F` and `CTRL-B` when there is only one
--- window and the value is smaller than 'lines' minus one. The screen
--- will scroll 'window' minus two lines, with a minimum of one.

View File

@ -211,7 +211,7 @@ local function reuse_client_default(client, config)
for _, config_folder in ipairs(config_folders) do
local found = false
for _, client_folder in ipairs(client.workspace_folders) do
for _, client_folder in ipairs(client.workspace_folders or {}) do
if config_folder.uri == client_folder.uri then
found = true
break

View File

@ -174,6 +174,10 @@ local validate = vim.validate
--- capabilities.
--- @field server_capabilities lsp.ServerCapabilities?
---
--- Response from the server sent on `initialize` describing information about
--- the server.
--- @field server_info lsp.ServerInfo?
---
--- A ring buffer (|vim.ringbuf()|) containing progress messages
--- sent by the server.
--- @field progress vim.lsp.Client.Progress
@ -556,6 +560,8 @@ function Client:initialize()
self.offset_encoding = self.server_capabilities.positionEncoding
end
self.server_info = result.serverInfo
if next(self.settings) then
self:notify(ms.workspace_didChangeConfiguration, { settings = self.settings })
end

View File

@ -40,6 +40,8 @@ local function check_active_clients()
local clients = vim.lsp.get_clients()
if next(clients) then
for _, client in pairs(clients) do
local server_version = vim.tbl_get(client, 'server_info', 'version')
or '? (no serverInfo.version response)'
local cmd ---@type string
local ccmd = client.config.cmd
if type(ccmd) == 'table' then
@ -62,6 +64,7 @@ local function check_active_clients()
end
report_info(table.concat({
string.format('%s (id: %d)', client.name, client.id),
string.format('- Version: %s', server_version),
dirs_info,
string.format('- Command: %s', cmd),
string.format('- Settings: %s', vim.inspect(client.settings, { newline = '\n ' })),

View File

@ -8,9 +8,9 @@ vim.api.nvim_create_user_command('Man', function(params)
if params.bang then
man.init_pager()
else
local ok, err = pcall(man.open_page, params.count, params.smods, params.fargs)
if not ok then
vim.notify(man.errormsg or err, vim.log.levels.ERROR)
local err = man.open_page(params.count, params.smods, params.fargs)
if err then
vim.notify('man.lua: ' .. err, vim.log.levels.ERROR)
end
end
end, {
@ -31,6 +31,9 @@ vim.api.nvim_create_autocmd('BufReadCmd', {
pattern = 'man://*',
nested = true,
callback = function(params)
require('man').read_page(vim.fn.matchstr(params.match, 'man://\\zs.*'))
local err = require('man').read_page(assert(params.match:match('man://(.*)')))
if err then
vim.notify('man.lua: ' .. err, vim.log.levels.ERROR)
end
end,
})

View File

@ -229,10 +229,9 @@ static Object _call_function(String fn, Array args, dict_T *self, Arena *arena,
funcexe.fe_selfdict = self;
TRY_WRAP(err, {
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (see above) to capture abort-causing non-exception errors.
call_func(fn.data, (int)fn.size, &rettv, (int)args.size,
vim_args, &funcexe);
// call_func() retval is deceptive, ignore it. Instead TRY_WRAP sets `msg_list` to capture
// abort-causing non-exception errors.
(void)call_func(fn.data, (int)fn.size, &rettv, (int)args.size, vim_args, &funcexe);
});
if (!ERROR_SET(err)) {
@ -280,18 +279,23 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena,
typval_T rettv;
bool mustfree = false;
switch (dict.type) {
case kObjectTypeString:
case kObjectTypeString: {
int eval_ret;
TRY_WRAP(err, {
eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE);
clear_evalarg(&EVALARG_EVALUATE, NULL);
});
eval_ret = eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE);
clear_evalarg(&EVALARG_EVALUATE, NULL);
});
if (ERROR_SET(err)) {
return rv;
}
if (eval_ret != OK) {
abort(); // Should not happen.
}
// Evaluation of the string arg created a new dict or increased the
// refcount of a dict. Not necessary for a RPC dict.
mustfree = true;
break;
}
case kObjectTypeDict:
object_to_vim(dict, &rettv, err);
break;

View File

@ -160,17 +160,11 @@
/// 'fillchars' to a space char, and clearing the
/// |hl-EndOfBuffer| region in 'winhighlight'.
/// - border: Style of (optional) window border. This can either be a string
/// or an array. The string values are
/// - "none": No border (default).
/// - "single": A single line box.
/// - "double": A double line box.
/// - "rounded": Like "single", but with rounded corners ("╭" etc.).
/// - "solid": Adds padding by a single whitespace cell.
/// - "shadow": A drop shadow effect by blending with the background.
/// - If it is an array, it should have a length of eight or any divisor of
/// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as:
/// or an array. The string values are the same as those described in 'winborder'.
/// If it is an array, it should have a length of eight or any divisor of
/// eight. The array will specify the eight chars building up the border
/// in a clockwise fashion starting with the top-left corner. As an
/// example, the double box style could be specified as:
/// ```
/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ].
/// ```
@ -937,11 +931,11 @@ static void parse_border_style(Object style, WinConfig *fconfig, Error *err)
char chars[8][MAX_SCHAR_SIZE];
bool shadow_color;
} defaults[] = {
{ "double", { "", "", "", "", "", "", "", "" }, false },
{ "single", { "", "", "", "", "", "", "", "" }, false },
{ "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true },
{ "rounded", { "", "", "", "", "", "", "", "" }, false },
{ "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false },
{ opt_winborder_values[0], { "", "", "", "", "", "", "", "" }, false },
{ opt_winborder_values[1], { "", "", "", "", "", "", "", "" }, false },
{ opt_winborder_values[2], { "", "", " ", " ", " ", " ", " ", "" }, true },
{ opt_winborder_values[3], { "", "", "", "", "", "", "", "" }, false },
{ opt_winborder_values[4], { " ", " ", " ", " ", " ", " ", " ", " " }, false },
{ NULL, { { NUL } }, false },
};
@ -1282,12 +1276,13 @@ static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fco
}
}
if (HAS_KEY_X(config, border)) {
if (HAS_KEY_X(config, border) || *p_winbd != NUL) {
if (is_split) {
api_set_error(err, kErrorTypeValidation, "non-float cannot have 'border'");
goto fail;
}
parse_border_style(config->border, fconfig, err);
Object style = config->border.type != kObjectTypeNil ? config->border : CSTR_AS_OBJ(p_winbd);
parse_border_style(style, fconfig, err);
if (ERROR_SET(err)) {
goto fail;
}

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
int vi_attr = 0; // attributes for Visual and incsearch 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 decor_attr = 0; // attributes desired by syntax and extmarks
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 word_end = 0; // last byte with same spell_attr
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 mb_l = 1; // multi-byte byte length
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
}
if ((State & MODE_INSERT) && in_curline && ins_compl_active()) {
area_highlighting = true;
}
win_line_start(wp, &wlv);
bool draw_cols = true;
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) {
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) {
@ -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);
}
// 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) {
const int v = (int)(ptr - line);
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 PmenuKindSel PmenuSel",
"default link PmenuSbar Pmenu",
"default link ComplMatchIns Normal",
"default link ComplMatchIns NONE",
"default link Substitute Search",
"default link StatusLineTerm StatusLine",
"default link StatusLineTermNC StatusLineNC",

View File

@ -958,7 +958,7 @@ static void ins_compl_insert_bytes(char *p, int len)
}
assert(len >= 0);
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
@ -2147,6 +2147,8 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval)
&& pum_visible()) {
word = xstrdup(compl_shown_match->cp_str);
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.
@ -3648,6 +3650,7 @@ void ins_compl_delete(bool new_leader)
return;
}
backspace_until_column(col);
compl_ins_end_col = curwin->w_cursor.col;
}
// TODO(vim): is this sufficient for redrawing? Redrawing everything

View File

@ -608,6 +608,7 @@ EXTERN OptInt p_wcm; ///< 'wildcharm'
EXTERN int p_wic; ///< 'wildignorecase'
EXTERN char *p_wim; ///< 'wildmode'
EXTERN int p_wmnu; ///< 'wildmenu'
EXTERN char *p_winbd; ///< 'winborder'
EXTERN OptInt p_wh; ///< 'winheight'
EXTERN OptInt p_wmh; ///< 'winminheight'
EXTERN OptInt p_wmw; ///< 'winminwidth'

View File

@ -10194,6 +10194,26 @@ return {
short_desc = N_('Controls transparency level for floating windows'),
type = 'number',
},
{
defaults = { if_true = '' },
cb = 'did_set_winborder',
values = { 'double', 'single', 'shadow', 'rounded', 'solid', 'none' },
desc = [=[
Defines the default border style of floating windows. The default value
is empty, which is equivalent to "none". Valid values include:
- "none": No border.
- "single": A single line box.
- "double": A double line box.
- "rounded": Like "single", but with rounded corners ("" etc.).
- "solid": Adds padding by a single whitespace cell.
- "shadow": A drop shadow effect by blending with the background.
]=],
full_name = 'winborder',
scope = { 'global' },
short_desc = N_('border of floating window'),
type = 'string',
varname = 'p_winbd',
},
{
abbreviation = 'wi',
cb = 'did_set_window',

View File

@ -2536,6 +2536,15 @@ const char *did_set_winhighlight(optset_T *args)
return NULL;
}
/// The 'winborder' option is changed.
const char *did_set_winborder(optset_T *args)
{
if (check_opt_strings(p_winbd, opt_winborder_values, true) != OK) {
return e_invarg;
}
return NULL;
}
int expand_set_winhighlight(optexpand_T *args, int *numMatches, char ***matches)
{
return expand_set_opt_generic(args, get_highlight_name, numMatches, matches);

View File

@ -641,9 +641,6 @@ bool terminal_enter(void)
curwin->w_p_so = 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
s->term->pending.cursor = true;
refresh_cursor(s->term);
@ -674,8 +671,8 @@ bool terminal_enter(void)
RedrawingDisabled = s->save_rd;
apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf);
shape_table[SHAPE_IDX_TERM] = save_cursorentry;
ui_mode_info_set();
// Restore the terminal cursor to what is set in 'guicursor'
(void)parse_shape_opt(SHAPE_CURSOR);
if (save_curwin == curwin->handle) { // Else: window was closed.
curwin->w_p_cul = save_w_p_cul;

View File

@ -1854,6 +1854,20 @@ describe('LSP', function()
end,
}
end)
it('vim.lsp.start when existing client has no workspace_folders', function()
exec_lua(create_server_definition)
eq(
{ 2, 'foo', 'foo' },
exec_lua(function()
local server = _G._create_server()
vim.lsp.start { cmd = server.cmd, name = 'foo' }
vim.lsp.start { cmd = server.cmd, name = 'foo', root_dir = 'bar' }
local foos = vim.lsp.get_clients()
return { #foos, foos[1].name, foos[2].name }
end)
)
end)
end)
describe('parsing tests', function()

View File

@ -21,13 +21,12 @@ local function get_search_history(name)
local man = require('man')
local res = {}
--- @diagnostic disable-next-line:duplicate-set-field
man.find_path = function(sect, name0)
man._find_path = function(name0, sect)
table.insert(res, { sect, name0 })
return nil
end
local ok, rv = pcall(man.open_page, -1, { tab = 0 }, args)
assert(not ok)
assert(rv and rv:match('no manual entry'))
local err = man.open_page(-1, { tab = 0 }, args)
assert(err and err:match('no manual entry'))
return res
end)
end
@ -225,7 +224,7 @@ describe(':Man', function()
matches('^/.+', actual_file)
local args = { nvim_prog, '--headless', '+:Man ' .. actual_file, '+q' }
matches(
('Error detected while processing command line:\r\n' .. 'man.lua: "no manual entry for %s"'):format(
('Error detected while processing command line:\r\n' .. 'man.lua: no manual entry for %s'):format(
pesc(actual_file)
),
fn.system(args, { '' })
@ -235,8 +234,8 @@ describe(':Man', function()
it('tries variants with spaces, underscores #22503', function()
eq({
{ '', 'NAME WITH SPACES' },
{ '', 'NAME_WITH_SPACES' },
{ vim.NIL, 'NAME WITH SPACES' },
{ vim.NIL, 'NAME_WITH_SPACES' },
}, get_search_history('NAME WITH SPACES'))
eq({
{ '3', 'some other man' },
@ -255,8 +254,8 @@ describe(':Man', function()
{ 'n', 'some_other_man' },
}, get_search_history('n some other man'))
eq({
{ '', '123some other man' },
{ '', '123some_other_man' },
{ vim.NIL, '123some other man' },
{ vim.NIL, '123some_other_man' },
}, get_search_history('123some other man'))
eq({
{ '1', 'other_man' },
@ -265,11 +264,10 @@ describe(':Man', function()
end)
it('can complete', function()
t.skip(t.is_os('mac') and t.is_arch('x86_64'), 'not supported on intel mac')
eq(
true,
exec_lua(function()
return #require('man').man_complete('f', 'Man g') > 0
return #require('man').man_complete('f', 'Man f') > 0
end)
)
end)

View File

@ -15,9 +15,20 @@ local skip = t.skip
describe(':terminal cursor', function()
local screen
local terminal_mode_idx ---@type number
before_each(function()
clear()
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)
it('moves the screen cursor when focused', function()
@ -143,13 +154,6 @@ describe(':terminal cursor', function()
it('can be modified by application #3681', function()
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 = {
[1] = { blink = true, shape = 'block' },
@ -171,13 +175,13 @@ describe(':terminal cursor', function()
]],
condition = function()
if v.blink then
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
else
eq(0, screen._mode_info[idx].blinkon)
eq(0, screen._mode_info[idx].blinkoff)
eq(0, screen._mode_info[terminal_mode_idx].blinkon)
eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
end
eq(v.shape, screen._mode_info[idx].cursor_shape)
eq(v.shape, screen._mode_info[terminal_mode_idx].cursor_shape)
end,
})
end
@ -191,20 +195,13 @@ describe(':terminal cursor', function()
]])
-- Cursor returns to default on TermLeave
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('block', screen._mode_info[idx].cursor_shape)
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
end)
it('can be modified per terminal', function()
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
tt.feed_csi('5 q')
@ -216,9 +213,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} |
]],
condition = function()
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape)
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
end,
})
@ -231,9 +228,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} |
]],
condition = function()
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape)
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
end,
})
@ -256,9 +253,9 @@ describe(':terminal cursor', function()
]],
condition = function()
-- New terminal, cursor resets to defaults
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('block', screen._mode_info[idx].cursor_shape)
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('block', screen._mode_info[terminal_mode_idx].cursor_shape)
end,
})
@ -275,9 +272,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} |
]],
condition = function()
eq(0, screen._mode_info[idx].blinkon)
eq(0, screen._mode_info[idx].blinkoff)
eq('horizontal', screen._mode_info[idx].cursor_shape)
eq(0, screen._mode_info[terminal_mode_idx].blinkon)
eq(0, screen._mode_info[terminal_mode_idx].blinkoff)
eq('horizontal', screen._mode_info[terminal_mode_idx].cursor_shape)
end,
})
@ -294,9 +291,9 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} |
]],
condition = function()
eq(500, screen._mode_info[idx].blinkon)
eq(500, screen._mode_info[idx].blinkoff)
eq('vertical', screen._mode_info[idx].cursor_shape)
eq(500, screen._mode_info[terminal_mode_idx].blinkon)
eq(500, screen._mode_info[terminal_mode_idx].blinkoff)
eq('vertical', screen._mode_info[terminal_mode_idx].cursor_shape)
end,
})
end)
@ -326,6 +323,32 @@ describe(':terminal cursor', function()
{3:-- TERMINAL --} |
]])
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)
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,
})
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
screen._handle_busy_start = 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,
})
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
screen._handle_busy_start = function() end
screen._handle_busy_stop = function() end

View File

@ -9621,6 +9621,116 @@ describe('float window', function()
})
end
end)
it('#winborder option', function()
local buf = api.nvim_create_buf(false,false)
local config = {relative='editor', width=4, height=4, row=2, col=2}
command('set winborder=single')
api.nvim_open_win(buf, true, config)
if multigrid then
screen:expect({
grid = [[
## grid 1
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
|
{0:~ }|*5
## grid 3
|
## grid 4
{5:}|
{5:}{1:^ }{5:}|
{5:}{2:~ }{5:}|*3
{5:}|
]], float_pos={
[4] = {1001, "NW", 1, 2, 2, true, 50};
}, win_viewport={
[2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
[4] = {win = 1001, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
},
[4] = {
bottom = 1,
left = 1,
right = 1,
top = 1,
win = 1001
}
}
})
else
screen:expect({
grid = [[
{5:} |
{0:~ }{5:}{1:^ }{5:}{0: }|
{0:~ }{5:}{2:~ }{5:}{0: }|*3
{0:~ }{5:}{0: }|
|
]]
})
end
command('fclose')
command('set winborder=double')
api.nvim_open_win(buf, true, config)
if multigrid then
screen:expect({
grid = [[
## grid 1
[2:----------------------------------------]|*6
[3:----------------------------------------]|
## grid 2
|
{0:~ }|*5
## grid 3
|
## grid 5
{5:}|
{5:}{1:^ }{5:}|
{5:}{2:~ }{5:}|*3
{5:}|
]], float_pos={
[5] = {1002, "NW", 1, 2, 2, true, 50};
}, win_viewport={
[2] = {win = 1000, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
[5] = {win = 1002, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1, sum_scroll_delta = 0};
}, win_viewport_margins={
[2] = {
bottom = 0,
left = 0,
right = 0,
top = 0,
win = 1000
},
[5] = {
bottom = 1,
left = 1,
right = 1,
top = 1,
win = 1002
}
}
})
else
screen:expect({
grid = [[
{5:} |
{0:~ }{5:}{1:^ }{5:}{0: }|
{0:~ }{5:}{2:~ }{5:}{0: }|*3
{0:~ }{5:}{0: }|
|
]]
})
end
command('fclose!')
end)
end
describe('with ext_multigrid', function()

View File

@ -94,7 +94,7 @@ describe('ui mode_change event', function()
}
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()
screen:try_resize(60, 6)
n.exec([[

View File

@ -1162,6 +1162,8 @@ describe('builtin popupmenu', function()
[6] = { foreground = Screen.colors.White, background = Screen.colors.Red },
[7] = { background = Screen.colors.Yellow }, -- Search
[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 },
kn = { foreground = Screen.colors.Red, background = Screen.colors.Plum1 },
xs = { foreground = Screen.colors.Black, background = Screen.colors.Grey },
@ -5625,6 +5627,114 @@ describe('builtin popupmenu', function()
{2:-- INSERT --} |
]])
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

View File

@ -75,6 +75,7 @@ let test_values = {
\ 'shada': [['', '''50', '"30'], ['xxx']],
\ 'termpastefilter': [['BS', 'HT', 'FF', 'ESC', 'DEL', 'C0', 'C1', 'C0,C1'],
\ ['xxx', 'C0,C1,xxx']],
\ 'winborder': [['rounded', 'none', 'single', 'solid'], ['xxx']],
\ 'winhighlight': [['', 'a:b', 'a:', 'a:b,c:d'],
\ ['a', ':', ':b', 'a:b:c', 'a:/', '/:b', ',', 'a:b,,', 'a:b,c']],
\

View File

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

View File

@ -1747,13 +1747,67 @@ func Test_pum_matchins_highlight()
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>")
call term_sendkeys(buf, "\<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 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)
endfunc