From 06347a64cac5e33574713a59ace9d1d0ea4b6f82 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 05:19:46 +0800 Subject: vim-patch:9.1.0443: Can't use blockwise selection with width for getregion() (#28985) Problem: Can't use a blockwise selection with a width for getregion(). Solution: Add support for blockwise selection with width like the return value of getregtype() or the "regtype" value of TextYankPost (zeertzjq). closes: vim/vim#14842 https://github.com/vim/vim/commit/afc2295c2201ae87bfbb42d5f5315ad0583ccabf --- runtime/doc/builtin.txt | 11 +++--- runtime/lua/vim/_meta/vimfn.lua | 11 +++--- src/nvim/eval.lua | 11 +++--- src/nvim/eval/funcs.c | 30 +++++++++------ test/old/testdir/test_visual.vim | 81 ++++++++++++++++++++++++++++++---------- 5 files changed, 96 insertions(+), 48 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index ff7d5f9ce8..5b1dd2ca47 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -2930,14 +2930,13 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()* The optional argument {opts} is a Dict and supports the following items: - type Specify the region's selection type - (default: "v"): - "v" for |charwise| mode - "V" for |linewise| mode - "" for |blockwise-visual| mode + type Specify the region's selection type. + See |getregtype()| for possible values, + except it cannot be an empty string. + (default: "v") exclusive If |TRUE|, use exclusive selection - for the end position + for the end position. (default: follow 'selection') You can get the last selection type by |visualmode()|. diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index f4daacfb7d..d1455fa993 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3536,14 +3536,13 @@ function vim.fn.getreginfo(regname) end --- The optional argument {opts} is a Dict and supports the --- following items: --- ---- type Specify the region's selection type ---- (default: "v"): ---- "v" for |charwise| mode ---- "V" for |linewise| mode ---- "" for |blockwise-visual| mode +--- type Specify the region's selection type. +--- See |getregtype()| for possible values, +--- except it cannot be an empty string. +--- (default: "v") --- --- exclusive If |TRUE|, use exclusive selection ---- for the end position +--- for the end position. --- (default: follow 'selection') --- --- You can get the last selection type by |visualmode()|. diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 7d4438ded6..4adf3ce959 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -4370,14 +4370,13 @@ M.funcs = { The optional argument {opts} is a Dict and supports the following items: - type Specify the region's selection type - (default: "v"): - "v" for |charwise| mode - "V" for |linewise| mode - "" for |blockwise-visual| mode + type Specify the region's selection type. + See |getregtype()| for possible values, + except it cannot be an empty string. + (default: "v") exclusive If |TRUE|, use exclusive selection - for the end position + for the end position. (default: follow 'selection') You can get the last selection type by |visualmode()|. diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e4cb63eb8e..3cb6ef41c0 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2824,7 +2824,7 @@ static char *block_def2str(struct block_def *bd) } static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2, - bool *const inclusive, MotionType *region_type, oparg_T *oa) + bool *const inclusive, MotionType *region_type, oparg_T *oap) FUNC_ATTR_NONNULL_ALL { tv_list_alloc_ret(rettv, kListLenMayKnow); @@ -2858,11 +2858,17 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 type = default_type; } + int block_width = 0; if (type[0] == 'v' && type[1] == NUL) { *region_type = kMTCharWise; } else if (type[0] == 'V' && type[1] == NUL) { *region_type = kMTLineWise; - } else if (type[0] == Ctrl_V && type[1] == NUL) { + } else if (type[0] == Ctrl_V) { + char *p = type + 1; + if (*p != NUL && ((block_width = getdigits_int(&p, false, 0)) <= 0 || *p != NUL)) { + semsg(_(e_invargNval), "type", type); + return FAIL; + } *region_type = kMTBlockWise; } else { semsg(_(e_invargNval), "type", type); @@ -2926,16 +2932,18 @@ static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2 colnr_T sc1, ec1, sc2, ec2; getvvcol(curwin, p1, &sc1, NULL, &ec1); getvvcol(curwin, p2, &sc2, NULL, &ec2); - oa->motion_type = kMTBlockWise; - oa->inclusive = true; - oa->op_type = OP_NOP; - oa->start = *p1; - oa->end = *p2; - oa->start_vcol = MIN(sc1, sc2); - if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { - oa->end_vcol = sc2 - 1; + oap->motion_type = kMTBlockWise; + oap->inclusive = true; + oap->op_type = OP_NOP; + oap->start = *p1; + oap->end = *p2; + oap->start_vcol = MIN(sc1, sc2); + if (block_width > 0) { + oap->end_vcol = oap->start_vcol + block_width - 1; + } else if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { + oap->end_vcol = sc2 - 1; } else { - oa->end_vcol = MAX(ec1, ec2); + oap->end_vcol = MAX(ec1, ec2); } } diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim index b7b5f611c4..f414f502f7 100644 --- a/test/old/testdir/test_visual.vim +++ b/test/old/testdir/test_visual.vim @@ -1968,6 +1968,14 @@ func Test_visual_getregion() #" using invalid value for "type" call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '' })", 'E475:') call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': 'v0' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': 'v0' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': 'V0' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': 'V0' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '\0' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '\0' })", 'E475:') + call assert_fails("call getregion(getpos('.'), getpos('.'), {'type': '\1:' })", 'E475:') + call assert_fails("call getregionpos(getpos('.'), getpos('.'), {'type': '\1:' })", 'E475:') #" using a mark from another buffer to current buffer new @@ -2546,30 +2554,65 @@ func Test_getregion_invalid_buf() bwipe! endfunc -func Test_getregion_maxcol() - new +func Test_getregion_after_yank() + func! Check_Results(type) + call assert_equal(g:expected_region, + \ getregion(getpos("'["), getpos("']"), #{ type: a:type })) + call assert_equal(g:expected_regionpos, + \ getregionpos(getpos("'["), getpos("']"), #{ type: a:type })) + call assert_equal(g:expected_region, + \ getregion(getpos("']"), getpos("'["), #{ type: a:type })) + call assert_equal(g:expected_regionpos, + \ getregionpos(getpos("']"), getpos("'["), #{ type: a:type })) + let g:checked = 1 + endfunc + autocmd TextYankPost * \ : if v:event.operator ==? 'y' - \ | call assert_equal([ - \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], - \ ], - \ getregionpos(getpos("'["), getpos("']"), - \ #{ mode: visualmode() })) - \ | call assert_equal(['abcd'], - \ getregion(getpos("'["), getpos("']"), - \ #{ mode: visualmode() })) - \ | call assert_equal([ - \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], - \ ], - \ getregionpos(getpos("']"), getpos("'["), - \ #{ mode: visualmode() })) - \ | call assert_equal(['abcd'], - \ getregion(getpos("']"), getpos("'["), - \ #{ mode: visualmode() })) + \ | call Check_Results(v:event.regtype) \ | endif - call setline(1, ['abcd', 'efghij']) + + new + call setline(1, ['abcd', 'efghijk', 'lmn']) + + let g:expected_region = ['abcd'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], + \ ] + let g:checked = 0 normal yy + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + + let g:expected_region = ['cd', 'ghijk', 'n'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 3, 0], [bufnr('%'), 1, 4, 0]], + \ [[bufnr('%'), 2, 3, 0], [bufnr('%'), 2, 7, 0]], + \ [[bufnr('%'), 3, 3, 0], [bufnr('%'), 3, 3, 0]], + \ ] + let g:checked = 0 + call feedkeys("gg0ll\jj$y", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + + let g:expected_region = ['bc', 'fg', 'mn'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 2, 0], [bufnr('%'), 1, 3, 0]], + \ [[bufnr('%'), 2, 2, 0], [bufnr('%'), 2, 3, 0]], + \ [[bufnr('%'), 3, 2, 0], [bufnr('%'), 3, 3, 0]], + \ ] + let g:checked = 0 + call feedkeys("gg0l\jjly", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + bwipe! + + unlet g:expected_region + unlet g:expected_regionpos + unlet g:checked + autocmd! TextYankPost + delfunc Check_Results endfunc func Test_visual_block_cursor_delete() -- cgit From 5d26934c7cda191f0b519c1326fa318b857ffcb8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 24 May 2024 18:31:25 -0500 Subject: feat(lsp): update LSP healthcheck format (#28980) This is mostly an aesthetic change, although there are a few new pieces of information included. Originally I wanted to investigate including server capabilities in the healthcheck, but until we have the ability to fold/unfold text in health checks that would be too much information. --- runtime/lua/vim/lsp/health.lua | 83 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index a79ae76eb9..b5dc710cc6 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -33,16 +33,22 @@ local function check_active_clients() local clients = vim.lsp.get_clients() if next(clients) then for _, client in pairs(clients) do - local attached_to = table.concat(vim.tbl_keys(client.attached_buffers or {}), ',') - report_info( + local cmd ---@type string + if type(client.config.cmd) == 'table' then + cmd = table.concat(client.config.cmd --[[@as table]], ' ') + elseif type(client.config.cmd) == 'function' then + cmd = tostring(client.config.cmd) + end + report_info(table.concat({ + string.format('%s (id: %d)', client.name, client.id), + string.format(' Root directory: %s', vim.fn.fnamemodify(client.root_dir, ':~')), + string.format(' Command: %s', cmd), + string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })), string.format( - '%s (id=%s, root_dir=%s, attached_to=[%s])', - client.name, - client.id, - vim.fn.fnamemodify(client.root_dir, ':~'), - attached_to - ) - ) + ' Attached buffers: %s', + vim.iter(pairs(client.attached_buffers)):map(tostring):join(', ') + ), + }, '\n')) end else report_info('No active clients') @@ -50,7 +56,7 @@ local function check_active_clients() end local function check_watcher() - vim.health.start('vim.lsp: File watcher') + vim.health.start('vim.lsp: File Watcher') -- Only run the check if file watching has been enabled by a client. local clients = vim.lsp.get_clients() @@ -94,11 +100,68 @@ local function check_watcher() end end +local function check_position_encodings() + vim.health.start('vim.lsp: Position Encodings') + local clients = vim.lsp.get_clients() + if next(clients) then + local position_encodings = {} ---@type table> + for _, client in pairs(clients) do + for bufnr in pairs(client.attached_buffers) do + if not position_encodings[bufnr] then + position_encodings[bufnr] = {} + end + if not position_encodings[bufnr][client.offset_encoding] then + position_encodings[bufnr][client.offset_encoding] = {} + end + table.insert(position_encodings[bufnr][client.offset_encoding], client.id) + end + end + + -- Check if any buffers are attached to multiple clients with different position encodings + local buffers = {} ---@type integer[] + for bufnr, encodings in pairs(position_encodings) do + local list = {} ---@type string[] + for k in pairs(encodings) do + list[#list + 1] = k + end + + if #list > 1 then + buffers[#buffers + 1] = bufnr + end + end + + if #buffers > 0 then + local lines = + { 'Found buffers attached to multiple clients with different position encodings.' } + for _, bufnr in ipairs(buffers) do + local encodings = position_encodings[bufnr] + local parts = {} + for encoding, client_ids in pairs(encodings) do + table.insert( + parts, + string.format('%s (client id(s): %s)', encoding:upper(), table.concat(client_ids, ', ')) + ) + end + table.insert(lines, string.format('- Buffer %d: %s', bufnr, table.concat(parts, ', '))) + end + report_warn( + table.concat(lines, '\n'), + 'Use the positionEncodings client capability to ensure all clients use the same position encoding' + ) + else + report_info('No buffers contain mixed position encodings') + end + else + report_info('No active clients') + end +end + --- Performs a healthcheck for LSP function M.check() check_log() check_active_clients() check_watcher() + check_position_encodings() end return M -- cgit From 93c55c238f4c1088da4dc6ec80103eb3ef4085d2 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 25 May 2024 01:39:06 +0200 Subject: test(lintdoc): check that input list is same length as output list (#28976) --- scripts/gen_help_html.lua | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua index cdfb85bde6..e238fee5f8 100644 --- a/scripts/gen_help_html.lua +++ b/scripts/gen_help_html.lua @@ -1434,12 +1434,10 @@ function M.test_gen(help_dir) help_dir = vim.fn.expand(help_dir or '$VIMRUNTIME/doc') print('doc path = ' .. vim.uv.fs_realpath(help_dir)) - local rv = M.gen( - help_dir, - tmpdir, - -- Because gen() is slow (~30s), this test is limited to a few files. - { 'help.txt', 'index.txt', 'nvim.txt' } - ) + -- Because gen() is slow (~30s), this test is limited to a few files. + local input = { 'help.txt', 'index.txt', 'nvim.txt' } + local rv = M.gen(help_dir, tmpdir, input) + eq(#input, #rv.helpfiles) eq(0, rv.err_count, 'parse errors in :help docs') eq({}, rv.invalid_links, 'invalid tags in :help docs') end -- cgit From 8b2b1fba2abfb99186e3a1f0123251a3e2eae3fe Mon Sep 17 00:00:00 2001 From: glepnir Date: Fri, 3 May 2024 15:53:13 +0800 Subject: fix(float): missing default highlight for title Problem: there is missing default title highlight when highlight not defined in title text chunk. Solution: when attr is not set use default title highlight group. --- runtime/doc/api.txt | 6 ++++-- runtime/lua/vim/_meta/api.lua | 6 ++++-- src/nvim/api/win_config.c | 9 +++------ src/nvim/drawscreen.c | 12 ++++++++---- test/functional/ui/float_spec.lua | 16 ++++++++-------- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 86f4c3875c..2ca34150f3 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -3270,13 +3270,15 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()* < • title: Title (optional) in window border, string or list. List should consist of `[text, highlight]` tuples. If - string, the default highlight group is `FloatTitle`. + string, or a tuple lacks a highlight, the default + highlight group is `FloatTitle`. • title_pos: Title position. Must be set with `title` option. Value can be one of "left", "center", or "right". Default is `"left"`. • footer: Footer (optional) in window border, string or list. List should consist of `[text, highlight]` tuples. - If string, the default highlight group is `FloatFooter`. + If string, or a tuple lacks a highlight, the default + highlight group is `FloatFooter`. • footer_pos: Footer position. Must be set with `footer` option. Value can be one of "left", "center", or "right". Default is `"left"`. diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 64c67be076..ae43863316 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -1731,13 +1731,15 @@ function vim.api.nvim_open_term(buffer, opts) end --- --- • title: Title (optional) in window border, string or list. --- List should consist of `[text, highlight]` tuples. If ---- string, the default highlight group is `FloatTitle`. +--- string, or a tuple lacks a highlight, the default +--- highlight group is `FloatTitle`. --- • title_pos: Title position. Must be set with `title` --- option. Value can be one of "left", "center", or "right". --- Default is `"left"`. --- • footer: Footer (optional) in window border, string or --- list. List should consist of `[text, highlight]` tuples. ---- If string, the default highlight group is `FloatFooter`. +--- If string, or a tuple lacks a highlight, the default +--- highlight group is `FloatFooter`. --- • footer_pos: Footer position. Must be set with `footer` --- option. Value can be one of "left", "center", or "right". --- Default is `"left"`. diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 3a9986a7d1..70235d8db6 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -189,13 +189,13 @@ /// ``` /// - title: Title (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatTitle`. +/// If string, or a tuple lacks a highlight, the default highlight group is `FloatTitle`. /// - title_pos: Title position. Must be set with `title` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. /// - footer: Footer (optional) in window border, string or list. /// List should consist of `[text, highlight]` tuples. -/// If string, the default highlight group is `FloatFooter`. +/// If string, or a tuple lacks a highlight, the default highlight group is `FloatFooter`. /// - footer_pos: Footer position. Must be set with `footer` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. @@ -851,7 +851,6 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, bool *is_present; VirtText *chunks; int *width; - int default_hl_id; switch (bordertext_type) { case kBorderTextTitle: if (fconfig->title) { @@ -861,7 +860,6 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, is_present = &fconfig->title; chunks = &fconfig->title_chunks; width = &fconfig->title_width; - default_hl_id = syn_check_group(S_LEN("FloatTitle")); break; case kBorderTextFooter: if (fconfig->footer) { @@ -871,7 +869,6 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, is_present = &fconfig->footer; chunks = &fconfig->footer_chunks; width = &fconfig->footer_width; - default_hl_id = syn_check_group(S_LEN("FloatFooter")); break; } @@ -881,7 +878,7 @@ static void parse_bordertext(Object bordertext, BorderTextType bordertext_type, return; } kv_push(*chunks, ((VirtTextChunk){ .text = xstrdup(bordertext.data.string.data), - .hl_id = default_hl_id })); + .hl_id = -1 })); *width = (int)mb_string2cells(bordertext.data.string.data); *is_present = true; return; diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index bda0ccc870..039bbd219c 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -65,6 +65,7 @@ #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" #include "nvim/buffer.h" +#include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cursor.h" @@ -715,14 +716,17 @@ void end_search_hl(void) screen_search_hl.rm.regprog = NULL; } -static void win_redr_bordertext(win_T *wp, VirtText vt, int col) +static void win_redr_bordertext(win_T *wp, VirtText vt, int col, BorderTextType bt) { for (size_t i = 0; i < kv_size(vt);) { - int attr = 0; + int attr = -1; char *text = next_virt_text_chunk(vt, &i, &attr); if (text == NULL) { break; } + if (attr == -1) { // No highlight specified. + attr = wp->w_ns_hl_attr[bt == kBorderTextTitle ? HLF_BTITLE : HLF_BFOOTER]; + } attr = hl_apply_winblend(wp, attr); col += grid_line_puts(col, text, -1, attr); } @@ -773,7 +777,7 @@ static void win_redr_border(win_T *wp) if (wp->w_config.title) { int title_col = win_get_bordertext_col(icol, wp->w_config.title_width, wp->w_config.title_pos); - win_redr_bordertext(wp, wp->w_config.title_chunks, title_col); + win_redr_bordertext(wp, wp->w_config.title_chunks, title_col, kBorderTextTitle); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[2], attrs[2]); @@ -809,7 +813,7 @@ static void win_redr_border(win_T *wp) if (wp->w_config.footer) { int footer_col = win_get_bordertext_col(icol, wp->w_config.footer_width, wp->w_config.footer_pos); - win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col); + win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col, kBorderTextFooter); } if (adj[1]) { grid_line_put_schar(icol + adj[3], chars[4], attrs[4]); diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 248220e28b..cdaae6cfee 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -2127,7 +2127,7 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:╔═════}🦄BB{5:╗}| + {5:╔═════}{11:🦄BB}{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| {5:╚═════════╝}| @@ -2141,7 +2141,7 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:╔═════}🦄BB{5:╗}{0: }| + {0:~ }{5:╔═════}{11:🦄BB}{5:╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| {0:~ }{5:╚═════════╝}{0: }| @@ -2275,7 +2275,7 @@ describe('float window', function() {5:╔═════════╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| - {5:╚═════}🦄BB{5:╝}| + {5:╚═════}{11:🦄BB}{5:╝}| ]], float_pos={ [4] = { 1001, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2289,7 +2289,7 @@ describe('float window', function() {0:~ }{5:╔═════════╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| - {0:~ }{5:╚═════}🦄BB{5:╝}{0: }| + {0:~ }{5:╚═════}{11:🦄BB}{5:╝}{0: }| | ]]} end @@ -2423,10 +2423,10 @@ describe('float window', function() ## grid 3 | ## grid 4 - {5:╔═════}🦄{7:BB}{5:╗}| + {5:╔═════}{11:🦄}{7:BB}{5:╗}| {5:║}{1: halloj! }{5:║}| {5:║}{1: BORDAA }{5:║}| - {5:╚═════}🦄{7:BB}{5:╝}| + {5:╚═════}{11:🦄}{7:BB}{5:╝}| ]], float_pos={ [4] = { 1001, "NW", 1, 2, 5, true } }, win_viewport={ @@ -2437,10 +2437,10 @@ describe('float window', function() screen:expect{grid=[[ ^ | {0:~ }| - {0:~ }{5:╔═════}🦄{7:BB}{5:╗}{0: }| + {0:~ }{5:╔═════}{11:🦄}{7:BB}{5:╗}{0: }| {0:~ }{5:║}{1: halloj! }{5:║}{0: }| {0:~ }{5:║}{1: BORDAA }{5:║}{0: }| - {0:~ }{5:╚═════}🦄{7:BB}{5:╝}{0: }| + {0:~ }{5:╚═════}{11:🦄}{7:BB}{5:╝}{0: }| | ]]} end -- cgit From 4c7fd323ec40de2c0884b2bd290d7470cda0826d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 24 May 2024 18:15:12 +0200 Subject: vim-patch:b1ffc52: runtime(i3config/swayconfig): fix floating_modifier highlight (vim/vim#14841) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/vim/vim/commit/b1ffc52694756efef339f01bbb1fc6ef4eaf16da Co-authored-by: Josef Litoš <54900518+JosefLitos@users.noreply.github.com> --- runtime/syntax/i3config.vim | 6 +++--- runtime/syntax/swayconfig.vim | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/runtime/syntax/i3config.vim b/runtime/syntax/i3config.vim index f4d789e418..c95cb879ad 100644 --- a/runtime/syntax/i3config.vim +++ b/runtime/syntax/i3config.vim @@ -2,8 +2,8 @@ " Language: i3 config file " Original Author: Josef Litos (JosefLitos/i3config.vim) " Maintainer: Quentin Hibon (github user hiqua) -" Version: 1.2.3 -" Last Change: 2024-05-23 +" Version: 1.2.4 +" Last Change: 2024-05-24 " References: " http://i3wm.org/docs/userguide.html#configuring @@ -67,7 +67,7 @@ syn keyword i3ConfigBindKeyword bindsym bindcode contained skipwhite nextgroup=i syn region i3ConfigModeBlock matchgroup=i3ConfigKeyword start=/mode\ze\( --pango_markup\)\? \([^'" {]\+\|'[^']\+'\|".\+"\)\s\+{$/ end=/^}\zs$/ contained contains=i3ConfigShParam,@i3ConfigStrVar,i3ConfigBindKeyword,i3ConfigComment,i3ConfigParen fold keepend extend " 4.7 Floating modifier -syn match i3ConfigKeyword /^floating_modifier [$0-9A-Za-z]*$/ contains=i3ConfigVariable,i3ConfigBindModkey +syn match i3ConfigKeyword /floating_modifier [$A-Z][0-9A-Za-z]*$/ contained contains=i3ConfigVariable,i3ConfigBindModkey " 4.8 Floating window size syn keyword i3ConfigSizeSpecial x contained diff --git a/runtime/syntax/swayconfig.vim b/runtime/syntax/swayconfig.vim index 401412adfd..d09d476a5a 100644 --- a/runtime/syntax/swayconfig.vim +++ b/runtime/syntax/swayconfig.vim @@ -2,8 +2,8 @@ " Language: sway config file " Original Author: Josef Litos (JosefLitos/i3config.vim) " Maintainer: James Eapen -" Version: 1.2.3 -" Last Change: 2024-05-23 +" Version: 1.2.4 +" Last Change: 2024-05-24 " References: " http://i3wm.org/docs/userguide.html#configuring @@ -34,12 +34,12 @@ syn region i3ConfigBindArgument start=/--input-device=['"]/ end=/\s/ contained c syn region i3ConfigBindCombo matchgroup=i3ConfigParen start=/{$/ end=/^\s*}$/ contained contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigComment fold keepend extend " hack for blocks with start outside parsing range -syn region swayConfigBlockOrphan start=/^\s\+\(--[a-z-]\+ \)*\([A-Z$][$a-zA-Z0-9_+]\+\|[a-z]\) [a-z[]/ skip=/\\$\|$\n^\s*}$/ end=/$/ contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigParen keepend extend +syn region swayConfigBlockOrphan start=/^\s\+\(--[a-z-]\+ \)*\([$A-Z][$0-9A-Za-z_+]\+\|[a-z]\) [a-z[]/ skip=/\\$\|$\n^\s*}$/ end=/$/ contains=i3ConfigBindArgument,i3ConfigBindCombo,i3ConfigParen keepend extend syn region i3ConfigExec start=/ {$/ end=/^\s*}$/ contained contains=i3ConfigExecAction,@i3ConfigSh,i3ConfigComment fold keepend extend syn keyword swayConfigFloatingModifierOpts normal inverse none contained -syn match i3ConfigKeyword /floating_modifier \(none\|[$a-zA-Z0-9+]\+ \(normal\|inverse\)\)$/ contained contains=i3ConfigVariable,i3ConfigBindModkey,swayConfigFloatingModifierOpts +syn match i3ConfigKeyword /floating_modifier \(none\|[$A-Z][0-9A-Za-z]\+ \(normal\|inverse\)\)$/ contained contains=i3ConfigVariable,i3ConfigBindModkey,swayConfigFloatingModifierOpts syn match swayConfigI3Param /--i3/ contains=i3ConfigShParam skipwhite nextgroup=i3ConfigEdgeOpts syn keyword i3ConfigKeyword hide_edge_borders contained skipwhite nextgroup=swayConfigI3Param,i3ConfigEdgeOpts @@ -71,7 +71,7 @@ syn keyword i3ConfigBindKeyword bindswitch contained skipwhite nextgroup=swayCon syn region swayConfigBlockOrphan start=/^\s\+\(lid\|tablet\):/ skip=/\\$\|$\n^\s*}$/ end=/$/ contains=swayConfigBindswitchArgument,swayConfigBindswitchType,i3ConfigParen keepend extend " Bindgesture -syn match swayConfigBindgestureArgument /--\(exact\|input-device=[:0-9a-zA-Z_/-]\+\|no-warn\) / contained nextgroup=swayConfigBindgestureArgument,swayConfigBindgestureCombo +syn match swayConfigBindgestureArgument /--\(exact\|input-device=[:0-9A-Za-z_/-]\+\|no-warn\) / contained nextgroup=swayConfigBindgestureArgument,swayConfigBindgestureCombo syn keyword swayConfigBindgestureType hold swipe pinch contained syn keyword swayConfigBindgestureDir up down left right inward outward clockwise counterclockwise contained syn match swayConfigBindgestureCombo /\(hold\(:[1-5]\)\?\|swipe\(:[3-5]\)\?\(:up\|:down\|:left\|:right\)\?\|pinch\(:[2-5]\)\?:\(+\?\(inward\|outward\|clockwise\|counterclockwise\|up\|down\|left\|right\)\)\+\) / contained contains=i3ConfigNumber,swayConfigBindgestureType,i3ConfigColonOperator,swayConfigBindgestureDir,i3ConfigBindModifier nextgroup=swayConfigBindgestureCombo,i3ConfigBind -- cgit From b43244adafa0f4d86409d1101754d5e23782c158 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 24 May 2024 19:09:31 +0200 Subject: vim-patch:5e45715: runtime(typescript): update outdated syntax files fixes: vim/vim#14721 fixes: HerringtonDarkholme/yats.vim#277 closes: vim/vim#14840 https://github.com/vim/vim/commit/5e4571508480c8f51748e49fb05c1891db0cb803 Co-authored-by: rhysd --- runtime/doc/syntax.txt | 13 ++ runtime/syntax/shared/typescriptcommon.vim | 192 ++++++++++++++++------------- runtime/syntax/typescript.vim | 2 +- runtime/syntax/typescriptreact.vim | 6 +- 4 files changed, 121 insertions(+), 92 deletions(-) diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 7893822a66..06d7ad8f7e 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -3289,6 +3289,19 @@ set "tf_minlines" to the value you desire. Example: > :let tf_minlines = your choice < +TYPESCRIPT *typescript.vim* *ft-typescript-syntax* + *typescriptreact.vim* *ft-typescriptreact-syntax* + +There is one option to control the TypeScript syntax highlighting. + + *g:typescript_host_keyword* +When this variable is set to 1, host-specific APIs such as `addEventListener` +are highlighted. To disable set it to zero in your .vimrc: > + + let g:typescript_host_keyword = 0 +< +The default value is 1. + VIM *vim.vim* *ft-vim-syntax* *g:vimsyn_minlines* *g:vimsyn_maxlines* There is a trade-off between more accurate syntax highlighting versus screen diff --git a/runtime/syntax/shared/typescriptcommon.vim b/runtime/syntax/shared/typescriptcommon.vim index d06525115e..3af79a38fb 100644 --- a/runtime/syntax/shared/typescriptcommon.vim +++ b/runtime/syntax/shared/typescriptcommon.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript and TypeScriptReact " Maintainer: Herrington Darkholme -" Last Change: 2023 Aug 24 +" Last Change: 2024 May 24 " Based On: Herrington Darkholme's yats.vim " Changes: See https://github.com/HerringtonDarkholme/yats.vim " Credits: See yats.vim on github @@ -49,13 +49,13 @@ syntax match typescriptProp contained /\K\k*!\?/ \ nextgroup=@afterIdentifier \ skipwhite skipempty -syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/rs=s+1 end=/]/he=e-1 contains=@typescriptValue nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty +syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/ end=/]/ contains=@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty syntax match typescriptDotNotation /\.\|?\.\|!\./ nextgroup=typescriptProp skipnl syntax match typescriptDotStyleNotation /\.style\./ nextgroup=typescriptDOMStyle transparent " syntax match typescriptFuncCall contained /[a-zA-Z]\k*\ze(/ nextgroup=typescriptFuncCallArg syntax region typescriptParenExp matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptComments,@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols skipwhite skipempty -syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl +syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments,typescriptCastKeyword nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl syntax region typescriptEventFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptEventExpression syntax region typescriptEventString contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/ contains=typescriptASCII,@events @@ -116,20 +116,33 @@ syntax match typescriptASCII contained /\\\d\d\d/ syntax region typescriptTemplateSubstitution matchgroup=typescriptTemplateSB \ start=/\${/ end=/}/ - \ contains=@typescriptValue + \ contains=@typescriptValue,typescriptCastKeyword \ contained -syntax region typescriptString +syntax region typescriptString \ start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+ \ contains=typescriptSpecial,@Spell + \ nextgroup=@typescriptSymbols + \ skipwhite skipempty \ extend syntax match typescriptSpecial contained "\v\\%(x\x\x|u%(\x{4}|\{\x{1,6}})|c\u|.)" -" From vim runtime -" -syntax region typescriptRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gimuy]\{0,5\}\s*$+ end=+/[gimuy]\{0,5\}\s*[;.,)\]}:]+me=e-1 nextgroup=typescriptDotNotation oneline +" From pangloss/vim-javascript +" +syntax region typescriptRegexpCharClass contained start=+\[+ skip=+\\.+ end=+\]+ contains=typescriptSpecial extend +syntax match typescriptRegexpBoundary contained "\v\c[$^]|\\b" +syntax match typescriptRegexpBackRef contained "\v\\[1-9]\d*" +syntax match typescriptRegexpQuantifier contained "\v[^\\]%([?*+]|\{\d+%(,\d*)?})\??"lc=1 +syntax match typescriptRegexpOr contained "|" +syntax match typescriptRegexpMod contained "\v\(\?[:=!>]"lc=1 +syntax region typescriptRegexpGroup contained start="[^\\]("lc=1 skip="\\.\|\[\(\\.\|[^]]\+\)\]" end=")" contains=typescriptRegexpCharClass,@typescriptRegexpSpecial keepend +syntax region typescriptRegexpString + \ start=+\%(\%(\" syntax match shellbang "^#!.*iojs\>" @@ -536,7 +561,7 @@ syntax region typescriptGenericFunc matchgroup=typescriptTypeBrackets \ contained skipwhite skipnl syntax region typescriptFuncType matchgroup=typescriptParens - \ start=/(/ end=/)\s*=>/me=e-2 + \ start=/(\(\k\+:\|)\)\@=/ end=/)\s*=>/me=e-2 \ contains=@typescriptParameterList \ nextgroup=typescriptFuncTypeArrow \ contained skipwhite skipnl oneline @@ -546,7 +571,6 @@ syntax match typescriptFuncTypeArrow /=>/ \ containedin=typescriptFuncType \ contained skipwhite skipnl - syntax keyword typescriptConstructorType new \ nextgroup=@typescriptFunctionType \ contained skipwhite skipnl @@ -623,25 +647,24 @@ syntax keyword typescriptReadonlyArrayKeyword readonly " extension -if get(g:, 'yats_host_keyword', 1) - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean - " use of nextgroup Suggested by Doug Kearns +if get(g:, 'typescript_host_keyword', 1) + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean nextgroup=typescriptFuncCallArg syntax keyword typescriptGlobal containedin=typescriptIdentifierName Error EvalError nextgroup=typescriptFuncCallArg - syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError - syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError - syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration - syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError - syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray - syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray - syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator - syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy + syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator nextgroup=typescriptFuncCallArg + syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy nextgroup=typescriptFuncCallArg syntax keyword typescriptGlobal containedin=typescriptIdentifierName arguments hi def link typescriptGlobal Structure syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName eval uneval nextgroup=typescriptFuncCallArg @@ -675,12 +698,12 @@ if get(g:, 'yats_host_keyword', 1) hi def link typescriptStringStaticMethod Keyword syntax keyword typescriptStringMethod contained anchor charAt charCodeAt codePointAt nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained concat endsWith includes indexOf lastIndexOf nextgroup=typescriptFuncCallArg - syntax keyword typescriptStringMethod contained link localeCompare match normalize nextgroup=typescriptFuncCallArg - syntax keyword typescriptStringMethod contained padStart padEnd repeat replace search nextgroup=typescriptFuncCallArg + syntax keyword typescriptStringMethod contained link localeCompare match matchAll normalize nextgroup=typescriptFuncCallArg + syntax keyword typescriptStringMethod contained padStart padEnd repeat replace replaceAll search nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained slice split startsWith substr substring nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained toLocaleLowerCase toLocaleUpperCase nextgroup=typescriptFuncCallArg syntax keyword typescriptStringMethod contained toLowerCase toString toUpperCase trim nextgroup=typescriptFuncCallArg - syntax keyword typescriptStringMethod contained valueOf nextgroup=typescriptFuncCallArg + syntax keyword typescriptStringMethod contained trimEnd trimStart valueOf nextgroup=typescriptFuncCallArg syntax cluster props add=typescriptStringMethod hi def link typescriptStringMethod Keyword @@ -689,18 +712,18 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptArrayStaticMethod contained from isArray of nextgroup=typescriptFuncCallArg hi def link typescriptArrayStaticMethod Keyword syntax keyword typescriptArrayMethod contained concat copyWithin entries every fill nextgroup=typescriptFuncCallArg - syntax keyword typescriptArrayMethod contained filter find findIndex forEach indexOf nextgroup=typescriptFuncCallArg - syntax keyword typescriptArrayMethod contained includes join keys lastIndexOf map nextgroup=typescriptFuncCallArg + syntax keyword typescriptArrayMethod contained filter find findIndex flat flatMap forEach nextgroup=typescriptFuncCallArg + syntax keyword typescriptArrayMethod contained includes indexOf join keys lastIndexOf map nextgroup=typescriptFuncCallArg syntax keyword typescriptArrayMethod contained pop push reduce reduceRight reverse nextgroup=typescriptFuncCallArg syntax keyword typescriptArrayMethod contained shift slice some sort splice toLocaleString nextgroup=typescriptFuncCallArg - syntax keyword typescriptArrayMethod contained toSource toString unshift nextgroup=typescriptFuncCallArg + syntax keyword typescriptArrayMethod contained toSource toString unshift values nextgroup=typescriptFuncCallArg syntax cluster props add=typescriptArrayMethod hi def link typescriptArrayMethod Keyword syntax keyword typescriptGlobal containedin=typescriptIdentifierName Object nextgroup=typescriptGlobalObjectDot,typescriptFuncCallArg syntax match typescriptGlobalObjectDot /\./ contained nextgroup=typescriptObjectStaticMethod,typescriptProp syntax keyword typescriptObjectStaticMethod contained create defineProperties defineProperty nextgroup=typescriptFuncCallArg - syntax keyword typescriptObjectStaticMethod contained entries freeze getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg + syntax keyword typescriptObjectStaticMethod contained entries freeze fromEntries getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg syntax keyword typescriptObjectStaticMethod contained getOwnPropertyDescriptor getOwnPropertyNames nextgroup=typescriptFuncCallArg syntax keyword typescriptObjectStaticMethod contained getOwnPropertySymbols getPrototypeOf nextgroup=typescriptFuncCallArg syntax keyword typescriptObjectStaticMethod contained is isExtensible isFrozen isSealed nextgroup=typescriptFuncCallArg @@ -715,7 +738,7 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptGlobal containedin=typescriptIdentifierName Symbol nextgroup=typescriptGlobalSymbolDot,typescriptFuncCallArg syntax match typescriptGlobalSymbolDot /\./ contained nextgroup=typescriptSymbolStaticProp,typescriptSymbolStaticMethod,typescriptProp - syntax keyword typescriptSymbolStaticProp contained length iterator match replace + syntax keyword typescriptSymbolStaticProp contained description length iterator match matchAll replace syntax keyword typescriptSymbolStaticProp contained search split hasInstance isConcatSpreadable syntax keyword typescriptSymbolStaticProp contained unscopables species toPrimitive syntax keyword typescriptSymbolStaticProp contained toStringTag @@ -771,7 +794,7 @@ if get(g:, 'yats_host_keyword', 1) syntax match typescriptGlobalRegExpDot /\./ contained nextgroup=typescriptRegExpStaticProp,typescriptProp syntax keyword typescriptRegExpStaticProp contained lastIndex hi def link typescriptRegExpStaticProp Keyword - syntax keyword typescriptRegExpProp contained global ignoreCase multiline source sticky + syntax keyword typescriptRegExpProp contained dotAll global ignoreCase multiline source sticky syntax cluster props add=typescriptRegExpProp hi def link typescriptRegExpProp Keyword syntax keyword typescriptRegExpMethod contained exec test nextgroup=typescriptFuncCallArg @@ -805,7 +828,7 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptGlobal containedin=typescriptIdentifierName Promise nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg syntax match typescriptGlobalPromiseDot /\./ contained nextgroup=typescriptPromiseStaticMethod,typescriptProp - syntax keyword typescriptPromiseStaticMethod contained resolve reject all race nextgroup=typescriptFuncCallArg + syntax keyword typescriptPromiseStaticMethod contained all allSettled any race reject resolve nextgroup=typescriptFuncCallArg hi def link typescriptPromiseStaticMethod Keyword syntax keyword typescriptPromiseMethod contained then catch finally nextgroup=typescriptFuncCallArg syntax cluster props add=typescriptPromiseMethod @@ -1232,7 +1255,8 @@ if get(g:, 'yats_host_keyword', 1) syntax cluster props add=typescriptBOMHistoryMethod hi def link typescriptBOMHistoryMethod Keyword - syntax keyword typescriptGlobal containedin=typescriptIdentifierName console + syntax keyword typescriptGlobal containedin=typescriptIdentifierName console nextgroup=typescriptGlobalConsoleDot + syntax match typescriptGlobalConsoleDot /\./ contained nextgroup=typescriptConsoleMethod,typescriptProp syntax keyword typescriptConsoleMethod contained count dir error group groupCollapsed nextgroup=typescriptFuncCallArg syntax keyword typescriptConsoleMethod contained groupEnd info log time timeEnd trace nextgroup=typescriptFuncCallArg syntax keyword typescriptConsoleMethod contained warn nextgroup=typescriptFuncCallArg @@ -1735,8 +1759,6 @@ if get(g:, 'yats_host_keyword', 1) syntax keyword typescriptServiceWorkerEvent contained install activate fetch syntax cluster events add=typescriptServiceWorkerEvent hi def link typescriptServiceWorkerEvent Title - - endif " patch @@ -1764,6 +1786,7 @@ syntax cluster typescriptPropertyMemberDeclaration contains= \ typescriptClassStatic, \ typescriptAccessibilityModifier, \ typescriptReadonlyModifier, + \ typescriptAutoAccessor, \ typescriptMethodAccessor, \ @typescriptMembers " \ typescriptMemberVariableDeclaration @@ -1780,7 +1803,9 @@ syntax keyword typescriptClassStatic static syntax keyword typescriptAccessibilityModifier public private protected contained -syntax keyword typescriptReadonlyModifier readonly contained +syntax keyword typescriptReadonlyModifier readonly override contained + +syntax keyword typescriptAutoAccessor accessor contained syntax region typescriptStringMember contained \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/ @@ -1789,7 +1814,7 @@ syntax region typescriptStringMember contained syntax region typescriptComputedMember contained matchgroup=typescriptProperty \ start=/\[/rs=s+1 end=/]/ - \ contains=@typescriptValue,typescriptMember,typescriptMappedIn + \ contains=@typescriptValue,typescriptMember,typescriptMappedIn,typescriptCastKeyword \ nextgroup=@memberNextGroup \ skipwhite skipempty @@ -1861,7 +1886,7 @@ syntax match typescriptInterfaceComma /,/ contained nextgroup=typescriptInterfac "Block VariableStatement EmptyStatement ExpressionStatement IfStatement IterationStatement ContinueStatement BreakStatement ReturnStatement WithStatement LabelledStatement SwitchStatement ThrowStatement TryStatement DebuggerStatement syntax cluster typescriptStatement - \ contains=typescriptBlock,typescriptVariable, + \ contains=typescriptBlock,typescriptVariable,typescriptUsing, \ @typescriptTopExpression,typescriptAssign, \ typescriptConditional,typescriptRepeat,typescriptBranch, \ typescriptLabel,typescriptStatementKeyword, @@ -1899,16 +1924,14 @@ syntax cluster typescriptValue syntax cluster typescriptEventExpression contains=typescriptArrowFuncDef,typescriptParenExp,@typescriptValue,typescriptRegexpString,@typescriptEventTypes,typescriptOperator,typescriptGlobal,jsxRegion syntax keyword typescriptAsyncFuncKeyword async - \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef + \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef,typescriptArrowFuncTypeParameter \ skipwhite syntax keyword typescriptAsyncFuncKeyword await - \ nextgroup=@typescriptValue + \ nextgroup=@typescriptValue,typescriptUsing \ skipwhite -syntax keyword typescriptFuncKeyword function - \ nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature - \ skipwhite skipempty +syntax keyword typescriptFuncKeyword function nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature skipwhite skipempty syntax match typescriptAsyncFunc contained /*/ \ nextgroup=typescriptFuncName,@typescriptCallSignature @@ -1918,39 +1941,33 @@ syntax match typescriptFuncName contained /\K\k*/ \ nextgroup=@typescriptCallSignature \ skipwhite -" destructuring ({ a: ee }) => -syntax match typescriptArrowFuncDef contained /(\(\s*\({\_[^}]*}\|\k\+\)\(:\_[^)]\)\?,\?\)\+)\s*=>/ - \ contains=typescriptArrowFuncArg,typescriptArrowFunc - \ nextgroup=@typescriptExpression,typescriptBlock - \ skipwhite skipempty - -" matches `(a) =>` or `([a]) =>` or -" `( -" a) =>` -syntax match typescriptArrowFuncDef contained /(\(\_s*[a-zA-Z\$_\[.]\_[^)]*\)*)\s*=>/ +syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/ \ contains=typescriptArrowFuncArg,typescriptArrowFunc \ nextgroup=@typescriptExpression,typescriptBlock \ skipwhite skipempty -syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/ - \ contains=typescriptArrowFuncArg,typescriptArrowFunc +syntax match typescriptArrowFuncDef contained /(\%(\_[^()]\+\|(\_[^()]*)\)*)\_s*=>/ + \ contains=typescriptArrowFuncArg,typescriptArrowFunc,@typescriptCallSignature \ nextgroup=@typescriptExpression,typescriptBlock \ skipwhite skipempty -" TODO: optimize this pattern -syntax region typescriptArrowFuncDef contained start=/(\_[^(^)]*):/ end=/=>/ - \ contains=typescriptArrowFuncArg,typescriptArrowFunc,typescriptTypeAnnotation +syntax region typescriptArrowFuncDef contained start=/(\%(\_[^()]\+\|(\_[^()]*)\)*):/ matchgroup=typescriptArrowFunc end=/=>/ + \ contains=typescriptArrowFuncArg,typescriptTypeAnnotation,@typescriptCallSignature \ nextgroup=@typescriptExpression,typescriptBlock \ skipwhite skipempty keepend +syntax region typescriptArrowFuncTypeParameter start=// + \ contains=@typescriptTypeParameterCluster + \ nextgroup=typescriptArrowFuncDef + \ contained skipwhite skipnl + syntax match typescriptArrowFunc /=>/ syntax match typescriptArrowFuncArg contained /\K\k*/ -syntax region typescriptArrowFuncArg contained start=/<\|(/ end=/\ze=>/ contains=@typescriptCallSignature syntax region typescriptReturnAnnotation contained start=/:/ end=/{/me=e-1 contains=@typescriptType nextgroup=typescriptBlock -syntax region typescriptFuncImpl contained start=/function\>/ end=/{/me=e-1 +syntax region typescriptFuncImpl contained start=/function\>/ end=/{\|;\|\n/me=e-1 \ contains=typescriptFuncKeyword \ nextgroup=typescriptBlock @@ -1970,7 +1987,7 @@ syntax match typescriptDecorator /@\([_$a-zA-Z][_$a-zA-Z0-9]*\.\)*[_$a-zA-Z][_$a \ nextgroup=typescriptFuncCallArg,typescriptTypeArguments \ contains=@_semantic,typescriptDotNotation -" Define the default highlighting. + hi def link typescriptReserved Error hi def link typescriptEndColons Exception @@ -2013,6 +2030,7 @@ hi def link typescriptDefault typescriptCase hi def link typescriptBranch Conditional hi def link typescriptIdentifier Structure hi def link typescriptVariable Identifier +hi def link typescriptUsing Identifier hi def link typescriptDestructureVariable PreProc hi def link typescriptEnumKeyword Identifier hi def link typescriptRepeat Repeat @@ -2050,16 +2068,13 @@ hi def link typescriptFuncKeyword Keyword hi def link typescriptAsyncFunc Keyword hi def link typescriptArrowFunc Type hi def link typescriptFuncName Function -hi def link typescriptFuncArg PreProc +hi def link typescriptFuncCallArg PreProc hi def link typescriptArrowFuncArg PreProc hi def link typescriptFuncComma Operator hi def link typescriptClassKeyword Keyword hi def link typescriptClassExtends Keyword -" hi def link typescriptClassName Function hi def link typescriptAbstract Special -" hi def link typescriptClassHeritage Function -" hi def link typescriptInterfaceHeritage Function hi def link typescriptClassStatic StorageClass hi def link typescriptReadonlyModifier Keyword hi def link typescriptInterfaceKeyword Keyword @@ -2077,6 +2092,7 @@ hi def link typescriptFuncTypeArrow Function hi def link typescriptConstructorType Function hi def link typescriptTypeQuery Keyword hi def link typescriptAccessibilityModifier Keyword +hi def link typescriptAutoAccessor Keyword hi def link typescriptOptionalMark PreProc hi def link typescriptFuncType Special hi def link typescriptMappedIn Special diff --git a/runtime/syntax/typescript.vim b/runtime/syntax/typescript.vim index 5389c21497..03520fd56a 100644 --- a/runtime/syntax/typescript.vim +++ b/runtime/syntax/typescript.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript " Maintainer: Herrington Darkholme -" Last Change: 2023 Aug 13 +" Last Change: 2024 May 24 " Based On: Herrington Darkholme's yats.vim " Changes: Go to https://github.com/HerringtonDarkholme/yats.vim for recent changes. " Origin: https://github.com/othree/yajs diff --git a/runtime/syntax/typescriptreact.vim b/runtime/syntax/typescriptreact.vim index 1c510459f5..9dc9a2b797 100644 --- a/runtime/syntax/typescriptreact.vim +++ b/runtime/syntax/typescriptreact.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript with React (JSX) " Maintainer: The Vim Project -" Last Change: 2023 Aug 13 +" Last Change: 2024 May 24 " Based On: Herrington Darkholme's yats.vim " Changes: See https://github.com/HerringtonDarkholme/yats.vim " Credits: See yats.vim on github @@ -118,13 +118,13 @@ syntax match tsxEqual +=+ display contained " " s~~~~~~e -syntax region tsxString contained start=+"+ end=+"+ contains=tsxEntity,@Spell display +syntax region tsxString contained start=+["']+ end=+["']+ contains=tsxEntity,@Spell display " " s~~~~~~~~~~~~~~e syntax region tsxEscJs \ contained - \ contains=@typescriptValue,@tsxComment + \ contains=@typescriptValue,@tsxComment,typescriptObjectSpread \ matchgroup=typescriptBraces \ start=+{+ \ end=+}+ -- cgit From 4757d497f3c85cc343f7dcbc09f95e43ba5c1314 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 16:53:10 +0800 Subject: vim-patch:9.1.0444: Not enough tests for getregion() with multibyte chars (#29000) Problem: Not enough tests for getregion() with multibyte chars. Solution: Add a few more tests (zeertzjq). closes: vim/vim#14844 https://github.com/vim/vim/commit/dff55a335889c746a79974f7c52cdcdebad682c2 --- runtime/doc/builtin.txt | 3 +- runtime/lua/vim/_meta/vimfn.lua | 3 +- src/nvim/eval.lua | 3 +- test/old/testdir/test_visual.vim | 62 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 5b1dd2ca47..1a762c6ec0 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -2932,7 +2932,8 @@ getregion({pos1}, {pos2} [, {opts}]) *getregion()* type Specify the region's selection type. See |getregtype()| for possible values, - except it cannot be an empty string. + except that the width can be omitted + and an empty string cannot be used. (default: "v") exclusive If |TRUE|, use exclusive selection diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index d1455fa993..f256f63768 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -3538,7 +3538,8 @@ function vim.fn.getreginfo(regname) end --- --- type Specify the region's selection type. --- See |getregtype()| for possible values, ---- except it cannot be an empty string. +--- except that the width can be omitted +--- and an empty string cannot be used. --- (default: "v") --- --- exclusive If |TRUE|, use exclusive selection diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 4adf3ce959..f0c8963459 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -4372,7 +4372,8 @@ M.funcs = { type Specify the region's selection type. See |getregtype()| for possible values, - except it cannot be an empty string. + except that the width can be omitted + and an empty string cannot be used. (default: "v") exclusive If |TRUE|, use exclusive selection diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim index f414f502f7..3c510ffd0b 100644 --- a/test/old/testdir/test_visual.vim +++ b/test/old/testdir/test_visual.vim @@ -2594,6 +2594,7 @@ func Test_getregion_after_yank() call feedkeys("gg0ll\jj$y", 'tx') call assert_equal(1, g:checked) call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) let g:expected_region = ['bc', 'fg', 'mn'] let g:expected_regionpos = [ @@ -2605,6 +2606,67 @@ func Test_getregion_after_yank() call feedkeys("gg0l\jjly", 'tx') call assert_equal(1, g:checked) call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + bwipe! + + new + let lines = ['asdfghjkl', '«口=口»', 'qwertyuiop', '口口=口口', 'zxcvbnm'] + call setline(1, lines) + + let g:expected_region = lines + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 9, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 11, 0]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 10, 0]], + \ [[bufnr('%'), 4, 1, 0], [bufnr('%'), 4, 13, 0]], + \ [[bufnr('%'), 5, 1, 0], [bufnr('%'), 5, 7, 0]], + \ ] + let g:checked = 0 + call feedkeys('ggyG', 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['=口»', 'qwertyuiop', '口口=口'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 2, 6, 0], [bufnr('%'), 2, 11, 0]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 10, 0]], + \ [[bufnr('%'), 4, 1, 0], [bufnr('%'), 4, 10, 0]], + \ ] + let g:checked = 0 + call feedkeys('2gg02lv2j2ly', 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['asdf', '«口=', 'qwer', '口口', 'zxcv'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 6, 0]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 4, 0]], + \ [[bufnr('%'), 4, 1, 0], [bufnr('%'), 4, 6, 0]], + \ [[bufnr('%'), 5, 1, 0], [bufnr('%'), 5, 4, 0]], + \ ] + let g:checked = 0 + call feedkeys("G0\3l4ky", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) + + let g:expected_region = ['ghjkl', '口»', 'tyuiop', '=口口', 'bnm'] + let g:expected_regionpos = [ + \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 9, 0]], + \ [[bufnr('%'), 2, 7, 0], [bufnr('%'), 2, 11, 0]], + \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 10, 0]], + \ [[bufnr('%'), 4, 7, 0], [bufnr('%'), 4, 13, 0]], + \ [[bufnr('%'), 5, 5, 0], [bufnr('%'), 5, 7, 0]], + \ ] + let g:checked = 0 + call feedkeys("G04l\$4ky", 'tx') + call assert_equal(1, g:checked) + call Check_Results(getregtype('"')) + call assert_equal(g:expected_region, getreg('"', v:true, v:true)) bwipe! -- cgit From bdb81afab3e5c43a33267666c2689feb284f6b52 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 25 May 2024 20:37:33 +0800 Subject: refactor(lua): rewrite vim.highlight.range() (#28986) - Use getregionpos(). - Use a single extmark for non-blockwise selection. --- runtime/doc/lua.txt | 4 +- runtime/lua/vim/highlight.lua | 55 ++++++++++++++++------ test/functional/lua/highlight_spec.lua | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+), 15 deletions(-) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 3d8453c5a2..64a3014388 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -646,8 +646,8 @@ vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {opts}) • {finish} (`integer[]|string`) End of region as a (line, column) tuple or string accepted by |getpos()| • {opts} (`table?`) A table with the following fields: - • {regtype}? (`string`, default: `'charwise'`) Type of - range. See |setreg()| + • {regtype}? (`string`, default: `'v'` i.e. charwise) Type + of range. See |getregtype()| • {inclusive}? (`boolean`, default: `false`) Indicates whether the range is end-inclusive • {priority}? (`integer`, default: diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index f278bd357f..89298ce568 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -20,8 +20,8 @@ M.priorities = { --- @class vim.highlight.range.Opts --- @inlinedoc --- ---- Type of range. See [setreg()] ---- (default: `'charwise'`) +--- Type of range. See [getregtype()] +--- (default: `'v'` i.e. charwise) --- @field regtype? string --- --- Indicates whether the range is end-inclusive @@ -49,20 +49,49 @@ function M.range(bufnr, ns, higroup, start, finish, opts) local priority = opts.priority or M.priorities.user local scoped = opts._scoped or false - -- TODO: in case of 'v', 'V' (not block), this should calculate equivalent - -- bounds (row, col, end_row, end_col) as multiline regions are natively - -- supported now - local region = vim.region(bufnr, start, finish, regtype, inclusive) - for linenr, cols in pairs(region) do - local end_row - if cols[2] == -1 then - end_row = linenr + 1 - cols[2] = 0 + local pos1 = type(start) == 'string' and vim.fn.getpos(start) + or { bufnr, start[1] + 1, start[2] + 1, 0 } + local pos2 = type(finish) == 'string' and vim.fn.getpos(finish) + or { bufnr, finish[1] + 1, finish[2] + 1, 0 } + + local buf_line_count = vim.api.nvim_buf_line_count(bufnr) + pos1[2] = math.min(pos1[2], buf_line_count) + pos2[2] = math.min(pos2[2], buf_line_count) + + if pos1[2] <= 0 or pos1[3] <= 0 or pos2[2] <= 0 or pos2[3] <= 0 then + return + end + + vim.api.nvim_buf_call(bufnr, function() + local max_col1 = vim.fn.col({ pos1[2], '$' }) + pos1[3] = math.min(pos1[3], max_col1) + local max_col2 = vim.fn.col({ pos2[2], '$' }) + pos2[3] = math.min(pos2[3], max_col2) + end) + + local region = vim.fn.getregionpos(pos1, pos2, { + type = regtype, + exclusive = not inclusive, + eol = true, + }) + -- For non-blockwise selection, use a single extmark. + if regtype == 'v' or regtype == 'V' then + region = { { region[1][1], region[#region][2] } } + end + + for _, res in ipairs(region) do + local start_row = res[1][2] - 1 + local start_col = res[1][3] - 1 + local end_row = res[2][2] - 1 + local end_col = res[2][3] + if regtype == 'V' then + end_row = end_row + 1 + end_col = 0 end - api.nvim_buf_set_extmark(bufnr, ns, linenr, cols[1], { + api.nvim_buf_set_extmark(bufnr, ns, start_row, start_col, { hl_group = higroup, end_row = end_row, - end_col = cols[2], + end_col = end_col, priority = priority, strict = false, scoped = scoped, diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua index c9f2d0a47f..8f099ac233 100644 --- a/test/functional/lua/highlight_spec.lua +++ b/test/functional/lua/highlight_spec.lua @@ -1,5 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') local exec_lua = n.exec_lua local eq = t.eq @@ -9,6 +10,88 @@ local command = n.command local clear = n.clear local api = n.api +describe('vim.highlight.range', function() + local screen + + before_each(function() + clear() + screen = Screen.new(60, 6) + screen:add_extra_attr_ids({ + [100] = { foreground = Screen.colors.Blue, background = Screen.colors.Yellow, bold = true }, + }) + screen:attach() + api.nvim_set_option_value('list', true, {}) + api.nvim_set_option_value('listchars', 'eol:$', {}) + api.nvim_buf_set_lines(0, 0, -1, true, { + 'asdfghjkl', + '«口=口»', + 'qwertyuiop', + '口口=口口', + 'zxcvbnm', + }) + end) + + it('works with charwise selection', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 1, 5 }, { 3, 10 }) + ]]) + screen:expect([[ + ^asdfghjkl{1:$} | + «口{10:=口»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:口口=口}口{1:$} | + zxcvbnm{1:$} | + | + ]]) + end) + + it('works with linewise selection', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 0 }, { regtype = 'V' }) + ]]) + screen:expect([[ + {10:^asdfghjkl}{100:$} | + {10:«口=口»}{100:$} | + {10:qwertyuiop}{100:$} | + {10:口口=口口}{100:$} | + {10:zxcvbnm}{100:$} | + | + ]]) + end) + + it('works with blockwise selection', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 0 }, { 4, 4 }, { regtype = '\022' }) + ]]) + screen:expect([[ + {10:^asdf}ghjkl{1:$} | + {10:«口=}口»{1:$} | + {10:qwer}tyuiop{1:$} | + {10:口口}=口口{1:$} | + {10:zxcv}bnm{1:$} | + | + ]]) + end) + + it('works with blockwise selection with width', function() + exec_lua([[ + local ns = vim.api.nvim_create_namespace('') + vim.highlight.range(0, ns, 'Search', { 0, 4 }, { 4, 7 }, { regtype = '\0226' }) + ]]) + screen:expect([[ + ^asdf{10:ghjkl}{1:$} | + «口={10:口»}{1:$} | + qwer{10:tyuiop}{1:$} | + 口口{10:=口口}{1:$} | + zxcv{10:bnm}{1:$} | + | + ]]) + end) +end) + describe('vim.highlight.on_yank', function() before_each(function() clear() -- cgit From fdeb01cd77404aba446c67af32134a2ff793a14b Mon Sep 17 00:00:00 2001 From: Rafael Kitover Date: Sat, 25 May 2024 12:44:39 +0000 Subject: feat(main): expand file ~\ or ~/ prefix on Windows (#28515) In command_line_scan() for MSWIN, expand "~\" or "~/" prefixed paths to the USERPROFILE environment variable for the user's profile directory. Fix #23901 Signed-off-by: Rafael Kitover --- runtime/doc/news.txt | 4 +++- src/nvim/main.c | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 708e127136..2d4017e3c4 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -87,7 +87,9 @@ DEFAULTS EDITOR -• TODO +* On Windows, filename arguments on the command-line prefixed with "~\" or + "~/" are now expanded to the user's profile directory, not a relative path + to a literal "~" directory. EVENTS diff --git a/src/nvim/main.c b/src/nvim/main.c index 30b6b6e86b..17a0bbf082 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1444,6 +1444,19 @@ scripterror: ga_grow(&global_alist.al_ga, 1); char *p = xstrdup(argv[0]); + // On Windows expand "~\" or "~/" prefix in file names to profile directory. +#ifdef MSWIN + if (*p == '~' && (p[1] == '\\' || p[1] == '/')) { + char *profile_dir = vim_getenv("HOME"); + size_t size = strlen(profile_dir) + strlen(p); + char *tilde_expanded = xmalloc(size); + snprintf(tilde_expanded, size, "%s%s", profile_dir, p + 1); + xfree(p); + xfree(profile_dir); + p = tilde_expanded; + } +#endif + if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0 && !os_isdir(alist_name(&GARGLIST[0]))) { char *r = concat_fnames(p, path_tail(alist_name(&GARGLIST[0])), true); -- cgit From 52389e724366ebb2fb58f08c657f580900dd09ee Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 13:33:59 +0200 Subject: test(unit): skip flaky 'typval.c dict extend() works' test --- test/unit/eval/typval_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua index c69c9b0fae..4e3b461396 100644 --- a/test/unit/eval/typval_spec.lua +++ b/test/unit/eval/typval_spec.lua @@ -2326,7 +2326,7 @@ describe('typval.c', function() return lib.tv_dict_extend(d1, d2, action) end, emsg) end - itp('works', function() + pending('works (skip due to flakiness)', function() local d1 = dict() alloc_log:check({ a.dict(d1) }) eq({}, dct2tbl(d1)) -- cgit From a4b554965510c9719c3d2bf22fdaa2d73081deb7 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 25 May 2024 10:20:10 +0200 Subject: refactor(tests): update screen:snapshot_util() to use new-style highlights This makes screen:snapshot_util() generate code with the new screen:add_extra_attr_ids { ... } pattern. For convenience, the old-style configuration is still detected and supported (until all tests have been refactored, which is my goal for the 0.11 cycle) Remove the last traces of the "ignore" attr anti-pattern. This code is no longer functional, it is just "ignore" argument being passed around like a hot potato at this point. --- test/functional/ui/screen.lua | 58 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 4625ce8553..f8e95f7d88 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -255,6 +255,7 @@ end function Screen:set_default_attr_ids(attr_ids) self._default_attr_ids = attr_ids + self._attrs_overridden = true end function Screen:add_extra_attr_ids(extra_attr_ids) @@ -699,9 +700,9 @@ screen:redraw_debug() to show all intermediate screen states.]] end, expected) end -function Screen:expect_unchanged(intermediate, waittime_ms, ignore_attrs) +function Screen:expect_unchanged(intermediate, waittime_ms) -- Collect the current screen state. - local kwargs = self:get_snapshot(nil, ignore_attrs) + local kwargs = self:get_snapshot() if intermediate then kwargs.intermediate = true @@ -1536,13 +1537,14 @@ end -- Use snapshot_util({}) to generate a text-only (no attributes) test. -- -- @see Screen:redraw_debug() -function Screen:snapshot_util(attrs, ignore, request_cb) +function Screen:snapshot_util(request_cb) + -- TODO: simplify this later when existing tests have been updated self:sleep(250, request_cb) - self:print_snapshot(attrs, ignore) + self:print_snapshot() end -function Screen:redraw_debug(attrs, ignore, timeout) - self:print_snapshot(attrs, ignore) +function Screen:redraw_debug(timeout) + self:print_snapshot() local function notification_cb(method, args) assert(method == 'redraw') for _, update in ipairs(args) do @@ -1552,7 +1554,7 @@ function Screen:redraw_debug(attrs, ignore, timeout) end end self:_redraw(args) - self:print_snapshot(attrs, ignore) + self:print_snapshot() return true end if timeout == nil then @@ -1596,23 +1598,12 @@ end -- Returns the current screen state in the form of a screen:expect() -- keyword-args map. -function Screen:get_snapshot(attrs, ignore) - if ignore == nil then - ignore = self._default_attr_ignore - end +function Screen:get_snapshot() local attr_state = { ids = {}, - ignore = ignore, mutable = true, -- allow _row_repr to add missing highlights } - if attrs == nil then - attrs = self._default_attr_ids - elseif isempty(attrs) then - attrs = nil - attr_state.ids = nil - else - attr_state.modified = true - end + local attrs = self._default_attr_ids if attrs ~= nil then for i, a in pairs(attrs) do @@ -1708,9 +1699,10 @@ local function fmt_ext_state(name, state) end end -function Screen:_print_snapshot(attrs, ignore) - local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore) +function Screen:_print_snapshot() + local kwargs, ext_state, attr_state = self:get_snapshot() local attrstr = '' + local modify_attrs = not self._attrs_overridden if attr_state.modified then local attrstrs = {} for i, a in pairs(attr_state.ids) do @@ -1721,16 +1713,20 @@ function Screen:_print_snapshot(attrs, ignore) dict = '{ ' .. self:_pprint_attrs(a) .. ' }' end local keyval = (type(i) == 'number') and '[' .. tostring(i) .. ']' or i - table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',') + if not (type(i) == 'number' and modify_attrs and i <= 30) then + table.insert(attrstrs, ' ' .. keyval .. ' = ' .. dict .. ',') + end + if modify_attrs then + self._default_attr_ids = attr_state.ids + end end - attrstr = (',\n attr_ids = {\n ' .. table.concat(attrstrs, '\n ') .. '\n },') - elseif isempty(attrs) then - attrstr = ',\n attr_ids = {},' + local fn_name = modify_attrs and 'add_extra_attr_ids' or 'set_default_attr_ids' + attrstr = ('screen:' .. fn_name .. ' {\n' .. table.concat(attrstrs, '\n') .. '\n}\n\n') end - local result = ('screen:expect({\n grid = [[\n %s\n ]]%s'):format( - kwargs.grid:gsub('\n', '\n '), - attrstr + local result = ('%sscreen:expect({\n grid = [[\n %s\n ]]'):format( + attrstr, + kwargs.grid:gsub('\n', '\n ') ) for _, k in ipairs(ext_keys) do if ext_state[k] ~= nil and not (k == 'win_viewport' and not self.options.ext_multigrid) then @@ -1742,8 +1738,8 @@ function Screen:_print_snapshot(attrs, ignore) return result end -function Screen:print_snapshot(attrs, ignore) - print('\n' .. self:_print_snapshot(attrs, ignore) .. '\n') +function Screen:print_snapshot() + print('\n' .. self:_print_snapshot() .. '\n') io.stdout:flush() end -- cgit From 520c2657bb6832dc527bff94f313a1cc458238a4 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 17:56:05 +0200 Subject: refactor: move provider-related to where they are used --- runtime/lua/vim/health.lua | 108 -------------------------- runtime/lua/vim/provider/health.lua | 150 ++++++++++++++++++++++++++++++------ 2 files changed, 127 insertions(+), 131 deletions(-) diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index f40f04a064..afeba2ee9d 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -275,114 +275,6 @@ function M.error(msg, ...) collect_output(input) end -function M._provider_disabled(provider) - local loaded_var = 'loaded_' .. provider .. '_provider' - local v = vim.g[loaded_var] - if v == 0 then - M.info('Disabled (' .. loaded_var .. '=' .. v .. ').') - return true - end - return false -end - --- Handler for s:system() function. -local function system_handler(self, _, data, event) - if event == 'stderr' then - if self.add_stderr_to_output then - self.output = self.output .. table.concat(data, '') - else - self.stderr = self.stderr .. table.concat(data, '') - end - elseif event == 'stdout' then - self.output = self.output .. table.concat(data, '') - end -end - --- Attempts to construct a shell command from an args list. --- Only for display, to help users debug a failed command. -local function shellify(cmd) - if type(cmd) ~= 'table' then - return cmd - end - local escaped = {} - for i, v in ipairs(cmd) do - if v:match('[^A-Za-z_/.-]') then - escaped[i] = vim.fn.shellescape(v) - else - escaped[i] = v - end - end - return table.concat(escaped, ' ') -end - -function M._cmd_ok(cmd) - local out = vim.fn.system(cmd) - return vim.v.shell_error == 0, out -end - ---- Run a system command and timeout after 30 seconds. ---- ---- @param cmd table List of command arguments to execute ---- @param args? table Optional arguments: ---- - stdin (string): Data to write to the job's stdin ---- - stderr (boolean): Append stderr to stdout ---- - ignore_error (boolean): If true, ignore error output ---- - timeout (number): Number of seconds to wait before timing out (default 30) -function M._system(cmd, args) - args = args or {} - local stdin = args.stdin or '' - local stderr = vim.F.if_nil(args.stderr, false) - local ignore_error = vim.F.if_nil(args.ignore_error, false) - - local shell_error_code = 0 - local opts = { - add_stderr_to_output = stderr, - output = '', - stderr = '', - on_stdout = system_handler, - on_stderr = system_handler, - on_exit = function(_, data) - shell_error_code = data - end, - } - local jobid = vim.fn.jobstart(cmd, opts) - - if jobid < 1 then - local message = - string.format('Command error (job=%d): %s (in %s)', jobid, shellify(cmd), vim.uv.cwd()) - error(message) - return opts.output, 1 - end - - if stdin:find('^%s$') then - vim.fn.chansend(jobid, stdin) - end - - local res = vim.fn.jobwait({ jobid }, vim.F.if_nil(args.timeout, 30) * 1000) - if res[1] == -1 then - error('Command timed out: ' .. shellify(cmd)) - vim.fn.jobstop(jobid) - elseif shell_error_code ~= 0 and not ignore_error then - local emsg = string.format( - 'Command error (job=%d, exit code %d): %s (in %s)', - jobid, - shell_error_code, - shellify(cmd), - vim.uv.cwd() - ) - if opts.output:find('%S') then - emsg = string.format('%s\noutput: %s', emsg, opts.output) - end - if opts.stderr:find('%S') then - emsg = string.format('%s\nstderr: %s', emsg, opts.stderr) - end - error(emsg) - end - - -- return opts.output - return vim.trim(vim.fn.system(cmd)), shell_error_code -end - local path2name = function(path) if path:match('%.lua$') then -- Lua: transform "../lua/vim/lsp/health.lua" into "vim.lsp" diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index 63e0da448a..d6932f651e 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -3,6 +3,112 @@ local iswin = vim.uv.os_uname().sysname == 'Windows_NT' local M = {} +local function cmd_ok(cmd) + local out = vim.fn.system(cmd) + return vim.v.shell_error == 0, out +end + +-- Attempts to construct a shell command from an args list. +-- Only for display, to help users debug a failed command. +local function shellify(cmd) + if type(cmd) ~= 'table' then + return cmd + end + local escaped = {} + for i, v in ipairs(cmd) do + if v:match('[^A-Za-z_/.-]') then + escaped[i] = vim.fn.shellescape(v) + else + escaped[i] = v + end + end + return table.concat(escaped, ' ') +end + +-- Handler for s:system() function. +local function system_handler(self, _, data, event) + if event == 'stderr' then + if self.add_stderr_to_output then + self.output = self.output .. table.concat(data, '') + else + self.stderr = self.stderr .. table.concat(data, '') + end + elseif event == 'stdout' then + self.output = self.output .. table.concat(data, '') + end +end + +--- @param cmd table List of command arguments to execute +--- @param args? table Optional arguments: +--- - stdin (string): Data to write to the job's stdin +--- - stderr (boolean): Append stderr to stdout +--- - ignore_error (boolean): If true, ignore error output +--- - timeout (number): Number of seconds to wait before timing out (default 30) +local function system(cmd, args) + args = args or {} + local stdin = args.stdin or '' + local stderr = vim.F.if_nil(args.stderr, false) + local ignore_error = vim.F.if_nil(args.ignore_error, false) + + local shell_error_code = 0 + local opts = { + add_stderr_to_output = stderr, + output = '', + stderr = '', + on_stdout = system_handler, + on_stderr = system_handler, + on_exit = function(_, data) + shell_error_code = data + end, + } + local jobid = vim.fn.jobstart(cmd, opts) + + if jobid < 1 then + local message = + string.format('Command error (job=%d): %s (in %s)', jobid, shellify(cmd), vim.uv.cwd()) + error(message) + return opts.output, 1 + end + + if stdin:find('^%s$') then + vim.fn.chansend(jobid, stdin) + end + + local res = vim.fn.jobwait({ jobid }, vim.F.if_nil(args.timeout, 30) * 1000) + if res[1] == -1 then + error('Command timed out: ' .. shellify(cmd)) + vim.fn.jobstop(jobid) + elseif shell_error_code ~= 0 and not ignore_error then + local emsg = string.format( + 'Command error (job=%d, exit code %d): %s (in %s)', + jobid, + shell_error_code, + shellify(cmd), + vim.uv.cwd() + ) + if opts.output:find('%S') then + emsg = string.format('%s\noutput: %s', emsg, opts.output) + end + if opts.stderr:find('%S') then + emsg = string.format('%s\nstderr: %s', emsg, opts.stderr) + end + error(emsg) + end + + -- return opts.output + return vim.trim(vim.fn.system(cmd)), shell_error_code +end + +local function provider_disabled(provider) + local loaded_var = 'loaded_' .. provider .. '_provider' + local v = vim.g[loaded_var] + if v == 0 then + health.info('Disabled (' .. loaded_var .. '=' .. v .. ').') + return true + end + return false +end + local function clipboard() health.start('Clipboard (optional)') @@ -10,7 +116,7 @@ local function clipboard() os.getenv('TMUX') and vim.fn.executable('tmux') == 1 and vim.fn.executable('pbpaste') == 1 - and not health._cmd_ok('pbpaste') + and not cmd_ok('pbpaste') then local tmux_version = string.match(vim.fn.system('tmux -V'), '%d+%.%d+') local advice = { @@ -40,7 +146,7 @@ end local function node() health.start('Node.js provider (optional)') - if health._provider_disabled('node') then + if provider_disabled('node') then return end @@ -60,7 +166,7 @@ local function node() end -- local node_v = vim.fn.split(system({'node', '-v'}), "\n")[1] or '' - local ok, node_v = health._cmd_ok({ 'node', '-v' }) + local ok, node_v = cmd_ok({ 'node', '-v' }) health.info('Node.js: ' .. node_v) if not ok or vim.version.lt(node_v, '6.0.0') then health.warn('Nvim node.js host does not support Node ' .. node_v) @@ -97,7 +203,7 @@ local function node() iswin and 'cmd /c ' .. manager .. ' info neovim --json' or manager .. ' info neovim --json' ) local latest_npm - ok, latest_npm = health._cmd_ok(vim.split(latest_npm_cmd, ' ')) + ok, latest_npm = cmd_ok(vim.split(latest_npm_cmd, ' ')) if not ok or latest_npm:find('^%s$') then health.error( 'Failed to run: ' .. latest_npm_cmd, @@ -115,7 +221,7 @@ local function node() local current_npm_cmd = { 'node', host, '--version' } local current_npm - ok, current_npm = health._cmd_ok(current_npm_cmd) + ok, current_npm = cmd_ok(current_npm_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_npm_cmd, ' '), @@ -143,7 +249,7 @@ end local function perl() health.start('Perl provider (optional)') - if health._provider_disabled('perl') then + if provider_disabled('perl') then return end @@ -162,7 +268,7 @@ local function perl() -- we cannot use cpanm that is on the path, as it may not be for the perl -- set with g:perl_host_prog - local ok = health._cmd_ok({ perl_exec, '-W', '-MApp::cpanminus', '-e', '' }) + local ok = cmd_ok({ perl_exec, '-W', '-MApp::cpanminus', '-e', '' }) if not ok then return { perl_exec, '"App::cpanminus" module is not installed' } end @@ -174,7 +280,7 @@ local function perl() 'my $app = App::cpanminus::script->new; $app->parse_options ("--info", "-q", "Neovim::Ext"); exit $app->doit', } local latest_cpan - ok, latest_cpan = health._cmd_ok(latest_cpan_cmd) + ok, latest_cpan = cmd_ok(latest_cpan_cmd) if not ok or latest_cpan:find('^%s*$') then health.error( 'Failed to run: ' .. table.concat(latest_cpan_cmd, ' '), @@ -205,7 +311,7 @@ local function perl() local current_cpan_cmd = { perl_exec, '-W', '-MNeovim::Ext', '-e', 'print $Neovim::Ext::VERSION' } local current_cpan - ok, current_cpan = health._cmd_ok(current_cpan_cmd) + ok, current_cpan = cmd_ok(current_cpan_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_cpan_cmd, ' '), @@ -292,7 +398,7 @@ end local function download(url) local has_curl = vim.fn.executable('curl') == 1 if has_curl and vim.fn.system({ 'curl', '-V' }):find('Protocols:.*https') then - local out, rc = health._system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) + local out, rc = system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) if rc ~= 0 then return 'curl error with ' .. url .. ': ' .. rc else @@ -305,7 +411,7 @@ local function download(url) from urllib2 import urlopen\n\ response = urlopen('" .. url .. "')\n\ print(response.read().decode('utf8'))\n" - local out, rc = health._system({ 'python', '-c', script }) + local out, rc = system({ 'python', '-c', script }) if out == '' and rc ~= 0 then return 'python urllib.request error: ' .. rc else @@ -362,7 +468,7 @@ end local function version_info(python) local pypi_version = latest_pypi_version() - local python_version, rc = health._system({ + local python_version, rc = system({ python, '-c', 'import sys; print(".".join(str(x) for x in sys.version_info[:3]))', @@ -373,7 +479,7 @@ local function version_info(python) end local nvim_path - nvim_path, rc = health._system({ + nvim_path, rc = system({ python, '-c', 'import sys; sys.path = [p for p in sys.path if p != ""]; import neovim; print(neovim.__file__)', @@ -398,7 +504,7 @@ local function version_info(python) -- Try to get neovim.VERSION (added in 0.1.11dev). local nvim_version - nvim_version, rc = health._system({ + nvim_version, rc = system({ python, '-c', 'from neovim import VERSION as v; print("{}.{}.{}{}".format(v.major, v.minor, v.patch, v.prerelease))', @@ -445,7 +551,7 @@ local function python() local host_prog_var = pyname .. '_host_prog' local python_multiple = {} - if health._provider_disabled(pyname) then + if provider_disabled(pyname) then return end @@ -487,7 +593,7 @@ local function python() end if pyenv ~= '' then - python_exe = health._system({ pyenv, 'which', pyname }, { stderr = true }) + python_exe = system({ pyenv, 'which', pyname }, { stderr = true }) if python_exe == '' then health.warn('pyenv could not find ' .. pyname .. '.') end @@ -710,9 +816,7 @@ local function python() health.info(msg) health.info( 'Python version: ' - .. health._system( - 'python -c "import platform, sys; sys.stdout.write(platform.python_version())"' - ) + .. system('python -c "import platform, sys; sys.stdout.write(platform.python_version())"') ) health.ok('$VIRTUAL_ENV provides :!python.') end @@ -721,7 +825,7 @@ end local function ruby() health.start('Ruby provider (optional)') - if health._provider_disabled('ruby') then + if provider_disabled('ruby') then return end @@ -732,7 +836,7 @@ local function ruby() ) return end - health.info('Ruby: ' .. health._system({ 'ruby', '-v' })) + health.info('Ruby: ' .. system({ 'ruby', '-v' })) local host, _ = vim.provider.ruby.detect() if (not host) or host:find('^%s*$') then @@ -748,7 +852,7 @@ local function ruby() health.info('Host: ' .. host) local latest_gem_cmd = (iswin and 'cmd /c gem list -ra "^^neovim$"' or 'gem list -ra ^neovim$') - local ok, latest_gem = health._cmd_ok(vim.split(latest_gem_cmd, ' ')) + local ok, latest_gem = cmd_ok(vim.split(latest_gem_cmd, ' ')) if not ok or latest_gem:find('^%s*$') then health.error( 'Failed to run: ' .. latest_gem_cmd, @@ -761,7 +865,7 @@ local function ruby() local current_gem_cmd = { host, '--version' } local current_gem - ok, current_gem = health._cmd_ok(current_gem_cmd) + ok, current_gem = cmd_ok(current_gem_cmd) if not ok then health.error( 'Failed to run: ' .. table.concat(current_gem_cmd, ' '), -- cgit From f03b1622ad1b8e2df16504631f05e7577e217854 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 25 May 2024 21:22:41 +0200 Subject: fix(lsp): handle nil root_dir in health check (#29007) The root directory could show up as something like: Root directory: ~/path/to/cwd/v:null Despite being `nil` --- runtime/doc/lsp.txt | 2 +- runtime/lua/vim/lsp/client.lua | 3 +-- runtime/lua/vim/lsp/health.lua | 5 ++++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 50fffca497..a66b577b11 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -996,7 +996,7 @@ Lua module: vim.lsp.client *lsp-client* if the client supports workspace folders. It can be `null` if the client supports workspace folders but none are configured. - • {root_dir} (`string`) + • {root_dir} (`string?`) • {attached_buffers} (`table`) • {commands} (`table`) Table of command name to function which is diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 4beb7fefda..58ea7d02b3 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -182,7 +182,7 @@ local validate = vim.validate --- It can be `null` if the client supports workspace folders but none are --- configured. --- @field workspace_folders lsp.WorkspaceFolder[]? ---- @field root_dir string +--- @field root_dir string? --- --- @field attached_buffers table --- @@ -470,7 +470,6 @@ function Client.create(config) _on_exit_cbs = ensure_list(config.on_exit), _on_attach_cbs = ensure_list(config.on_attach), _on_error_cb = config.on_error, - _root_dir = config.root_dir, _trace = get_trace(config.trace), --- Contains $/progress report messages. diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index b5dc710cc6..ffe595ab37 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -41,7 +41,10 @@ local function check_active_clients() end report_info(table.concat({ string.format('%s (id: %d)', client.name, client.id), - string.format(' Root directory: %s', vim.fn.fnamemodify(client.root_dir, ':~')), + string.format( + ' Root directory: %s', + client.root_dir and vim.fn.fnamemodify(client.root_dir, ':~') or nil + ), string.format(' Command: %s', cmd), string.format(' Settings: %s', vim.inspect(client.settings, { newline = '\n ' })), string.format( -- cgit From 7994fdba6a1e10aad0698dfabcbaf544b4d35eb4 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 25 May 2024 21:23:04 +0200 Subject: fix(snippet): don't override unnamed register on tabstop select (#28998) --- runtime/lua/vim/snippet.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3d8f73f362..3fd2555046 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -315,7 +315,7 @@ local function select_tabstop(tabstop) move_cursor_to(range[1] + 1, range[2] + 1) feedkeys('v') move_cursor_to(range[3] + 1, range[4]) - feedkeys('o') + feedkeys('o_') end end -- cgit From eaaf3d9048f37b2bf5914d34f7348a1ba6ebe250 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 25 May 2024 23:21:30 +0200 Subject: vim-patch:0076ddc: runtime(debian): update Debian runtime files (vim/vim#14849) * Add space in template for 'commentstring' * Add 'comments' and 'commentstring' support to debcontrol * debversions: Move Ubuntu releases outside of standard support to unsupported Although trust, xenial, and bionic are not EOL yet, their standard support period has ended. Reported-by: Riley Bruins https://github.com/vim/vim/commit/0076ddc07dc1d97afcf3252fd361885abbaf23d5 Co-authored-by: James McCoy Co-authored-by: Riley Bruins --- runtime/ftplugin/deb822sources.vim | 4 ++-- runtime/ftplugin/debcontrol.vim | 7 +++++-- runtime/ftplugin/debsources.vim | 4 ++-- runtime/syntax/shared/debversions.vim | 9 +++++---- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/runtime/ftplugin/deb822sources.vim b/runtime/ftplugin/deb822sources.vim index 4936f42bf9..31c81b1a5d 100644 --- a/runtime/ftplugin/deb822sources.vim +++ b/runtime/ftplugin/deb822sources.vim @@ -1,6 +1,6 @@ " Language: Debian sources.list " Maintainer: Debian Vim Maintainers -" Last Change: 2024 Mar 20 +" Last Change: 2024 May 25 " License: Vim License " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/deb822sources.vim @@ -10,7 +10,7 @@ endif let b:did_ftplugin=1 setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions-=t let b:undo_ftplugin = 'setlocal comments< commentstring< formatoptions<' diff --git a/runtime/ftplugin/debcontrol.vim b/runtime/ftplugin/debcontrol.vim index bb710e597c..5b8292ba6e 100644 --- a/runtime/ftplugin/debcontrol.vim +++ b/runtime/ftplugin/debcontrol.vim @@ -2,7 +2,7 @@ " Language: Debian control files " Maintainer: Debian Vim Maintainers " Former Maintainer: Pierre Habouzit -" Last Change: 2023 Jan 16 +" Last Change: 2024 May 25 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/debcontrol.vim " Do these settings once per buffer @@ -19,8 +19,11 @@ if exists('g:debcontrol_fold_enable') endif setlocal textwidth=0 +setlocal comments=:# +setlocal commentstring=#\ %s + " Clean unloading -let b:undo_ftplugin = 'setlocal tw< foldmethod< foldexpr< foldtext<' +let b:undo_ftplugin = 'setlocal tw< foldmethod< foldexpr< foldtext< comments< commentstring<' " }}}1 diff --git a/runtime/ftplugin/debsources.vim b/runtime/ftplugin/debsources.vim index cbb4fafd22..2c5ea3599f 100644 --- a/runtime/ftplugin/debsources.vim +++ b/runtime/ftplugin/debsources.vim @@ -1,6 +1,6 @@ " Language: Debian sources.list " Maintainer: Debian Vim Maintainers -" Last Change: 2023 Aug 30 +" Last Change: 2024 May 25 " License: Vim License " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/ftplugin/debsources.vim @@ -10,7 +10,7 @@ endif let b:did_ftplugin=1 setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions-=t let b:undo_ftplugin = 'setlocal comments< commentstring< formatoptions<' diff --git a/runtime/syntax/shared/debversions.vim b/runtime/syntax/shared/debversions.vim index e18eca96b1..56f18b969a 100644 --- a/runtime/syntax/shared/debversions.vim +++ b/runtime/syntax/shared/debversions.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: Debian version information " Maintainer: Debian Vim Maintainers -" Last Change: 2024 Apr 27 +" Last Change: 2024 May 25 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/main/syntax/shared/debversions.vim let s:cpo = &cpo @@ -11,7 +11,7 @@ let g:debSharedSupportedVersions = [ \ 'oldstable', 'stable', 'testing', 'unstable', 'experimental', 'sid', 'rc-buggy', \ 'bullseye', 'bookworm', 'trixie', 'forky', \ - \ 'trusty', 'xenial', 'bionic', 'focal', 'jammy', 'mantic', 'noble', 'oracular', + \ 'focal', 'jammy', 'mantic', 'noble', 'oracular', \ 'devel' \ ] let g:debSharedUnsupportedVersions = [ @@ -22,8 +22,9 @@ let g:debSharedUnsupportedVersions = [ \ 'warty', 'hoary', 'breezy', 'dapper', 'edgy', 'feisty', \ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid', \ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy', - \ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic', - \ 'disco', 'eoan', 'hirsute', 'impish', 'kinetic', 'lunar', 'groovy' + \ 'trusty', 'utopic', 'vivid', 'wily', 'xenial', 'yakkety', 'zesty', + \ 'artful', 'bionic', 'cosmic', 'disco', 'eoan', 'hirsute', + \ 'impish', 'kinetic', 'lunar', 'groovy' \ ] let &cpo=s:cpo -- cgit From 3d39ea3ea9b6e66640e59731d155d731218e7e62 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 26 May 2024 07:11:50 +0800 Subject: vim-patch:9.1.0442: hare runtime files outdated (#29011) Problem: hare runtime files outdated Solution: runtime(hare): update hare.vim to match upstream (Amelia Clarke) closes: vim/vim#14836 https://github.com/vim/vim/commit/35dfe58a540e2fb0eff953630f8e4fcbf4bc26ca Co-authored-by: Amelia Clarke --- runtime/autoload/hare.vim | 26 +++++ runtime/compiler/hare.vim | 23 ++--- runtime/doc/filetype.txt | 6 ++ runtime/doc/ft_hare.txt | 77 +++++++++++++++ runtime/ftplugin/hare.vim | 56 ++++++++--- runtime/ftplugin/haredoc.vim | 44 +++++++++ runtime/indent/hare.vim | 31 +++--- runtime/lua/vim/filetype.lua | 2 +- runtime/lua/vim/filetype/detect.lua | 24 +++++ runtime/syntax/hare.vim | 188 ++++++++++++++++++++---------------- runtime/syntax/haredoc.vim | 32 ++++++ test/old/testdir/test_filetype.vim | 35 +++++++ 12 files changed, 421 insertions(+), 123 deletions(-) create mode 100644 runtime/autoload/hare.vim create mode 100644 runtime/doc/ft_hare.txt create mode 100644 runtime/ftplugin/haredoc.vim create mode 100644 runtime/syntax/haredoc.vim diff --git a/runtime/autoload/hare.vim b/runtime/autoload/hare.vim new file mode 100644 index 0000000000..c4581fccf9 --- /dev/null +++ b/runtime/autoload/hare.vim @@ -0,0 +1,26 @@ +" Vim autoload file. +" Language: Hare +" Maintainer: Amelia Clarke +" Last Updated: 2024-05-10 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim + +" Attempt to find the directory for a given Hare module. +function hare#FindModule(str) + let path = substitute(trim(a:str, ':', 2), '::', '/', 'g') + let dir = finddir(path) + while !empty(path) && empty(dir) + let path = substitute(path, '/\?\h\w*$', '', '') + let dir = finddir(path) + endwhile + return dir +endfunction + +" Return the value of HAREPATH if it exists. Otherwise use a reasonable default. +function hare#GetPath() + if empty($HAREPATH) + return '/usr/src/hare/stdlib,/usr/src/hare/third-party' + endif + return substitute($HAREPATH, ':', ',', 'g') +endfunction + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/compiler/hare.vim b/runtime/compiler/hare.vim index c98bbb9c63..33edb3a281 100644 --- a/runtime/compiler/hare.vim +++ b/runtime/compiler/hare.vim @@ -1,28 +1,29 @@ -" Vim compiler file -" Compiler: Hare Compiler -" Maintainer: Amelia Clarke -" Last Change: 2022-09-21 -" 2024 Apr 05 by The Vim Project (removed :CompilerSet definition) +" Vim compiler file. +" Compiler: Hare +" Maintainer: Amelia Clarke +" Last Change: 2024-05-23 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim -if exists("g:current_compiler") +if exists('current_compiler') finish endif -let g:current_compiler = "hare" +let current_compiler = 'hare' let s:cpo_save = &cpo set cpo&vim -if filereadable("Makefile") || filereadable("makefile") +if filereadable('Makefile') || filereadable('makefile') CompilerSet makeprg=make else CompilerSet makeprg=hare\ build endif CompilerSet errorformat= - \Error\ %f:%l:%c:\ %m, - \Syntax\ error:\ %.%#\ at\ %f:%l:%c\\,\ %m, + \%f:%l:%c:\ syntax\ error:\ %m, + \%f:%l:%c:\ error:\ %m, \%-G%.%# let &cpo = s:cpo_save unlet s:cpo_save -" vim: tabstop=2 shiftwidth=2 expandtab + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 5eae78744c..eddf14014a 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -602,6 +602,12 @@ The mapping can be disabled with: > let g:no_gprof_maps = 1 +HARE *ft-hare* + +Since the text for this plugin is rather long it has been put in a separate +file: |ft_hare.txt|. + + JAVA *ft-java-plugin* Whenever the variable "g:ftplugin_java_source_path" is defined and its value diff --git a/runtime/doc/ft_hare.txt b/runtime/doc/ft_hare.txt new file mode 100644 index 0000000000..937c5e0961 --- /dev/null +++ b/runtime/doc/ft_hare.txt @@ -0,0 +1,77 @@ +*ft_hare.txt* Support for the Hare programming language + +============================================================================== +CONTENTS *hare* + +1. Introduction |hare-intro| +2. Filetype plugin |hare-plugin| +3. Settings |hare-settings| + +============================================================================== +INTRODUCTION *hare-intro* + +This plugin provides syntax highlighting, indentation, and other functionality +for the Hare programming language. Support is also provided for README files +inside Hare modules, but this must be enabled by setting |g:filetype_haredoc|. + +============================================================================== +FILETYPE PLUGIN *hare-plugin* + +This plugin automatically sets the value of 'path' to include the contents of +the HAREPATH environment variable, allowing commands such as |gf| to directly +open standard library or third-party modules. If HAREPATH is not set, it +defaults to the recommended paths for most Unix-like filesystems, namely +/usr/src/hare/stdlib and /usr/src/hare/third-party. + +============================================================================== +SETTINGS *hare-settings* + +This plugin provides a small number of variables that you can define in your +vimrc to configure its behavior. + + *g:filetype_haredoc* +This plugin is able to automatically detect Hare modules and set the "haredoc" +filetype for any README files. As the recursive directory search used as a +heuristic has a minor performance impact, this feature is disabled by default +and must be specifically opted into: > + let g:filetype_haredoc = 1 +< +See |g:haredoc_search_depth| for ways to tweak the searching behavior. + + *g:hare_recommended_style* +The following options are set by default, in accordance with the official Hare +style guide: > + setlocal noexpandtab + setlocal shiftwidth=0 + setlocal softtabstop=0 + setlocal tabstop=8 + setlocal textwidth=80 +< +To disable this behavior: > + let g:hare_recommended_style = 0 +< + *g:hare_space_error* +By default, trailing whitespace and tabs preceded by space characters are +highlighted as errors. This is automatically turned off when in insert mode. +To disable this highlighting completely: > + let g:hare_space_error = 0 +< + *g:haredoc_search_depth* +By default, when |g:filetype_haredoc| is enabled, only the current directory +and its immediate subdirectories are searched for Hare files. The maximum +search depth may be adjusted with: > + let g:haredoc_search_depth = 2 +< + Value Effect~ + 0 Only search the current directory. + 1 Search the current directory and immediate + subdirectories. + 2 Search the current directory and two levels of + subdirectories. + +The maximum search depth can be set to any integer, but using values higher +than 2 is not recommended, and will likely provide no tangible benefit in most +situations. + +============================================================================== + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/ftplugin/hare.vim b/runtime/ftplugin/hare.vim index 0200ba5913..422bb7b4e8 100644 --- a/runtime/ftplugin/hare.vim +++ b/runtime/ftplugin/hare.vim @@ -1,35 +1,59 @@ -" Vim filetype plugin -" Language: Hare -" Maintainer: Amelia Clarke -" Previous Maintainer: Drew DeVault -" Last Updated: 2022-09-28 -" 2023 Aug 28 by Vim Project (undo_ftplugin) +" Vim filetype plugin. +" Language: Hare +" Maintainer: Amelia Clarke +" Last Updated: 2024-05-10 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim if exists('b:did_ftplugin') finish endif let b:did_ftplugin = 1 -" Formatting settings. -setlocal formatoptions-=t formatoptions+=croql/ +let s:cpo_save = &cpo +set cpo&vim + +" Set the default compiler. +compiler hare -" Miscellaneous. +" Formatting settings. setlocal comments=:// setlocal commentstring=//\ %s +setlocal formatlistpat=^\ \\?-\ +setlocal formatoptions+=croqnlj/ formatoptions-=t + +" Search for Hare modules. +setlocal include=^\\s*use\\> +setlocal includeexpr=hare#FindModule(v:fname) +setlocal isfname+=: setlocal suffixesadd=.ha -let b:undo_ftplugin = "setl cms< com< fo< sua<" +" Add HAREPATH to the default search paths. +setlocal path-=/usr/include,, +let &l:path .= ',' .. hare#GetPath() .. ',,' -" Hare recommended style. -if get(g:, "hare_recommended_style", 1) +let b:undo_ftplugin = 'setl cms< com< flp< fo< inc< inex< isf< pa< sua< mp<' + +" Follow the Hare style guide by default. +if get(g:, 'hare_recommended_style', 1) setlocal noexpandtab - setlocal shiftwidth=8 + setlocal shiftwidth=0 setlocal softtabstop=0 setlocal tabstop=8 setlocal textwidth=80 - let b:undo_ftplugin ..= " | setl et< sts< sw< ts< tw<" + let b:undo_ftplugin .= ' et< sts< sw< ts< tw<' endif -compiler hare +augroup hare.vim + autocmd! + + " Highlight whitespace errors by default. + if get(g:, 'hare_space_error', 1) + autocmd InsertEnter * hi link hareSpaceError NONE + autocmd InsertLeave * hi link hareSpaceError Error + endif +augroup END + +let &cpo = s:cpo_save +unlet s:cpo_save -" vim: et sw=2 sts=2 ts=8 +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/ftplugin/haredoc.vim b/runtime/ftplugin/haredoc.vim new file mode 100644 index 0000000000..69030b47ba --- /dev/null +++ b/runtime/ftplugin/haredoc.vim @@ -0,0 +1,44 @@ +" Vim filetype plugin. +" Language: Haredoc (Hare documentation format) +" Maintainer: Amelia Clarke +" Last Updated: 2024-05-02 +" Upstream: https://git.sr.ht/~selene/hare.vim + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +" Formatting settings. +setlocal comments=:\ +setlocal formatlistpat=^\ \\?-\ +setlocal formatoptions+=tnlj formatoptions-=c formatoptions-=q + +" Search for Hare modules. +setlocal includeexpr=hare#FindModule(v:fname) +setlocal isfname+=: +setlocal suffixesadd=.ha + +" Add HAREPATH to the default search paths. +setlocal path-=/usr/include,, +let &l:path .= ',' .. hare#GetPath() .. ',,' + +let b:undo_ftplugin = 'setl com< flp< fo< inex< isf< pa< sua<' + +" Follow the Hare style guide by default. +if get(g:, 'hare_recommended_style', 1) + setlocal noexpandtab + setlocal shiftwidth=0 + setlocal softtabstop=0 + setlocal tabstop=8 + setlocal textwidth=80 + let b:undo_ftplugin .= ' et< sts< sw< ts< tw<' +endif + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/indent/hare.vim b/runtime/indent/hare.vim index 0a9d8dafd8..1b51d1e80a 100644 --- a/runtime/indent/hare.vim +++ b/runtime/indent/hare.vim @@ -1,19 +1,16 @@ " Vim indent file -" Language: Hare -" Maintainer: Amelia Clarke -" Last Change: 2022 Sep 22 -" 2023 Aug 28 by Vim Project (undo_indent) +" Language: Hare +" Maintainer: Amelia Clarke +" Last Change: 2024-04-14 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim -if exists("b:did_indent") +if exists('b:did_indent') finish endif let b:did_indent = 1 -if !has("cindent") || !has("eval") - finish -endif - -setlocal cindent +let s:cpo_save = &cpo +set cpo&vim " L0 -> don't deindent labels " (s -> use one indent after a trailing ( @@ -41,7 +38,11 @@ setlocal cinwords=if,else,for,switch,match setlocal indentexpr=GetHareIndent() -let b:undo_indent = "setl cin< cino< cinw< inde< indk<" +let b:undo_indent = 'setl cino< cinw< inde< indk<' + +if exists('*GetHareIndent()') + finish +endif function! FloorCindent(lnum) return cindent(a:lnum) / shiftwidth() * shiftwidth() @@ -122,7 +123,8 @@ function! GetHareIndent() " Indent the body of a case. " If the previous line ended in a semicolon and the line before that was a " case, don't do any special indenting. - if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' && line !~# '\v^\s*}' + if prevline =~# '\v;\s*(//.*)?$' && prevprevline =~# '\v\=\>\s*(//.*)?$' + \ && line !~# '\v^\s*}' return indent(prevlnum) endif @@ -138,4 +140,7 @@ function! GetHareIndent() return l:indent endfunction -" vim: tabstop=2 shiftwidth=2 expandtab +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: et sw=2 sts=2 ts=8 diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index d1fdd0aa16..2ab6cc6059 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1637,7 +1637,7 @@ local filename = { ['.xsdbcmdhistory'] = 'tcl', ['texmf.cnf'] = 'texmf', COPYING = 'text', - README = 'text', + README = detect_seq(detect.haredoc, 'text'), LICENSE = 'text', AUTHORS = 'text', tfrc = 'tf', diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index ba86d8de5a..58d2666564 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -650,6 +650,30 @@ function M.header(_, bufnr) end end +--- Recursively search for Hare source files in a directory and any +--- subdirectories, up to a given depth. +--- @param dir string +--- @param depth number +--- @return boolean +local function is_hare_module(dir, depth) + depth = math.max(depth, 0) + for name, _ in vim.fs.dir(dir, { depth = depth + 1 }) do + if name:find('%.ha$') then + return true + end + end + return false +end + +--- @type vim.filetype.mapfn +function M.haredoc(path, _) + if vim.g.filetype_haredoc then + if is_hare_module(vim.fs.dirname(path), vim.g.haredoc_search_depth or 1) then + return 'haredoc' + end + end +end + --- @type vim.filetype.mapfn function M.html(_, bufnr) for _, line in ipairs(getlines(bufnr, 1, 10)) do diff --git a/runtime/syntax/hare.vim b/runtime/syntax/hare.vim index 07cf33fb11..4c7ae92486 100644 --- a/runtime/syntax/hare.vim +++ b/runtime/syntax/hare.vim @@ -1,119 +1,142 @@ -" PRELUDE {{{1 -" Vim syntax file -" Language: Hare -" Maintainer: Amelia Clarke -" Last Change: 2022-09-21 +" Vim syntax file. +" Language: Hare +" Maintainer: Amelia Clarke +" Last Change: 2024-05-10 +" Upstream: https://git.sr.ht/~sircmpwn/hare.vim -if exists("b:current_syntax") +if exists('b:current_syntax') finish endif -let b:current_syntax = "hare" +syn include @haredoc syntax/haredoc.vim +let b:current_syntax = 'hare' -" SYNTAX {{{1 +" Syntax {{{1 syn case match +syn iskeyword @,48-57,@-@,_ -" KEYWORDS {{{2 -syn keyword hareConditional if else match switch +" Keywords {{{2 +syn keyword hareConditional else if match switch +syn keyword hareDefine def +syn keyword hareInclude use syn keyword hareKeyword break continue return yield +syn keyword hareKeyword case +syn keyword hareKeyword const let syn keyword hareKeyword defer +syn keyword hareKeyword export static syn keyword hareKeyword fn -syn keyword hareKeyword let -syn keyword hareLabel case syn keyword hareOperator as is syn keyword hareRepeat for -syn keyword hareStorageClass const def export nullable static -syn keyword hareStructure enum struct union syn keyword hareTypedef type -" C ABI. -syn keyword hareKeyword vastart vaarg vaend - -" BUILTINS {{{2 -syn keyword hareBuiltin abort +" Attributes. +syn keyword hareAttribute @fini @init @test +syn keyword hareAttribute @offset @packed +syn keyword hareAttribute @symbol +syn keyword hareAttribute @threadlocal + +" Builtins. +syn keyword hareBuiltin abort assert +syn keyword hareBuiltin align len offset syn keyword hareBuiltin alloc free syn keyword hareBuiltin append delete insert -syn keyword hareBuiltin assert -syn keyword hareBuiltin len offset +syn keyword hareBuiltin vaarg vaend vastart -" TYPES {{{2 +" Types {{{2 syn keyword hareType bool -syn keyword hareType char str +syn keyword hareType done syn keyword hareType f32 f64 -syn keyword hareType u8 u16 u32 u64 i8 i16 i32 i64 -syn keyword hareType uint int -syn keyword hareType rune +syn keyword hareType i8 i16 i32 i64 int +syn keyword hareType never +syn keyword hareType opaque +syn keyword hareType rune str +syn keyword hareType u8 u16 u32 u64 uint syn keyword hareType uintptr +syn keyword hareType valist syn keyword hareType void -" C ABI. -syn keyword hareType valist +" Other types. +syn keyword hareStorageClass nullable +syn keyword hareStructure enum struct union -" LITERALS {{{2 -syn keyword hareBoolean true false -syn keyword hareNull null - -" Number literals. -syn match hareNumber "\v(\.@1" display -syn match hareNumber "\v(\.@1" display -syn match hareNumber "\v(\.@1" display -syn match hareNumber "\v(\.@1" display - -" Floating-point number literals. -syn match hareFloat "\v<\d+\.\d+([Ee][+-]?\d+)?(f32|f64)?>" display -syn match hareFloat "\v<\d+([Ee][+-]?\d+)?(f32|f64)>" display - -" String and rune literals. -syn match hareEscape "\\[\\'"0abfnrtv]" contained display -syn match hareEscape "\v\\(x\x{2}|u\x{4}|U\x{8})" contained display -syn match hareFormat "\v\{\d*(\%\d*|(:[ 0+-]?\d*(\.\d+)?[Xbox]?))?}" contained display -syn match hareFormat "\({{\|}}\)" contained display -syn region hareRune start="'" end="'\|$" skip="\\'" contains=hareEscape display extend -syn region hareString start=+"+ end=+"\|$+ skip=+\\"+ contains=hareEscape,hareFormat display extend -syn region hareString start="`" end="`\|$" contains=hareFormat display - -" MISCELLANEOUS {{{2 -syn keyword hareTodo FIXME TODO XXX contained +" Literals {{{2 +syn keyword hareBoolean false true +syn keyword hareConstant null -" Attributes. -syn match hareAttribute "@[a-z]*" +" Integer literals. +syn match hareNumber '\v<%(0|[1-9]%(_?\d)*)%([Ee]\+?\d+)?%([iu]%(8|16|32|64)?|z)?>' display +syn match hareNumber '\v<0b[01]%(_?[01])*%([iu]%(8|16|32|64)?|z)?>' display +syn match hareNumber '\v<0o\o%(_?\o)*%([iu]%(8|16|32|64)?|z)?>' display +syn match hareNumber '\v<0x\x%(_?\x)*%([iu]%(8|16|32|64)?|z)?>' display -" Blocks. -syn region hareBlock start="{" end="}" fold transparent +" Floating-point literals. +syn match hareFloat '\v<%(0|[1-9]%(_?\d)*)\.\d%(_?\d)*%([Ee][+-]?\d+)?%(f32|f64)?>' display +syn match hareFloat '\v<%(0|[1-9]%(_?\d)*)%([Ee][+-]?\d+)?%(f32|f64)>' display +syn match hareFloat '\v<0x\x%(_?\x)*%(\.\x%(_?\x)*)?[Pp][+-]?\d+%(f32|f64)?>' display + +" Rune and string literals. +syn region hareRune start="'" skip="\\'" end="'" contains=hareEscape +syn region hareString start='"' skip='\\"' end='"' contains=hareEscape,hareFormat +syn region hareString start='`' end='`' contains=hareFormat + +" Escape sequences. +syn match hareEscape '\\[0abfnrtv\\'"]' contained +syn match hareEscape '\v\\%(x\x{2}|u\x{4}|U\x{8})' contained display + +" Format sequences. +syn match hareFormat '\v\{\d*%(:%(\.?\d+|[ +\-=Xbefgox]|F[.2ESUs]|_%(.|\\%([0abfnrtv\\'"]|x\x{2}|u\x{4}|U\x{8})))*)?}' contained contains=hareEscape display +syn match hareFormat '{\d*%\d*}' contained display +syn match hareFormat '{{\|}}' contained display + +" Miscellaneous {{{2 " Comments. -syn region hareComment start="//" end="$" contains=hareCommentDoc,hareTodo,@Spell display keepend -syn region hareCommentDoc start="\[\[" end="]]\|\ze\_s" contained display +syn region hareComment start='//' end='$' contains=hareTodo,@haredoc,@Spell display +syn keyword hareTodo FIXME TODO XXX contained + +" Identifiers. +syn match hareDelimiter '::' display +syn match hareName '\<\h\w*\>' nextgroup=@harePostfix skipempty skipwhite transparent -" The size keyword can be either a builtin or a type. -syn match hareBuiltin "\v\ze(\_s*//.*\_$)*\_s*\(" contains=hareComment -syn match hareType "\v((\_s*//.*\_$)*\_s*\()@!" contains=hareComment +" Labels. +syn match hareLabel ':\h\w*\>' display -" Trailing whitespace. -syn match hareSpaceError "\v\s+$" display excludenl -syn match hareSpaceError "\v\zs +\ze\t" display +" Match `size` as a type unless it is followed by an open paren. +syn match hareType '\' display +syn match hareBuiltin '\'hs=s+1 contained contains=hareNumber nextgroup=@harePostfix skipempty skipwhite +syn region hareIndex start='\[' end=']' contained nextgroup=@harePostfix skipempty skipwhite transparent +syn region hareParens start='(' end=')' nextgroup=@harePostfix skipempty skipwhite transparent -syn match hareErrorAssertion "\v(^([^/]|//@!)*\)\_s*)@<=!\=@!" -syn match hareQuestionMark "?" +" Whitespace errors. +syn match hareSpaceError '^ \+\ze\t' display +syn match hareSpaceError excludenl '\s\+$' containedin=ALL display -" DEFAULT HIGHLIGHTING {{{1 -hi def link hareAttribute Keyword +" Folding {{{3 +syn region hareBlock start='{' end='}' fold transparent + +" Default highlighting {{{1 +hi def link hareAttribute PreProc hi def link hareBoolean Boolean -hi def link hareBuiltin Function +hi def link hareBuiltin Operator hi def link hareComment Comment -hi def link hareCommentDoc SpecialComment hi def link hareConditional Conditional +hi def link hareConstant Constant +hi def link hareDefine Define +hi def link hareDelimiter Delimiter +hi def link hareErrorTest Special hi def link hareEscape SpecialChar hi def link hareFloat Float hi def link hareFormat SpecialChar +hi def link hareInclude Include hi def link hareKeyword Keyword -hi def link hareLabel Label -hi def link hareNull Constant +hi def link hareLabel Special hi def link hareNumber Number hi def link hareOperator Operator -hi def link hareQuestionMark Special hi def link hareRepeat Repeat hi def link hareRune Character hi def link hareStorageClass StorageClass @@ -122,12 +145,13 @@ hi def link hareStructure Structure hi def link hareTodo Todo hi def link hareType Type hi def link hareTypedef Typedef -hi def link hareUse PreProc -hi def link hareSpaceError Error -autocmd InsertEnter * hi link hareSpaceError NONE -autocmd InsertLeave * hi link hareSpaceError Error +" Highlight embedded haredoc references. +hi! def link haredocRefValid SpecialComment -hi def hareErrorAssertion ctermfg=red cterm=bold guifg=red gui=bold +" Highlight whitespace errors by default. +if get(g:, 'hare_space_error', 1) + hi def link hareSpaceError Error +endif -" vim: tabstop=8 shiftwidth=2 expandtab +" vim: et sts=2 sw=2 ts=8 diff --git a/runtime/syntax/haredoc.vim b/runtime/syntax/haredoc.vim new file mode 100644 index 0000000000..09c99c1d56 --- /dev/null +++ b/runtime/syntax/haredoc.vim @@ -0,0 +1,32 @@ +" Vim syntax file. +" Language: Haredoc (Hare documentation format) +" Maintainer: Amelia Clarke +" Last Change: 2024-05-10 +" Upstream: https://git.sr.ht/~selene/hare.vim + +if exists('b:current_syntax') + finish +endif +let b:current_syntax = 'haredoc' + +" Syntax {{{1 +syn case match +syn iskeyword @,48-57,_ + +" Code samples. +syn region haredocCodeSample excludenl start='\t\zs' end='$' contains=@NoSpell display + +" References to other declarations and modules. +syn region haredocRef start='\[\[' end=']]' contains=haredocRefValid,@NoSpell display keepend oneline +syn match haredocRefValid '\v\[\[\h\w*%(::\h\w*)*%(::)?]]' contained contains=@NoSpell display + +" Miscellaneous. +syn keyword haredocTodo FIXME TODO XXX + +" Default highlighting {{{1 +hi def link haredocCodeSample Comment +hi def link haredocRef Error +hi def link haredocRefValid Special +hi def link haredocTodo Todo + +" vim: et sts=2 sw=2 ts=8 diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index 34fe93fd55..16125559cf 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -1511,6 +1511,41 @@ func Test_git_file() filetype off endfunc +func Test_haredoc_file() + filetype on + call assert_true(mkdir('foo/bar', 'pR')) + + call writefile([], 'README', 'D') + split README + call assert_notequal('haredoc', &filetype) + bwipe! + + let g:filetype_haredoc = 1 + split README + call assert_notequal('haredoc', &filetype) + bwipe! + + call writefile([], 'foo/quux.ha') + split README + call assert_equal('haredoc', &filetype) + bwipe! + call delete('foo/quux.ha') + + call writefile([], 'foo/bar/baz.ha', 'D') + split README + call assert_notequal('haredoc', &filetype) + bwipe! + + let g:haredoc_search_depth = 2 + split README + call assert_equal('haredoc', &filetype) + bwipe! + unlet g:filetype_haredoc + unlet g:haredoc_search_depth + + filetype off +endfunc + func Test_hook_file() filetype on -- cgit From fb43741f80175ba5e26addb785162dd83d33c859 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 25 May 2024 19:18:57 +0200 Subject: refactor(tests): use more global highlight definitions --- test/functional/api/buffer_spec.lua | 113 ++++++--------- test/functional/api/vim_spec.lua | 277 +++++++++++++++--------------------- test/functional/api/window_spec.lua | 150 +++++++------------ 3 files changed, 213 insertions(+), 327 deletions(-) diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index cf69958fd8..f836c1c540 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -125,11 +125,6 @@ describe('api/buf', function() it('cursor position is maintained consistently with viewport', function() local screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() local lines = { 'line1', 'line2', 'line3', 'line4', 'line5', 'line6' } @@ -143,11 +138,11 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| line5 | line6 | {1:~ }|*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -158,11 +153,11 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| boogalo 5 | line6 | {1:~ }|*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -172,11 +167,11 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| boogalo 5 | ^line6 | {1:~ }|*2 - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -216,11 +211,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() api.nvim_buf_set_lines( 0, @@ -243,12 +233,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] }| + {3:[No Name] }| | ]], } @@ -258,12 +248,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -274,12 +264,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -290,12 +280,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], unchanged = true, @@ -306,12 +296,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| wwweeee | xxx | ^yyy | zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -321,12 +311,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| mmmeeeee | wwweeee | xxx | ^yyy | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -343,12 +333,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -358,12 +348,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -374,12 +364,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -389,12 +379,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], unchanged = true, @@ -416,12 +406,12 @@ describe('api/buf', function() ccc | ddd | www | - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -434,12 +424,12 @@ describe('api/buf', function() ddd | www | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -453,12 +443,12 @@ describe('api/buf', function() ddd | wwweeee | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -471,12 +461,12 @@ describe('api/buf', function() ddd | mmm | wwweeee | - {2:[No Name] [+] }| + {3:[No Name] [+] }| wwweeee | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -745,10 +735,6 @@ describe('api/buf', function() it("set_lines of invisible buffer doesn't move cursor in current window", function() local screen = Screen.new(20, 5) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { bold = true }, - }) screen:attach() insert([[ @@ -771,7 +757,7 @@ describe('api/buf', function() A real window | with proper tex^t | {1:~ }| - {2:-- INSERT --} | + {5:-- INSERT --} | ]]) end) @@ -1756,11 +1742,6 @@ describe('api/buf', function() local screen before_each(function() screen = Screen.new(20, 12) - screen:set_default_attr_ids { - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { reverse = true, bold = true }, - [3] = { reverse = true }, - } screen:attach() api.nvim_buf_set_lines( 0, @@ -1783,12 +1764,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] }| + {3:[No Name] }| | ]], } @@ -1798,12 +1779,12 @@ describe('api/buf', function() grid = [[ | {1:~ }|*4 - {3:[No Name] }| + {2:[No Name] }| www | xxx | yyy | ^zzz | - {2:[No Name] [+] }| + {3:[No Name] [+] }| | ]], } @@ -1820,12 +1801,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -1835,12 +1816,12 @@ describe('api/buf', function() grid = [[ ^ | {1:~ }|*4 - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -1861,12 +1842,12 @@ describe('api/buf', function() ccc | ddd | www | - {2:[No Name] }| + {3:[No Name] }| www | xxx | yyy | zzz | - {3:[No Name] }| + {2:[No Name] }| | ]], } @@ -1879,12 +1860,12 @@ describe('api/buf', function() ddd | www | xxx | - {2:[No Name] [+] }| + {3:[No Name] [+] }| www | xxx | yyy | zzz | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index fd0535aa51..b32f2b1cb2 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -367,14 +367,11 @@ describe('API', function() it('displays messages when opts.output=false', function() local screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_exec2("echo 'hello'", { output = false }) screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 hello | ]], } @@ -383,14 +380,11 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_exec2("echo 'hello'", { output = true }) screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 | ]], } @@ -403,7 +397,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } @@ -1533,16 +1527,12 @@ describe('API', function() eq({ 1, 5 }, api.nvim_win_get_cursor(0)) local screen = Screen.new(60, 3) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Yellow }, - }) screen:attach() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -1551,7 +1541,7 @@ describe('API', function() screen:expect { grid = [[ foo ^foo foo | - {0:~ }| + {1:~ }| | ]], } @@ -1559,8 +1549,8 @@ describe('API', function() eq(1, eval('v:hlsearch')) screen:expect { grid = [[ - {1:foo} {1:^foo} {1:foo} | - {0:~ }| + {10:foo} {10:^foo} {10:foo} | + {1:~ }| | ]], } @@ -2254,12 +2244,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, foreground = Screen.colors.SeaGreen }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Blue }, - }) end) it('prints long messages correctly #20534', function() @@ -2287,11 +2271,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| + {1:~ }|*3 + {3: }| | a | - {1:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } feed('') @@ -2299,12 +2283,12 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*2 - {2: }| + {1:~ }|*2 + {3: }| b | | c | - {1:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2314,11 +2298,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| - aaa{3:^@}bbb{3:^@^@}ccc | - ddd{3:^@^@^@}eee | - {1:Press ENTER or type command to continue}^ | + {1:~ }|*3 + {3: }| + aaa{18:^@}bbb{18:^@^@}ccc | + ddd{18:^@^@^@}eee | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2330,20 +2314,14 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, - [3] = { bold = true, reverse = true }, - }) end) it('can show one line', function() async_meths.nvim_err_write('has bork\n') screen:expect([[ ^ | - {0:~ }|*6 - {1:has bork} | + {1:~ }|*6 + {9:has bork} | ]]) end) @@ -2351,11 +2329,11 @@ describe('API', function() async_meths.nvim_err_write('something happened\nvery bad\n') screen:expect([[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:something happened} | - {1:very bad} | - {2:Press ENTER or type command to continue}^ | + {9:something happened} | + {9:very bad} | + {6:Press ENTER or type command to continue}^ | ]]) end) @@ -2363,13 +2341,13 @@ describe('API', function() async_meths.nvim_err_write('FAILURE\nERROR\nEXCEPTION\nTRACEBACK\n') screen:expect([[ | - {0:~ }| + {1:~ }| {3: }| - {1:FAILURE} | - {1:ERROR} | - {1:EXCEPTION} | - {1:TRACEBACK} | - {2:Press ENTER or type command to continue}^ | + {9:FAILURE} | + {9:ERROR} | + {9:EXCEPTION} | + {9:TRACEBACK} | + {6:Press ENTER or type command to continue}^ | ]]) end) @@ -2379,8 +2357,8 @@ describe('API', function() async_meths.nvim_err_write('fail\n') screen:expect([[ ^ | - {0:~ }|*6 - {1:very fail} | + {1:~ }|*6 + {9:very fail} | ]]) n.poke_eventloop() @@ -2388,11 +2366,11 @@ describe('API', function() async_meths.nvim_err_write('more fail\ntoo fail\n') screen:expect([[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:more fail} | - {1:too fail} | - {2:Press ENTER or type command to continue}^ | + {9:more fail} | + {9:too fail} | + {6:Press ENTER or type command to continue}^ | ]]) feed('') -- exit the press ENTER screen end) @@ -2402,11 +2380,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 + {1:~ }|*3 {3: }| - {1:aaa^@bbb^@^@ccc} | - {1:ddd^@^@^@eee} | - {2:Press ENTER or type command to continue}^ | + {9:aaa^@bbb^@^@ccc} | + {9:ddd^@^@^@eee} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -2418,30 +2396,24 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, - [3] = { bold = true, reverse = true }, - }) end) it('shows only one return prompt after all lines are shown', function() async_meths.nvim_err_writeln('FAILURE\nERROR\nEXCEPTION\nTRACEBACK') screen:expect([[ | - {0:~ }| + {1:~ }| {3: }| - {1:FAILURE} | - {1:ERROR} | - {1:EXCEPTION} | - {1:TRACEBACK} | - {2:Press ENTER or type command to continue}^ | + {9:FAILURE} | + {9:ERROR} | + {9:EXCEPTION} | + {9:TRACEBACK} | + {6:Press ENTER or type command to continue}^ | ]]) feed('') screen:expect([[ ^ | - {0:~ }|*6 + {1:~ }|*6 | ]]) end) @@ -3102,9 +3074,6 @@ describe('API', function() eq(1, api.nvim_get_current_buf()) local screen = Screen.new(20, 4) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - }) screen:attach() -- @@ -3458,13 +3427,6 @@ describe('API', function() before_each(function() screen = Screen.new(40, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, foreground = Screen.colors.SeaGreen }, - [2] = { bold = true, reverse = true }, - [3] = { foreground = Screen.colors.Brown, bold = true }, -- Statement - [4] = { foreground = Screen.colors.SlateBlue }, -- Special - }) command('highlight Statement gui=bold guifg=Brown') command('highlight Special guifg=SlateBlue') end) @@ -3474,7 +3436,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 + {1:~ }|*6 msg | ]], } @@ -3489,8 +3451,8 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*6 - msg_a{3:msg_b}{4:msg_c} | + {1:~ }|*6 + msg_a{15:msg_b}{16:msg_c} | ]], } end) @@ -3500,11 +3462,11 @@ describe('API', function() screen:expect { grid = [[ | - {0:~ }|*3 - {2: }| - {3:msg_a} | - {3:msg_a}{4:msg_b} | - {1:Press ENTER or type command to continue}^ | + {1:~ }|*3 + {3: }| + {15:msg_a} | + {15:msg_a}{16:msg_b} | + {6:Press ENTER or type command to continue}^ | ]], } end) @@ -3528,24 +3490,16 @@ describe('API', function() before_each(function() screen = Screen.new(100, 35) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.Plum1 }, - [2] = { background = tonumber('0xffff40'), bg_indexed = true }, - [3] = { - background = Screen.colors.Plum1, - fg_indexed = true, - foreground = tonumber('0x00e000'), - }, - [4] = { bold = true, reverse = true, background = Screen.colors.Plum1 }, - [5] = { - foreground = Screen.colors.Blue, + screen:add_extra_attr_ids { + [100] = { background = tonumber('0xffff40'), bg_indexed = true }, + [101] = { background = Screen.colors.LightMagenta, - bold = true, + foreground = tonumber('0x00e000'), + fg_indexed = true, }, - [6] = { bold = true }, - [7] = { reverse = true, background = Screen.colors.LightMagenta }, - }) + [102] = { background = Screen.colors.LightMagenta, reverse = true }, + [103] = { background = Screen.colors.LightMagenta, bold = true, reverse = true }, + } end) it('can batch process sequences', function() @@ -3561,38 +3515,38 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~}{1::smile }{0: }| - {0:~}{1: }{2:oooo$$$$$$$$$$$$oooo}{1: }{0: }| - {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{0: }| - {0:~}{1: }{2:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:o$}{1: }{2:$$}{1: }{2:o$}{1: }{0: }| - {0:~}{1: }{2:o}{1: }{2:$}{1: }{2:oo}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{1: }{2:$$}{1: }{2:$$}{1: }{2:$$o$}{1: }{0: }| - {0:~}{1: }{2:oo}{1: }{2:$}{1: }{2:$}{1: "}{2:$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$o}{1: }{2:$$$o$$o$}{1: }{0: }| - {0:~}{1: "}{2:$$$$$$o$}{1: }{2:o$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$o}{1: }{2:$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$}{1: }{2:$$$$$$$$$$$$$$}{1: """}{2:$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$}{1:""""}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$}{1: }{0: }| - {0:~}{1: }{2:$$$}{1: }{2:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: "}{2:$$$o}{1: }{0: }| - {0:~}{1: }{2:o$$}{1:" }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$o}{1: }{0: }| - {0:~}{1: }{2:$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" "}{2:$$$$$$ooooo$$$$o}{1: }{0: }| - {0:~}{1: }{2:o$$$oooo$$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:o$$$$$$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$}{1:"}{2:$$$$}{1: }{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1: }{2:$$$$}{1:"""""""" }{0: }| - {0:~}{1: """" }{2:$$$$}{1: "}{2:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{1:" }{2:o$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$o}{1: """}{2:$$$$$$$$$$$$$$$$$$}{1:"}{2:$$}{1:" }{2:$$$}{1: }{0: }| - {0:~}{1: }{2:$$$o}{1: "}{2:$$}{1:""}{2:$$$$$$}{1:"""" }{2:o$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$o}{1: }{2:o$$$}{1:" }{0: }| - {0:~}{1: "}{2:$$$$o}{1: }{2:o$$$$$$o}{1:"}{2:$$$$o}{1: }{2:o$$$$}{1: }{0: }| - {0:~}{1: "}{2:$$$$$oo}{1: ""}{2:$$$$o$$$$$o}{1: }{2:o$$$$}{1:"" }{0: }| - {0:~}{1: ""}{2:$$$$$oooo}{1: "}{2:$$$o$$$$$$$$$}{1:""" }{0: }| - {0:~}{1: ""}{2:$$$$$$$oo}{1: }{2:$$$$$$$$$$}{1: }{0: }| - {0:~}{1: """"}{2:$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$$$}{1: }{0: }| - {0:~}{1: }{2:$$$$$$$$$$}{1:" }{0: }| - {0:~}{1: "}{2:$$$}{1:"""" }{0: }| - {0:~}{1: }{0: }| - {0:~}{3:Press ENTER or type command to continue}{1: }{0: }| - {0:~}{4:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{0: }| - {0:~}{1::call nvim__screenshot("smile2.cat") }{0: }| - {0:~ }|*2 + {1:~}{4::smile }{1: }| + {1:~}{4: }{100:oooo$$$$$$$$$$$$oooo}{4: }{1: }| + {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{1: }| + {1:~}{4: }{100:oo$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:o$}{4: }{100:$$}{4: }{100:o$}{4: }{1: }| + {1:~}{4: }{100:o}{4: }{100:$}{4: }{100:oo}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$o}{4: }{100:$$}{4: }{100:$$}{4: }{100:$$o$}{4: }{1: }| + {1:~}{4: }{100:oo}{4: }{100:$}{4: }{100:$}{4: "}{100:$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$o}{4: }{100:$$$o$$o$}{4: }{1: }| + {1:~}{4: "}{100:$$$$$$o$}{4: }{100:o$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$o}{4: }{100:$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$}{4: }{100:$$$$$$$$$$$$$$}{4: """}{100:$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$}{4:""""}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$}{4: }{1: }| + {1:~}{4: }{100:$$$}{4: }{100:o$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: "}{100:$$$o}{4: }{1: }| + {1:~}{4: }{100:o$$}{4:" }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$o}{4: }{1: }| + {1:~}{4: }{100:$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" "}{100:$$$$$$ooooo$$$$o}{4: }{1: }| + {1:~}{4: }{100:o$$$oooo$$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:o$$$$$$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$}{4:"}{100:$$$$}{4: }{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4: }{100:$$$$}{4:"""""""" }{1: }| + {1:~}{4: """" }{100:$$$$}{4: "}{100:$$$$$$$$$$$$$$$$$$$$$$$$$$$$}{4:" }{100:o$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$o}{4: """}{100:$$$$$$$$$$$$$$$$$$}{4:"}{100:$$}{4:" }{100:$$$}{4: }{1: }| + {1:~}{4: }{100:$$$o}{4: "}{100:$$}{4:""}{100:$$$$$$}{4:"""" }{100:o$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$o}{4: }{100:o$$$}{4:" }{1: }| + {1:~}{4: "}{100:$$$$o}{4: }{100:o$$$$$$o}{4:"}{100:$$$$o}{4: }{100:o$$$$}{4: }{1: }| + {1:~}{4: "}{100:$$$$$oo}{4: ""}{100:$$$$o$$$$$o}{4: }{100:o$$$$}{4:"" }{1: }| + {1:~}{4: ""}{100:$$$$$oooo}{4: "}{100:$$$o$$$$$$$$$}{4:""" }{1: }| + {1:~}{4: ""}{100:$$$$$$$oo}{4: }{100:$$$$$$$$$$}{4: }{1: }| + {1:~}{4: """"}{100:$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$$$}{4: }{1: }| + {1:~}{4: }{100:$$$$$$$$$$}{4:" }{1: }| + {1:~}{4: "}{100:$$$}{4:"""" }{1: }| + {1:~}{4: }{1: }| + {1:~}{101:Press ENTER or type command to continue}{4: }{1: }| + {1:~}{103:term://~/config2/docs/pres//32693:vim --clean +smile 29,39 All}{1: }| + {1:~}{4::call nvim__screenshot("smile2.cat") }{1: }| + {1:~ }|*2 | ]], } @@ -3624,9 +3578,9 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{1:^ }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 + {1:~}{4:^ }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 | ]], } @@ -3635,10 +3589,10 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{7: }{1: }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 - {6:-- TERMINAL --} | + {1:~}{102: }{4: }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 + {5:-- TERMINAL --} | ]], } @@ -3651,10 +3605,10 @@ describe('API', function() screen:expect { grid = [[ | - {0:~}{1:herrejösses!}{7: }{1: }{0: }| - {0:~}{1: }{0: }|*4 - {0:~ }|*3 - {6:-- TERMINAL --} | + {1:~}{4:herrejösses!}{102: }{4: }{1: }| + {1:~}{4: }{1: }|*4 + {1:~ }|*3 + {5:-- TERMINAL --} | ]], } eq('ba\024blaherrejösses!', exec_lua [[ return stream ]]) @@ -4472,10 +4426,6 @@ describe('API', function() end) it('does not interfere with printing line in Ex mode #19400', function() local screen = Screen.new(60, 7) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - }) screen:attach() insert([[ foo @@ -4484,8 +4434,8 @@ describe('API', function() screen:expect([[ foo | bar | - {0:~ }|*2 - {1: }| + {1:~ }|*2 + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1^ | ]]) @@ -4494,7 +4444,7 @@ describe('API', function() screen:expect([[ foo | bar | - {1: }| + {3: }| Entering Ex mode. Type "visual" to go to Normal mode. | :1 | foo | @@ -4934,14 +4884,11 @@ describe('API', function() it("doesn't display messages when output=true", function() local screen = Screen.new(40, 6) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - }) api.nvim_cmd({ cmd = 'echo', args = { [['hello']] } }, { output = true }) screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 | ]], } @@ -4954,7 +4901,7 @@ describe('API', function() screen:expect { grid = [[ ^ | - {0:~ }|*4 + {1:~ }|*4 15 | ]], } diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 15b9b0945c..77611cc750 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -170,11 +170,6 @@ describe('API/win', function() it('updates the screen, and also when the window is unfocused', function() local screen = Screen.new(30, 9) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, - [2] = { bold = true, reverse = true }, - [3] = { reverse = true }, - }) screen:attach() insert('prologue') @@ -221,10 +216,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| prologue | |*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -235,10 +230,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| |*2 epilogue | - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -249,10 +244,10 @@ describe('API/win', function() grid = [[ ^ | {1:~ }|*2 - {2:[No Name] }| + {3:[No Name] }| prologue | |*2 - {3:[No Name] [+] }| + {2:[No Name] [+] }| | ]], } @@ -286,12 +281,6 @@ describe('API/win', function() it('updates cursorline and statusline ruler in non-current window', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [2] = { background = Screen.colors.Grey90 }, -- CursorLine - [3] = { bold = true, reverse = true }, -- StatusLine - [4] = { reverse = true }, -- StatusLineNC - }) screen:attach() command('set ruler') command('set cursorline') @@ -306,31 +295,25 @@ describe('API/win', function() aaa │aaa | bbb │bbb | ccc │ccc | - {2:dd^d }│{2:ddd }| + {21:dd^d }│{21:ddd }| {1:~ }│{1:~ }|*2 - {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 4,3 All}| + {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 4,3 All}| | ]]) api.nvim_win_set_cursor(oldwin, { 1, 0 }) screen:expect([[ - aaa │{2:aaa }| + aaa │{21:aaa }| bbb │bbb | ccc │ccc | - {2:dd^d }│ddd | + {21:dd^d }│ddd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] 4,3 All }{4:[No Name] [+] 1,1 All}| + {3:[No Name] [+] 4,3 All }{2:[No Name] [+] 1,1 All}| | ]]) end) it('updates cursorcolumn in non-current window', function() local screen = Screen.new(60, 8) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [2] = { background = Screen.colors.Grey90 }, -- CursorColumn - [3] = { bold = true, reverse = true }, -- StatusLine - [4] = { reverse = true }, -- StatusLineNC - }) screen:attach() command('set cursorcolumn') insert([[ @@ -341,22 +324,22 @@ describe('API/win', function() local oldwin = curwin() command('vsplit') screen:expect([[ - aa{2:a} │aa{2:a} | - bb{2:b} │bb{2:b} | - cc{2:c} │cc{2:c} | + aa{21:a} │aa{21:a} | + bb{21:b} │bb{21:b} | + cc{21:c} │cc{21:c} | dd^d │ddd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] }{4:[No Name] [+] }| + {3:[No Name] [+] }{2:[No Name] [+] }| | ]]) api.nvim_win_set_cursor(oldwin, { 2, 0 }) screen:expect([[ - aa{2:a} │{2:a}aa | - bb{2:b} │bbb | - cc{2:c} │{2:c}cc | - dd^d │{2:d}dd | + aa{21:a} │{21:a}aa | + bb{21:b} │bbb | + cc{21:c} │{21:c}cc | + dd^d │{21:d}dd | {1:~ }│{1:~ }|*2 - {3:[No Name] [+] }{4:[No Name] [+] }| + {3:[No Name] [+] }{2:[No Name] [+] }| | ]]) end) @@ -874,22 +857,6 @@ describe('API/win', function() it('with two diff windows', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue1, bold = true }, - [1] = { foreground = Screen.colors.Blue4, background = Screen.colors.Grey }, - [2] = { foreground = Screen.colors.Brown }, - [3] = { - foreground = Screen.colors.Blue1, - background = Screen.colors.LightCyan1, - bold = true, - }, - [4] = { background = Screen.colors.LightBlue }, - [5] = { foreground = Screen.colors.Blue4, background = Screen.colors.LightGrey }, - [6] = { background = Screen.colors.Plum1 }, - [7] = { background = Screen.colors.Red, bold = true }, - [8] = { reverse = true }, - [9] = { bold = true, reverse = true }, - }) screen:attach() exec([[ set diffopt+=context:2 number @@ -902,35 +869,35 @@ describe('API/win', function() feed('24gg') screen:expect { grid = [[ - {1: }{2: }{3:----------------}│{1: }{2: 1 }{4:00000001! }| - {1: }{2: }{3:----------------}│{1: }{2: 2 }{4:00000002!! }| - {1: }{2: 1 }00000003!!! │{1: }{2: 3 }00000003!!! | - {1: }{2: 2 }00000004!!!! │{1: }{2: 4 }00000004!!!! | - {1:+ }{2: 3 }{5:+-- 14 lines: 00}│{1:+ }{2: 5 }{5:+-- 14 lines: 00}| - {1: }{2: 17 }00000019!!!!!!!!│{1: }{2: 19 }00000019!!!!!!!!| - {1: }{2: 18 }00000020!!!!!!!!│{1: }{2: 20 }00000020!!!!!!!!| - {1: }{2: }{3:----------------}│{1: }{2: 21 }{4:00000025!!!!!!!!}| - {1: }{2: }{3:----------------}│{1: }{2: 22 }{4:00000026!!!!!!!!}| - {1: }{2: }{3:----------------}│{1: }{2: 23 }{4:00000027!!!!!!!!}| - {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!| - {1: }{2: 20 }00000029!!!!!!!!│{1: }{2: 25 }00000029!!!!!!!!| - {1:+ }{2: 21 }{5:+-- 14 lines: 00}│{1:+ }{2: 26 }{5:+-- 14 lines: 00}| - {1: }{2: 35 }00000044!!!!!!!!│{1: }{2: 40 }00000044!!!!!!!!| - {1: }{2: 36 }00000045!!!!!!!!│{1: }{2: 41 }00000045!!!!!!!!| - {1: }{2: 37 }{4:00000046!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 38 }{4:00000047!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 39 }{4:00000048!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 40 }{4:00000049!!!!!!!!}│{1: }{2: }{3:----------------}| - {1: }{2: 41 }{4:00000050!!!!!!!!}│{1: }{2: }{3:----------------}| - {8:[No Name] [+] }{9:[No Name] [+] }| + {7: }{8: }{23:----------------}│{7: }{8: 1 }{22:00000001! }| + {7: }{8: }{23:----------------}│{7: }{8: 2 }{22:00000002!! }| + {7: }{8: 1 }00000003!!! │{7: }{8: 3 }00000003!!! | + {7: }{8: 2 }00000004!!!! │{7: }{8: 4 }00000004!!!! | + {7:+ }{8: 3 }{13:+-- 14 lines: 00}│{7:+ }{8: 5 }{13:+-- 14 lines: 00}| + {7: }{8: 17 }00000019!!!!!!!!│{7: }{8: 19 }00000019!!!!!!!!| + {7: }{8: 18 }00000020!!!!!!!!│{7: }{8: 20 }00000020!!!!!!!!| + {7: }{8: }{23:----------------}│{7: }{8: 21 }{22:00000025!!!!!!!!}| + {7: }{8: }{23:----------------}│{7: }{8: 22 }{22:00000026!!!!!!!!}| + {7: }{8: }{23:----------------}│{7: }{8: 23 }{22:00000027!!!!!!!!}| + {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| + {7: }{8: 20 }00000029!!!!!!!!│{7: }{8: 25 }00000029!!!!!!!!| + {7:+ }{8: 21 }{13:+-- 14 lines: 00}│{7:+ }{8: 26 }{13:+-- 14 lines: 00}| + {7: }{8: 35 }00000044!!!!!!!!│{7: }{8: 40 }00000044!!!!!!!!| + {7: }{8: 36 }00000045!!!!!!!!│{7: }{8: 41 }00000045!!!!!!!!| + {7: }{8: 37 }{22:00000046!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 38 }{22:00000047!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 39 }{22:00000048!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 40 }{22:00000049!!!!!!!!}│{7: }{8: }{23:----------------}| + {7: }{8: 41 }{22:00000050!!!!!!!!}│{7: }{8: }{23:----------------}| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } screen:try_resize(45, 3) screen:expect { grid = [[ - {1: }{2: 19 }00000028!!!!!!!!│{1: }{2: 24 }^00000028!!!!!!!!| - {8:[No Name] [+] }{9:[No Name] [+] }| + {7: }{8: 19 }00000028!!!!!!!!│{7: }{8: 24 }^00000028!!!!!!!!| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } @@ -1008,11 +975,6 @@ describe('API/win', function() it('with wrapped lines', function() local X = api.nvim_get_vvar('maxcol') local screen = Screen.new(45, 22) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue1, bold = true }, - [1] = { foreground = Screen.colors.Brown }, - [2] = { background = Screen.colors.Yellow }, - }) screen:attach() exec([[ set number cpoptions+=n @@ -1035,26 +997,26 @@ describe('API/win', function() ) screen:expect { grid = [[ - {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| + {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar-foobar-foobar-foobar-foobar-f| oobar-foobar-foobar-foobar-foobar-foobar-foob| ar-foobar-foobar-foobar-foobar- | - {1: 2 }foobar-foobar-foobar-foobar-foobar-foobar| + {8: 2 }foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| - obar-foobar-fo{2:???????????????}obar-foobar-foob| + obar-foobar-fo{10:???????????????}obar-foobar-foob| ar-foobar-foobar-foobar-foobar-foobar-foobar-| foobar-foobar-foobar-foobar-foobar-foobar-foo| bar-foobar-foobar-foobar-foobar-foobar-foobar| - | - {1: 3 }foobar-foobar-foobar-foobar-foobar-foobar| + {8: 3 }foobar-foobar-foobar-foobar-foobar-foobar| -foobar-foobar-foobar-foobar-foobar-foobar-fo| obar-foobar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar-foobar-foobar-foobar-foobar-f| - oobar-foobar-foobar-foob{2:!!!!!!!!!!!!!!!!!!!!!}| - {2:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}| - {2:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| + oobar-foobar-foobar-foob{10:!!!!!!!!!!!!!!!!!!!!!}| + {10:!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}| + {10:!!!!!!!!!}ar-foobar-foobar-foobar-foobar-fooba| r-foobar-foobar- | | ]], @@ -1062,7 +1024,7 @@ describe('API/win', function() screen:try_resize(45, 2) screen:expect { grid = [[ - {1: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| + {8: 1 }^foobar-foobar-foobar-foobar-foobar-foobar| | ]], } @@ -2563,10 +2525,6 @@ describe('API/win', function() it('updates statusline when moving bottom split', function() local screen = Screen.new(10, 10) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - }) screen:attach() exec([[ set laststatus=0 @@ -2575,10 +2533,10 @@ describe('API/win', function() ]]) screen:expect([[ ^ | - {0:~ }|*3 - {1:[No Name] }| + {1:~ }|*3 + {3:[No Name] }| | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) -- cgit From b90d7c36cf8a93e02d834eb53f5d0c8f19a9d7fa Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 26 May 2024 09:34:29 +0200 Subject: refactor(tests): more global highlight definitions --- test/functional/core/fileio_spec.lua | 11 +- test/functional/core/job_spec.lua | 13 +- test/functional/editor/completion_spec.lua | 593 +++++++++++++-------------- test/functional/editor/mode_cmdline_spec.lua | 12 +- test/functional/editor/mode_insert_spec.lua | 20 +- test/functional/editor/tabpage_spec.lua | 23 +- 6 files changed, 319 insertions(+), 353 deletions(-) diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua index 5b0be1e83c..1c4f42eb43 100644 --- a/test/functional/core/fileio_spec.lua +++ b/test/functional/core/fileio_spec.lua @@ -276,11 +276,6 @@ describe('fileio', function() write_file('Xtest-overwrite-forced', 'foobar') command('set nofixendofline') local screen = Screen.new(40, 4) - screen:set_default_attr_ids({ - [1] = { bold = true, foreground = Screen.colors.Blue1 }, - [2] = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - [3] = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) screen:attach() command('set shortmess-=F') @@ -300,9 +295,9 @@ describe('fileio', function() -- use async feed_command because nvim basically hangs on the prompt feed_command('w') screen:expect([[ - {2:WARNING: The file has been changed since}| - {2: reading it!!!} | - {3:Do you really want to write to it (y/n)?}| + {9:WARNING: The file has been changed since}| + {9: reading it!!!} | + {6:Do you really want to write to it (y/n)?}| ^ | ]]) diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index e1efc07452..bf10033f53 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -910,11 +910,6 @@ describe('jobs', function() it('hides cursor and flushes messages before blocking', function() local screen = Screen.new(50, 6) - screen:set_default_attr_ids({ - [0] = { foreground = Screen.colors.Blue, bold = true }, -- NonText - [1] = { bold = true, reverse = true }, -- MsgSeparator - [2] = { bold = true, foreground = Screen.colors.SeaGreen }, -- MoreMsg - }) screen:attach() command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]]) source([[ @@ -928,8 +923,8 @@ describe('jobs', function() screen:expect { grid = [[ | - {0:~ }|*2 - {1: }| + {1:~ }|*2 + {3: }| aaa | bbb | ]], @@ -938,11 +933,11 @@ describe('jobs', function() screen:expect { grid = [[ | - {1: }| + {3: }| aaa | bbb | ccc | - {2:Press ENTER or type command to continue}^ | + {6:Press ENTER or type command to continue}^ | ]], } feed('') diff --git a/test/functional/editor/completion_spec.lua b/test/functional/editor/completion_spec.lua index 62bb7e19f3..a28e449f49 100644 --- a/test/functional/editor/completion_spec.lua +++ b/test/functional/editor/completion_spec.lua @@ -18,19 +18,10 @@ describe('completion', function() clear() screen = Screen.new(60, 8) screen:attach() - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { background = Screen.colors.LightMagenta }, - [2] = { background = Screen.colors.Grey }, - [3] = { bold = true }, - [4] = { bold = true, foreground = Screen.colors.SeaGreen }, - [5] = { foreground = Screen.colors.Red }, - [6] = { background = Screen.colors.Black }, - [7] = { foreground = Screen.colors.White, background = Screen.colors.Red }, - [8] = { reverse = true }, - [9] = { bold = true, reverse = true }, - [10] = { foreground = Screen.colors.Grey0, background = Screen.colors.Yellow }, - }) + screen:add_extra_attr_ids { + [100] = { foreground = Screen.colors.Gray0, background = Screen.colors.Yellow }, + [101] = { background = Screen.colors.Gray0 }, + } end) describe('v:completed_item', function() @@ -42,15 +33,15 @@ describe('completion', function() screen:expect([[ foo | foo^ | - {0:~ }|*5 - {3:-- Keyword Local completion (^N^P) The only match} | + {1:~ }|*5 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('') screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('') eq({}, eval('v:completed_item')) @@ -104,10 +95,10 @@ describe('completion', function() eq('foo', eval('getline(1)')) screen:expect([[ foo^ | - {2:bar foobaz baz }{0: }| - {1:abbr kind menu }{0: }| - {0:~ }|*4 - {3:-- Omni completion (^O^N^P) }{4:match 1 of 2} | + {12:bar foobaz baz }{1: }| + {4:abbr kind menu }{1: }| + {1:~ }|*4 + {5:-- Omni completion (^O^N^P) }{6:match 1 of 2} | ]]) eq({ word = 'foo', @@ -136,24 +127,24 @@ describe('completion', function() screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('') -- the ^X prompt, only test this once screen:expect([[ foo | ^ | - {0:~ }|*5 - {3:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | + {1:~ }|*5 + {5:-- ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)} | ]]) feed('') screen:expect([[ foo | foo^ | - {2:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) The only match} | + {12:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('bar') eq('foobar', eval('getline(2)')) @@ -162,9 +153,9 @@ describe('completion', function() foo | foobar | foo^ | - {2:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {12:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) eq('foo', eval('getline(3)')) end) @@ -174,16 +165,16 @@ describe('completion', function() screen:expect([[ foo | ^ | - {2:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) The only match} | + {12:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) The only match} | ]]) feed('') screen:expect([[ foo | foo^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) feed('') eq('foo', eval('getline(2)')) @@ -191,9 +182,9 @@ describe('completion', function() screen:expect([[ foo |*2 ^ | - {2:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {12:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('') eq('foo', eval('getline(3)')) @@ -204,16 +195,16 @@ describe('completion', function() screen:expect([[ foo | ^ | - {1:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('b') screen:expect([[ foo | b^ | - {0:~ }|*5 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {1:~ }|*5 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('ar') eq('bar', eval('getline(2)')) @@ -222,9 +213,9 @@ describe('completion', function() foo | bar | ^ | - {1:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {4:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('bar') eq('bar', eval('getline(3)')) @@ -235,15 +226,15 @@ describe('completion', function() screen:expect([[ foo | ^ | - {1:foo }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ foo | ^ | - {0:~ }|*5 + {1:~ }|*5 | ]]) eq('', eval('getline(2)')) @@ -252,16 +243,16 @@ describe('completion', function() foo | | ^ | - {1:foo }{0: }| - {0:~ }|*3 - {3:-- INSERT --} | + {4:foo }{1: }| + {1:~ }|*3 + {5:-- INSERT --} | ]]) feed('') screen:expect([[ foo | | ^ | - {0:~ }|*4 + {1:~ }|*4 | ]]) eq('', eval('getline(3)')) @@ -367,44 +358,44 @@ describe('completion', function() feed('i') screen:expect([[ ^ | - {1:January }{6: }{0: }| - {1:February }{6: }{0: }| - {1:March }{6: }{0: }| - {1:April }{2: }{0: }| - {1:May }{2: }{0: }| - {1:June }{2: }{0: }| - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{101: }{1: }| + {4:February }{101: }{1: }| + {4:March }{101: }{1: }| + {4:April }{12: }{1: }| + {4:May }{12: }{1: }| + {4:June }{12: }{1: }| + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('u') screen:expect([[ u^ | - {1:January }{0: }| - {1:February }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {1:August }{0: }| - {0:~ }| - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {4:February }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {4:August }{1: }| + {1:~ }| + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('g') screen:expect([[ ug^ | - {1:August }{0: }| - {0:~ }|*5 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:August }{1: }| + {1:~ }|*5 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ ug^ | - {2:August }{0: }| - {0:~ }|*5 - {3:-- User defined completion (^U^N^P) The only match} | + {12:August }{1: }| + {1:~ }|*5 + {5:-- User defined completion (^U^N^P) The only match} | ]]) feed('') screen:expect([[ August^ | - {0:~ }|*6 - {3:-- INSERT --} | + {1:~ }|*6 + {5:-- INSERT --} | ]]) expect('August') end) @@ -414,45 +405,45 @@ describe('completion', function() screen:expect([[ | Ja^ | - {1:January }{0: }| - {0:~ }|*4 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {1:~ }|*4 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ | J^ | - {1:January }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{5:Back at original} | + {4:January }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{19:Back at original} | ]]) feed('') screen:expect([[ | January^ | - {2:January }{0: }| - {1:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{4:match 1 of 3} | + {12:January }{1: }| + {4:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{6:match 1 of 3} | ]]) feed('') screen:expect([[ | June^ | - {1:January }{0: }| - {2:June }{0: }| - {1:July }{0: }| - {0:~ }|*2 - {3:-- User defined completion (^U^N^P) }{4:match 2 of 3} | + {4:January }{1: }| + {12:June }{1: }| + {4:July }{1: }| + {1:~ }|*2 + {5:-- User defined completion (^U^N^P) }{6:match 2 of 3} | ]]) feed('') screen:expect([[ | Jun^e | - {0:~ }|*5 + {1:~ }|*5 | ]]) feed('.') @@ -460,7 +451,7 @@ describe('completion', function() | June | Jun^e | - {0:~ }|*4 + {1:~ }|*4 | ]]) expect([[ @@ -485,46 +476,46 @@ describe('completion', function() feed('i=TestComplete()') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('7') screen:expect([[ 7^ | - {1:7 }{6: }{0: }| - {1:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {4:7 }{101: }{1: }| + {4:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ 7^ | - {2:7 }{6: }{0: }| - {1:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {12:7 }{101: }{1: }| + {4:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ 70^ | - {1:7 }{6: }{0: }| - {2:70 }{6: }{0: }| - {1:71 }{6: }{0: }| - {1:72 }{2: }{0: }| - {1:73 }{2: }{0: }| - {1:74 }{2: }{0: }| - {3:-- INSERT --} | + {4:7 }{101: }{1: }| + {12:70 }{101: }{1: }| + {4:71 }{101: }{1: }| + {4:72 }{12: }{1: }| + {4:73 }{12: }{1: }| + {4:74 }{12: }{1: }| + {5:-- INSERT --} | ]]) end) @@ -532,107 +523,107 @@ describe('completion', function() feed('i=TestComplete()') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {2:3 }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {12:3 }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:5 }{6: }{0: }| - {1:6 }{2: }{0: }| - {2:7 }{0: }| - {1:8 }{2: }{0: }| - {1:9 }{2: }{0: }| - {1:10 }{2: }{0: }| - {3:-- INSERT --} | + {4:5 }{101: }{1: }| + {4:6 }{12: }{1: }| + {12:7 }{1: }| + {4:8 }{12: }{1: }| + {4:9 }{12: }{1: }| + {4:10 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:5 }{6: }{0: }| - {1:6 }{2: }{0: }| - {1:7 }{2: }{0: }| - {2:8 }{0: }| - {1:9 }{2: }{0: }| - {1:10 }{2: }{0: }| - {3:-- INSERT --} | + {4:5 }{101: }{1: }| + {4:6 }{12: }{1: }| + {4:7 }{12: }{1: }| + {12:8 }{1: }| + {4:9 }{12: }{1: }| + {4:10 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:2 }{6: }{0: }| - {1:3 }{2: }{0: }| - {2:4 }{0: }| - {1:5 }{2: }{0: }| - {1:6 }{2: }{0: }| - {1:7 }{2: }{0: }| - {3:-- INSERT --} | + {4:2 }{101: }{1: }| + {4:3 }{12: }{1: }| + {12:4 }{1: }| + {4:5 }{12: }{1: }| + {4:6 }{12: }{1: }| + {4:7 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') -- stop on first item screen:expect([[ ^ | - {2:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {12:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') -- when on first item, unselect screen:expect([[ ^ | - {1:0 }{6: }{0: }| - {1:1 }{2: }{0: }| - {1:2 }{2: }{0: }| - {1:3 }{2: }{0: }| - {1:4 }{2: }{0: }| - {1:5 }{2: }{0: }| - {3:-- INSERT --} | + {4:0 }{101: }{1: }| + {4:1 }{12: }{1: }| + {4:2 }{12: }{1: }| + {4:3 }{12: }{1: }| + {4:4 }{12: }{1: }| + {4:5 }{12: }{1: }| + {5:-- INSERT --} | ]]) feed('') -- when unselected, select last item screen:expect([[ ^ | - {1:95 }{2: }{0: }| - {1:96 }{2: }{0: }| - {1:97 }{2: }{0: }| - {1:98 }{2: }{0: }| - {1:99 }{2: }{0: }| - {2:100 }{6: }{0: }| - {3:-- INSERT --} | + {4:95 }{12: }{1: }| + {4:96 }{12: }{1: }| + {4:97 }{12: }{1: }| + {4:98 }{12: }{1: }| + {4:99 }{12: }{1: }| + {12:100 }{101: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ ^ | - {1:94 }{2: }{0: }| - {1:95 }{2: }{0: }| - {2:96 }{0: }| - {1:97 }{2: }{0: }| - {1:98 }{2: }{0: }| - {1:99 }{6: }{0: }| - {3:-- INSERT --} | + {4:94 }{12: }{1: }| + {4:95 }{12: }{1: }| + {12:96 }{1: }| + {4:97 }{12: }{1: }| + {4:98 }{12: }{1: }| + {4:99 }{101: }{1: }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ 96^ | - {0:~ }|*6 - {3:-- INSERT --} | + {1:~ }|*6 + {5:-- INSERT --} | ]]) end) end) @@ -668,9 +659,9 @@ describe('completion', function() screen:expect([[ inc uninc indent unindent | ind^ | - {2:indent }{0: }| - {0:~ }|*4 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {12:indent }{1: }| + {1:~ }|*4 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) -- Indents when the item is selected @@ -678,8 +669,8 @@ describe('completion', function() screen:expect([[ inc uninc indent unindent | indent^ | - {0:~ }|*5 - {3:-- INSERT --} | + {1:~ }|*5 + {5:-- INSERT --} | ]]) -- Indents when completion is exited using ESC. feed('ind') @@ -687,7 +678,7 @@ describe('completion', function() inc uninc indent unindent | indent | in^d | - {0:~ }|*4 + {1:~ }|*4 | ]]) -- Works for unindenting too. @@ -699,9 +690,9 @@ describe('completion', function() indent | ind | unind^ | - {0:~ }{2: unindent }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: unindent }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) -- Works when going back and forth. feed('c') @@ -710,9 +701,9 @@ describe('completion', function() indent | ind | uninc^ | - {0:~ }{2: uninc }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: uninc }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) feed('d') screen:expect([[ @@ -720,9 +711,9 @@ describe('completion', function() indent | ind | unind^ | - {0:~ }{2: unindent }{0: }| - {0:~ }|*2 - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 2} | + {1:~ }{12: unindent }{1: }| + {1:~ }|*2 + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 2} | ]]) feed('') screen:expect([[ @@ -730,7 +721,7 @@ describe('completion', function() indent | ind | uninden^t | - {0:~ }|*3 + {1:~ }|*3 | ]]) end) @@ -741,15 +732,15 @@ describe('completion', function() screen:expect([[ ^foo | bar | - {0:~ }|*5 + {1:~ }|*5 | ]]) feed('A') screen:expect([[ foo^ | bar | - {0:~ }|*5 - {3:-- Whole line completion (^L^N^P) }{7:Pattern not found} | + {1:~ }|*5 + {5:-- Whole line completion (^L^N^P) }{9:Pattern not found} | ]]) eq(-1, eval('foldclosed(1)')) end) @@ -761,10 +752,10 @@ describe('completion', function() screen:expect([[ foobar fooegg | fooegg^ | - {1:foobar }{0: }| - {2:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {4:foobar }{1: }| + {12:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) assert_alive() @@ -773,10 +764,10 @@ describe('completion', function() grid = [[ foobar fooegg | fooegg^ | - {1:foobar }{0: }| - {2:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {4:foobar }{1: }| + {12:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]], unchanged = true, } @@ -786,10 +777,10 @@ describe('completion', function() screen:expect([[ foobar fooegg | foobar^ | - {2:foobar }{0: }| - {1:fooegg }{0: }| - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {12:foobar }{1: }| + {4:fooegg }{1: }| + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) end) @@ -800,7 +791,7 @@ describe('completion', function() screen:expect { grid = [[ | - {0:~ }|*6 + {1:~ }|*6 :lua CURRENT_TESTING_VAR^ | ]], } @@ -813,8 +804,8 @@ describe('completion', function() screen:expect { grid = [[ | - {0:~ }|*5 - {10:CURRENT_TESTING_BAR}{9: CURRENT_TESTING_FOO }| + {1:~ }|*5 + {100:CURRENT_TESTING_BAR}{3: CURRENT_TESTING_FOO }| :lua CURRENT_TESTING_BAR^ | ]], unchanged = true, @@ -847,30 +838,30 @@ describe('completion', function() feed('ifoo faa fee f') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee f^ | - {0:~ }|*3 - {9:[Command Line] }| - {3:-- INSERT --} | + {2:[No Name] }| + {1::}foo faa fee f^ | + {1:~ }|*3 + {3:[Command Line] }| + {5:-- INSERT --} | ]]) feed('') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee foo^ | - {0:~ }{2: foo }{0: }| - {0:~ }{1: faa }{0: }| - {0:~ }{1: fee }{0: }| - {9:[Command Line] }| - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 3} | + {2:[No Name] }| + {1::}foo faa fee foo^ | + {1:~ }{12: foo }{1: }| + {1:~ }{4: faa }{1: }| + {1:~ }{4: fee }{1: }| + {3:[Command Line] }| + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 3} | ]]) feed('') screen:expect([[ | - {8:[No Name] }| - {0::}foo faa fee foo | - {0:~ }|*3 - {9:[Command Line] }| + {2:[No Name] }| + {1::}foo faa fee foo | + {1:~ }|*3 + {3:[Command Line] }| :foo faa fee foo^ | ]]) end) @@ -903,9 +894,9 @@ describe('completion', function() feed('i=TestComplete()') screen:expect([[ ^ | - {1:1 3 2 }{0: }| - {0:~ }|*5 - {3:-- INSERT --} | + {4:1 3 2 }{1: }| + {1:~ }|*5 + {5:-- INSERT --} | ]]) end) end) @@ -918,12 +909,12 @@ describe('completion', function() grid = [[ *backers.txt* Nvim | Xnull^ | - {2:Xnull }{6: } | - {1:Xoxomoon }{6: } | - {1:Xu }{6: } NVIM REFERENCE MANUAL | - {1:Xpayn }{2: } | - {1:Xinity }{2: } | - {3:-- Keyword Local completion (^N^P) }{4:match 1 of 7} | + {12:Xnull }{101: } | + {4:Xoxomoon }{101: } | + {4:Xu }{101: } NVIM REFERENCE MANUAL | + {4:Xpayn }{12: } | + {4:Xinity }{12: } | + {5:-- Keyword Local completion (^N^P) }{6:match 1 of 7} | ]], } end) @@ -950,8 +941,8 @@ describe('completion', function() bar | foobar | f^ | - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, @@ -970,8 +961,8 @@ describe('completion', function() bar | foobar | foob^ | - {0:~ }|*3 - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {1:~ }|*3 + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]], popupmenu = { anchor = { 1, 3, 0 }, @@ -992,10 +983,10 @@ describe('completion', function() bar | foobar | f^ | - {1:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{5:Back at original} | + {4:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{19:Back at original} | ]]) eq( { completed_item = {}, width = 15, height = 2, size = 2, col = 0, row = 4, scrollbar = false }, @@ -1007,10 +998,10 @@ describe('completion', function() bar | foobar | foo^ | - {2:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('') @@ -1019,10 +1010,10 @@ describe('completion', function() bar | foobar | foobar^ | - {1:foo }{0: }| - {2:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:foo }{1: }| + {12:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('') @@ -1031,10 +1022,10 @@ describe('completion', function() bar | foobar | foobar^ | - {2:foo }{0: }| - {1:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) eq('foo', eval('g:word')) feed('') @@ -1043,10 +1034,10 @@ describe('completion', function() bar | foobar | foobar^ | - {1:foo }{0: }| - {2:foobar }{0: }| - {0:~ }| - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:foo }{1: }| + {12:foobar }{1: }| + {1:~ }| + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) eq('foobar', eval('g:word')) feed('') @@ -1061,11 +1052,11 @@ describe('completion', function() hullo | heeee | hello^ | - {2:hello }{0: }| - {1:hullo }{0: }| - {1:heeee }{0: }| - {0:~ }|*6 - {3:-- }{4:match 1 of 3} | + {12:hello }{1: }| + {4:hullo }{1: }| + {4:heeee }{1: }| + {1:~ }|*6 + {5:-- }{6:match 1 of 3} | ]]) command([[call timer_start(100, { -> execute('stopinsert') })]]) vim.uv.sleep(200) @@ -1075,7 +1066,7 @@ describe('completion', function() hullo | heee^e | hello | - {0:~ }|*9 + {1:~ }|*9 | ]]) end) @@ -1090,9 +1081,9 @@ describe('completion', function() screen:expect([[ ii | ii^ | - {2:ii }{0: }| - {0:~ }|*4 - {3:-- Keyword completion (^N^P) The only match} | + {12:ii }{1: }| + {1:~ }|*4 + {5:-- Keyword completion (^N^P) The only match} | ]]) assert_alive() end) @@ -1129,22 +1120,22 @@ describe('completion', function() screen:expect { grid = [[ foo^ | - {2:foo }{0: }| - {1:bar }{0: }| - {1:foa }{0: }| - {1:.hidden }{0: }| - {0:~ }|*3 - {3:-- }{4:match 1 of 4} | + {12:foo }{1: }| + {4:bar }{1: }| + {4:foa }{1: }| + {4:.hidden }{1: }| + {1:~ }|*3 + {5:-- }{6:match 1 of 4} | ]], } feed('ccf') screen:expect { grid = [[ foo^ | - {2:foo }{0: }| - {1:foa }{0: }| - {0:~ }|*5 - {3:-- }{4:match 1 of 2} | + {12:foo }{1: }| + {4:foa }{1: }| + {1:~ }|*5 + {5:-- }{6:match 1 of 2} | ]], } end) @@ -1168,10 +1159,10 @@ describe('completion', function() eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) feed('0YppiaggI') screen:expect([[ - aaaa{7:^aa}aa | - {2:aaaa } | - {1:aaaaa } | - {3:-- Keyword completion (^N^P) }{4:match 1 of 2} | + aaaa{9:^aa}aa | + {12:aaaa } | + {4:aaaaa } | + {5:-- Keyword completion (^N^P) }{6:match 1 of 2} | ]]) feed('') eq(eval('mark'), eval("nvim_buf_get_extmark_by_id(0, ns_id, mark_id, { 'details':1 })")) @@ -1180,16 +1171,16 @@ describe('completion', function() feed('') screen:expect([[ aaaaa^ | - {1:aaaa } | - {2:aaaaa } | - {3:-- Keyword completion (^N^P) }{4:match 2 of 2} | + {4:aaaa } | + {12:aaaaa } | + {5:-- Keyword completion (^N^P) }{6:match 2 of 2} | ]]) feed('') screen:expect([[ - {7:aa}aa^ | + {9:aa}aa^ | aaaa | aaaaa | - {3:-- INSERT --} | + {5:-- INSERT --} | ]]) end) end) diff --git a/test/functional/editor/mode_cmdline_spec.lua b/test/functional/editor/mode_cmdline_spec.lua index 70bdc5d4c2..efd7a37c0b 100644 --- a/test/functional/editor/mode_cmdline_spec.lua +++ b/test/functional/editor/mode_cmdline_spec.lua @@ -48,18 +48,14 @@ describe('cmdline', function() it('redraws statusline when toggling overstrike', function() local screen = Screen.new(60, 4) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { reverse = true, bold = true }, -- StatusLine - }) screen:attach() command('set laststatus=2 statusline=%!mode(1)') feed(':') screen:expect { grid = [[ | - {0:~ }| - {1:c }| + {1:~ }| + {3:c }| :^ | ]], } @@ -67,8 +63,8 @@ describe('cmdline', function() screen:expect { grid = [[ | - {0:~ }| - {1:cr }| + {1:~ }| + {3:cr }| :^ | ]], } diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua index fb3dda4bf4..fc1e6c4ee4 100644 --- a/test/functional/editor/mode_insert_spec.lua +++ b/test/functional/editor/mode_insert_spec.lua @@ -180,12 +180,6 @@ describe('insert-mode', function() it('multi-char mapping updates screen properly #25626', function() local screen = Screen.new(60, 6) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, -- NonText - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- StatusLineNC - [3] = { bold = true }, -- ModeMsg - }) screen:attach() command('vnew') insert('foo\nfoo\nfoo') @@ -197,10 +191,10 @@ describe('insert-mode', function() grid = [[ foo │ | foo │β^jβ | - foo │{0:~ }| - {0:~ }│{0:~ }| - {2:[No Name] [+] }{1:[No Name] [+] }| - {3:-- INSERT --} | + foo │{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] [+] }{3:[No Name] [+] }| + {5:-- INSERT --} | ]], } feed('k') @@ -208,9 +202,9 @@ describe('insert-mode', function() grid = [[ foo │ | foo │^βββ | - foo │{0:~ }| - {0:~ }│{0:~ }| - {2:[No Name] [+] }{1:[No Name] [+] }| + foo │{1:~ }| + {1:~ }│{1:~ }| + {2:[No Name] [+] }{3:[No Name] [+] }| | ]], } diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua index 0b26494436..c20a6e5cb5 100644 --- a/test/functional/editor/tabpage_spec.lua +++ b/test/functional/editor/tabpage_spec.lua @@ -102,14 +102,9 @@ describe('tabpage', function() it('switching tabpage after setting laststatus=3 #19591', function() local screen = Screen.new(40, 8) - screen:set_default_attr_ids({ - [0] = { bold = true, foreground = Screen.colors.Blue }, - [1] = { bold = true, reverse = true }, -- StatusLine - [2] = { reverse = true }, -- TabLineFill - [3] = { bold = true }, -- TabLineSel - [4] = { background = Screen.colors.LightGrey, underline = true }, -- TabLine - [5] = { bold = true, foreground = Screen.colors.Magenta }, - }) + screen:add_extra_attr_ids { + [100] = { bold = true, foreground = Screen.colors.Fuchsia }, + } screen:attach() command('tabnew') @@ -118,18 +113,18 @@ describe('tabpage', function() command('tabnext') feed('') screen:expect([[ - {4: [No Name] }{3: [No Name] }{2: }{4:X}| + {24: [No Name] }{5: [No Name] }{2: }{24:X}| ^ | - {0:~ }|*4 - {1:[No Name] }| + {1:~ }|*4 + {3:[No Name] }| "[No Name]" --No lines in buffer-- | ]]) command('vnew') screen:expect([[ - {4: [No Name] }{3: }{5:2}{3: [No Name] }{2: }{4:X}| + {24: [No Name] }{5: }{100:2}{5: [No Name] }{2: }{24:X}| ^ │ | - {0:~ }│{0:~ }|*4 - {1:[No Name] }| + {1:~ }│{1:~ }|*4 + {3:[No Name] }| "[No Name]" --No lines in buffer-- | ]]) end) -- cgit From da7056ffff95822fc8115f6af0cd2c52e2a355ea Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 26 May 2024 11:05:56 +0200 Subject: build(deps): bump luajit to HEAD - 93e87998b --- cmake.deps/deps.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt index 6b72ed5b52..50f86e766a 100644 --- a/cmake.deps/deps.txt +++ b/cmake.deps/deps.txt @@ -4,8 +4,8 @@ LIBUV_SHA256 8c253adb0f800926a6cbd1c6576abae0bc8eb86a4f891049b72f9e5b7dc58f33 MSGPACK_URL https://github.com/msgpack/msgpack-c/archive/c-6.0.1.tar.gz MSGPACK_SHA256 58d5fe49d0ee2b374d60a61aabf8028b2c92004e6f11bff04e74b639fc8ad541 -LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/75e92777988017fe47c5eb290998021bbf972d1f.tar.gz -LUAJIT_SHA256 0f69288190024d732c67645e40ed5b137d67aa950fedf0f44a9ad0f3dba6d5d2 +LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/93e87998b24021b94de8d1c8db244444c46fb6e9.tar.gz +LUAJIT_SHA256 026eb4531cddff20acc72ec97378ccfc30326173c491d6c01834b48b42a80518 LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333 -- cgit From 61b3a26e5b3d7fb6a19dd587994277bc4479307f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 26 May 2024 12:17:47 +0200 Subject: build(deps): bump tree-sitter-query to v0.4.0 --- cmake.deps/deps.txt | 4 ++-- runtime/queries/query/highlights.scm | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt index 50f86e766a..ca43c53b66 100644 --- a/cmake.deps/deps.txt +++ b/cmake.deps/deps.txt @@ -49,8 +49,8 @@ TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar. TREESITTER_VIM_SHA256 9f856f8b4a10ab43348550fa2d3cb2846ae3d8e60f45887200549c051c66f9d5 TREESITTER_VIMDOC_URL https://github.com/neovim/tree-sitter-vimdoc/archive/v2.5.1.tar.gz TREESITTER_VIMDOC_SHA256 063645096504b21603585507c41c6d8718ff3c11b2150c5bfc31e8f3ee9afea3 -TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.3.0.tar.gz -TREESITTER_QUERY_SHA256 f878ff37abcb83250e31a6569e997546f3dbab74dcb26683cb2d613f7568cfc0 +TREESITTER_QUERY_URL https://github.com/tree-sitter-grammars/tree-sitter-query/archive/v0.4.0.tar.gz +TREESITTER_QUERY_SHA256 d3a423ab66dc62b2969625e280116678a8a22582b5ff087795222108db2f6a6e TREESITTER_PYTHON_URL https://github.com/tree-sitter/tree-sitter-python/archive/v0.21.0.tar.gz TREESITTER_PYTHON_SHA256 720304a603271fa89e4430a14d6a81a023d6d7d1171b1533e49c0ab44f1e1c13 TREESITTER_BASH_URL https://github.com/tree-sitter/tree-sitter-bash/archive/v0.21.0.tar.gz diff --git a/runtime/queries/query/highlights.scm b/runtime/queries/query/highlights.scm index 210d03dc33..c02ee3f2a0 100644 --- a/runtime/queries/query/highlights.scm +++ b/runtime/queries/query/highlights.scm @@ -5,9 +5,6 @@ (capture (identifier) @type) -(anonymous_node - (identifier) @string) - (predicate name: (identifier) @function.call) -- cgit From 98536dd78e73da41b9fd4ede3433dd6114139088 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 26 May 2024 12:19:19 +0200 Subject: build(deps): bump tree-sitter-c to v0.21.3 --- cmake.deps/deps.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt index ca43c53b66..f76a6a1b70 100644 --- a/cmake.deps/deps.txt +++ b/cmake.deps/deps.txt @@ -41,8 +41,8 @@ GETTEXT_SHA256 66415634c6e8c3fa8b71362879ec7575e27da43da562c798a8a2f223e6e47f5c LIBICONV_URL https://github.com/neovim/deps/raw/b9bf36eb31f27e8136d907da38fa23518927737e/opt/libiconv-1.17.tar.gz LIBICONV_SHA256 8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313 -TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.21.0.tar.gz -TREESITTER_C_SHA256 6f0f5d1b71cf8ffd8a37fb638c6022fa1245bd630150b538547d52128ce0ea7e +TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.21.3.tar.gz +TREESITTER_C_SHA256 75a3780df6114cd37496761c4a7c9fd900c78bee3a2707f590d78c0ca3a24368 TREESITTER_LUA_URL https://github.com/tree-sitter-grammars/tree-sitter-lua/archive/v0.1.0.tar.gz TREESITTER_LUA_SHA256 230cfcbfa74ed1f7b8149e9a1f34c2efc4c589a71fe0f5dc8560622f8020d722 TREESITTER_VIM_URL https://github.com/neovim/tree-sitter-vim/archive/v0.4.0.tar.gz -- cgit From 2ed6423c7e9d4911343d3e2049908f4b78ec7a55 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 12:56:32 +0200 Subject: fix(tohtml): replace ipairs with pairs --- runtime/lua/tohtml.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 505de720ba..5a6fc77e5c 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -521,7 +521,7 @@ local function _styletable_extmarks_virt_text(state, extmark) hl_mode = 'blend', hl_group = 'combine', } - for opt, val in ipairs(not_supported) do + for opt, val in pairs(not_supported) do if extmark[4][opt] == val then vim.notify_once( ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) -- cgit From 8cd9feb50166202bf55315934f14f74e63c8fcb4 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 13:08:57 +0200 Subject: fix(tohtml): ignore lsp inlay hints --- runtime/lua/tohtml.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 5a6fc77e5c..f7d8538b8f 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -481,10 +481,17 @@ end --- @param state vim.tohtml.state --- @param extmark {[1]:integer,[2]:integer,[3]:integer,[4]:vim.api.keyset.set_extmark|any} -local function _styletable_extmarks_virt_text(state, extmark) +--- @param namespaces table +local function _styletable_extmarks_virt_text(state, extmark, namespaces) if not extmark[4].virt_text then return end + ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only + ---generated in visible lines, and not in the whole buffer. + if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then + vim.notify_once('Info(TOhtml): lsp inlay hints are not supported, HTML may be incorrect') + return + end local styletable = state.style --- @type integer,integer local row, col = extmark[2], extmark[3] @@ -586,7 +593,7 @@ local function styletable_extmarks(state) _styletable_extmarks_conceal(state, v) end for _, v in ipairs(extmarks) do - _styletable_extmarks_virt_text(state, v) + _styletable_extmarks_virt_text(state, v, namespaces) end for _, v in ipairs(extmarks) do _styletable_extmarks_virt_lines(state, v) -- cgit From 88c7997503e12088e134ba663fe352399f8fa104 Mon Sep 17 00:00:00 2001 From: altermo <107814000+altermo@users.noreply.github.com> Date: Sun, 26 May 2024 13:28:14 +0200 Subject: fix(tohtml): show how many warnings are hidden --- runtime/lua/tohtml.lua | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index f7d8538b8f..0fc349e86d 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -57,6 +57,26 @@ --- @field [3] any[][] virt_text --- @field [4] any[][] overlay_text +--- @type string[] +local notifications = {} + +---@param msg string +local function notify(msg) + if #notifications == 0 then + vim.schedule(function() + if #notifications > 1 then + vim.notify( + ('TOhtml: %s (+ %d more warnings)'):format(notifications[1], tostring(#notifications - 1)) + ) + elseif #notifications == 1 then + vim.notify('TOhtml: ' .. notifications[1]) + end + notifications = {} + end) + end + table.insert(notifications, msg) +end + local HIDE_ID = -1 -- stylua: ignore start local cterm_8_to_hex={ @@ -215,7 +235,7 @@ local function cterm_to_hex(colorstr) if hex then cterm_color_cache[color] = hex else - vim.notify_once("Info(TOhtml): Couldn't get terminal colors, using fallback") + notify("Couldn't get terminal colors, using fallback") local t_Co = tonumber(vim.api.nvim_eval('&t_Co')) if t_Co <= 8 then cterm_color_cache = cterm_8_to_hex @@ -241,7 +261,7 @@ local function get_background_color() end local hex = try_query_terminal_color('background') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal background colors, using fallback") + notify("Couldn't get terminal background colors, using fallback") hex = vim.o.background == 'light' and '#ffffff' or '#000000' end background_color_cache = hex @@ -259,7 +279,7 @@ local function get_foreground_color() end local hex = try_query_terminal_color('foreground') if not hex or not hex:match('#%x%x%x%x%x%x') then - vim.notify_once("Info(TOhtml): Couldn't get terminal foreground colors, using fallback") + notify("Couldn't get terminal foreground colors, using fallback") hex = vim.o.background == 'light' and '#000000' or '#ffffff' end foreground_color_cache = hex @@ -467,7 +487,7 @@ local function _styletable_extmarks_highlight(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_semantic_tokens') then - vim.notify_once('Info(TOhtml): lsp semantic tokens are not supported, HTML may be incorrect') + notify('lsp semantic tokens are not supported, HTML may be incorrect') return end local srow, scol, erow, ecol = @@ -489,7 +509,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) ---TODO(altermo) LSP semantic tokens (and some other extmarks) are only ---generated in visible lines, and not in the whole buffer. if (namespaces[extmark[4].ns_id] or ''):find('vim_lsp_inlayhint') then - vim.notify_once('Info(TOhtml): lsp inlay hints are not supported, HTML may be incorrect') + notify('lsp inlay hints are not supported, HTML may be incorrect') return end local styletable = state.style @@ -530,9 +550,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) } for opt, val in pairs(not_supported) do if extmark[4][opt] == val then - vim.notify_once( - ('Info(TOhtml): extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val) - ) + notify(('extmark.%s="%s" is not supported, HTML may be incorrect'):format(opt, val)) end end end @@ -618,9 +636,7 @@ local function styletable_folds(state) end end if has_folded and type(({ pcall(vim.api.nvim_eval, vim.o.foldtext) })[2]) == 'table' then - vim.notify_once( - 'Info(TOhtml): foldtext returning a table is half supported, HTML may be incorrect' - ) + notify('foldtext returning a table with highlights is not supported, HTML may be incorrect') end end -- cgit From eb37241d38ad35b9e6bfac6379dd10e60aa0350c Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Sun, 26 May 2024 10:27:12 -0700 Subject: fix(tohtml): properly handle multiple hl groups #29012 Problem: :TOhtml doesn't properly handle virtual text when it has multiple highlight groups. It also improperly calculates position offset for multi-byte virt_text characters. Solution: Apply the `vim.api.nvim_strwidth` broadly to properly calculate character offset, and handle the cases where the `hl` argument can be a table of multiple hl groups. --- runtime/lua/tohtml.lua | 14 +++++++++----- test/functional/plugin/tohtml_spec.lua | 8 +++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 0fc349e86d..5e145950b7 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -188,6 +188,8 @@ local background_color_cache = nil --- @type string? local foreground_color_cache = nil +local len = vim.api.nvim_strwidth + --- @see https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands --- @param color "background"|"foreground"|integer --- @return string? @@ -312,9 +314,12 @@ local function style_line_insert_virt_text(style_line, col, val) end --- @param state vim.tohtml.state ---- @param hl string|integer|nil +--- @param hl string|integer|string[]|integer[]? --- @return nil|integer local function register_hl(state, hl) + if type(hl) == 'table' then + hl = hl[#hl] + end if type(hl) == 'nil' then return elseif type(hl) == 'string' then @@ -537,7 +542,7 @@ local function _styletable_extmarks_virt_text(state, extmark, namespaces) else style_line_insert_virt_text(styletable[row + 1], col + 1, { i[1], hlid }) end - virt_text_len = virt_text_len + #i[1] + virt_text_len = virt_text_len + len(i[1]) end if extmark[4].virt_text_pos == 'overlay' then styletable_insert_range(state, row + 1, col + 1, row + 1, col + virt_text_len + 1, HIDE_ID) @@ -782,7 +787,7 @@ local function styletable_statuscolumn(state) statuscolumn, { winid = state.winid, use_statuscol_lnum = row, highlights = true } ) - local width = vim.api.nvim_strwidth(status.str) + local width = len(status.str) if width > minwidth then minwidth = width end @@ -797,7 +802,7 @@ local function styletable_statuscolumn(state) for k, v in ipairs(hls) do local text = str:sub(v.start + 1, hls[k + 1] and hls[k + 1].start or nil) if k == #hls then - text = text .. (' '):rep(minwidth - vim.api.nvim_strwidth(str)) + text = text .. (' '):rep(minwidth - len(str)) end if text ~= '' then local hlid = register_hl(state, v.group) @@ -817,7 +822,6 @@ local function styletable_listchars(state) local function utf8_sub(str, i, j) return vim.fn.strcharpart(str, i - 1, j and j - i + 1 or nil) end - local len = vim.api.nvim_strwidth --- @type table local listchars = vim.opt_local.listchars:get() local ids = setmetatable({}, { diff --git a/test/functional/plugin/tohtml_spec.lua b/test/functional/plugin/tohtml_spec.lua index 200a5f34b2..be5bada901 100644 --- a/test/functional/plugin/tohtml_spec.lua +++ b/test/functional/plugin/tohtml_spec.lua @@ -287,7 +287,13 @@ describe(':TOhtml', function() 0, { virt_text = { { 'foo' } }, virt_text_pos = 'overlay' } ) - api.nvim_buf_set_extmark(0, ns, 2, 0, { virt_text = { { 'foo' } }, virt_text_pos = 'inline' }) + api.nvim_buf_set_extmark( + 0, + ns, + 2, + 0, + { virt_text = { { 'fo┊o', { 'Conceal', 'Comment' } } }, virt_text_pos = 'inline' } + ) --api.nvim_buf_set_extmark(0,ns,3,0,{virt_text={{'foo'}},virt_text_pos='right_align'}) run_tohtml_and_assert(screen) end) -- cgit From bc63ffcf39e8ad6c0925c0ad8503bfb3ed8497f3 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 26 May 2024 19:54:08 +0200 Subject: fix(tui): reset clear_region attributes during startup #28713 Problem: Fix added in #28676 worked accidentally(used variables were themselves uninitialized at this point during startup) and does not always work. Solution: Reset attributes when clearing regions during startup. --- src/nvim/tui/tui.c | 21 ++++++----- test/functional/terminal/tui_spec.lua | 65 ++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 2a9530defb..dc8c8def5b 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -115,6 +115,7 @@ struct TUIData { kvec_t(HlAttrs) attrs; int print_attr_id; bool default_attr; + bool set_default_colors; bool can_clear_attr; ModeShape showing_mode; Integer verbose; @@ -166,14 +167,6 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb) tui->seen_error_exit = 0; tui->loop = &main_loop; tui->url = -1; - // Because setting the default colors is delayed until after startup to avoid - // flickering with the default colorscheme background, any flush that happens - // during startup in turn would result in clearing invalidated regions with - // uninitialized attrs(black). Instead initialize clear_attrs with current - // terminal background so that it is at least not perceived as flickering, even - // though it may be different from the colorscheme that is set during startup. - tui->clear_attrs.rgb_bg_color = normal_bg; - tui->clear_attrs.cterm_bg_color = (int16_t)cterm_normal_bg_color; kv_init(tui->invalid_regions); kv_init(tui->urlbuf); @@ -1016,7 +1009,16 @@ static void clear_region(TUIData *tui, int top, int bot, int left, int right, in { UGrid *grid = &tui->grid; - update_attrs(tui, attr_id); + // Setting the default colors is delayed until after startup to avoid flickering + // with the default colorscheme background. Consequently, any flush that happens + // during startup would result in clearing invalidated regions with zeroed + // clear_attrs, perceived as a black flicker. Reset attributes to clear with + // current terminal background instead(#28667, #28668). + if (tui->set_default_colors) { + update_attrs(tui, attr_id); + } else { + unibi_out(tui, unibi_exit_attribute_mode); + } // Background is set to the default color and the right edge matches the // screen end, try to use terminal codes for clearing the requested area. @@ -1419,6 +1421,7 @@ void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Intege tui->clear_attrs.cterm_bg_color = (int16_t)cterm_bg; tui->print_attr_id = -1; + tui->set_default_colors = true; invalidate(tui, 0, tui->grid.height, 0, tui->grid.width); } diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index d4628ea626..efa65b7441 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2003,38 +2003,39 @@ describe('TUI', function() ]]) end) - it('invalidated regions are cleared with terminal background attr', function() - local screen = Screen.new(50, 10) - screen:set_default_attr_ids({ [1] = { foreground = Screen.colors.Black } }) - screen:attach() - fn.termopen({ - nvim_prog, - '--clean', - '--cmd', - 'set termguicolors', - '--cmd', - 'sleep 10', - }, { - env = { - VIMRUNTIME = os.getenv('VIMRUNTIME'), - }, - }) - screen:expect({ - grid = [[ - {1:^ }| - {1: }|*8 - | - ]], - }) - screen:try_resize(51, 11) - screen:expect({ - grid = [[ - {1:^ }| - {1: }|*9 - | - ]], - }) - end) + -- #28667, #28668 + for _, guicolors in ipairs({ 'notermguicolors', 'termguicolors' }) do + it('has no black flicker when clearing regions during startup with ' .. guicolors, function() + local screen = Screen.new(50, 10) + screen:attach() + fn.termopen({ + nvim_prog, + '--clean', + '--cmd', + 'set ' .. guicolors, + '--cmd', + 'sleep 10', + }, { + env = { + VIMRUNTIME = os.getenv('VIMRUNTIME'), + }, + }) + screen:expect({ + grid = [[ + ^ | + |*9 + ]], + intermediate = true, + }) + screen:try_resize(51, 11) + screen:expect({ + grid = [[ + ^ | + |*10 + ]], + }) + end) + end it('argv[0] can be overridden #23953', function() if not exec_lua('return pcall(require, "ffi")') then -- cgit From 43a2019f09e855c4eae33bfdbdec4cc7b2985075 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sun, 26 May 2024 19:55:57 +0200 Subject: fix(extmarks): issues with revalidating marks #28961 Problem: Invalid marks appear to be revalidated multiple times, and decor is added at the old position for unpaired marks. Solution: Avoid revalidating already valid marks, and don't use old position to add to decor for unpaired marks. --- src/nvim/extmark.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 3236590010..4e47fa76fe 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -117,9 +117,16 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool MarkTreeIter itr[1] = { 0 }; MTKey key = marktree_lookup(buf->b_marktree, mark, itr); if (key.pos.row < 0 || (key.pos.row == row && key.pos.col == col)) { + // Does this hold? If it doesn't, we should still revalidate. + assert(!invalid || !mt_invalid(key)); return; } + // Key already revalidated(how?) Avoid adding to decor again. + if (invalid && !mt_invalid(key)) { + invalid = false; + } + // Only the position before undo needs to be redrawn here, // as the position after undo should be marked as changed. if (!invalid && mt_decor_any(key) && key.pos.row != row) { @@ -140,8 +147,8 @@ static void extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col, bool marktree_move(buf->b_marktree, itr, row, col); if (invalid) { - MTPos end = marktree_get_altpos(buf->b_marktree, key, NULL); - buf_put_decor(buf, mt_decor(key), row, end.row); + row2 = mt_paired(key) ? marktree_get_altpos(buf->b_marktree, key, NULL).row : row; + buf_put_decor(buf, mt_decor(key), row, row2); } else if (key.flags & MT_FLAG_DECOR_SIGNTEXT && buf->b_signcols.autom) { buf_signcols_count_range(buf, row1, row2, 0, kNone); } -- cgit From 22fe04452e12944b409c8ee92cf4069ac8026987 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 05:50:49 +0800 Subject: vim-patch:9.1.0446: getregionpos() inconsistent for partly-selected multibyte char (#29032) Problem: getregionpos() behaves inconsistently for a partly-selected multibyte char. Solution: Always use column of the first byte for a partly-selected multibyte char (zeertzjq). closes: vim/vim#14851 https://github.com/vim/vim/commit/ef73374dc3e4bf8104ba31d5b22517f8028b467a --- src/nvim/eval/funcs.c | 5 +++-- test/old/testdir/test_visual.vim | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 3cb6ef41c0..8b22c7a797 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3042,6 +3042,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { pos_T ret_p1, ret_p2; + char *line = ml_get(lnum); colnr_T line_len = ml_get_len(lnum); if (region_type == kMTLineWise) { @@ -3060,7 +3061,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr if (bd.is_oneChar) { // selection entirely inside one char if (region_type == kMTBlockWise) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - (bd.start_vcol - oa.start_vcol); } else { ret_p1.col = p1.col + 1; @@ -3072,7 +3073,7 @@ static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr ret_p1.coladd = oa.start_vcol - bd.start_vcol; bd.is_oneChar = true; } else if (bd.startspaces > 0) { - ret_p1.col = bd.textcol; + ret_p1.col = (colnr_T)(mb_prevptr(line, bd.textstart) - line) + 1; ret_p1.coladd = bd.start_char_vcols - bd.startspaces; } else { ret_p1.col = bd.textcol + 1; diff --git a/test/old/testdir/test_visual.vim b/test/old/testdir/test_visual.vim index 3c510ffd0b..0b840944bf 100644 --- a/test/old/testdir/test_visual.vim +++ b/test/old/testdir/test_visual.vim @@ -2077,10 +2077,12 @@ func Test_visual_getregion() \ getregion(getpos('v'), getpos('.'), {'type': "\" })) call assert_equal([ \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 5, 0]], - \ [[bufnr('%'), 2, 10, 1], [bufnr('%'), 2, 10, 2]], + \ [[bufnr('%'), 2, 7, 1], [bufnr('%'), 2, 7, 2]], \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 5, 0]], \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': "\" })) + call assert_equal(['efghijk«', '🇦«🇧«🇨«🇩', '12345'], + \ getregion(getpos('v'), getpos('.'), {'type': 'v' })) call assert_equal([ \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 13, 0]], \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 22, 0]], @@ -2088,6 +2090,28 @@ func Test_visual_getregion() \ ], \ getregionpos(getpos('v'), getpos('.'), {'type': 'v' })) + call cursor(1, 5) + call feedkeys("\\5l2j", 'xt') + call assert_equal(['efghij', ' «🇨« ', '567890'], + \ getregion(getpos('v'), getpos('.'), {'type': "\" })) + call assert_equal([ + \ [[bufnr('%'), 1, 5, 0], [bufnr('%'), 1, 10, 0]], + \ [[bufnr('%'), 2, 7, 1], [bufnr('%'), 2, 19, 1]], + \ [[bufnr('%'), 3, 5, 0], [bufnr('%'), 3, 10, 0]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': "\" })) + + call cursor(1, 4) + call feedkeys("\\02j", 'xt') + call assert_equal(['abcd', '🇦« ', '1234'], + \ getregion(getpos('v'), getpos('.'), {'type': "\" })) + call assert_equal([ + \ [[bufnr('%'), 1, 1, 0], [bufnr('%'), 1, 4, 0]], + \ [[bufnr('%'), 2, 1, 0], [bufnr('%'), 2, 7, 1]], + \ [[bufnr('%'), 3, 1, 0], [bufnr('%'), 3, 4, 0]], + \ ], + \ getregionpos(getpos('v'), getpos('.'), {'type': "\" })) + #" characterwise selection with multibyte chars call cursor(1, 1) call feedkeys("\vj", 'xt') -- cgit From 14a7644181fb3244d548e5d3a0fa23d67580def2 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 26 May 2024 20:07:46 +0200 Subject: vim-patch:76174e7: runtime(asm): remove the indent plugin since it has too many issues fixes: vim/vim#14791 https://github.com/vim/vim/commit/76174e71101503900d54d38e00b3a869af1fdd85 Co-authored-by: Christian Brabandt --- runtime/indent/asm.vim | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 runtime/indent/asm.vim diff --git a/runtime/indent/asm.vim b/runtime/indent/asm.vim deleted file mode 100644 index 054612b9d6..0000000000 --- a/runtime/indent/asm.vim +++ /dev/null @@ -1,29 +0,0 @@ -" Vim indent file -" Language: asm -" Maintainer: Philip Jones -" Upstream: https://github.com/philj56/vim-asm-indent -" Last Change: 2017-Jul-01 -" 2024 Apr 25 by Vim Project (undo_indent) - -if exists("b:did_indent") - finish -endif -let b:did_indent = 1 - -setlocal indentexpr=s:getAsmIndent() -setlocal indentkeys=<:>,!^F,o,O - -let b:undo_indent = "setlocal indentexpr< indentkeys<" - -function! s:getAsmIndent() - let line = getline(v:lnum) - let ind = shiftwidth() - - " If the line is a label (starts with ':' terminated keyword), - " then don't indent - if line =~ '^\s*\k\+:' - let ind = 0 - endif - - return ind -endfunction -- cgit From ffbd09ef6acfbfac897be19d5ae847af6e6bd03d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 26 May 2024 20:08:13 +0200 Subject: vim-patch:8607192: runtime(typescriptreact): fix highlighting nested and escaped quotes in string props (vim/vim#14852) https://github.com/vim/vim/commit/86071925ede1030d86e764054e36ef8ab56fc666 Co-authored-by: Linda_pp --- runtime/syntax/typescriptreact.vim | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/syntax/typescriptreact.vim b/runtime/syntax/typescriptreact.vim index 9dc9a2b797..061ec4d81e 100644 --- a/runtime/syntax/typescriptreact.vim +++ b/runtime/syntax/typescriptreact.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: TypeScript with React (JSX) " Maintainer: The Vim Project -" Last Change: 2024 May 24 +" Last Change: 2024 May 26 " Based On: Herrington Darkholme's yats.vim " Changes: See https://github.com/HerringtonDarkholme/yats.vim " Credits: See yats.vim on github @@ -118,7 +118,8 @@ syntax match tsxEqual +=+ display contained " " s~~~~~~e -syntax region tsxString contained start=+["']+ end=+["']+ contains=tsxEntity,@Spell display +syntax region tsxString contained start=+"+ skip=+\\"+ end=+"+ contains=tsxEntity,@Spell display +syntax region tsxString contained start=+'+ skip=+\\'+ end=+'+ contains=tsxEntity,@Spell display " " s~~~~~~~~~~~~~~e -- cgit From 9a0239fdc8b380a8a32739a7c722fe90e3c2e910 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 14:37:22 +0800 Subject: fix(drawline): don't draw beyond end of window (#29035) --- src/nvim/drawline.c | 15 ++++++------- test/functional/ui/screen_basic_spec.lua | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 07944081da..4d534d78a2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1596,6 +1596,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // hide virt_text on text hidden by 'nowrap' or 'smoothscroll' decor_redraw_col(wp, (colnr_T)(ptr - line) - 1, wlv.off, true, &decor_state); } + if (wlv.col >= grid->cols) { + wlv.col = wlv.off = grid->cols; + goto end_check; + } } if (cul_screenline && wlv.filler_todo <= 0 @@ -2650,13 +2654,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s conceal_cursor_used = conceal_cursor_line(curwin); } - // When the window is too narrow draw all "@" lines. - if (leftcols_width >= wp->w_grid.cols && is_wrapped) { - win_draw_end(wp, schar_from_ascii('@'), true, wlv.row, wp->w_grid.rows, HLF_AT); - set_empty_rows(wp, wlv.row); - wlv.row = endrow; - } - break; } @@ -2844,10 +2841,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } +end_check: // At end of screen line and there is more to come: Display the line // so far. If there is no more to display it is caught above. if (wlv.col >= grid->cols && (!has_foldtext || virt_line_offset >= 0) - && (*ptr != NUL + && (wlv.col <= leftcols_width + || *ptr != NUL || wlv.filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL && lcs_eol_todo) || (wlv.n_extra != 0 && (wlv.sc_extra != NUL || *wlv.p_extra != NUL)) diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 54580bf47c..85a653df36 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -4,6 +4,7 @@ local Screen = require('test.functional.ui.screen') local spawn, set_session, clear = n.spawn, n.set_session, n.clear local feed, command = n.feed, n.command +local exec = n.exec local insert = n.insert local eq = t.eq local fn, api = n.fn, n.api @@ -819,3 +820,39 @@ it("showcmd doesn't cause empty grid_line with redrawdebug=compositor #22593", f ]], } end) + +it("scrolling in narrow window doesn't draw over separator #29033", function() + clear() + local screen = Screen.new(60, 8) + screen:attach() + feed('100Oagg') + exec([[ + set number nowrap + vsplit + set scrollbind + wincmd l + set scrollbind + wincmd | + ]]) + screen:expect([[ + {8: }│{8: 1 }^a | + {8: }│{8: 2 }a | + {8: }│{8: 3 }a | + {8: }│{8: 4 }a | + {8: }│{8: 5 }a | + {8: }│{8: 6 }a | + {2:< }{3:[No Name] [+] }| + | + ]]) + feed('') + screen:expect([[ + {8: }│{8: 5 }^a | + {8: }│{8: 6 }a | + {8: }│{8: 7 }a | + {8: }│{8: 8 }a | + {8: }│{8: 9 }a | + {8: }│{8: 10 }a | + {2:< }{3:[No Name] [+] }| + | + ]]) +end) -- cgit From 104800ce2eadd21475b5a4897265a8a177e58d77 Mon Sep 17 00:00:00 2001 From: Malte Dehling Date: Mon, 27 May 2024 04:14:57 -0700 Subject: build: "popcount" name conflict on NetBSD #28983 Problem: NetBSD's libc already has a function by the same name. Solution: Rename popcount to xpopcount and add #if defined(__NetBSD__) to prefer NetBSD's own implementation. This fixes #28983. --- src/nvim/api/vim.c | 4 ++-- src/nvim/math.c | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index fc780e1248..52ab18cbff 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2354,8 +2354,8 @@ void nvim__redraw(Dict(redraw) *opts, Error *err) } } - int count = (win != NULL) + (buf != NULL); - VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { + unsigned count = (win != NULL) + (buf != NULL); + VALIDATE(xpopcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { return; }); diff --git a/src/nvim/math.c b/src/nvim/math.c index 1ccf4d7806..4ca212413b 100644 --- a/src/nvim/math.c +++ b/src/nvim/math.c @@ -78,13 +78,15 @@ int xctz(uint64_t x) } /// Count number of set bits in bit field. -int popcount(uint64_t x) +unsigned xpopcount(uint64_t x) { // Use compiler builtin if possible. -#if defined(__clang__) || defined(__GNUC__) - return __builtin_popcountll(x); +#if defined(__NetBSD__) + return popcount64(x); +#elif defined(__clang__) || defined(__GNUC__) + return (unsigned)__builtin_popcountll(x); #else - int count = 0; + unsigned count = 0; for (; x != 0; x >>= 1) { if (x & 1) { count++; -- cgit From c4eb0b64bd4923a72fe737837cfe234c80fb539c Mon Sep 17 00:00:00 2001 From: Guilherme Soares <48023091+guilhas07@users.noreply.github.com> Date: Mon, 27 May 2024 13:20:03 +0200 Subject: fix(treesitter): find buffer in multiple windows #28922 Problem: 1. When interacting with multiple :InspectTree and the source buffer windows there is a high chance of errors due to the window ids not being updated and validated. 2. Not all InspectTree windows were closed when the source buffer was closed. Solution: 1. Update InspectTree window id on `CursorMoved` event and validate source buffer window id before trying to navigate to it. 2. Close all InspectTree windows --- runtime/lua/vim/treesitter/dev.lua | 22 +++++++++- test/functional/treesitter/inspect_tree_spec.lua | 53 ++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/treesitter/dev.lua b/runtime/lua/vim/treesitter/dev.lua index 5c91f101c0..ca8cf85eda 100644 --- a/runtime/lua/vim/treesitter/dev.lua +++ b/runtime/lua/vim/treesitter/dev.lua @@ -325,7 +325,10 @@ function M.inspect_tree(opts) opts = opts or {} + -- source buffer local buf = api.nvim_get_current_buf() + + -- window id for source buffer local win = api.nvim_get_current_win() local treeview = assert(TSTreeView:new(buf, opts.lang)) @@ -334,12 +337,14 @@ function M.inspect_tree(opts) close_win(vim.b[buf].dev_inspect) end + -- window id for tree buffer local w = opts.winid if not w then vim.cmd(opts.command or '60vnew') w = api.nvim_get_current_win() end + -- tree buffer local b = opts.bufnr if b then api.nvim_win_set_buf(w, b) @@ -375,6 +380,12 @@ function M.inspect_tree(opts) callback = function() local row = api.nvim_win_get_cursor(w)[1] local lnum, col = treeview:get(row).node:start() + + -- update source window if original was closed + if not api.nvim_win_is_valid(win) then + win = vim.fn.win_findbuf(buf)[1] + end + api.nvim_set_current_win(win) api.nvim_win_set_cursor(win, { lnum + 1, col }) end, @@ -432,6 +443,7 @@ function M.inspect_tree(opts) return true end + w = api.nvim_get_current_win() api.nvim_buf_clear_namespace(buf, treeview.ns, 0, -1) local row = api.nvim_win_get_cursor(w)[1] local lnum, col, end_lnum, end_col = treeview:get(row).node:range() @@ -441,6 +453,11 @@ function M.inspect_tree(opts) hl_group = 'Visual', }) + -- update source window if original was closed + if not api.nvim_win_is_valid(win) then + win = vim.fn.win_findbuf(buf)[1] + end + local topline, botline = vim.fn.line('w0', win), vim.fn.line('w$', win) -- Move the cursor if highlighted range is completely out of view @@ -506,7 +523,10 @@ function M.inspect_tree(opts) buffer = buf, once = true, callback = function() - close_win(w) + -- close all tree windows + for _, window in pairs(vim.fn.win_findbuf(b)) do + close_win(window) + end end, }) end diff --git a/test/functional/treesitter/inspect_tree_spec.lua b/test/functional/treesitter/inspect_tree_spec.lua index f5acfe7c4a..b403cca735 100644 --- a/test/functional/treesitter/inspect_tree_spec.lua +++ b/test/functional/treesitter/inspect_tree_spec.lua @@ -114,4 +114,57 @@ describe('vim.treesitter.inspect_tree', function() (fenced_code_block_delimiter)))) ; [2, 0] - [2, 3] markdown ]] end) + + it('updates source and tree buffer windows and closes them correctly', function() + insert([[ + print() + ]]) + + -- setup two windows for the source buffer + exec_lua([[ + source_win = vim.api.nvim_get_current_win() + vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left' + }) + ]]) + + -- setup three windows for the tree buffer + exec_lua([[ + vim.treesitter.start(0, 'lua') + vim.treesitter.inspect_tree() + tree_win = vim.api.nvim_get_current_win() + tree_win_copy_1 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left' + }) + tree_win_copy_2 = vim.api.nvim_open_win(0, false, { + win = 0, + split = 'left' + }) + ]]) + + -- close original source window + exec_lua('vim.api.nvim_win_close(source_win, false)') + + -- navigates correctly to the remaining source buffer window + feed('') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close original tree window + exec_lua([[ + vim.api.nvim_set_current_win(tree_win_copy_1) + vim.api.nvim_win_close(tree_win, false) + ]]) + + -- navigates correctly to the remaining source buffer window + feed('') + eq('', n.api.nvim_get_vvar('errmsg')) + + -- close source buffer window and all remaining tree windows + t.pcall_err(exec_lua, 'vim.api.nvim_win_close(0, false)') + + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_1)')) + eq(false, exec_lua('return vim.api.nvim_win_is_valid(tree_win_copy_2)')) + end) end) -- cgit From 48251134ee59a3e2f0aeb89608fa820c21b25d4f Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 27 May 2024 08:08:23 -0500 Subject: perf: add fast path to vim.validate (#28977) For many small/simple functions (like those found in shared.lua), the runtime of vim.validate can far exceed the runtime of the function itself. Add an "overload" to vim.validate that uses a simple assertion pattern, rather than parsing a full "validation spec". --- runtime/doc/lua.txt | 21 ++++++++++- runtime/lua/vim/shared.lua | 76 ++++++++++++++++++++++++++++++++-------- test/functional/lua/vim_spec.lua | 20 ++++++++++- 3 files changed, 101 insertions(+), 16 deletions(-) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 64a3014388..fd0cd3252f 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -2366,7 +2366,26 @@ vim.trim({s}) *vim.trim()* • https://www.lua.org/pil/20.2.html vim.validate({opt}) *vim.validate()* - Validates a parameter specification (types and values). Specs are + Validate function arguments. + + This function has two valid forms: + 1. vim.validate(name: str, value: any, type: string, optional?: bool) + 2. vim.validate(spec: table) + + Form 1 validates that argument {name} with value {value} has the type + {type}. {type} must be a value returned by |lua-type()|. If {optional} is + true, then {value} may be null. This form is significantly faster and + should be preferred for simple cases. + + Example: >lua + function vim.startswith(s, prefix) + vim.validate('s', s, 'string') + vim.validate('prefix', prefix, 'string') + ... + end +< + + Form 2 validates a parameter specification (types and values). Specs are evaluated in alphanumeric order, until the first failure. Usage example: >lua diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index e9e4326057..2641d1feb0 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -214,7 +214,7 @@ end ---@param t table (table) Table ---@return T[] : List of keys function vim.tbl_keys(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table local keys = {} @@ -231,7 +231,7 @@ end ---@param t table (table) Table ---@return T[] : List of values function vim.tbl_values(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') local values = {} for _, v in @@ -332,7 +332,7 @@ end ---@param value any Value to compare ---@return boolean `true` if `t` contains `value` function vim.list_contains(t, value) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table for _, v in ipairs(t) do @@ -350,7 +350,7 @@ end ---@param t table Table to check ---@return boolean `true` if `t` is empty function vim.tbl_isempty(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') return next(t) == nil end @@ -580,7 +580,7 @@ end ---@return fun(table: table, index?: K):K, V # |for-in| iterator over sorted keys and their values ---@return T function vim.spairs(t) - assert(type(t) == 'table', ('expected table, got %s'):format(type(t))) + vim.validate('t', t, 'table') --- @cast t table -- collect the keys @@ -691,7 +691,7 @@ end ---@param t table Table ---@return integer : Number of non-nil values in table function vim.tbl_count(t) - vim.validate({ t = { t, 't' } }) + vim.validate('t', t, 'table') --- @cast t table local count = 0 @@ -723,7 +723,7 @@ end ---@param s string String to trim ---@return string String with whitespace removed from its beginning and end function vim.trim(s) - vim.validate({ s = { s, 's' } }) + vim.validate('s', s, 'string') return s:match('^%s*(.*%S)') or '' end @@ -733,7 +733,7 @@ end ---@param s string String to escape ---@return string %-escaped pattern string function vim.pesc(s) - vim.validate({ s = { s, 's' } }) + vim.validate('s', s, 'string') return (s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')) end @@ -743,7 +743,8 @@ end ---@param prefix string Prefix to match ---@return boolean `true` if `prefix` is a prefix of `s` function vim.startswith(s, prefix) - vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } }) + vim.validate('s', s, 'string') + vim.validate('prefix', prefix, 'string') return s:sub(1, #prefix) == prefix end @@ -753,7 +754,8 @@ end ---@param suffix string Suffix to match ---@return boolean `true` if `suffix` is a suffix of `s` function vim.endswith(s, suffix) - vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } }) + vim.validate('s', s, 'string') + vim.validate('suffix', suffix, 'string') return #suffix == 0 or s:sub(-#suffix) == suffix end @@ -877,8 +879,30 @@ do return true end - --- Validates a parameter specification (types and values). Specs are evaluated in alphanumeric - --- order, until the first failure. + --- Validate function arguments. + --- + --- This function has two valid forms: + --- + --- 1. vim.validate(name: str, value: any, type: string, optional?: bool) + --- 2. vim.validate(spec: table) + --- + --- Form 1 validates that argument {name} with value {value} has the type + --- {type}. {type} must be a value returned by |lua-type()|. If {optional} is + --- true, then {value} may be null. This form is significantly faster and + --- should be preferred for simple cases. + --- + --- Example: + --- + --- ```lua + --- function vim.startswith(s, prefix) + --- vim.validate('s', s, 'string') + --- vim.validate('prefix', prefix, 'string') + --- ... + --- end + --- ``` + --- + --- Form 2 validates a parameter specification (types and values). Specs are + --- evaluated in alphanumeric order, until the first failure. --- --- Usage example: --- @@ -930,8 +954,32 @@ do --- only if the argument is valid. Can optionally return an additional --- informative error message as the second returned value. --- - msg: (optional) error string if validation fails - function vim.validate(opt) - local ok, err_msg = is_valid(opt) + --- @overload fun(name: string, val: any, expected: string, optional?: boolean) + function vim.validate(opt, ...) + local ok = false + local err_msg ---@type string? + local narg = select('#', ...) + if narg == 0 then + ok, err_msg = is_valid(opt) + elseif narg >= 2 then + -- Overloaded signature for fast/simple cases + local name = opt --[[@as string]] + local v, expected, optional = ... ---@type string, string, boolean? + local actual = type(v) + + ok = (actual == expected) or (v == nil and optional == true) + if not ok then + err_msg = ('%s: expected %s, got %s%s'):format( + name, + expected, + actual, + v and (' (%s)'):format(v) or '' + ) + end + else + error('invalid arguments') + end + if not ok then error(err_msg, 2) end diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index c8f94c6ffa..d50b646085 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -1408,7 +1408,25 @@ describe('lua stdlib', function() exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}") exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}") exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}") - + vim.validate('arg1', 5, 'number') + vim.validate('arg1', '5', 'string') + vim.validate('arg1', { 5 }, 'table') + vim.validate('arg1', function() + return 5 + end, 'function') + vim.validate('arg1', nil, 'number', true) + vim.validate('arg1', nil, 'string', true) + vim.validate('arg1', nil, 'table', true) + vim.validate('arg1', nil, 'function', true) + + matches('arg1: expected number, got nil', pcall_err(vim.validate, 'arg1', nil, 'number')) + matches('arg1: expected string, got nil', pcall_err(vim.validate, 'arg1', nil, 'string')) + matches('arg1: expected table, got nil', pcall_err(vim.validate, 'arg1', nil, 'table')) + matches('arg1: expected function, got nil', pcall_err(vim.validate, 'arg1', nil, 'function')) + matches('arg1: expected string, got number', pcall_err(vim.validate, 'arg1', 5, 'string')) + matches('arg1: expected table, got number', pcall_err(vim.validate, 'arg1', 5, 'table')) + matches('arg1: expected function, got number', pcall_err(vim.validate, 'arg1', 5, 'function')) + matches('arg1: expected number, got string', pcall_err(vim.validate, 'arg1', '5', 'number')) matches('expected table, got number', pcall_err(exec_lua, "vim.validate{ 1, 'x' }")) matches('invalid type name: x', pcall_err(exec_lua, "vim.validate{ arg1={ 1, 'x' }}")) matches('invalid type name: 1', pcall_err(exec_lua, 'vim.validate{ arg1={ 1, 1 }}')) -- cgit From dbc2678f46970703616765dadff1234fdcce27b7 Mon Sep 17 00:00:00 2001 From: glepnir Date: Mon, 27 May 2024 22:02:24 +0800 Subject: vim-patch:9.1.0447: completion may be wrong when deleting all chars (#29040) Problem: completion may be wrong when deleting all chars. Solution: reset compl_shown_match (glepnir). closes: https://github.com/vim/vim/pull/14854 https://github.com/vim/vim/commit/53387c55a13bc1013a6ab721d4bd0bd04c6935c4 --- src/nvim/insexpand.c | 4 ++++ test/old/testdir/test_ins_complete.vim | 16 ++++++++-------- test/old/testdir/test_popup.vim | 2 ++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index b557b9802e..8b1c09b32f 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -1198,6 +1198,10 @@ static int ins_compl_build_pum(void) // match after it, don't highlight anything. bool shown_match_ok = match_at_original_text(compl_shown_match); + if (strequal(compl_leader, compl_orig_text) && !shown_match_ok) { + compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next; + } + compl_T *shown_compl = NULL; bool did_find_shown_match = false; int cur = -1; diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index 3f67a06999..45db2a7364 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -700,14 +700,14 @@ func Test_pum_with_preview_win() CheckScreendump let lines =<< trim END - funct Omni_test(findstart, base) - if a:findstart - return col(".") - 1 - endif - return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] - endfunc - set omnifunc=Omni_test - set completeopt+=longest + funct Omni_test(findstart, base) + if a:findstart + return col(".") - 1 + endif + return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}] + endfunc + set omnifunc=Omni_test + set completeopt+=longest END call writefile(lines, 'Xpreviewscript') diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim index 56c881b958..5ae2ed5ed5 100644 --- a/test/old/testdir/test_popup.vim +++ b/test/old/testdir/test_popup.vim @@ -1178,6 +1178,8 @@ func Test_CompleteChanged() set completeopt=menu,menuone call feedkeys("i\\\\\f", 'tx') call assert_equal('five', g:word) + call feedkeys("i\\\\\f\", 'tx') + call assert_equal('one', g:word) autocmd! AAAAA_Group set complete& completeopt& -- cgit From 8893b7b340e012b714cc42f0562f37405be32d51 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 27 May 2024 22:38:10 +0800 Subject: vim-patch:393708c: runtime(vim): re-generate vim syntax from generator (#29041) related: vim/vim#14861 https://github.com/vim/vim/commit/393708cff6f92ee34b450b054dfdb73a65f5bcf7 Co-authored-by: Christian Brabandt --- runtime/syntax/vim.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index 4fc640bab1..22c1e16a30 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -60,7 +60,8 @@ syn case ignore syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo " Default highlighting groups {{{2 -syn keyword vimHLGroup contained ErrorMsg IncSearch ModeMsg NonText StatusLine StatusLineNC EndOfBuffer VertSplit DiffText PmenuSbar TabLineSel TabLineFill Cursor lCursor QuickFixLine CursorLineSign CursorLineFold CurSearch PmenuKind PmenuKindSel PmenuExtra PmenuExtraSel Normal Directory LineNr CursorLineNr MoreMsg Question Search SpellBad SpellCap SpellRare SpellLocal PmenuThumb Pmenu PmenuSel SpecialKey Title WarningMsg WildMenu Folded FoldColumn SignColumn Visual DiffAdd DiffChange DiffDelete TabLine CursorColumn CursorLine ColorColumn Conceal MatchParen CursorIM LineNrAbove LineNrBelow +syn keyword vimHLGroup contained ErrorMsg IncSearch ModeMsg NonText StatusLine StatusLineNC EndOfBuffer VertSplit DiffText PmenuSbar TabLineSel TabLineFill Cursor lCursor QuickFixLine CursorLineSign CursorLineFold CurSearch PmenuKind PmenuKindSel PmenuExtra PmenuExtraSel Normal Directory LineNr CursorLineNr MoreMsg Question Search SpellBad SpellCap SpellRare SpellLocal PmenuThumb Pmenu PmenuSel SpecialKey Title WarningMsg WildMenu Folded FoldColumn SignColumn Visual DiffAdd DiffChange DiffDelete TabLine CursorColumn CursorLine ColorColumn MatchParen CursorIM LineNrAbove LineNrBelow +syn match vimHLGroup contained "\" syn keyword vimOnlyHLGroup contained Menu Scrollbar StatusLineTerm StatusLineTermNC ToolbarButton ToolbarLine Tooltip VisualNOS syn keyword nvimHLGroup contained FloatBorder FloatFooter FloatTitle MsgSeparator NormalFloat NormalNC Substitute TermCursor TermCursorNC VisualNC Whitespace WinBar WinBarNC WinSeparator "}}}2 -- cgit From 292365fa1b8f543ffa2240bb30af34051ad2d7c8 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Mon, 27 May 2024 11:06:03 -0400 Subject: fix(lsp): do not detach from buffer if there are uninitialized clients (#29029) Problem: if on_lines is called before the LSP is initialized, the buffer is detached. Solution: check for uninitialized clients before detaching. --- runtime/lua/vim/lsp.lua | 3 ++- test/functional/plugin/lsp_spec.lua | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 1592fd3151..60b3f3e502 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -577,7 +577,8 @@ local function buf_attach(bufnr) api.nvim_buf_attach(bufnr, false, { on_lines = function(_, _, changedtick, firstline, lastline, new_lastline) if #lsp.get_clients({ bufnr = bufnr }) == 0 then - return true -- detach + -- detach if there are no clients + return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 end util.buf_versions[bufnr] = changedtick changetracking.send_changes(bufnr, firstline, lastline, new_lastline) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index c95a96baca..0cf84b50c2 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -530,6 +530,34 @@ describe('LSP', function() ]]) end) + it('should allow on_lines + nvim_buf_delete during LSP initialization #28575', function() + clear() + exec_lua(create_server_definition) + exec_lua([[ + local initialized = false + local server = _create_server({ + handlers = { + initialize = function(method, params, callback) + vim.schedule(function() + callback(nil, { capabilities = {} }) + initialized = true + end) + end + } + }) + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + local client_id = vim.lsp.start({ + name = 'detach-dummy', + cmd = server.cmd, + }) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {"hello"}) + vim.api.nvim_buf_delete(bufnr, {}) + local ok = vim.wait(1000, function() return initialized end) + assert(ok, "lsp did not initialize") + ]]) + end) + it('client should return settings via workspace/configuration handler', function() local expected_handlers = { { NIL, {}, { method = 'shutdown', client_id = 1 } }, -- cgit From 608543f8a90b08cbe84cea878a14f053789f45a4 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 27 May 2024 08:18:10 -0700 Subject: fix(snippet): cancel snippet session when leaving the buffer (#29031) --- runtime/lua/vim/snippet.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3fd2555046..8e384e0f97 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -395,6 +395,15 @@ local function setup_autocmds(bufnr) end end, }) + + vim.api.nvim_create_autocmd('BufLeave', { + group = snippet_group, + desc = 'Stop the snippet session when leaving the buffer', + buffer = bufnr, + callback = function() + M.stop() + end, + }) end --- Expands the given snippet text. -- cgit From f70af5c3cad098ee9c7f1956bc18991cbd515507 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 27 May 2024 18:42:45 +0200 Subject: ci: bump backport action to version 3 --- .github/workflows/backport.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 9fbe837106..16ed889841 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -14,15 +14,10 @@ jobs: - uses: actions/checkout@v4 - name: Create backport PR id: backport - uses: korthout/backport-action@v2 + uses: korthout/backport-action@v3 with: pull_title: "${pull_title}" label_pattern: "^ci:backport ([^ ]+)$" - # https://github.com/korthout/backport-action/pull/399 - experimental: > - { - "detect_merge_method": true - } - if: ${{steps.backport.outputs.was_successful == 'true'}} uses: actions/github-script@v7 -- cgit From 6e8a728e3dad747d0c46dc47a530b76e8997bc08 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 25 May 2024 20:35:37 +0200 Subject: refactor: fix luals type warnings --- runtime/lua/tohtml.lua | 4 +- runtime/lua/vim/_meta.lua | 2 + runtime/lua/vim/_meta/vimfn.lua | 2 +- runtime/lua/vim/deprecated/health.lua | 2 +- runtime/lua/vim/health.lua | 12 ++--- runtime/lua/vim/health/health.lua | 3 +- runtime/lua/vim/lsp/util.lua | 4 +- runtime/lua/vim/provider/health.lua | 82 +++++++++++++++++------------------ scripts/gen_help_html.lua | 4 +- scripts/gen_vimdoc.lua | 4 +- scripts/luacats_parser.lua | 2 +- src/nvim/eval.lua | 1 + 12 files changed, 62 insertions(+), 60 deletions(-) diff --git a/runtime/lua/tohtml.lua b/runtime/lua/tohtml.lua index 5e145950b7..120247ed4e 100644 --- a/runtime/lua/tohtml.lua +++ b/runtime/lua/tohtml.lua @@ -65,9 +65,7 @@ local function notify(msg) if #notifications == 0 then vim.schedule(function() if #notifications > 1 then - vim.notify( - ('TOhtml: %s (+ %d more warnings)'):format(notifications[1], tostring(#notifications - 1)) - ) + vim.notify(('TOhtml: %s (+ %d more warnings)'):format(notifications[1], #notifications - 1)) elseif #notifications == 1 then vim.notify('TOhtml: ' .. notifications[1]) end diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 731dd5b923..c9f207cb20 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -34,3 +34,5 @@ vim.uri_from_fname = uri.uri_from_fname vim.uri_from_bufnr = uri.uri_from_bufnr vim.uri_to_fname = uri.uri_to_fname vim.uri_to_bufnr = uri.uri_to_bufnr + +vim.provider = require('vim.provider') diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index f256f63768..84bb26a135 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -1642,7 +1642,7 @@ function vim.fn.execute(command, silent) end --- If {expr} starts with "./" the |current-directory| is used. --- --- @param expr any ---- @return any +--- @return string function vim.fn.exepath(expr) end --- The result is a Number, which is |TRUE| if {expr} is diff --git a/runtime/lua/vim/deprecated/health.lua b/runtime/lua/vim/deprecated/health.lua index 0f6b1f578c..64a755b248 100644 --- a/runtime/lua/vim/deprecated/health.lua +++ b/runtime/lua/vim/deprecated/health.lua @@ -1,7 +1,7 @@ local M = {} local health = vim.health -local deprecated = {} +local deprecated = {} ---@type {[1]: string, [2]: table, [3]: string}[] function M.check() if next(deprecated) == nil then diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index afeba2ee9d..236f9da752 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -104,10 +104,10 @@ local function filepath_to_healthcheck(path) local subpath = path:gsub('.*lua/', '') if vim.fs.basename(subpath) == 'health.lua' then -- */health.lua - name = assert(vim.fs.dirname(subpath)) + name = vim.fs.dirname(subpath) else -- */health/init.lua - name = assert(vim.fs.dirname(assert(vim.fs.dirname(subpath)))) + name = vim.fs.dirname(vim.fs.dirname(subpath)) end name = name:gsub('/', '.') @@ -301,11 +301,13 @@ end local PATTERNS = { '/autoload/health/*.vim', '/lua/**/**/health.lua', '/lua/**/**/health/init.lua' } --- :checkhealth completion function used by cmdexpand.c get_healthcheck_names() M._complete = function() - local unique = vim + local unique = vim ---@type table + ---@param pattern string .iter(vim.tbl_map(function(pattern) return vim.tbl_map(path2name, vim.api.nvim_get_runtime_file(pattern, true)) end, PATTERNS)) :flatten() + ---@param t table :fold({}, function(t, name) t[name] = true -- Remove duplicates return t @@ -364,7 +366,7 @@ function M._check(mods, plugin_names) vim.fn.call(func, {}) else local f = assert(loadstring(func)) - local ok, output = pcall(f) + local ok, output = pcall(f) ---@type boolean, string if not ok then M.error( string.format('Failed to run healthcheck for "%s" plugin. Exception:\n%s\n', name, output) @@ -391,7 +393,7 @@ function M._check(mods, plugin_names) end s_output[#s_output + 1] = '' s_output = vim.list_extend(header, s_output) - vim.fn.append('$', s_output) + vim.fn.append(vim.fn.line('$'), s_output) vim.cmd.redraw() end diff --git a/runtime/lua/vim/health/health.lua b/runtime/lua/vim/health/health.lua index 5bc03199ee..235dacb82a 100644 --- a/runtime/lua/vim/health/health.lua +++ b/runtime/lua/vim/health/health.lua @@ -239,6 +239,7 @@ local function check_tmux() return end + ---@param option string local get_tmux_option = function(option) local cmd = 'tmux show-option -qvg ' .. option -- try global scope local out = vim.fn.system(vim.fn.split(cmd)) @@ -378,7 +379,7 @@ local function check_terminal() 'SSH_TTY', }) do if vim.env[env_var] then - health.info(vim.fn.printf('$%s="%s"', env_var, vim.env[env_var])) + health.info(string.format('$%s="%s"', env_var, vim.env[env_var])) end end end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 5a229a1169..0099e82f52 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -616,7 +616,7 @@ function M.rename(old_fname, new_fname, opts) buf_rename[b] = { from = old_bname, to = new_bname } end - local newdir = assert(vim.fs.dirname(new_fname)) + local newdir = vim.fs.dirname(new_fname) vim.fn.mkdir(newdir, 'p') local ok, err = os.rename(old_fname_full, new_fname) @@ -625,7 +625,7 @@ function M.rename(old_fname, new_fname, opts) local old_undofile = vim.fn.undofile(old_fname_full) if uv.fs_stat(old_undofile) ~= nil then local new_undofile = vim.fn.undofile(new_fname) - vim.fn.mkdir(assert(vim.fs.dirname(new_undofile)), 'p') + vim.fn.mkdir(vim.fs.dirname(new_undofile), 'p') os.rename(old_undofile, new_undofile) end diff --git a/runtime/lua/vim/provider/health.lua b/runtime/lua/vim/provider/health.lua index d6932f651e..fa2c452268 100644 --- a/runtime/lua/vim/provider/health.lua +++ b/runtime/lua/vim/provider/health.lua @@ -95,10 +95,10 @@ local function system(cmd, args) error(emsg) end - -- return opts.output return vim.trim(vim.fn.system(cmd)), shell_error_code end +---@param provider string local function provider_disabled(provider) local loaded_var = 'loaded_' .. provider .. '_provider' local v = vim.g[loaded_var] @@ -126,9 +126,9 @@ local function clipboard() health.error('pbcopy does not work with tmux version: ' .. tmux_version, advice) end - local clipboard_tool = vim.fn['provider#clipboard#Executable']() + local clipboard_tool = vim.fn['provider#clipboard#Executable']() ---@type string if vim.g.clipboard ~= nil and clipboard_tool == '' then - local error_message = vim.fn['provider#clipboard#Error']() + local error_message = vim.fn['provider#clipboard#Error']() ---@type string health.error( error_message, "Use the example in :help g:clipboard as a template, or don't set g:clipboard at all." @@ -179,7 +179,7 @@ local function node() ) end - local node_detect_table = vim.fn['provider#node#Detect']() + local node_detect_table = vim.fn['provider#node#Detect']() ---@type string[] local host = node_detect_table[1] if host:find('^%s*$') then health.warn('Missing "neovim" npm (or yarn, pnpm) package.', { @@ -290,7 +290,7 @@ local function perl() elseif latest_cpan[1] == '!' then local cpanm_errs = vim.split(latest_cpan, '!') if cpanm_errs[1]:find("Can't write to ") then - local advice = {} + local advice = {} ---@type string[] for i = 2, #cpanm_errs do advice[#advice + 1] = cpanm_errs[i] end @@ -303,7 +303,7 @@ local function perl() return end end - latest_cpan = vim.fn.matchstr(latest_cpan, [[\(\.\?\d\)\+]]) + latest_cpan = tostring(vim.fn.matchstr(latest_cpan, [[\(\.\?\d\)\+]])) if latest_cpan:find('^%s*$') then health.error('Cannot parse version number from cpanm output: ' .. latest_cpan) return @@ -349,9 +349,11 @@ local function python_exepath(invocation) return vim.fs.normalize(vim.trim(p.stdout)) end --- Check if pyenv is available and a valid pyenv root can be found, then return --- their respective paths. If either of those is invalid, return two empty --- strings, effectively ignoring pyenv. +--- Check if pyenv is available and a valid pyenv root can be found, then return +--- their respective paths. If either of those is invalid, return two empty +--- strings, effectively ignoring pyenv. +--- +--- @return {[1]: string, [2]: string} local function check_for_pyenv() local pyenv_path = vim.fn.resolve(vim.fn.exepath('pyenv')) @@ -394,7 +396,9 @@ local function check_bin(bin) return true end --- Fetch the contents of a URL. +--- Fetch the contents of a URL. +--- +--- @param url string local function download(url) local has_curl = vim.fn.executable('curl') == 1 if has_curl and vim.fn.system({ 'curl', '-V' }):find('Protocols:.*https') then @@ -429,25 +433,24 @@ local function download(url) return message end --- Get the latest Nvim Python client (pynvim) version from PyPI. +--- Get the latest Nvim Python client (pynvim) version from PyPI. local function latest_pypi_version() local pypi_version = 'unable to get pypi response' local pypi_response = download('https://pypi.python.org/pypi/pynvim/json') if pypi_response ~= '' then local pcall_ok, output = pcall(vim.fn.json_decode, pypi_response) - local pypi_data - if pcall_ok then - pypi_data = output - else + if not pcall_ok then return 'error: ' .. pypi_response end + local pypi_data = output local pypi_element = pypi_data['info'] or {} pypi_version = pypi_element['version'] or 'unable to parse' end return pypi_version end +--- @param s string local function is_bad_response(s) local lower = s:lower() return vim.startswith(lower, 'unable') @@ -455,16 +458,18 @@ local function is_bad_response(s) or vim.startswith(lower, 'outdated') end --- Get version information using the specified interpreter. The interpreter is --- used directly in case breaking changes were introduced since the last time --- Nvim's Python client was updated. --- --- Returns: { --- {python executable version}, --- {current nvim version}, --- {current pypi nvim status}, --- {installed version status} --- } +--- Get version information using the specified interpreter. The interpreter is +--- used directly in case breaking changes were introduced since the last time +--- Nvim's Python client was updated. +--- +--- @param python string +--- +--- Returns: { +--- {python executable version}, +--- {current nvim version}, +--- {current pypi nvim status}, +--- {installed version status} +--- } local function version_info(python) local pypi_version = latest_pypi_version() @@ -512,9 +517,9 @@ local function version_info(python) if rc ~= 0 or nvim_version == '' then nvim_version = 'unable to find pynvim module version' local base = vim.fs.basename(nvim_path) - local metas = vim.fn.glob(base .. '-*/METADATA', 1, 1) - vim.list_extend(metas, vim.fn.glob(base .. '-*/PKG-INFO', 1, 1)) - vim.list_extend(metas, vim.fn.glob(base .. '.egg-info/PKG-INFO', 1, 1)) + local metas = vim.fn.glob(base .. '-*/METADATA', true, 1) + vim.list_extend(metas, vim.fn.glob(base .. '-*/PKG-INFO', true, 1)) + vim.list_extend(metas, vim.fn.glob(base .. '.egg-info/PKG-INFO', true, 1)) metas = table.sort(metas, compare) if metas and next(metas) ~= nil then @@ -544,14 +549,13 @@ end local function python() health.start('Python 3 provider (optional)') - local pyname = 'python3' ---@type string? local python_exe = '' local virtual_env = os.getenv('VIRTUAL_ENV') local venv = virtual_env and vim.fn.resolve(virtual_env) or '' - local host_prog_var = pyname .. '_host_prog' - local python_multiple = {} + local host_prog_var = 'python3_host_prog' + local python_multiple = {} ---@type string[] - if provider_disabled(pyname) then + if provider_disabled('python3') then return end @@ -564,8 +568,7 @@ local function python() health.info(message) end - local pythonx_warnings - pyname, pythonx_warnings = vim.provider.python.detect_by_module('neovim') + local pyname, pythonx_warnings = vim.provider.python.detect_by_module('neovim') if not pyname then health.warn( @@ -653,12 +656,7 @@ local function python() ) health.warn('pyenv is not set up optimally.', advice) elseif venv ~= '' then - local venv_root - if pyenv_root ~= '' then - venv_root = pyenv_root - else - venv_root = vim.fs.dirname(venv) - end + local venv_root = pyenv_root ~= '' and pyenv_root or vim.fs.dirname(venv) if vim.startswith(vim.fn.resolve(python_exe), venv_root .. '/') then local advice = string.format( @@ -743,9 +741,9 @@ local function python() health.ok('no $VIRTUAL_ENV') return end - local errors = {} + local errors = {} ---@type string[] -- Keep hints as dict keys in order to discard duplicates. - local hints = {} + local hints = {} ---@type table -- The virtualenv should contain some Python executables, and those -- executables should be first both on Nvim's $PATH and the $PATH of -- subshells launched from Nvim. diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua index e238fee5f8..722efc489f 100644 --- a/scripts/gen_help_html.lua +++ b/scripts/gen_help_html.lua @@ -1372,7 +1372,7 @@ function M.validate(help_dir, include, parser_path) parser_path = parser_path and vim.fn.expand(parser_path) or nil for _, f in ipairs(helpfiles) do - local helpfile = assert(vim.fs.basename(f)) + local helpfile = vim.fs.basename(f) local rv = validate_one(f, parser_path) print(('validated (%-4s errors): %s'):format(#rv.parse_errors, helpfile)) if #rv.parse_errors > 0 then @@ -1430,7 +1430,7 @@ end --- :help files, we can be precise about the tolerances here. --- @param help_dir? string e.g. '$VIMRUNTIME/doc' or './runtime/doc' function M.test_gen(help_dir) - local tmpdir = assert(vim.fs.dirname(vim.fn.tempname())) + local tmpdir = vim.fs.dirname(vim.fn.tempname()) help_dir = vim.fn.expand(help_dir or '$VIMRUNTIME/doc') print('doc path = ' .. vim.uv.fs_realpath(help_dir)) diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua index 9c6225efc3..b88bdff99b 100755 --- a/scripts/gen_vimdoc.lua +++ b/scripts/gen_vimdoc.lua @@ -813,7 +813,7 @@ local function get_script_path() end local script_path = get_script_path() -local base_dir = vim.fs.dirname(assert(vim.fs.dirname(script_path))) +local base_dir = vim.fs.dirname(vim.fs.dirname(script_path)) local function delete_lines_below(doc_file, tokenstr) local lines = {} --- @type string[] @@ -965,7 +965,7 @@ local function gen_target(cfg) end end -- FIXME: Using f_base will confuse `_meta/protocol.lua` with `protocol.lua` - local f_base = assert(vim.fs.basename(f)) + local f_base = vim.fs.basename(f) sections[f_base] = make_section(f_base, cfg, briefs_txt, funs_txt) end diff --git a/scripts/luacats_parser.lua b/scripts/luacats_parser.lua index cb301b32e4..66fe8ed616 100644 --- a/scripts/luacats_parser.lua +++ b/scripts/luacats_parser.lua @@ -458,7 +458,7 @@ local function dump_uncommitted(filename, uncommitted) local out_path = 'luacats-uncommited/' .. filename:gsub('/', '%%') .. '.txt' if #uncommitted > 0 then print(string.format('Could not commit %d objects in %s', #uncommitted, filename)) - vim.fn.mkdir(assert(vim.fs.dirname(out_path)), 'p') + vim.fn.mkdir(vim.fs.dirname(out_path), 'p') local f = assert(io.open(out_path, 'w')) for i, x in ipairs(uncommitted) do f:write(i) diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f0c8963459..ceaba11f41 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -2133,6 +2133,7 @@ M.funcs = { name = 'exepath', params = { { 'expr', 'any' } }, signature = 'exepath({expr})', + returns = 'string', }, exists = { args = 1, -- cgit From ff097f2091e7a970e5b12960683b4dade5563040 Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sun, 4 Feb 2024 14:13:23 -0800 Subject: feat(lsp): completion side effects --- runtime/doc/lsp.txt | 26 + runtime/doc/news.txt | 3 +- runtime/lua/vim/lsp.lua | 5 +- runtime/lua/vim/lsp/_completion.lua | 276 ---------- runtime/lua/vim/lsp/client.lua | 23 +- runtime/lua/vim/lsp/completion.lua | 734 +++++++++++++++++++++++++ runtime/lua/vim/lsp/handlers.lua | 2 +- runtime/lua/vim/lsp/protocol.lua | 10 +- scripts/gen_vimdoc.lua | 1 + test/functional/plugin/lsp/completion_spec.lua | 5 +- 10 files changed, 789 insertions(+), 296 deletions(-) delete mode 100644 runtime/lua/vim/lsp/_completion.lua create mode 100644 runtime/lua/vim/lsp/completion.lua diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 50fffca497..0e165e6f54 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1604,6 +1604,32 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()* • {client_id} (`integer`) +============================================================================== +Lua module: vim.lsp.completion *lsp-completion* + +*vim.lsp.completion.BufferOpts* + + Fields: ~ + • {autotrigger}? (`boolean`) Whether to trigger completion + automatically. Default: false + + + *vim.lsp.completion.enable()* +enable({enable}, {client_id}, {bufnr}, {opts}) + Enables or disables completions from the given language client in the + given buffer. + + Parameters: ~ + • {enable} (`boolean`) True to enable, false to disable + • {client_id} (`integer`) Client ID + • {bufnr} (`integer`) Buffer handle, or 0 for the current buffer + • {opts} (`vim.lsp.completion.BufferOpts?`) See + |vim.lsp.completion.BufferOpts|. + +trigger() *vim.lsp.completion.trigger()* + Trigger LSP completion in the current buffer. + + ============================================================================== Lua module: vim.lsp.inlay_hint *lsp-inlay_hint* diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 708e127136..439316f62e 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -95,7 +95,8 @@ EVENTS LSP -• TODO +• Completion side effects (including snippet expansion, execution of commands + and application of additional text edits) is now built-in. LUA diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 1592fd3151..da3d4d91f2 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -3,7 +3,6 @@ local validate = vim.validate local lsp = vim._defer_require('vim.lsp', { _changetracking = ..., --- @module 'vim.lsp._changetracking' - _completion = ..., --- @module 'vim.lsp._completion' _dynamic = ..., --- @module 'vim.lsp._dynamic' _snippet_grammar = ..., --- @module 'vim.lsp._snippet_grammar' _tagfunc = ..., --- @module 'vim.lsp._tagfunc' @@ -11,6 +10,7 @@ local lsp = vim._defer_require('vim.lsp', { buf = ..., --- @module 'vim.lsp.buf' client = ..., --- @module 'vim.lsp.client' codelens = ..., --- @module 'vim.lsp.codelens' + completion = ..., --- @module 'vim.lsp.completion' diagnostic = ..., --- @module 'vim.lsp.diagnostic' handlers = ..., --- @module 'vim.lsp.handlers' inlay_hint = ..., --- @module 'vim.lsp.inlay_hint' @@ -1002,8 +1002,7 @@ end --- - findstart=0: column where the completion starts, or -2 or -3 --- - findstart=1: list of matches (actually just calls |complete()|) function lsp.omnifunc(findstart, base) - log.debug('omnifunc.findstart', { findstart = findstart, base = base }) - return vim.lsp._completion.omnifunc(findstart, base) + return vim.lsp.completion._omnifunc(findstart, base) end --- @class vim.lsp.formatexpr.Opts diff --git a/runtime/lua/vim/lsp/_completion.lua b/runtime/lua/vim/lsp/_completion.lua deleted file mode 100644 index a169f96565..0000000000 --- a/runtime/lua/vim/lsp/_completion.lua +++ /dev/null @@ -1,276 +0,0 @@ -local M = {} -local api = vim.api -local lsp = vim.lsp -local protocol = lsp.protocol -local ms = protocol.Methods - ---- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] - --- TODO(mariasolos): Remove this declaration once we figure out a better way to handle --- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). ---- @class lsp.ItemDefaults ---- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil ---- @field insertTextFormat lsp.InsertTextFormat? ---- @field insertTextMode lsp.InsertTextMode? ---- @field data any - ----@param input string unparsed snippet ----@return string parsed snippet -local function parse_snippet(input) - local ok, parsed = pcall(function() - return vim.lsp._snippet_grammar.parse(input) - end) - return ok and tostring(parsed) or input -end - ---- Returns text that should be inserted when selecting completion item. The ---- precedence is as follows: textEdit.newText > insertText > label ---- ---- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion ---- ----@param item lsp.CompletionItem ----@return string -local function get_completion_word(item) - if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.textEdit.newText - else - return parse_snippet(item.textEdit.newText) - end - elseif item.insertText ~= nil and item.insertText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.insertText - else - return parse_snippet(item.insertText) - end - end - return item.label -end - ---- Applies the given defaults to the completion item, modifying it in place. ---- ---- @param item lsp.CompletionItem ---- @param defaults lsp.ItemDefaults? -local function apply_defaults(item, defaults) - if not defaults then - return - end - - item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat - item.insertTextMode = item.insertTextMode or defaults.insertTextMode - item.data = item.data or defaults.data - if defaults.editRange then - local textEdit = item.textEdit or {} - item.textEdit = textEdit - textEdit.newText = textEdit.newText or item.textEditText or item.insertText - if defaults.editRange.start then - textEdit.range = textEdit.range or defaults.editRange - elseif defaults.editRange.insert then - textEdit.insert = defaults.editRange.insert - textEdit.replace = defaults.editRange.replace - end - end -end - ----@param result vim.lsp.CompletionResult ----@return lsp.CompletionItem[] -local function get_items(result) - if result.items then - for _, item in ipairs(result.items) do - ---@diagnostic disable-next-line: param-type-mismatch - apply_defaults(item, result.itemDefaults) - end - return result.items - else - return result - end -end - ---- Turns the result of a `textDocument/completion` request into vim-compatible ---- |complete-items|. ---- ----@param result vim.lsp.CompletionResult Result of `textDocument/completion` ----@param prefix string prefix to filter the completion items ----@return table[] ----@see complete-items -function M._lsp_to_complete_items(result, prefix) - local items = get_items(result) - if vim.tbl_isempty(items) then - return {} - end - - local function matches_prefix(item) - return vim.startswith(get_completion_word(item), prefix) - end - - items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] - table.sort(items, function(a, b) - return (a.sortText or a.label) < (b.sortText or b.label) - end) - - local matches = {} - for _, item in ipairs(items) do - local info = '' - local documentation = item.documentation - if documentation then - if type(documentation) == 'string' and documentation ~= '' then - info = documentation - elseif type(documentation) == 'table' and type(documentation.value) == 'string' then - info = documentation.value - else - vim.notify( - ('invalid documentation value %s'):format(vim.inspect(documentation)), - vim.log.levels.WARN - ) - end - end - local word = get_completion_word(item) - table.insert(matches, { - word = word, - abbr = item.label, - kind = protocol.CompletionItemKind[item.kind] or 'Unknown', - menu = item.detail or '', - info = #info > 0 and info or nil, - icase = 1, - dup = 1, - empty = 1, - user_data = { - nvim = { - lsp = { - completion_item = item, - }, - }, - }, - }) - end - return matches -end - ----@param lnum integer 0-indexed ----@param items lsp.CompletionItem[] -local function adjust_start_col(lnum, line, items, encoding) - local min_start_char = nil - for _, item in pairs(items) do - if item.textEdit and item.textEdit.range.start.line == lnum then - if min_start_char and min_start_char ~= item.textEdit.range.start.character then - return nil - end - min_start_char = item.textEdit.range.start.character - end - end - if min_start_char then - return vim.lsp.util._str_byteindex_enc(line, min_start_char, encoding) - else - return nil - end -end - ----@private ----@param line string line content ----@param lnum integer 0-indexed line number ----@param client_start_boundary integer 0-indexed word boundary ----@param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character ----@param result vim.lsp.CompletionResult ----@param encoding string ----@return table[] matches ----@return integer? server_start_boundary -function M._convert_results( - line, - lnum, - cursor_col, - client_start_boundary, - server_start_boundary, - result, - encoding -) - -- Completion response items may be relative to a position different than `client_start_boundary`. - -- Concrete example, with lua-language-server: - -- - -- require('plenary.asy| - -- ▲ ▲ ▲ - -- │ │ └── cursor_pos: 20 - -- │ └────── client_start_boundary: 17 - -- └────────────── textEdit.range.start.character: 9 - -- .newText = 'plenary.async' - -- ^^^ - -- prefix (We'd remove everything not starting with `asy`, - -- so we'd eliminate the `plenary.async` result - -- - -- `adjust_start_col` is used to prefer the language server boundary. - -- - local candidates = get_items(result) - local curstartbyte = adjust_start_col(lnum, line, candidates, encoding) - if server_start_boundary == nil then - server_start_boundary = curstartbyte - elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then - server_start_boundary = client_start_boundary - end - local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col) - local matches = M._lsp_to_complete_items(result, prefix) - return matches, server_start_boundary -end - ----@param findstart integer 0 or 1, decides behavior ----@param base integer findstart=0, text to match against ----@return integer|table Decided by {findstart}: ---- - findstart=0: column where the completion starts, or -2 or -3 ---- - findstart=1: list of matches (actually just calls |complete()|) -function M.omnifunc(findstart, base) - assert(base) -- silence luals - local bufnr = api.nvim_get_current_buf() - local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) - local remaining = #clients - if remaining == 0 then - return findstart == 1 and -1 or {} - end - - local win = api.nvim_get_current_win() - local cursor = api.nvim_win_get_cursor(win) - local lnum = cursor[1] - 1 - local cursor_col = cursor[2] - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) - local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] - local server_start_boundary = nil - local items = {} - - local function on_done() - local mode = api.nvim_get_mode()['mode'] - if mode == 'i' or mode == 'ic' then - vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) - end - end - - local util = vim.lsp.util - for _, client in ipairs(clients) do - local params = util.make_position_params(win, client.offset_encoding) - client.request(ms.textDocument_completion, params, function(err, result) - if err then - vim.lsp.log.warn(err.message) - end - if result and vim.fn.mode() == 'i' then - local matches - matches, server_start_boundary = M._convert_results( - line, - lnum, - cursor_col, - client_start_boundary, - server_start_boundary, - result, - client.offset_encoding - ) - vim.list_extend(items, matches) - end - remaining = remaining - 1 - if remaining == 0 then - vim.schedule(on_done) - end - end, bufnr) - end - - -- Return -2 to signal that we should continue completion so that we can - -- async complete. - return -2 -end - -return M diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 4beb7fefda..c8616bf728 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -869,7 +869,8 @@ end --- @param command lsp.Command --- @param context? {bufnr: integer} --- @param handler? lsp.Handler only called if a server command -function Client:_exec_cmd(command, context, handler) +--- @param on_unsupported? function handler invoked when the command is not supported by the client. +function Client:_exec_cmd(command, context, handler, on_unsupported) context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]] context.bufnr = context.bufnr or api.nvim_get_current_buf() context.client_id = self.id @@ -883,14 +884,18 @@ function Client:_exec_cmd(command, context, handler) local command_provider = self.server_capabilities.executeCommandProvider local commands = type(command_provider) == 'table' and command_provider.commands or {} if not vim.list_contains(commands, cmdname) then - vim.notify_once( - string.format( - 'Language server `%s` does not support command `%s`. This command may require a client extension.', - self.name, - cmdname - ), - vim.log.levels.WARN - ) + if on_unsupported then + on_unsupported() + else + vim.notify_once( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + self.name, + cmdname + ), + vim.log.levels.WARN + ) + end return end -- Not using command directly to exclude extra properties, diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua new file mode 100644 index 0000000000..25b3d53c8c --- /dev/null +++ b/runtime/lua/vim/lsp/completion.lua @@ -0,0 +1,734 @@ +local M = {} + +local api = vim.api +local lsp = vim.lsp +local protocol = lsp.protocol +local ms = protocol.Methods + +local rtt_ms = 50 +local ns_to_ms = 0.000001 + +--- @alias vim.lsp.CompletionResult lsp.CompletionList | lsp.CompletionItem[] + +-- TODO(mariasolos): Remove this declaration once we figure out a better way to handle +-- literal/anonymous types (see https://github.com/neovim/neovim/pull/27542/files#r1495259331). +--- @nodoc +--- @class lsp.ItemDefaults +--- @field editRange lsp.Range | { insert: lsp.Range, replace: lsp.Range } | nil +--- @field insertTextFormat lsp.InsertTextFormat? +--- @field insertTextMode lsp.InsertTextMode? +--- @field data any + +--- @nodoc +--- @class vim.lsp.completion.BufHandle +--- @field clients table +--- @field triggers table + +--- @type table +local buf_handles = {} + +--- @nodoc +--- @class vim.lsp.completion.Context +local Context = { + cursor = nil, --- @type { [1]: integer, [2]: integer }? + last_request_time = nil, --- @type integer? + pending_requests = {}, --- @type function[] + isIncomplete = false, +} + +--- @nodoc +function Context:cancel_pending() + for _, cancel in ipairs(self.pending_requests) do + cancel() + end + + self.pending_requests = {} +end + +--- @nodoc +function Context:reset() + -- Note that the cursor isn't reset here, it needs to survive a `CompleteDone` event. + self.isIncomplete = false + self.last_request_time = nil + self:cancel_pending() +end + +--- @type uv.uv_timer_t? +local completion_timer = nil + +--- @return uv.uv_timer_t +local function new_timer() + return assert(vim.uv.new_timer()) +end + +local function reset_timer() + if completion_timer then + completion_timer:stop() + completion_timer:close() + end + + completion_timer = nil +end + +--- @param window integer +--- @param warmup integer +--- @return fun(sample: number): number +local function exp_avg(window, warmup) + local count = 0 + local sum = 0 + local value = 0 + + return function(sample) + if count < warmup then + count = count + 1 + sum = sum + sample + value = sum / count + else + local factor = 2.0 / (window + 1) + value = value * (1 - factor) + sample * factor + end + return value + end +end +local compute_new_average = exp_avg(10, 10) + +--- @return number +local function next_debounce() + if not Context.last_request_time then + return rtt_ms + end + + local ms_since_request = (vim.uv.hrtime() - Context.last_request_time) * ns_to_ms + return math.max((ms_since_request - rtt_ms) * -1, 0) +end + +--- @param input string Unparsed snippet +--- @return string # Parsed snippet if successful, else returns its input +local function parse_snippet(input) + local ok, parsed = pcall(function() + return lsp._snippet_grammar.parse(input) + end) + return ok and tostring(parsed) or input +end + +--- @param item lsp.CompletionItem +--- @param suffix? string +local function apply_snippet(item, suffix) + if item.textEdit then + vim.snippet.expand(item.textEdit.newText .. suffix) + elseif item.insertText then + vim.snippet.expand(item.insertText .. suffix) + end +end + +--- Returns text that should be inserted when a selecting completion item. The +--- precedence is as follows: textEdit.newText > insertText > label +--- +--- See https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--- +--- @param item lsp.CompletionItem +--- @return string +local function get_completion_word(item) + if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then + if item.insertTextFormat == protocol.InsertTextFormat.PlainText then + return item.textEdit.newText + else + return parse_snippet(item.textEdit.newText) + end + elseif item.insertText ~= nil and item.insertText ~= '' then + if item.insertTextFormat == protocol.InsertTextFormat.PlainText then + return item.insertText + else + return parse_snippet(item.insertText) + end + end + return item.label +end + +--- Applies the given defaults to the completion item, modifying it in place. +--- +--- @param item lsp.CompletionItem +--- @param defaults lsp.ItemDefaults? +local function apply_defaults(item, defaults) + if not defaults then + return + end + + item.insertTextFormat = item.insertTextFormat or defaults.insertTextFormat + item.insertTextMode = item.insertTextMode or defaults.insertTextMode + item.data = item.data or defaults.data + if defaults.editRange then + local textEdit = item.textEdit or {} + item.textEdit = textEdit + textEdit.newText = textEdit.newText or item.textEditText or item.insertText + if defaults.editRange.start then + textEdit.range = textEdit.range or defaults.editRange + elseif defaults.editRange.insert then + textEdit.insert = defaults.editRange.insert + textEdit.replace = defaults.editRange.replace + end + end +end + +--- @param result vim.lsp.CompletionResult +--- @return lsp.CompletionItem[] +local function get_items(result) + if result.items then + -- When we have a list, apply the defaults and return an array of items. + for _, item in ipairs(result.items) do + ---@diagnostic disable-next-line: param-type-mismatch + apply_defaults(item, result.itemDefaults) + end + return result.items + else + -- Else just return the items as they are. + return result + end +end + +--- Turns the result of a `textDocument/completion` request into vim-compatible +--- |complete-items|. +--- +--- @private +--- @param result vim.lsp.CompletionResult Result of `textDocument/completion` +--- @param prefix string prefix to filter the completion items +--- @param client_id integer? Client ID +--- @return table[] +--- @see complete-items +function M._lsp_to_complete_items(result, prefix, client_id) + local items = get_items(result) + if vim.tbl_isempty(items) then + return {} + end + + local function matches_prefix(item) + return vim.startswith(get_completion_word(item), prefix) + end + + items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] + table.sort(items, function(a, b) + return (a.sortText or a.label) < (b.sortText or b.label) + end) + + local matches = {} + for _, item in ipairs(items) do + local info = '' + local documentation = item.documentation + if documentation then + if type(documentation) == 'string' and documentation ~= '' then + info = documentation + elseif type(documentation) == 'table' and type(documentation.value) == 'string' then + info = documentation.value + else + vim.notify( + ('invalid documentation value %s'):format(vim.inspect(documentation)), + vim.log.levels.WARN + ) + end + end + local word = get_completion_word(item) + table.insert(matches, { + word = word, + abbr = item.label, + kind = protocol.CompletionItemKind[item.kind] or 'Unknown', + menu = item.detail or '', + info = #info > 0 and info or '', + icase = 1, + dup = 1, + empty = 1, + user_data = { + nvim = { + lsp = { + completion_item = item, + client_id = client_id, + }, + }, + }, + }) + end + return matches +end + +--- @param lnum integer 0-indexed +--- @param line string +--- @param items lsp.CompletionItem[] +--- @param encoding string +--- @return integer? +local function adjust_start_col(lnum, line, items, encoding) + local min_start_char = nil + for _, item in pairs(items) do + if item.textEdit and item.textEdit.range.start.line == lnum then + if min_start_char and min_start_char ~= item.textEdit.range.start.character then + return nil + end + min_start_char = item.textEdit.range.start.character + end + end + if min_start_char then + return lsp.util._str_byteindex_enc(line, min_start_char, encoding) + else + return nil + end +end + +--- @private +--- @param line string line content +--- @param lnum integer 0-indexed line number +--- @param cursor_col integer +--- @param client_id integer client ID +--- @param client_start_boundary integer 0-indexed word boundary +--- @param server_start_boundary? integer 0-indexed word boundary, based on textEdit.range.start.character +--- @param result vim.lsp.CompletionResult +--- @param encoding string +--- @return table[] matches +--- @return integer? server_start_boundary +function M._convert_results( + line, + lnum, + cursor_col, + client_id, + client_start_boundary, + server_start_boundary, + result, + encoding +) + -- Completion response items may be relative to a position different than `client_start_boundary`. + -- Concrete example, with lua-language-server: + -- + -- require('plenary.asy| + -- ▲ ▲ ▲ + -- │ │ └── cursor_pos: 20 + -- │ └────── client_start_boundary: 17 + -- └────────────── textEdit.range.start.character: 9 + -- .newText = 'plenary.async' + -- ^^^ + -- prefix (We'd remove everything not starting with `asy`, + -- so we'd eliminate the `plenary.async` result + -- + -- `adjust_start_col` is used to prefer the language server boundary. + -- + local candidates = get_items(result) + local curstartbyte = adjust_start_col(lnum, line, candidates, encoding) + if server_start_boundary == nil then + server_start_boundary = curstartbyte + elseif curstartbyte ~= nil and curstartbyte ~= server_start_boundary then + server_start_boundary = client_start_boundary + end + local prefix = line:sub((server_start_boundary or client_start_boundary) + 1, cursor_col) + local matches = M._lsp_to_complete_items(result, prefix, client_id) + return matches, server_start_boundary +end + +--- Implements 'omnifunc' compatible LSP completion. +--- +--- @see |complete-functions| +--- @see |complete-items| +--- @see |CompleteDone| +--- +--- @param findstart integer 0 or 1, decides behavior +--- @param base integer findstart=0, text to match against +--- +--- @return integer|table Decided by {findstart}: +--- - findstart=0: column where the completion starts, or -2 or -3 +--- - findstart=1: list of matches (actually just calls |complete()|) +function M._omnifunc(findstart, base) + vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) + assert(base) -- silence luals + local bufnr = api.nvim_get_current_buf() + local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) + local remaining = #clients + if remaining == 0 then + return findstart == 1 and -1 or {} + end + + local win = api.nvim_get_current_win() + local cursor = api.nvim_win_get_cursor(win) + local lnum = cursor[1] - 1 + local cursor_col = cursor[2] + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] + local server_start_boundary = nil + local items = {} + + local function on_done() + local mode = api.nvim_get_mode()['mode'] + if mode == 'i' or mode == 'ic' then + vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) + end + end + + local util = vim.lsp.util + for _, client in ipairs(clients) do + local params = util.make_position_params(win, client.offset_encoding) + client.request(ms.textDocument_completion, params, function(err, result) + if err then + lsp.log.warn(err.message) + end + if result and vim.fn.mode() == 'i' then + local matches + matches, server_start_boundary = M._convert_results( + line, + lnum, + cursor_col, + client.id, + client_start_boundary, + server_start_boundary, + result, + client.offset_encoding + ) + vim.list_extend(items, matches) + end + remaining = remaining - 1 + if remaining == 0 then + vim.schedule(on_done) + end + end, bufnr) + end + + -- Return -2 to signal that we should continue completion so that we can + -- async complete. + return -2 +end + +--- @param clients table +--- @param bufnr integer +--- @param win integer +--- @param callback fun(responses: table) +--- @return function # Cancellation function +local function request(clients, bufnr, win, callback) + local responses = {} --- @type table + local request_ids = {} --- @type table + local remaining_requests = vim.tbl_count(clients) + + for client_id, client in pairs(clients) do + local params = lsp.util.make_position_params(win, client.offset_encoding) + local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result) + responses[client_id] = { err = err, result = result } + remaining_requests = remaining_requests - 1 + if remaining_requests == 0 then + callback(responses) + end + end, bufnr) + + if ok then + request_ids[client_id] = request_id + end + end + + return function() + for client_id, request_id in pairs(request_ids) do + local client = lsp.get_client_by_id(client_id) + if client then + client.cancel_request(request_id) + end + end + end +end + +--- @param handle vim.lsp.completion.BufHandle +local function on_insert_char_pre(handle) + if tonumber(vim.fn.pumvisible()) == 1 then + if Context.isIncomplete then + reset_timer() + + local debounce_ms = next_debounce() + if debounce_ms == 0 then + vim.schedule(M.trigger) + else + completion_timer = new_timer() + completion_timer:start(debounce_ms, 0, vim.schedule_wrap(M.trigger)) + end + end + + return + end + + local char = api.nvim_get_vvar('char') + if not completion_timer and handle.triggers[char] then + completion_timer = assert(vim.uv.new_timer()) + completion_timer:start(25, 0, function() + reset_timer() + vim.schedule(M.trigger) + end) + end +end + +local function on_insert_leave() + reset_timer() + Context.cursor = nil + Context:reset() +end + +local function on_complete_done() + local completed_item = api.nvim_get_vvar('completed_item') + if not completed_item or not completed_item.user_data or not completed_item.user_data.nvim then + Context:reset() + return + end + + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(0)) --- @type integer, integer + cursor_row = cursor_row - 1 + local completion_item = completed_item.user_data.nvim.lsp.completion_item --- @type lsp.CompletionItem + local client_id = completed_item.user_data.nvim.lsp.client_id --- @type integer + if not completion_item or not client_id then + Context:reset() + return + end + + local bufnr = api.nvim_get_current_buf() + local expand_snippet = completion_item.insertTextFormat == protocol.InsertTextFormat.Snippet + and (completion_item.textEdit ~= nil or completion_item.insertText ~= nil) + + Context:reset() + + local client = lsp.get_client_by_id(client_id) + if not client then + return + end + + local offset_encoding = client.offset_encoding or 'utf-16' + local resolve_provider = (client.server_capabilities.completionProvider or {}).resolveProvider + + local function clear_word() + if not expand_snippet then + return nil + end + + -- Remove the already inserted word. + local start_char = cursor_col - #completed_item.word + local line = api.nvim_buf_get_lines(bufnr, cursor_row, cursor_row + 1, true)[1] + api.nvim_buf_set_text(bufnr, cursor_row, start_char, cursor_row, #line, { '' }) + return line:sub(cursor_col + 1) + end + + --- @param suffix? string + local function apply_snippet_and_command(suffix) + if expand_snippet then + apply_snippet(completion_item, suffix) + end + + local command = completion_item.command + if command then + client:_exec_cmd(command, { bufnr = bufnr }, nil, function() + vim.lsp.log.warn( + string.format( + 'Language server `%s` does not support command `%s`. This command may require a client extension.', + client.name, + command.command + ) + ) + end) + end + end + + if completion_item.additionalTextEdits and next(completion_item.additionalTextEdits) then + local suffix = clear_word() + lsp.util.apply_text_edits(completion_item.additionalTextEdits, bufnr, offset_encoding) + apply_snippet_and_command(suffix) + elseif resolve_provider and type(completion_item) == 'table' then + local changedtick = vim.b[bufnr].changedtick + + --- @param result lsp.CompletionItem + client.request(ms.completionItem_resolve, completion_item, function(err, result) + if changedtick ~= vim.b[bufnr].changedtick then + return + end + + local suffix = clear_word() + if err then + vim.notify_once(err.message, vim.log.levels.WARN) + elseif result and result.additionalTextEdits then + lsp.util.apply_text_edits(result.additionalTextEdits, bufnr, offset_encoding) + if result.command then + completion_item.command = result.command + end + end + + apply_snippet_and_command(suffix) + end, bufnr) + else + local suffix = clear_word() + apply_snippet_and_command(suffix) + end +end + +--- @class vim.lsp.completion.BufferOpts +--- @field autotrigger? boolean Whether to trigger completion automatically. Default: false + +--- @param client_id integer +---@param bufnr integer +---@param opts vim.lsp.completion.BufferOpts +local function enable_completions(client_id, bufnr, opts) + if not buf_handles[bufnr] then + buf_handles[bufnr] = { clients = {}, triggers = {} } + + -- Attach to buffer events. + api.nvim_buf_attach(bufnr, false, { + on_detach = function(_, buf) + buf_handles[buf] = nil + end, + on_reload = function(_, buf) + M.enable(true, client_id, buf, opts) + end, + }) + + -- Set up autocommands. + local group = + api.nvim_create_augroup(string.format('vim/lsp/completion-%d', bufnr), { clear = true }) + api.nvim_create_autocmd('CompleteDone', { + group = group, + buffer = bufnr, + callback = function() + local reason = api.nvim_get_vvar('event').reason --- @type string + if reason == 'accept' then + on_complete_done() + end + end, + }) + if opts.autotrigger then + api.nvim_create_autocmd('InsertCharPre', { + group = group, + buffer = bufnr, + callback = function() + on_insert_char_pre(buf_handles[bufnr]) + end, + }) + api.nvim_create_autocmd('InsertLeave', { + group = group, + buffer = bufnr, + callback = on_insert_leave, + }) + end + end + + if not buf_handles[bufnr].clients[client_id] then + local client = lsp.get_client_by_id(client_id) + assert(client, 'invalid client ID') + + -- Add the new client to the buffer's clients. + buf_handles[bufnr].clients[client_id] = client + + -- Add the new client to the clients that should be triggered by its trigger characters. + --- @type string[] + local triggers = vim.tbl_get( + client.server_capabilities, + 'completionProvider', + 'triggerCharacters' + ) or {} + for _, char in ipairs(triggers) do + local clients_for_trigger = buf_handles[bufnr].triggers[char] + if not clients_for_trigger then + clients_for_trigger = {} + buf_handles[bufnr].triggers[char] = clients_for_trigger + end + local client_exists = vim.iter(clients_for_trigger):any(function(c) + return c.id == client_id + end) + if not client_exists then + table.insert(clients_for_trigger, client) + end + end + end +end + +--- @param client_id integer +--- @param bufnr integer +local function disable_completions(client_id, bufnr) + local handle = buf_handles[bufnr] + if not handle then + return + end + + handle.clients[client_id] = nil + if not next(handle.clients) then + buf_handles[bufnr] = nil + api.nvim_del_augroup_by_name(string.format('vim/lsp/completion-%d', bufnr)) + else + for char, clients in pairs(handle.triggers) do + --- @param c vim.lsp.Client + handle.triggers[char] = vim.tbl_filter(function(c) + return c.id ~= client_id + end, clients) + end + end +end + +--- Enables or disables completions from the given language client in the given buffer. +--- +--- @param enable boolean True to enable, false to disable +--- @param client_id integer Client ID +--- @param bufnr integer Buffer handle, or 0 for the current buffer +--- @param opts? vim.lsp.completion.BufferOpts +function M.enable(enable, client_id, bufnr, opts) + bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr + + if enable then + enable_completions(client_id, bufnr, opts or {}) + else + disable_completions(client_id, bufnr) + end +end + +--- Trigger LSP completion in the current buffer. +function M.trigger() + reset_timer() + Context:cancel_pending() + + local win = api.nvim_get_current_win() + local bufnr = api.nvim_get_current_buf() + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local clients = (buf_handles[bufnr] or {}).clients or {} + local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') + local start_time = vim.uv.hrtime() + Context.last_request_time = start_time + + local cancel_request = request(clients, bufnr, win, function(responses) + local end_time = vim.uv.hrtime() + rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) + + Context.pending_requests = {} + Context.isIncomplete = false + + local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row + local mode = api.nvim_get_mode().mode + if row_changed or not (mode == 'i' or mode == 'ic') then + return + end + + local matches = {} + local server_start_boundary --- @type integer? + for client_id, response in pairs(responses) do + if response.err then + vim.notify_once(response.err.message, vim.log.levels.warn) + end + + local result = response.result + if result then + Context.isIncomplete = Context.isIncomplete or result.isIncomplete + local client = lsp.get_client_by_id(client_id) + local encoding = client and client.offset_encoding or 'utf-16' + local client_matches + client_matches, server_start_boundary = M._convert_results( + line, + cursor_row - 1, + cursor_col, + client_id, + word_boundary, + nil, + result, + encoding + ) + vim.list_extend(matches, client_matches) + end + end + local start_col = (server_start_boundary or word_boundary) + 1 + vim.fn.complete(start_col, matches) + end) + + table.insert(Context.pending_requests, cancel_request) +end + +return M diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index f9d394642c..38c43893eb 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -3,7 +3,7 @@ local protocol = require('vim.lsp.protocol') local ms = protocol.Methods local util = require('vim.lsp.util') local api = vim.api -local completion = require('vim.lsp._completion') +local completion = require('vim.lsp.completion') --- @type table local M = {} diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 419c2ff644..8ac4cc794b 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -738,14 +738,16 @@ function protocol.make_client_capabilities() completion = { dynamicRegistration = false, completionItem = { - -- Until we can actually expand snippet, move cursor and allow for true snippet experience, - -- this should be disabled out of the box. - -- However, users can turn this back on if they have a snippet plugin. - snippetSupport = false, + snippetSupport = true, commitCharactersSupport = false, preselectSupport = false, deprecatedSupport = false, documentationFormat = { constants.MarkupKind.Markdown, constants.MarkupKind.PlainText }, + resolveSupport = { + properties = { + 'additionalTextEdits', + }, + }, }, completionItemKind = { valueSet = get_value_set(constants.CompletionItemKind), diff --git a/scripts/gen_vimdoc.lua b/scripts/gen_vimdoc.lua index 9c6225efc3..d85089116e 100755 --- a/scripts/gen_vimdoc.lua +++ b/scripts/gen_vimdoc.lua @@ -273,6 +273,7 @@ local config = { 'buf.lua', 'diagnostic.lua', 'codelens.lua', + 'completion.lua', 'inlay_hint.lua', 'tagfunc.lua', 'semantic_tokens.lua', diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 2798d57381..1052b00dae 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -21,7 +21,7 @@ local function complete(line, candidates, lnum) local line, cursor_col, lnum, result = ... local line_to_cursor = line:sub(1, cursor_col) local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local items, server_start_boundary = require("vim.lsp._completion")._convert_results( + local items, server_start_boundary = require("vim.lsp.completion")._convert_results( line, lnum, cursor_col, @@ -42,7 +42,7 @@ local function complete(line, candidates, lnum) ) end -describe('vim.lsp._completion', function() +describe('vim.lsp.completion', function() before_each(n.clear) -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion @@ -159,6 +159,7 @@ describe('vim.lsp._completion', function() end, result.items) eq(expected, result) end) + it('uses correct start boundary', function() local completion_list = { isIncomplete = false, -- cgit From 490c2109e6139c268b64c6a88f4678f7c7af51ea Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 27 Apr 2024 14:59:39 -0700 Subject: test(lsp): add completion tests --- test/functional/plugin/lsp/completion_spec.lua | 232 ++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 1 deletion(-) diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 1052b00dae..5b7232ad7e 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -1,9 +1,16 @@ ---@diagnostic disable: no-unknown local t = require('test.testutil') +local t_lsp = require('test.functional.plugin.lsp.testutil') local n = require('test.functional.testnvim')() +local clear = n.clear local eq = t.eq +local neq = t.neq local exec_lua = n.exec_lua +local feed = n.feed +local retry = t.retry + +local create_server_definition = t_lsp.create_server_definition --- Convert completion results. --- @@ -25,6 +32,7 @@ local function complete(line, candidates, lnum) line, lnum, cursor_col, + 1, client_start_boundary, nil, result, @@ -42,7 +50,7 @@ local function complete(line, candidates, lnum) ) end -describe('vim.lsp.completion', function() +describe('vim.lsp.completion: item conversion', function() before_each(n.clear) -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion @@ -187,6 +195,7 @@ describe('vim.lsp.completion', function() dup = 1, empty = 1, icase = 1, + info = '', kind = 'Module', menu = '', word = 'this_thread', @@ -241,6 +250,7 @@ describe('vim.lsp.completion', function() dup = 1, empty = 1, icase = 1, + info = '', kind = 'Module', menu = '', word = 'this_thread', @@ -279,4 +289,224 @@ describe('vim.lsp.completion', function() eq('item-property-has-priority', item.data) eq({ line = 1, character = 1 }, item.textEdit.range.start) end) + + it( + 'uses insertText as textEdit.newText if there are editRange defaults but no textEditText', + function() + --- @type lsp.CompletionList + local completion_list = { + isIncomplete = false, + itemDefaults = { + editRange = { + start = { line = 1, character = 1 }, + ['end'] = { line = 1, character = 4 }, + }, + insertTextFormat = 2, + data = 'foobar', + }, + items = { + { + insertText = 'the-insertText', + label = 'hello', + data = 'item-property-has-priority', + }, + }, + } + local result = complete('|', completion_list) + eq(1, #result.items) + local text = result.items[1].user_data.nvim.lsp.completion_item.textEdit.newText + eq('the-insertText', text) + end + ) +end) + +describe('vim.lsp.completion: protocol', function() + before_each(function() + clear() + exec_lua(create_server_definition) + exec_lua([[ + _G.capture = {} + vim.fn.complete = function(col, matches) + _G.capture.col = col + _G.capture.matches = matches + end + ]]) + end) + + after_each(clear) + + --- @param completion_result lsp.CompletionList + --- @return integer + local function create_server(completion_result) + return exec_lua( + [[ + local result = ... + local server = _create_server({ + capabilities = { + completionProvider = { + triggerCharacters = { '.' } + } + }, + handlers = { + ['textDocument/completion'] = function(_, _, callback) + callback(nil, result) + end + } + }) + + bufnr = vim.api.nvim_get_current_buf() + vim.api.nvim_win_set_buf(0, bufnr) + return vim.lsp.start({ name = 'dummy', cmd = server.cmd, on_attach = function(client, bufnr) + vim.lsp.completion.enable(true, client.id, bufnr) + end}) + ]], + completion_result + ) + end + + local function assert_matches(fn) + retry(nil, nil, function() + fn(exec_lua('return _G.capture.matches')) + end) + end + + --- @param pos { [1]: integer, [2]: integer } + local function trigger_at_pos(pos) + exec_lua( + [[ + local win = vim.api.nvim_get_current_win() + vim.api.nvim_win_set_cursor(win, ...) + vim.lsp.completion.trigger() + ]], + pos + ) + + retry(nil, nil, function() + neq(nil, exec_lua('return _G.capture.col')) + end) + end + + it('fetches completions and shows them using complete on trigger', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'hello', + }, + }, + }) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + assert_matches(function(matches) + eq({ + { + abbr = 'hello', + dup = 1, + empty = 1, + icase = 1, + info = '', + kind = 'Unknown', + menu = '', + user_data = { + nvim = { + lsp = { + client_id = 1, + completion_item = { + label = 'hello', + }, + }, + }, + }, + word = 'hello', + }, + }, matches) + end) + end) + + it('merges results from multiple clients', function() + create_server({ + isIncomplete = false, + items = { + { + label = 'hello', + }, + }, + }) + create_server({ + isIncomplete = false, + items = { + { + label = 'hallo', + }, + }, + }) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + assert_matches(function(matches) + eq(2, #matches) + eq('hello', matches[1].word) + eq('hallo', matches[2].word) + end) + end) + + it('executes commands', function() + local completion_list = { + isIncomplete = false, + items = { + { + label = 'hello', + command = { + arguments = { '1', '0' }, + command = 'dummy', + title = '', + }, + }, + }, + } + local client_id = create_server(completion_list) + + exec_lua( + [[ + _G.called = false + local client = vim.lsp.get_client_by_id(...) + client.commands.dummy = function () + _G.called = true + end + ]], + client_id + ) + + feed('ih') + trigger_at_pos({ 1, 1 }) + + exec_lua( + [[ + local client_id, item = ... + vim.v.completed_item = { + user_data = { + nvim = { + lsp = { + client_id = client_id, + completion_item = item + } + } + } + } + ]], + client_id, + completion_list.items[1] + ) + + feed('') + + assert_matches(function(matches) + eq(1, #matches) + eq('hello', matches[1].word) + eq(true, exec_lua('return _G.called')) + end) + end) end) -- cgit From 7b16c1fa8451880c72769f6d3c311f24c74f4fc7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 May 2024 06:39:07 +0800 Subject: fix(runtime): source c ftplugin properly for cpp on Windows (#29053) On Windows, '{' is currently not treated as a wildcard char, so another wildcard char is needed for the pattern to be treated as a wildcard. It may be worth trying to make '{' always a wildcard char in the future, but that'll be a bit harder as it'll be necessary to make sure '{' is escaped at various places. --- runtime/ftplugin/cpp.vim | 3 ++- test/functional/lua/runtime_spec.lua | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/runtime/ftplugin/cpp.vim b/runtime/ftplugin/cpp.vim index d4931a2533..5cdad8fdc8 100644 --- a/runtime/ftplugin/cpp.vim +++ b/runtime/ftplugin/cpp.vim @@ -10,7 +10,8 @@ if exists("b:did_ftplugin") endif " Behaves mostly just like C -runtime! ftplugin/c.{vim,lua} ftplugin/c_*.{vim,lua} ftplugin/c/*.{vim,lua} +" XXX: "[.]" in the first pattern makes it a wildcard on Windows +runtime! ftplugin/c[.]{vim,lua} ftplugin/c_*.{vim,lua} ftplugin/c/*.{vim,lua} " C++ uses templates with " Disabled, because it gives an error for typing an unmatched ">". diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index 4adce42c3e..c6b0577ebe 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -401,4 +401,12 @@ describe('runtime:', function() eq('ABab', eval('g:seq')) end) end) + + it('cpp ftplugin loads c ftplugin #29053', function() + eq('', eval('&commentstring')) + eq('', eval('&omnifunc')) + exec('edit file.cpp') + eq('/*%s*/', eval('&commentstring')) + eq('ccomplete#Complete', eval('&omnifunc')) + end) end) -- cgit From 4e2c8dc37468fc06897ba26498c8b5dae7dc5a94 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 28 May 2024 14:40:09 +0800 Subject: vim-patch:0b74eec: runtime(stylus): remove remaining css code (vim/vim#14866) This seems to be a forgotten fixup in https://github.com/vim/vim/commit/2d919d2744a99c9bb9e79984e85b8e8f5ec14c07#r141568461 https://github.com/vim/vim/commit/0b74eeceb856e7a4c2823f5b6c2c2ee95a72331c --- runtime/syntax/stylus.vim | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/runtime/syntax/stylus.vim b/runtime/syntax/stylus.vim index fd0f33b65a..d8bf641e60 100644 --- a/runtime/syntax/stylus.vim +++ b/runtime/syntax/stylus.vim @@ -4,17 +4,7 @@ " Filenames: *.styl, *.stylus " Based On: Tim Pope (sass.vim) " Created: Dec 14, 2011 -" Modified: Apr 29, 2024 - -if main_syntax == "css" - syn sync minlines=10 -endif - -" let b:current_syntax = "css" -" -if main_syntax == 'css' - unlet main_syntax -endif +" Modified: May 28, 2024 syn case ignore -- cgit From 5b6477be45c54ebac4dce6bda51028542167fd1f Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Tue, 28 May 2024 11:43:56 +0200 Subject: fix(ui): flush ext_cmdline events before doing cmdpreview #27950 Problem: Unable to update the screen for external cmdline during cmdpreview. Solution: Flush the cmdline UI before cmdpreview state. --- src/nvim/ex_getln.c | 4 +++ test/functional/lua/ui_event_spec.lua | 53 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index f18dc0f747..cc2608433d 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2532,6 +2532,10 @@ static bool cmdpreview_may_show(CommandLineState *s) goto end; } + // Flush now: external cmdline may itself wish to update the screen which is + // currently disallowed during cmdpreview(no longer needed in case that changes). + cmdline_ui_flush(); + // Swap invalid command range if needed if ((ea.argt & EX_RANGE) && ea.line1 > ea.line2) { linenr_T lnum = ea.line1; diff --git a/test/functional/lua/ui_event_spec.lua b/test/functional/lua/ui_event_spec.lua index 1e80c88403..0a6deaa41c 100644 --- a/test/functional/lua/ui_event_spec.lua +++ b/test/functional/lua/ui_event_spec.lua @@ -37,6 +37,9 @@ describe('vim.ui_attach', function() [2] = { bold = true }, [3] = { background = Screen.colors.Grey }, [4] = { background = Screen.colors.LightMagenta }, + [5] = { reverse = true }, + [6] = { reverse = true, bold = true }, + [7] = { background = Screen.colors.Yellow1 }, }) screen:attach() end) @@ -188,6 +191,56 @@ describe('vim.ui_attach', function() feed('versionv') n.assert_alive() end) + + it("preserved 'incsearch/command' screen state after :redraw from ext_cmdline", function() + exec_lua([[ + vim.cmd.norm('ifoobar') + vim.cmd('1split cmdline') + local buf = vim.api.nvim_get_current_buf() + vim.cmd.wincmd('p') + vim.ui_attach(ns, { ext_cmdline = true }, function(event, ...) + if event == 'cmdline_show' then + local content = select(1, ...) + vim.api.nvim_buf_set_lines(buf, -2, -1, false, {content[1][2]}) + vim.cmd('redraw') + end + return true + end) + ]]) + -- Updates a cmdline window + feed(':cmdline') + screen:expect({ + grid = [[ + cmdline | + {5:cmdline [+] }| + fooba^r | + {6:[No Name] [+] }| + | + ]], + }) + -- Does not clear 'incsearch' highlighting + feed('/foo') + screen:expect({ + grid = [[ + foo | + {5:cmdline [+] }| + {5:foo}ba^r | + {6:[No Name] [+] }| + | + ]], + }) + -- Shows new cmdline state during 'inccommand' + feed(':%s/bar/baz') + screen:expect({ + grid = [[ + %s/bar/baz | + {5:cmdline [+] }| + foo{7:ba^z} | + {6:[No Name] [+] }| + | + ]], + }) + end) end) describe('vim.ui_attach', function() -- cgit From 90a4b1a59cf0c204cb39ec7789ab8783626e449d Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 28 May 2024 03:07:13 -0700 Subject: refactor: deprecate vim.region() #28416 Problem: `vim.region()` is redundant with `getregionpos()`. Solution: Deprecate `vim.region()`. --- runtime/doc/deprecated.txt | 2 ++ runtime/doc/lua.txt | 24 ------------------------ runtime/doc/news-0.10.txt | 2 +- runtime/lua/vim/_editor.lua | 3 +++ runtime/lua/vim/lsp/buf.lua | 2 +- 5 files changed, 7 insertions(+), 26 deletions(-) diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 646ba72bd8..be220fc307 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -19,6 +19,8 @@ API - nvim_subscribe() Plugins must maintain their own "multicast" channels list. - nvim_unsubscribe() Plugins must maintain their own "multicast" channels list. +LUA +- vim.region() Use |getregionpos()| instead. ------------------------------------------------------------------------------ DEPRECATED IN 0.10 *deprecated-0.10* diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index fd0cd3252f..36d6e0d41e 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -1708,30 +1708,6 @@ vim.print({...}) *vim.print()* • |vim.inspect()| • |:=| - *vim.region()* -vim.region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive}) - Gets a dict of line segment ("chunk") positions for the region from `pos1` - to `pos2`. - - Input and output positions are byte positions, (0,0)-indexed. "End of - line" column position (for example, |linewise| visual selection) is - returned as |v:maxcol| (big number). - - Parameters: ~ - • {bufnr} (`integer`) Buffer number, or 0 for current buffer - • {pos1} (`integer[]|string`) Start of region as a (line, column) - tuple or |getpos()|-compatible string - • {pos2} (`integer[]|string`) End of region as a (line, column) - tuple or |getpos()|-compatible string - • {regtype} (`string`) |setreg()|-style selection type - • {inclusive} (`boolean`) Controls whether the ending column is - inclusive (see also 'selection'). - - Return: ~ - (`table`) region Dict of the form `{linenr = {startcol,endcol}}`. - `endcol` is exclusive, and whole lines are returned as - `{startcol,endcol} = {0,-1}`. - vim.schedule_wrap({fn}) *vim.schedule_wrap()* Returns a function which calls {fn} via |vim.schedule()|. diff --git a/runtime/doc/news-0.10.txt b/runtime/doc/news-0.10.txt index 8a0e7e92e7..d611eee242 100644 --- a/runtime/doc/news-0.10.txt +++ b/runtime/doc/news-0.10.txt @@ -307,7 +307,7 @@ The following new features were added. a predicate function that is checked for each value. (Use |vim.list_contains()| for checking list-like tables (integer keys without gaps) for literal values.) - • |vim.region()| can use a string accepted by |getpos()| as position. + • vim.region() can use a string accepted by |getpos()| as position. • Options: • 'winfixbuf' keeps a window focused onto a specific buffer diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 5e9be509c8..9f952db4fc 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -494,6 +494,7 @@ do vim.t = make_dict_accessor('t') end +--- @deprecated --- Gets a dict of line segment ("chunk") positions for the region from `pos1` to `pos2`. --- --- Input and output positions are byte positions, (0,0)-indexed. "End of line" column @@ -507,6 +508,8 @@ end ---@return table region Dict of the form `{linenr = {startcol,endcol}}`. `endcol` is exclusive, and ---whole lines are returned as `{startcol,endcol} = {0,-1}`. function vim.region(bufnr, pos1, pos2, regtype, inclusive) + vim.deprecate('vim.region', 'vim.fn.getregionpos()', '0.13') + if not vim.api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 49833eaeec..299b68e134 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -135,7 +135,7 @@ end ---@param mode "v"|"V" ---@return table {start={row,col}, end={row,col}} using (1, 0) indexing local function range_from_selection(bufnr, mode) - -- TODO: Use `vim.region()` instead https://github.com/neovim/neovim/pull/13896 + -- TODO: Use `vim.fn.getregionpos()` instead. -- [bufnum, lnum, col, off]; both row and column 1-indexed local start = vim.fn.getpos('v') -- cgit From ff7f22c28b602c84350785624b4b6fc9ae35f950 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 28 May 2024 13:03:00 +0200 Subject: refactor(fileio): remove useless use of FileDescriptor FileDescriptor is used to buffer togheter many small writes to fewer syscalls. if the data to write already is in a single buffer, it is perfectly fine to just use os_write directly (which will take care of the reverse problem: splitting a too big write into many syscalls) --- src/nvim/main.c | 14 ++------------ src/nvim/os/fileio.c | 11 ----------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/src/nvim/main.c b/src/nvim/main.c index 17a0bbf082..cf1324d37f 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1100,23 +1100,13 @@ static void command_line_scan(mparm_T *parmp) // set stdout to binary to avoid crlf in --api-info output _setmode(STDOUT_FILENO, _O_BINARY); #endif - FileDescriptor fp; - const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, - kFileWriteOnly); - if (fof_ret != 0) { - semsg(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret)); - } String data = api_metadata_raw(); - const ptrdiff_t written_bytes = file_write(&fp, data.data, data.size); + const ptrdiff_t written_bytes = os_write(STDOUT_FILENO, data.data, data.size, false); if (written_bytes < 0) { - msgpack_file_write_error((int)written_bytes); + semsg(_("E5420: Failed to write to file: %s"), os_strerror((int)written_bytes)); } - const int ff_ret = file_flush(&fp); - if (ff_ret < 0) { - msgpack_file_write_error(ff_ret); - } os_exit(0); } else if (STRICMP(argv[0] + argv_idx, "headless") == 0) { headless_mode = true; diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index da6fb13768..fbb2be5104 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -365,14 +365,3 @@ ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) return (ptrdiff_t)read_bytes; } - -/// Print error which occurs when failing to write msgpack data -/// -/// @param[in] error Error code of the error to print. -/// -/// @return -1 (error return for msgpack_packer callbacks). -int msgpack_file_write_error(const int error) -{ - semsg(_("E5420: Failed to write to file: %s"), os_strerror(error)); - return -1; -} -- cgit From b386334cdbbc3e9d79773243fdbd53091488e14d Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 26 May 2024 11:36:18 +0200 Subject: refactor(shada): remove ShaDaReadDef secondary wrapper `FileDescriptor` is already a wrapper around an fd and a buffer. By allowing to just use the buffer without an fd, it can already handle in-memory reads. --- src/nvim/os/fileio.c | 20 +++ src/nvim/os/fileio_defs.h | 2 + src/nvim/rbuffer.c | 19 ++- src/nvim/shada.c | 310 ++++++++-------------------------- test/functional/shada/errors_spec.lua | 2 +- 5 files changed, 114 insertions(+), 239 deletions(-) diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index da6fb13768..4575c394b8 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -126,6 +126,7 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags) ret_fp->rv->data = ret_fp; ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; } + ret_fp->bytes_read = 0; return 0; } @@ -140,6 +141,18 @@ int file_open_stdin(FileDescriptor *fp) return error; } +/// opens buffer for reading +void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len) +{ + ret_fp->wr = false; + ret_fp->non_blocking = false; + ret_fp->fd = -1; + ret_fp->eof = true; + ret_fp->rv = rbuffer_new_wrap_buf(data, len); + ret_fp->_error = 0; + ret_fp->bytes_read = 0; +} + /// Close file and free its buffer /// /// @param[in,out] fp File to close. @@ -149,6 +162,11 @@ int file_open_stdin(FileDescriptor *fp) int file_close(FileDescriptor *const fp, const bool do_fsync) FUNC_ATTR_NONNULL_ALL { + if (fp->fd < 0) { + rbuffer_free(fp->rv); + return 0; + } + const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp)); const int close_error = os_close(fp->fd); rbuffer_free(fp->rv); @@ -294,6 +312,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t fp->non_blocking); if (r_ret >= 0) { read_remaining -= (size_t)r_ret; + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } else if (r_ret < 0) { return r_ret; @@ -314,6 +333,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t called_read = true; } } + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h index 3dc8c7b22a..10277d2a7a 100644 --- a/src/nvim/os/fileio_defs.h +++ b/src/nvim/os/fileio_defs.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "nvim/func_attr.h" #include "nvim/rbuffer_defs.h" @@ -13,6 +14,7 @@ typedef struct { bool wr; ///< True if file is in write mode. bool eof; ///< True if end of file was encountered. bool non_blocking; ///< True if EAGAIN should not restart syscalls. + uint64_t bytes_read; ///< total bytes read so far } FileDescriptor; static inline bool file_eof(const FileDescriptor *fp) diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index 493c079d4c..cf2e10f90d 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -29,6 +29,23 @@ RBuffer *rbuffer_new(size_t capacity) return rv; } +/// Creates a new `RBuffer` instance for reading from a buffer. +/// +/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced! +RBuffer *rbuffer_new_wrap_buf(char *data, size_t len) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET +{ + RBuffer *rv = xcalloc(1, sizeof(RBuffer)); + rv->full_cb = rv->nonfull_cb = NULL; + rv->data = NULL; + rv->size = len; + rv->read_ptr = data; + rv->write_ptr = data + len; + rv->end_ptr = NULL; + rv->temp = NULL; + return rv; +} + void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL { xfree(buf->temp); @@ -129,7 +146,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count) assert(count <= buf->size); buf->read_ptr += count; - if (buf->read_ptr >= buf->end_ptr) { + if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) { buf->read_ptr -= rbuffer_capacity(buf); } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 6f2eefeb92..597c7551fd 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -356,35 +356,6 @@ typedef struct { PMap(cstr_t) file_marks; ///< All file marks. } WriteMergerState; -typedef struct sd_read_def ShaDaReadDef; - -/// Function used to close files defined by ShaDaReadDef -typedef void (*ShaDaReadCloser)(ShaDaReadDef *const sd_reader) - REAL_FATTR_NONNULL_ALL; - -/// Function used to read ShaDa files -typedef ptrdiff_t (*ShaDaFileReader)(ShaDaReadDef *const sd_reader, - void *const dest, - const size_t size) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - -/// Function used to skip in ShaDa files -typedef int (*ShaDaFileSkipper)(ShaDaReadDef *const sd_reader, - const size_t offset) - REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; - -/// Structure containing necessary pointers for reading ShaDa files -struct sd_read_def { - ShaDaFileReader read; ///< Reader function. - ShaDaReadCloser close; ///< Close function. - ShaDaFileSkipper skip; ///< Function used to skip some bytes. - void *cookie; ///< Data describing object read from. - bool eof; ///< True if reader reached end of file. - const char *error; ///< Error message in case of error. - uintmax_t fpos; ///< Current position (amount of bytes read since - ///< reader structure initialization). May overflow. -}; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "shada.c.generated.h" #endif @@ -587,70 +558,6 @@ static inline void hmll_dealloc(HMLList *const hmll) xfree(hmll->entries); } -/// Wrapper for reading from file descriptors -/// -/// @return -1 or number of bytes read. -static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size); - sd_reader->eof = file_eof(sd_reader->cookie); - if (ret < 0) { - sd_reader->error = os_strerror((int)ret); - return -1; - } - sd_reader->fpos += (size_t)ret; - return ret; -} - -/// Read one character -static int read_char(ShaDaReadDef *const sd_reader) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - uint8_t ret; - ptrdiff_t read_bytes = sd_reader->read(sd_reader, &ret, 1); - if (read_bytes != 1) { - return EOF; - } - return (int)ret; -} - -/// Wrapper for closing file descriptors opened for reading -static void close_sd_reader(ShaDaReadDef *const sd_reader) - FUNC_ATTR_NONNULL_ALL -{ - close_file(sd_reader->cookie); - xfree(sd_reader->cookie); -} - -/// Wrapper for read that reads to IObuff and ignores bytes read -/// -/// Used for skipping. -/// -/// @param[in,out] sd_reader File read. -/// @param[in] offset Amount of bytes to skip. -/// -/// @return FAIL in case of failure, OK in case of success. May set -/// sd_reader->eof or sd_reader->error. -static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset); - if (skip_bytes < 0) { - sd_reader->error = os_strerror((int)skip_bytes); - return FAIL; - } else if (skip_bytes != (ptrdiff_t)offset) { - assert(skip_bytes < (ptrdiff_t)offset); - sd_reader->eof = file_eof(sd_reader->cookie); - if (!sd_reader->eof) { - sd_reader->error = _("too few bytes read"); - } - return FAIL; - } - sd_reader->fpos += (size_t)skip_bytes; - return OK; -} - /// Wrapper for read that can be used when lseek cannot be used /// /// E.g. when trying to read from a pipe. @@ -660,55 +567,30 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offse /// /// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or /// kSDReadStatusSuccess. -static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_t offset) +static ShaDaReadResult sd_reader_skip(FileDescriptor *const sd_reader, const size_t offset) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - if (sd_reader->skip(sd_reader, offset) != OK) { - if (sd_reader->error != NULL) { - semsg(_(SERR "System error while skipping in ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { + const ptrdiff_t skip_bytes = file_skip(sd_reader, offset); + if (skip_bytes < 0) { + semsg(_(SERR "System error while skipping in ShaDa file: %s"), + os_strerror((int)skip_bytes)); + return kSDReadStatusReadError; + } else if (skip_bytes != (ptrdiff_t)offset) { + assert(skip_bytes < (ptrdiff_t)offset); + if (file_eof(sd_reader)) { semsg(_(RCERR "Error while reading ShaDa file: " "last entry specified that it occupies %" PRIu64 " bytes, " "but file ended earlier"), (uint64_t)offset); - return kSDReadStatusNotShaDa; + } else { + semsg(_(SERR "System error while skipping in ShaDa file: %s"), + _("too few bytes read")); } - abort(); + return kSDReadStatusNotShaDa; } return kSDReadStatusSuccess; } -/// Open ShaDa file for reading -/// -/// @param[in] fname File name to open. -/// @param[out] sd_reader Location where reader structure will be saved. -/// -/// @return libuv error in case of error, 0 otherwise. -static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL -{ - *sd_reader = (ShaDaReadDef) { - .read = &read_file, - .close = &close_sd_reader, - .skip = &sd_reader_skip_read, - .error = NULL, - .eof = false, - .fpos = 0, - .cookie = xmalloc(sizeof(FileDescriptor)), - }; - int error = file_open(sd_reader->cookie, fname, kFileReadOnly, 0); - if (error) { - XFREE_CLEAR(sd_reader->cookie); - return error; - } - - assert(strcmp(p_enc, "utf-8") == 0); - - return 0; -} - /// Wrapper for closing file descriptors static void close_file(FileDescriptor *cookie) { @@ -757,8 +639,8 @@ static int shada_read_file(const char *const file, const int flags) char *const fname = shada_filename(file); - ShaDaReadDef sd_reader; - const int of_ret = open_shada_file_for_reading(fname, &sd_reader); + FileDescriptor sd_reader; + int of_ret = file_open(&sd_reader, fname, kFileReadOnly, 0); if (p_verbose > 1) { verbose_enter(); @@ -782,7 +664,7 @@ static int shada_read_file(const char *const file, const int flags) xfree(fname); shada_read(&sd_reader, flags); - sd_reader.close(&sd_reader); + close_file(&sd_reader); return OK; } @@ -1094,7 +976,7 @@ static inline bool marks_equal(const pos_T a, const pos_T b) /// /// @param[in] sd_reader Structure containing file reader definition. /// @param[in] flags What to read, see ShaDaReadFileFlags enum. -static void shada_read(ShaDaReadDef *const sd_reader, const int flags) +static void shada_read(FileDescriptor *const sd_reader, const int flags) FUNC_ATTR_NONNULL_ALL { list_T *oldfiles_list = get_vim_var_list(VV_OLDFILES); @@ -1849,13 +1731,13 @@ static int compare_file_marks(const void *a, const void *b) /// /// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or /// kSDReadStatusSuccess. -static inline ShaDaReadResult shada_parse_msgpack(ShaDaReadDef *const sd_reader, +static inline ShaDaReadResult shada_parse_msgpack(FileDescriptor *const sd_reader, const size_t length, msgpack_unpacked *ret_unpacked, char **const ret_buf) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { - const uintmax_t initial_fpos = sd_reader->fpos; + const uintmax_t initial_fpos = sd_reader->bytes_read; char *const buf = xmalloc(length); const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length); @@ -2021,7 +1903,7 @@ static const char *shada_format_pfreed_entry(const PossiblyFreedShadaEntry pfs_e /// @param[in,out] ret_wms Location where results are saved. /// @param[out] packer MessagePack packer for entries which are not /// merged. -static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_reader, +static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_reader, const unsigned srni_flags, const size_t max_kbyte, WriteMergerState *const wms, @@ -2483,7 +2365,8 @@ static int hist_type2char(const int type) /// @param[in] sd_reader Structure containing file reader definition. If it is /// not NULL then contents of this file will be merged /// with current Neovim runtime. -static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDef *const sd_reader) +static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, + FileDescriptor *const sd_reader) FUNC_ATTR_NONNULL_ARG(1) { ShaDaWriteResult ret = kSDWriteSuccessful; @@ -2958,12 +2841,13 @@ int shada_write_file(const char *const file, bool nomerge) char *const fname = shada_filename(file); char *tempname = NULL; FileDescriptor sd_writer; - ShaDaReadDef sd_reader = { .close = NULL }; + FileDescriptor sd_reader; bool did_open_writer = false; + bool did_open_reader = false; if (!nomerge) { int error; - if ((error = open_shada_file_for_reading(fname, &sd_reader)) != 0) { + if ((error = file_open(&sd_reader, fname, kFileReadOnly, 0)) != 0) { if (error != UV_ENOENT) { semsg(_(SERR "System error while opening ShaDa file %s for reading " "to merge before writing it: %s"), @@ -2973,6 +2857,8 @@ int shada_write_file(const char *const file, bool nomerge) } nomerge = true; goto shada_write_file_nomerge; + } else { + did_open_reader = true; } tempname = modname(fname, ".tmp.a", false); if (tempname == NULL) { @@ -3001,8 +2887,9 @@ shada_write_file_open: {} fname); xfree(fname); xfree(tempname); - assert(sd_reader.close != NULL); - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); + } return FAIL; } (*wp)++; @@ -3047,8 +2934,8 @@ shada_write_file_nomerge: {} if (!did_open_writer) { xfree(fname); xfree(tempname); - if (sd_reader.cookie != NULL) { - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); } return FAIL; } @@ -3062,7 +2949,9 @@ shada_write_file_nomerge: {} const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader)); assert(sw_ret != kSDWriteIgnError); if (!nomerge) { - sd_reader.close(&sd_reader); + if (did_open_reader) { + close_file(&sd_reader); + } bool did_remove = false; if (sw_ret == kSDWriteSuccessful) { FileInfo old_info; @@ -3235,18 +3124,18 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits) /// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if /// there were not enough bytes to read or kSDReadStatusReadError if /// there was some error while reading. -static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buffer, +static ShaDaReadResult fread_len(FileDescriptor *const sd_reader, char *const buffer, const size_t length) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - const ptrdiff_t read_bytes = sd_reader->read(sd_reader, buffer, length); + const ptrdiff_t read_bytes = file_read(sd_reader, buffer, length); + if (read_bytes < 0) { + semsg(_(SERR "System error while reading ShaDa file: %s"), + os_strerror((int)read_bytes)); + return kSDReadStatusReadError; + } if (read_bytes != (ptrdiff_t)length) { - if (sd_reader->error != NULL) { - semsg(_(SERR "System error while reading ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } semsg(_(RCERR "Error while reading ShaDa file: " "last entry specified that it occupies %" PRIu64 " bytes, " "but file ended earlier"), @@ -3272,26 +3161,32 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buff /// @return kSDReadStatusSuccess if reading was successful, /// kSDReadStatusNotShaDa if there were not enough bytes to read or /// kSDReadStatusReadError if reading failed for whatever reason. -static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const int first_char, +/// kSDReadStatusFinished if eof and that was allowed +static ShaDaReadResult msgpack_read_uint64(FileDescriptor *const sd_reader, bool allow_eof, uint64_t *const result) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - const uintmax_t fpos = sd_reader->fpos - 1; - - if (first_char == EOF) { - if (sd_reader->error) { - semsg(_(SERR "System error while reading integer from ShaDa file: %s"), - sd_reader->error); - return kSDReadStatusReadError; - } else if (sd_reader->eof) { - semsg(_(RCERR "Error while reading ShaDa file: " - "expected positive integer at position %" PRIu64 - ", but got nothing"), - (uint64_t)fpos); - return kSDReadStatusNotShaDa; + const uintmax_t fpos = sd_reader->bytes_read; + + uint8_t ret; + ptrdiff_t read_bytes = file_read(sd_reader, (char *)&ret, 1); + + if (read_bytes < 0) { + semsg(_(SERR "System error while reading integer from ShaDa file: %s"), + os_strerror((int)read_bytes)); + return kSDReadStatusReadError; + } else if (read_bytes == 0) { + if (allow_eof && file_eof(sd_reader)) { + return kSDReadStatusFinished; } + semsg(_(RCERR "Error while reading ShaDa file: " + "expected positive integer at position %" PRIu64 + ", but got nothing"), + (uint64_t)fpos); + return kSDReadStatusNotShaDa; } + int first_char = (int)ret; if (~first_char & 0x80) { // Positive fixnum *result = (uint64_t)((uint8_t)first_char); @@ -3465,8 +3360,9 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const /// greater then given. /// /// @return Any value from ShaDaReadResult enum. -static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader, ShadaEntry *const entry, - const unsigned flags, const size_t max_kbyte) +static ShaDaReadResult shada_read_next_item(FileDescriptor *const sd_reader, + ShadaEntry *const entry, const unsigned flags, + const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { ShaDaReadResult ret = kSDReadStatusMalformed; @@ -3476,7 +3372,7 @@ shada_read_next_item_start: // somebody calls goto shada_read_next_item_error before anything is set in // the switch. CLEAR_POINTER(entry); - if (sd_reader->eof) { + if (file_eof(sd_reader)) { return kSDReadStatusFinished; } @@ -3486,19 +3382,15 @@ shada_read_next_item_start: uint64_t timestamp_u64; uint64_t length_u64; - const uint64_t initial_fpos = (uint64_t)sd_reader->fpos; - const int first_char = read_char(sd_reader); - if (first_char == EOF && sd_reader->eof) { - return kSDReadStatusFinished; - } + const uint64_t initial_fpos = sd_reader->bytes_read; ShaDaReadResult mru_ret; - if (((mru_ret = msgpack_read_uint64(sd_reader, first_char, &type_u64)) + if (((mru_ret = msgpack_read_uint64(sd_reader, true, &type_u64)) != kSDReadStatusSuccess) - || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader), + || ((mru_ret = msgpack_read_uint64(sd_reader, false, ×tamp_u64)) != kSDReadStatusSuccess) - || ((mru_ret = msgpack_read_uint64(sd_reader, read_char(sd_reader), + || ((mru_ret = msgpack_read_uint64(sd_reader, false, &length_u64)) != kSDReadStatusSuccess)) { return mru_ret; @@ -4158,63 +4050,6 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf) } while (var_iter != NULL); } -/// Wrapper for reading from msgpack_sbuffer. -/// -/// @return number of bytes read. -static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, const size_t size) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; - const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos); - if (bytes_read < size) { - sd_reader->eof = true; - } - memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read); - sd_reader->fpos += bytes_read; - return (ptrdiff_t)bytes_read; -} - -/// Wrapper for read that ignores bytes read from msgpack_sbuffer. -/// -/// Used for skipping. -/// -/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer. -/// @param[in] offset Amount of bytes to skip. -/// -/// @return FAIL in case of failure, OK in case of success. May set -/// sd_reader->eof. -static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; - assert(sbuf->size >= sd_reader->fpos); - const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos); - if (skip_bytes < offset) { - sd_reader->eof = true; - return FAIL; - } - sd_reader->fpos += offset; - return OK; -} - -/// Prepare ShaDaReadDef with msgpack_sbuffer for reading. -/// -/// @param[in] sbuf msgpack_sbuffer to read from. -/// @param[out] sd_reader Location where reader structure will be saved. -static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, ShaDaReadDef *sd_reader) - FUNC_ATTR_NONNULL_ALL -{ - *sd_reader = (ShaDaReadDef) { - .read = &read_sbuf, - .close = NULL, - .skip = &sd_sbuf_reader_skip_read, - .error = NULL, - .eof = false, - .fpos = 0, - .cookie = (void *)sbuf, - }; -} - /// Read ShaDa from msgpack_sbuffer. /// /// @param[in] file msgpack_sbuffer to read from. @@ -4226,7 +4061,8 @@ void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags) if (sbuf->data == NULL) { return; } - ShaDaReadDef sd_reader; - open_shada_sbuf_for_reading(sbuf, &sd_reader); + FileDescriptor sd_reader; + file_open_buffer(&sd_reader, sbuf->data, sbuf->size); shada_read(&sd_reader, flags); + close_file(&sd_reader); } diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua index a9084da929..e000d0988b 100644 --- a/test/functional/shada/errors_spec.lua +++ b/test/functional/shada/errors_spec.lua @@ -28,7 +28,7 @@ describe('ShaDa error handling', function() it('fails on zero', function() wshada('\000') eq( - 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 0, but got nothing', + 'Vim(rshada):E576: Error while reading ShaDa file: expected positive integer at position 1, but got nothing', exc_exec(sdrcmd()) ) end) -- cgit From 8ba73f0e4cc6c82032a348a1d6c8d794ed150fd7 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 08:51:44 -0500 Subject: feat(diagnostic): add vim.diagnostic.jump() (#26745) Deprecate vim.diagnostic.goto_prev() and vim.diagnostic.goto_next() in favor of a unified vim.diagnostic.jump() interface. We cannot name the function "goto()" because some of our tooling (luacheck and stylua) fail to parse it, presumably because "goto" is a keyword in newer versions of Lua. vim.diagnostic.jump() also allows moving to a specific diagnostic and moving by multiple diagnostics at a time (useful for creating mappings that use v:count). --- runtime/doc/deprecated.txt | 17 +- runtime/doc/diagnostic.txt | 91 +++++----- runtime/lua/vim/diagnostic.lua | 193 +++++++++++++++------ test/functional/lua/diagnostic_spec.lua | 289 +++++++++++++++++++++++--------- 4 files changed, 401 insertions(+), 189 deletions(-) diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index be220fc307..6c6585d76e 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -22,6 +22,20 @@ API LUA - vim.region() Use |getregionpos()| instead. +DIAGNOSTICS +- *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count = 1}` instead. +- *vim.diagnostic.goto_prev()* Use |vim.diagnostic.jump()| with `{count = -1}` instead. +- *vim.diagnostic.get_next_pos()* + Use the "lnum" and "col" fields from the return value of + |vim.diagnostic.get_next()| instead. +- *vim.diagnostic.get_prev_pos()* + Use the "lnum" and "col" fields from the return value of + |vim.diagnostic.get_prev()| instead. +- The "win_id" parameter used by various functions is deprecated in favor of + "winid" |winid| +- The "cursor_position" parameter of |vim.diagnostic.JumpOpts| is renamed to + "pos" + ------------------------------------------------------------------------------ DEPRECATED IN 0.10 *deprecated-0.10* @@ -204,9 +218,6 @@ internally and are no longer exposed as part of the API. Instead, use - *vim.lsp.diagnostic.set_underline()* - *vim.lsp.diagnostic.set_virtual_text()* -Configuring |diagnostic-signs| with |:sign-define| or |sign_define()| is no -longer supported. Use the "signs" key of |vim.diagnostic.config()| instead. - LSP FUNCTIONS - *vim.lsp.buf.server_ready()* Use |LspAttach| instead, depending on your use-case. "Server ready" is not diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 36616b9a0d..be9e54d6cd 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -378,28 +378,37 @@ Lua module: vim.diagnostic *diagnostic-api* • {severity}? (`vim.diagnostic.SeverityFilter`) See |diagnostic-severity|. -*vim.diagnostic.GotoOpts* +*vim.diagnostic.JumpOpts* Extends: |vim.diagnostic.GetOpts| Configuration table with the following keys: Fields: ~ - • {cursor_position}? (`{[1]:integer,[2]:integer}`, default: current cursor position) - Cursor position as a `(row, col)` tuple. See - |nvim_win_get_cursor()|. - • {wrap}? (`boolean`, default: `true`) Whether to loop - around file or not. Similar to 'wrapscan'. - • {severity}? (`vim.diagnostic.SeverityFilter`) See - |diagnostic-severity|. - • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: - `true`) If `true`, call - |vim.diagnostic.open_float()| after moving. If a - table, pass the table as the {opts} parameter to - |vim.diagnostic.open_float()|. Unless overridden, - the float will show diagnostics at the new cursor - position (as if "cursor" were passed to the - "scope" option). - • {win_id}? (`integer`, default: `0`) Window ID + • {diagnostic}? (`vim.Diagnostic`) The diagnostic to jump to. Mutually + exclusive with {count}, {namespace}, and {severity}. + See |vim.Diagnostic|. + • {count}? (`integer`) The number of diagnostics to move by, + starting from {pos}. A positive integer moves forward + by {count} diagnostics, while a negative integer moves + backward by {count} diagnostics. Mutually exclusive + with {diagnostic}. + • {pos}? (`{[1]:integer,[2]:integer}`) Cursor position as a + `(row, col)` tuple. See |nvim_win_get_cursor()|. Used + to find the nearest diagnostic when {count} is used. + Only used when {count} is non-nil. Default is the + current cursor position. + • {wrap}? (`boolean`, default: `true`) Whether to loop around + file or not. Similar to 'wrapscan'. + • {severity}? (`vim.diagnostic.SeverityFilter`) See + |diagnostic-severity|. + • {float}? (`boolean|vim.diagnostic.Opts.Float`, default: `true`) + If `true`, call |vim.diagnostic.open_float()| after + moving. If a table, pass the table as the {opts} + parameter to |vim.diagnostic.open_float()|. Unless + overridden, the float will show diagnostics at the new + cursor position (as if "cursor" were passed to the + "scope" option). + • {winid}? (`integer`, default: `0`) Window ID *vim.diagnostic.NS* @@ -678,52 +687,20 @@ get_next({opts}) *vim.diagnostic.get_next()* Get the next diagnostic closest to the cursor position. Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. + • {opts} (`vim.diagnostic.JumpOpts?`) See |vim.diagnostic.JumpOpts|. Return: ~ (`vim.Diagnostic?`) Next diagnostic. See |vim.Diagnostic|. -get_next_pos({opts}) *vim.diagnostic.get_next_pos()* - Return the position of the next diagnostic in the current buffer. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - - Return: ~ - (`table|false`) Next diagnostic position as a `(row, col)` tuple or - false if no next diagnostic. - get_prev({opts}) *vim.diagnostic.get_prev()* Get the previous diagnostic closest to the cursor position. Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. + • {opts} (`vim.diagnostic.JumpOpts?`) See |vim.diagnostic.JumpOpts|. Return: ~ (`vim.Diagnostic?`) Previous diagnostic. See |vim.Diagnostic|. -get_prev_pos({opts}) *vim.diagnostic.get_prev_pos()* - Return the position of the previous diagnostic in the current buffer. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - - Return: ~ - (`table|false`) Previous diagnostic position as a `(row, col)` tuple - or `false` if there is no prior diagnostic. - -goto_next({opts}) *vim.diagnostic.goto_next()* - Move to the next diagnostic. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - -goto_prev({opts}) *vim.diagnostic.goto_prev()* - Move to the previous diagnostic in the current buffer. - - Parameters: ~ - • {opts} (`vim.diagnostic.GotoOpts?`) See |vim.diagnostic.GotoOpts|. - hide({namespace}, {bufnr}) *vim.diagnostic.hide()* Hide currently displayed diagnostics. @@ -753,6 +730,16 @@ is_enabled({filter}) *vim.diagnostic.is_enabled()* Return: ~ (`boolean`) +jump({opts}) *vim.diagnostic.jump()* + Move to a diagnostic. + + Parameters: ~ + • {opts} (`vim.diagnostic.JumpOpts`) See |vim.diagnostic.JumpOpts|. + + Return: ~ + (`vim.Diagnostic?`) The diagnostic that was moved to. See + |vim.Diagnostic|. + *vim.diagnostic.match()* match({str}, {pat}, {groups}, {severity_map}, {defaults}) Parse a diagnostic from a string. @@ -792,7 +779,7 @@ open_float({opts}) *vim.diagnostic.open_float()* Return (multiple): ~ (`integer?`) float_bufnr - (`integer?`) win_id + (`integer?`) winid reset({namespace}, {bufnr}) *vim.diagnostic.reset()* Remove all diagnostics from the given namespace. diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 348204abb7..8e68e9608a 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -835,21 +835,36 @@ local function filter_highest(diagnostics) end end ---- @param position {[1]: integer, [2]: integer} --- @param search_forward boolean ---- @param bufnr integer ---- @param opts vim.diagnostic.GotoOpts ---- @param namespace integer[]|integer +--- @param opts vim.diagnostic.JumpOpts? --- @return vim.Diagnostic? -local function next_diagnostic(position, search_forward, bufnr, opts, namespace) +local function next_diagnostic(search_forward, opts) + opts = opts or {} + + -- Support deprecated win_id alias + if opts.win_id then + vim.deprecate('opts.win_id', 'opts.winid', '0.13') + opts.winid = opts.win_id + opts.win_id = nil + end + + -- Support deprecated cursor_position alias + if opts.cursor_position then + vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') + opts.pos = opts.cursor_position + opts.cursor_position = nil + end + + local winid = opts.winid or api.nvim_get_current_win() + local bufnr = api.nvim_win_get_buf(winid) + local position = opts.pos or api.nvim_win_get_cursor(winid) + + -- Adjust row to be 0-indexed position[1] = position[1] - 1 - bufnr = get_bufnr(bufnr) - local wrap = if_nil(opts.wrap, true) - local get_opts = vim.deepcopy(opts) - get_opts.namespace = get_opts.namespace or namespace + local wrap = if_nil(opts.wrap, true) - local diagnostics = get_diagnostics(bufnr, get_opts, true) + local diagnostics = get_diagnostics(bufnr, opts, true) if opts._highest then filter_highest(diagnostics) @@ -902,32 +917,41 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) end end ---- @param opts vim.diagnostic.GotoOpts? ---- @param pos {[1]:integer,[2]:integer}|false -local function diagnostic_move_pos(opts, pos) - opts = opts or {} - - local float = if_nil(opts.float, true) - local win_id = opts.win_id or api.nvim_get_current_win() - - if not pos then +--- Move the cursor to the given diagnostic. +--- +--- @param diagnostic vim.Diagnostic? +--- @param opts vim.diagnostic.JumpOpts? +local function goto_diagnostic(diagnostic, opts) + if not diagnostic then api.nvim_echo({ { 'No more valid diagnostics to move to', 'WarningMsg' } }, true, {}) return end - api.nvim_win_call(win_id, function() + opts = opts or {} + + -- Support deprecated win_id alias + if opts.win_id then + vim.deprecate('opts.win_id', 'opts.winid', '0.13') + opts.winid = opts.win_id + opts.win_id = nil + end + + local winid = opts.winid or api.nvim_get_current_win() + + api.nvim_win_call(winid, function() -- Save position in the window's jumplist vim.cmd("normal! m'") - api.nvim_win_set_cursor(win_id, { pos[1] + 1, pos[2] }) + api.nvim_win_set_cursor(winid, { diagnostic.lnum + 1, diagnostic.col }) -- Open folds under the cursor vim.cmd('normal! zv') end) + local float = if_nil(opts.float, true) if float then local float_opts = type(float) == 'table' and float or {} vim.schedule(function() M.open_float(vim.tbl_extend('keep', float_opts, { - bufnr = api.nvim_win_get_buf(win_id), + bufnr = api.nvim_win_get_buf(winid), scope = 'cursor', focus = false, })) @@ -1114,24 +1138,24 @@ end --- Get the previous diagnostic closest to the cursor position. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return vim.Diagnostic? : Previous diagnostic function M.get_prev(opts) - opts = opts or {} - - local win_id = opts.win_id or api.nvim_get_current_win() - local bufnr = api.nvim_win_get_buf(win_id) - local cursor_position = opts.cursor_position or api.nvim_win_get_cursor(win_id) - - return next_diagnostic(cursor_position, false, bufnr, opts, opts.namespace) + return next_diagnostic(false, opts) end --- Return the position of the previous diagnostic in the current buffer. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return table|false: Previous diagnostic position as a `(row, col)` tuple --- or `false` if there is no prior diagnostic. +---@deprecated function M.get_prev_pos(opts) + vim.deprecate( + 'vim.diagnostic.get_prev_pos()', + 'access the lnum and col fields from get_prev() instead', + '0.13' + ) local prev = M.get_prev(opts) if not prev then return false @@ -1141,31 +1165,33 @@ function M.get_prev_pos(opts) end --- Move to the previous diagnostic in the current buffer. ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts +---@deprecated function M.goto_prev(opts) - return diagnostic_move_pos(opts, M.get_prev_pos(opts)) + vim.deprecate('vim.diagnostic.goto_prev()', 'vim.diagnostic.jump()', '0.13') + goto_diagnostic(M.get_prev(opts), opts) end --- Get the next diagnostic closest to the cursor position. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return vim.Diagnostic? : Next diagnostic function M.get_next(opts) - opts = opts or {} - - local win_id = opts.win_id or api.nvim_get_current_win() - local bufnr = api.nvim_win_get_buf(win_id) - local cursor_position = opts.cursor_position or api.nvim_win_get_cursor(win_id) - - return next_diagnostic(cursor_position, true, bufnr, opts, opts.namespace) + return next_diagnostic(true, opts) end --- Return the position of the next diagnostic in the current buffer. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts ---@return table|false : Next diagnostic position as a `(row, col)` tuple or false if no next --- diagnostic. +---@deprecated function M.get_next_pos(opts) + vim.deprecate( + 'vim.diagnostic.get_next_pos()', + 'access the lnum and col fields from get_next() instead', + '0.13' + ) local next = M.get_next(opts) if not next then return false @@ -1187,12 +1213,21 @@ end --- @field severity? vim.diagnostic.SeverityFilter --- Configuration table with the following keys: ---- @class vim.diagnostic.GotoOpts : vim.diagnostic.GetOpts +--- @class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts +--- +--- The diagnostic to jump to. Mutually exclusive with {count}, {namespace}, +--- and {severity}. +--- @field diagnostic? vim.Diagnostic +--- +--- The number of diagnostics to move by, starting from {pos}. A positive +--- integer moves forward by {count} diagnostics, while a negative integer moves +--- backward by {count} diagnostics. Mutually exclusive with {diagnostic}. +--- @field count? integer --- ---- Cursor position as a `(row, col)` tuple. ---- See |nvim_win_get_cursor()|. ---- (default: current cursor position) ---- @field cursor_position? {[1]:integer,[2]:integer} +--- Cursor position as a `(row, col)` tuple. See |nvim_win_get_cursor()|. Used +--- to find the nearest diagnostic when {count} is used. Only used when {count} +--- is non-nil. Default is the current cursor position. +--- @field pos? {[1]:integer,[2]:integer} --- --- Whether to loop around file or not. Similar to 'wrapscan'. --- (default: `true`) @@ -1214,13 +1249,69 @@ end --- --- Window ID --- (default: `0`) ---- @field win_id? integer +--- @field winid? integer + +--- Move to a diagnostic. +--- +--- @param opts vim.diagnostic.JumpOpts +--- @return vim.Diagnostic? # The diagnostic that was moved to. +function M.jump(opts) + -- One of "diagnostic" or "count" must be provided + assert( + opts.diagnostic or opts.count, + 'One of "diagnostic" or "count" must be specified in the options to vim.diagnostic.jump()' + ) + + if opts.diagnostic then + goto_diagnostic(opts.diagnostic, opts) + return opts.diagnostic + end + + local count = opts.count + if count == 0 then + return nil + end + + -- Support deprecated cursor_position alias + if opts.cursor_position then + vim.deprecate('opts.cursor_position', 'opts.pos', '0.13') + opts.pos = opts.cursor_position + opts.cursor_position = nil + end + + -- Copy the opts table so that we can modify it + local opts_ = vim.deepcopy(opts, true) + + local diag = nil + while count ~= 0 do + local next = next_diagnostic(count > 0, opts_) + if not next then + break + end + + -- Update cursor position + opts_.pos = { next.lnum + 1, next.col } + + if count > 0 then + count = count - 1 + else + count = count + 1 + end + diag = next + end + + goto_diagnostic(diag, opts) + + return diag +end --- Move to the next diagnostic. --- ----@param opts? vim.diagnostic.GotoOpts +---@param opts? vim.diagnostic.JumpOpts +---@deprecated function M.goto_next(opts) - diagnostic_move_pos(opts, M.get_next_pos(opts)) + vim.deprecate('vim.diagnostic.goto_next()', 'vim.diagnostic.jump()', '0.13') + goto_diagnostic(M.get_next(opts), opts) end M.handlers.signs = { @@ -1688,7 +1779,7 @@ end --- ---@param opts vim.diagnostic.Opts.Float? ---@return integer? float_bufnr ----@return integer? win_id +---@return integer? winid function M.open_float(opts, ...) -- Support old (bufnr, opts) signature local bufnr --- @type integer? diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 05082bc132..76246fc2d1 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -843,17 +843,18 @@ describe('vim.diagnostic', function() end) end) - describe('get_next_pos()', function() + describe('get_next()', function() it('can find the next pos with only one namespace', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - return vim.diagnostic.get_next_pos() - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + local next = vim.diagnostic.get_next() + return { next.lnum, next.col } + ]] ) end) @@ -861,14 +862,15 @@ describe('vim.diagnostic', function() eq( { 4, 4 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } + ]] ) end) @@ -876,27 +878,29 @@ describe('vim.diagnostic', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } + ]] ) end) it('will not cycle when wrap is off', function() eq( - false, + vim.NIL, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns, wrap = false } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns, wrap = false }) + return next + ]] ) end) @@ -904,13 +908,14 @@ describe('vim.diagnostic', function() eq( { 4, 4 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + return { prev.lnum, prev.col } + ]] ) end) @@ -918,15 +923,16 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, 0, 4, 0), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 3, 9001, 3, 9001), + make_error('Diagnostic #2', 4, 0, 4, 0), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {1, 1}) + vim.diagnostic.jump({ count = 1, float = false }) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } + ]] ) end) @@ -935,13 +941,14 @@ describe('vim.diagnostic', function() { 4, 0 }, exec_lua [[ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 3, 9001, 3, 9001), - make_error('Diagnostic #2', 4, -1, 4, -1), + make_error('Diagnostic #1', 3, 9001, 3, 9001), + make_error('Diagnostic #2', 4, -1, 4, -1), }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {1, 1}) - vim.diagnostic.goto_next { float = false } - return vim.diagnostic.get_next_pos { namespace = diagnostic_ns } + vim.diagnostic.jump({ count = 1, float = false }) + local next = vim.diagnostic.get_next({ namespace = diagnostic_ns }) + return { next.lnum, next.col } ]] ) end) @@ -1044,33 +1051,35 @@ describe('vim.diagnostic', function() end) end) - describe('get_prev_pos()', function() - it('can find the prev pos with only one namespace', function() + describe('get_prev()', function() + it('can find the previous diagnostic with only one namespace', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos() - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev() + return { prev.lnum, prev.col } + ]] ) end) - it('can find prev pos with two errors', function() + it('can find the previous diagnostic with two errors', function() eq( { 1, 1 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #1', 1, 1, 1, 1), - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 1, 1, 1, 1), + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + return { prev.lnum, prev.col } + ]] ) end) @@ -1078,27 +1087,29 @@ describe('vim.diagnostic', function() eq( { 4, 4 }, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns } - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns }) + return { prev.lnum, prev.col } + ]] ) end) it('respects wrap parameter', function() eq( - false, + vim.NIL, exec_lua [[ - vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { - make_error('Diagnostic #2', 4, 4, 4, 4), - }) - vim.api.nvim_win_set_buf(0, diagnostic_bufnr) - vim.api.nvim_win_set_cursor(0, {3, 1}) - return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns, wrap = false} - ]] + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #2', 4, 4, 4, 4), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + vim.api.nvim_win_set_cursor(0, {3, 1}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false}) + return prev + ]] ) end) @@ -1126,6 +1137,118 @@ describe('vim.diagnostic', function() end) end) + describe('jump()', function() + before_each(function() + exec_lua([[ + vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, { + make_error('Diagnostic #1', 0, 0, 0, 2), + make_error('Diagnostic #2', 1, 1, 1, 4), + make_warning('Diagnostic #3', 2, -1, 2, -1), + make_info('Diagnostic #4', 3, 0, 3, 3), + }) + vim.api.nvim_win_set_buf(0, diagnostic_bufnr) + ]]) + end) + + it('can move forward', function() + eq( + { 2, 1 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 3 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('can move backward', function() + eq( + { 3, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -1 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 1, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -3 }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 1, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = -math.huge, wrap = false }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('can filter by severity', function() + eq( + { 3, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 1, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 3, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = 9999, severity = vim.diagnostic.severity.WARN }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + + it('can wrap', function() + eq( + { 1, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 4, 0 }) + vim.diagnostic.jump({ count = 1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + + eq( + { 4, 0 }, + exec_lua([[ + vim.api.nvim_win_set_cursor(0, { 1, 0 }) + vim.diagnostic.jump({ count = -1, wrap = true }) + return vim.api.nvim_win_get_cursor(0) + ]]) + ) + end) + end) + describe('get()', function() it('returns an empty table when no diagnostics are present', function() eq({}, exec_lua [[return vim.diagnostic.get(diagnostic_bufnr, {namespace=diagnostic_ns})]]) -- cgit From e6cfcaed184d4ecdc8a8638429e1bd9e1b3251dc Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Sat, 25 May 2024 10:23:05 -0700 Subject: feat(snippet): add default keymaps during snippet session --- runtime/doc/news.txt | 6 ++++ runtime/lua/vim/snippet.lua | 63 ++++++++++++++++++++++++++++++++++++ test/functional/lua/snippet_spec.lua | 27 +++++++++++++--- 3 files changed, 91 insertions(+), 5 deletions(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 439316f62e..f1b402c92e 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -85,6 +85,12 @@ DEFAULTS - |gra| in Normal and Visual mode maps to |vim.lsp.buf.code_action()| - CTRL-S in Insert mode maps to |vim.lsp.buf.signature_help()| +• Snippet: + - `` in Insert and Select mode maps to |vim.snippet.jump({ direction = 1 })| + when a snippet is active and jumpable forwards. + - `` in Insert and Select mode maps to |vim.snippet.jump({ direction = -1 })| + when a snippet is active and jumpable backwards. + EDITOR • TODO diff --git a/runtime/lua/vim/snippet.lua b/runtime/lua/vim/snippet.lua index 3d8f73f362..1ec5235d7b 100644 --- a/runtime/lua/vim/snippet.lua +++ b/runtime/lua/vim/snippet.lua @@ -2,6 +2,8 @@ local G = vim.lsp._snippet_grammar local snippet_group = vim.api.nvim_create_augroup('vim/snippet', {}) local snippet_ns = vim.api.nvim_create_namespace('vim/snippet') local hl_group = 'SnippetTabstop' +local jump_forward_key = '' +local jump_backward_key = '' --- Returns the 0-based cursor position. --- @@ -182,6 +184,8 @@ end --- @field extmark_id integer --- @field tabstops table --- @field current_tabstop vim.snippet.Tabstop +--- @field tab_keymaps { i: table?, s: table? } +--- @field shift_tab_keymaps { i: table?, s: table? } local Session = {} --- Creates a new snippet session in the current buffer. @@ -197,6 +201,8 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) extmark_id = snippet_extmark, tabstops = {}, current_tabstop = Tabstop.new(0, bufnr, { 0, 0, 0, 0 }), + tab_keymaps = { i = nil, s = nil }, + shift_tab_keymaps = { i = nil, s = nil }, }, { __index = Session }) -- Create the tabstops. @@ -207,9 +213,64 @@ function Session.new(bufnr, snippet_extmark, tabstop_data) end end + self:set_keymaps() + return self end +--- Sets the snippet navigation keymaps. +--- +--- @package +function Session:set_keymaps() + local function maparg(key, mode) + local map = vim.fn.maparg(key, mode, false, true) --[[ @as table ]] + if not vim.tbl_isempty(map) and map.buffer == 1 then + return map + else + return nil + end + end + + local function set(jump_key, direction) + vim.keymap.set({ 'i', 's' }, jump_key, function() + return vim.snippet.active({ direction = direction }) + and 'lua vim.snippet.jump(' .. direction .. ')' + or jump_key + end, { expr = true, silent = true, buffer = self.bufnr }) + end + + self.tab_keymaps = { + i = maparg(jump_forward_key, 'i'), + s = maparg(jump_forward_key, 's'), + } + self.shift_tab_keymaps = { + i = maparg(jump_backward_key, 'i'), + s = maparg(jump_backward_key, 's'), + } + set(jump_forward_key, 1) + set(jump_backward_key, -1) +end + +--- Restores/deletes the keymaps used for snippet navigation. +--- +--- @package +function Session:restore_keymaps() + local function restore(keymap, lhs, mode) + if keymap then + vim.api.nvim_buf_call(self.bufnr, function() + vim.fn.mapset(keymap) + end) + else + vim.api.nvim_buf_del_keymap(self.bufnr, mode, lhs) + end + end + + restore(self.tab_keymaps.i, jump_forward_key, 'i') + restore(self.tab_keymaps.s, jump_forward_key, 's') + restore(self.shift_tab_keymaps.i, jump_backward_key, 'i') + restore(self.shift_tab_keymaps.s, jump_backward_key, 's') +end + --- Returns the destination tabstop index when jumping in the given direction. --- --- @package @@ -619,6 +680,8 @@ function M.stop() return end + M._session:restore_keymaps() + vim.api.nvim_clear_autocmds({ group = snippet_group, buffer = M._session.bufnr }) vim.api.nvim_buf_clear_namespace(M._session.bufnr, snippet_ns, 0, -1) diff --git a/test/functional/lua/snippet_spec.lua b/test/functional/lua/snippet_spec.lua index 413aa93994..bca0a59cb4 100644 --- a/test/functional/lua/snippet_spec.lua +++ b/test/functional/lua/snippet_spec.lua @@ -1,3 +1,5 @@ +---@diagnostic disable: no-unknown + local t = require('test.testutil') local n = require('test.functional.testnvim')() @@ -16,11 +18,6 @@ local retry = t.retry describe('vim.snippet', function() before_each(function() clear() - - exec_lua([[ - vim.keymap.set({ 'i', 's' }, '', function() vim.snippet.jump(1) end, { buffer = true }) - vim.keymap.set({ 'i', 's' }, '', function() vim.snippet.jump(-1) end, { buffer = true }) - ]]) end) after_each(clear) @@ -286,4 +283,24 @@ describe('vim.snippet', function() ]] ) end) + + it('restores snippet navigation keymaps', function() + -- Create a buffer keymap in insert mode that deletes all lines. + local curbuf = api.nvim_get_current_buf() + exec_lua('vim.api.nvim_buf_set_keymap(..., "i", "", "normal ggdG", {})', curbuf) + + test_expand_success({ 'var $1 = $2' }, { 'var = ' }) + + -- While the snippet is active, should navigate between tabstops. + feed('x') + poke_eventloop() + feed('0') + eq({ 'var x = 0' }, buf_lines(0)) + + exec_lua('vim.snippet.stop()') + + -- After exiting the snippet, the buffer keymap should be restored. + feed('O') + eq({ '' }, buf_lines(0)) + end) end) -- cgit From 1c6d9200521acb2329be55ab8bec3056deade66a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 13:24:16 -0500 Subject: feat(defaults): use vim.diagnostic.jump() for default mappings (#29066) This allows the mappings to work with a count and also enables new ]D and [D mappings to go to the last/first diagnostic in the buffer. --- runtime/doc/news.txt | 7 +++++-- runtime/doc/tagsrch.txt | 16 ++++++++++++---- runtime/doc/vim_diff.txt | 2 ++ runtime/lua/vim/_defaults.lua | 16 ++++++++++++---- test/functional/lua/diagnostic_spec.lua | 16 ++++++++-------- 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index b5ba2921e6..ceb638a459 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -34,11 +34,14 @@ API DEFAULTS -• TODO +• |]d-default| and |[d-default| accept a count. +• |[D-default| and |]D-default| jump to the first and last diagnostic in the + current buffer, respectively. EDITOR -• The order in which signs are placed was changed. Higher priority signs will now appear left of lower priority signs. +• The order in which signs are placed was changed. Higher priority signs will + now appear left of lower priority signs. EVENTS diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index ef1654d365..8b2813785f 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -781,15 +781,15 @@ CTRL-W i Open a new window, with the cursor on the first line count'th matching line is displayed. *[d-default* - Mapped to |vim.diagnostic.goto_prev()| by default. - |default-mappings| + Jumps to the previous diagnostic in the current buffer + by default. |vim.diagnostic.jump()| |default-mappings| *]d* ]d like "[d", but start at the current cursor position. *]d-default* - Mapped to |vim.diagnostic.goto_next()| by default. - |default-mappings| + Jumps to the next diagnostic in the current buffer by + default. |vim.diagnostic.jump()| |default-mappings| *:ds* *:dsearch* :[range]ds[earch][!] [count] [/]string[/] @@ -803,9 +803,17 @@ CTRL-W i Open a new window, with the cursor on the first line displayed for the found lines. The search starts from the beginning of the file. + *[D-default* + Jumps to the first diagnostic in the current buffer by + default. |vim.diagnostic.jump()| |default-mappings| + *]D* ]D like "[D", but start at the current cursor position. + *]D-default* + Jumps to the last diagnostic in the current buffer by + default. |vim.diagnostic.jump()| |default-mappings| + *:dli* *:dlist* :[range]dli[st][!] [/]string[/] Like `[D` and `]D`, but search in [range] lines diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 5d894bb5e1..ac20948f14 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -145,6 +145,8 @@ of these in your config by simply removing the mapping, e.g. ":unmap Y". - |i_CTRL-S| - ]d |]d-default| - [d |[d-default| +- [D |[D-default| +- ]D |]D-default| - d |CTRL-W_d-default| - Nvim LSP client defaults |lsp-defaults| - K |K-lsp-default| diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 5b964b84a0..26d8729029 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -180,12 +180,20 @@ do --- See |[d-default|, |]d-default|, and |CTRL-W_d-default|. do vim.keymap.set('n', ']d', function() - vim.diagnostic.goto_next({ float = false }) - end, { desc = 'Jump to the next diagnostic' }) + vim.diagnostic.jump({ count = vim.v.count1, float = false }) + end, { desc = 'Jump to the next diagnostic in the current buffer' }) vim.keymap.set('n', '[d', function() - vim.diagnostic.goto_prev({ float = false }) - end, { desc = 'Jump to the previous diagnostic' }) + vim.diagnostic.jump({ count = -vim.v.count1, float = false }) + end, { desc = 'Jump to the previous diagnostic in the current buffer' }) + + vim.keymap.set('n', ']D', function() + vim.diagnostic.jump({ count = math.huge, wrap = false, float = false }) + end, { desc = 'Jump to the last diagnostic in the current buffer' }) + + vim.keymap.set('n', '[D', function() + vim.diagnostic.jump({ count = -math.huge, wrap = false, float = false }) + end, { desc = 'Jump to the first diagnostic in the current buffer' }) vim.keymap.set('n', 'd', function() vim.diagnostic.open_float() diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua index 76246fc2d1..a4f882e363 100644 --- a/test/functional/lua/diagnostic_spec.lua +++ b/test/functional/lua/diagnostic_spec.lua @@ -969,7 +969,7 @@ describe('vim.diagnostic', function() eq( { 3, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -977,7 +977,7 @@ describe('vim.diagnostic', function() eq( { 5, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -998,7 +998,7 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1006,7 +1006,7 @@ describe('vim.diagnostic', function() eq( { 6, 0 }, exec_lua([[ - vim.diagnostic.goto_next({_highest = true}) + vim.diagnostic.jump({ count = 1, _highest = true }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1028,7 +1028,7 @@ describe('vim.diagnostic', function() eq( { 2, 0 }, exec_lua([[ - vim.diagnostic.goto_next() + vim.diagnostic.jump({ count = 1 }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1036,7 +1036,7 @@ describe('vim.diagnostic', function() eq( { 3, 0 }, exec_lua([[ - vim.diagnostic.goto_next() + vim.diagnostic.jump({ count = 1 }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1044,7 +1044,7 @@ describe('vim.diagnostic', function() eq( { 4, 0 }, exec_lua([[ - vim.diagnostic.goto_next() + vim.diagnostic.jump({ count = 1 }) return vim.api.nvim_win_get_cursor(0) ]]) ) @@ -1107,7 +1107,7 @@ describe('vim.diagnostic', function() }) vim.api.nvim_win_set_buf(0, diagnostic_bufnr) vim.api.nvim_win_set_cursor(0, {3, 1}) - local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false}) + local prev = vim.diagnostic.get_prev({ namespace = diagnostic_ns, wrap = false }) return prev ]] ) -- cgit From f09f5c45facc597bb3f70b7821412641bf31a592 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 28 May 2024 11:03:49 +0200 Subject: build: reuse code for deps.txt for both deps and main build --- CMakeLists.txt | 27 ++++++++++++++------------- cmake.deps/CMakeLists.txt | 19 ------------------- cmake.deps/deps.txt | 5 +++++ cmake/Deps.cmake | 26 ++++++++++++++++++++++++++ test/CMakeLists.txt | 6 +++--- 5 files changed, 48 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c0f8483ea..1b070fef21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,12 @@ include(InstallHelpers) include(PreventInTreeBuilds) include(Util) +#------------------------------------------------------------------------------- +# User settings +#------------------------------------------------------------------------------- + +set(DEPS_IGNORE_SHA FALSE) + #------------------------------------------------------------------------------- # Variables #------------------------------------------------------------------------------- @@ -47,9 +53,6 @@ set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) file(GLOB DOCFILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/runtime/doc/*.txt) -set_directory_properties(PROPERTIES - EP_PREFIX "${DEPS_BUILD_DIR}") - if(NOT CI_BUILD) set(CMAKE_INSTALL_MESSAGE NEVER) endif() @@ -241,7 +244,7 @@ add_glob_target( GLOB_DIRS runtime scripts src test GLOB_PAT *.lua TOUCH_STRATEGY PER_DIR) -add_dependencies(lintlua-luacheck lua-dev-deps) +add_dependencies(lintlua-luacheck lua_dev_deps) add_glob_target( TARGET lintlua-stylua @@ -300,26 +303,24 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(cmake.packaging) endif() +get_externalproject_options(uncrustify ${DEPS_IGNORE_SHA}) ExternalProject_Add(uncrustify - URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.79.0.tar.gz - URL_HASH SHA256=e7afaeabf636b7f0ce4e3e9747b95f7bd939613a8db49579755dddf44fedca5f DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/uncrustify CMAKE_ARGS ${DEPS_CMAKE_ARGS} EXCLUDE_FROM_ALL TRUE - DOWNLOAD_NO_PROGRESS TRUE) + ${EXTERNALPROJECT_OPTIONS}) option(USE_BUNDLED_BUSTED "Use bundled busted" ON) if(USE_BUNDLED_BUSTED) - ExternalProject_Add(lua-dev-deps - URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz - URL_HASH SHA256=27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2 - DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua-dev-deps + get_externalproject_options(lua_dev_deps ${DEPS_IGNORE_SHA}) + ExternalProject_Add(lua_dev_deps + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua_dev_deps SOURCE_DIR ${DEPS_SHARE_DIR} CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" EXCLUDE_FROM_ALL TRUE - DOWNLOAD_NO_PROGRESS TRUE) + ${EXTERNALPROJECT_OPTIONS}) else() - add_custom_target(lua-dev-deps) + add_custom_target(lua_dev_deps) endif() diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt index 4853a1ab14..5b1f149dd7 100644 --- a/cmake.deps/CMakeLists.txt +++ b/cmake.deps/CMakeLists.txt @@ -74,25 +74,6 @@ if(APPLE) message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() -set_directory_properties(PROPERTIES - EP_PREFIX "${DEPS_BUILD_DIR}" - CMAKE_CONFIGURE_DEPENDS deps.txt) - -file(READ deps.txt DEPENDENCIES) -STRING(REGEX REPLACE "\n" ";" DEPENDENCIES "${DEPENDENCIES}") -foreach(dep ${DEPENDENCIES}) - STRING(REGEX REPLACE " " ";" dep "${dep}") - list(GET dep 0 name) - list(GET dep 1 value) - if(NOT ${name}) - # _URL variables must NOT be set when USE_EXISTING_SRC_DIR is set, - # otherwise ExternalProject will try to re-download the sources. - if(NOT USE_EXISTING_SRC_DIR) - set(${name} ${value}) - endif() - endif() -endforeach() - if(USE_BUNDLED_LUAJIT) set(LUA_ENGINE LuaJit) elseif(USE_BUNDLED_LUA) diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt index f76a6a1b70..f2b152640e 100644 --- a/cmake.deps/deps.txt +++ b/cmake.deps/deps.txt @@ -59,3 +59,8 @@ TREESITTER_MARKDOWN_URL https://github.com/MDeiml/tree-sitter-markdown/archive/v TREESITTER_MARKDOWN_SHA256 4909d6023643f1afc3ab219585d4035b7403f3a17849782ab803c5f73c8a31d5 TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.22.6.tar.gz TREESITTER_SHA256 e2b687f74358ab6404730b7fb1a1ced7ddb3780202d37595ecd7b20a8f41861f + +UNCRUSTIFY_URL https://github.com/uncrustify/uncrustify/archive/uncrustify-0.79.0.tar.gz +UNCRUSTIFY_SHA256 e7afaeabf636b7f0ce4e3e9747b95f7bd939613a8db49579755dddf44fedca5f +LUA_DEV_DEPS_URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz +LUA_DEV_DEPS_SHA256 27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2 diff --git a/cmake/Deps.cmake b/cmake/Deps.cmake index 413e3a08a9..398d9564cd 100644 --- a/cmake/Deps.cmake +++ b/cmake/Deps.cmake @@ -58,6 +58,32 @@ if(CMAKE_OSX_SYSROOT) set(DEPS_C_COMPILER "${DEPS_C_COMPILER} -isysroot${CMAKE_OSX_SYSROOT}") endif() +get_filename_component(rootdir ${PROJECT_SOURCE_DIR} NAME) +if(${rootdir} MATCHES "cmake.deps") + set(depsfile ${PROJECT_SOURCE_DIR}/deps.txt) +else() + set(depsfile ${PROJECT_SOURCE_DIR}/cmake.deps/deps.txt) +endif() + +set_directory_properties(PROPERTIES + EP_PREFIX "${DEPS_BUILD_DIR}" + CMAKE_CONFIGURE_DEPENDS ${depsfile}) + +file(READ ${depsfile} DEPENDENCIES) +STRING(REGEX REPLACE "\n" ";" DEPENDENCIES "${DEPENDENCIES}") +foreach(dep ${DEPENDENCIES}) + STRING(REGEX REPLACE " " ";" dep "${dep}") + list(GET dep 0 name) + list(GET dep 1 value) + if(NOT ${name}) + # _URL variables must NOT be set when USE_EXISTING_SRC_DIR is set, + # otherwise ExternalProject will try to re-download the sources. + if(NOT USE_EXISTING_SRC_DIR) + set(${name} ${value}) + endif() + endif() +endforeach() + function(get_externalproject_options name DEPS_IGNORE_SHA) string(TOUPPER ${name} name_allcaps) set(url ${${name_allcaps}_URL}) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3ae11bd1a7..8db05ac839 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,7 +19,7 @@ if(LUA_HAS_FFI) ${TEST_OPTIONS} -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake USES_TERMINAL) - add_dependencies(unittest lua-dev-deps nvim) + add_dependencies(unittest lua_dev_deps nvim) else() message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}") endif() @@ -35,7 +35,7 @@ add_custom_target(functionaltest -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS printenv-test printargs-test shell-test pwsh-test streams-test tty-test USES_TERMINAL) -add_dependencies(functionaltest lua-dev-deps nvim) +add_dependencies(functionaltest lua_dev_deps nvim) add_custom_target(benchmark COMMAND ${CMAKE_COMMAND} @@ -44,4 +44,4 @@ add_custom_target(benchmark -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS tty-test USES_TERMINAL) -add_dependencies(benchmark lua-dev-deps nvim) +add_dependencies(benchmark lua_dev_deps nvim) -- cgit From efa45832ea02e777ce3f5556ef3cd959c164ec24 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 28 May 2024 14:54:50 -0500 Subject: feat: add "jump" options to vim.diagnostic.config() (#29067) Problem: There is no easy way to configure the behavior of the default diagnostic "jump" mappings. For example, some users way want to show the floating window, and some may not (likewise, some way want to only move between warnings/errors, or disable the "wrap" parameter). Solution: Add a "jump" table to vim.diagnostic.config() that sets default values for vim.diagnostic.jump(). Alternatives: Users can override the default mappings to use the exact options to vim.diagnostic.jump() that they want, but this has a couple issues: - While the default mappings are not complicated, they are also not trivial, so overriding them requires users to understand implementation details (specifically things like setting "count" properly). - If plugins want to change the default mappings, or configure the behavior in any way (e.g. floating window display), it becomes even harder for users to tweak specific behavior. vim.diagnostic.config() already works quite well as the "entry point" for tuning knobs with diagnostic UI elements, so this fits in nicely and composes well with existing mental models and idioms. --- runtime/doc/diagnostic.txt | 18 ++++++++++++++++-- runtime/doc/news.txt | 5 +++++ runtime/lua/vim/_defaults.lua | 8 ++++---- runtime/lua/vim/diagnostic.lua | 41 ++++++++++++++++++++++++++++++++++------- runtime/lua/vim/shared.lua | 2 +- 5 files changed, 60 insertions(+), 14 deletions(-) diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index be9e54d6cd..2438c48154 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -381,7 +381,8 @@ Lua module: vim.diagnostic *diagnostic-api* *vim.diagnostic.JumpOpts* Extends: |vim.diagnostic.GetOpts| - Configuration table with the following keys: + Configuration table with the keys listed below. Some parameters can have + their default values changed with |vim.diagnostic.config()|. Fields: ~ • {diagnostic}? (`vim.Diagnostic`) The diagnostic to jump to. Mutually @@ -419,7 +420,7 @@ Lua module: vim.diagnostic *diagnostic-api* • {disabled}? (`boolean`) *vim.diagnostic.Opts* - Each of the configuration options below accepts one of the following: + Many of the configuration options below accept one of the following: • `false`: Disable this feature • `true`: Enable this feature, use default settings. • `table`: Enable this feature with overrides. Use an empty table to use @@ -450,6 +451,9 @@ Lua module: vim.diagnostic *diagnostic-api* displayed before lower severities (e.g. ERROR is displayed before WARN). Options: • {reverse}? (boolean) Reverse sort order + • {jump}? (`vim.diagnostic.Opts.Jump`) Default values for + |vim.diagnostic.jump()|. See + |vim.diagnostic.Opts.Jump|. *vim.diagnostic.Opts.Float* @@ -509,6 +513,16 @@ Lua module: vim.diagnostic *diagnostic-api* • {focus_id}? (`string`) • {border}? (`string`) see |nvim_open_win()|. +*vim.diagnostic.Opts.Jump* + + Fields: ~ + • {float}? (`boolean|vim.diagnostic.Opts.Float`) Default value of + the {float} parameter of |vim.diagnostic.jump()|. + • {wrap}? (`boolean`) Default value of the {wrap} parameter of + |vim.diagnostic.jump()|. + • {severity}? (`vim.diagnostic.SeverityFilter`) Default value of the + {severity} parameter of |vim.diagnostic.jump()|. + *vim.diagnostic.Opts.Signs* Fields: ~ diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index ceb638a459..13e4b23ea1 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -38,6 +38,11 @@ DEFAULTS • |[D-default| and |]D-default| jump to the first and last diagnostic in the current buffer, respectively. +DIAGNOSTICS + +• |vim.diagnostic.config()| accepts a "jump" table to specify defaults for + |vim.diagnostic.jump()|. + EDITOR • The order in which signs are placed was changed. Higher priority signs will diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index 26d8729029..79fe5a8513 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -180,19 +180,19 @@ do --- See |[d-default|, |]d-default|, and |CTRL-W_d-default|. do vim.keymap.set('n', ']d', function() - vim.diagnostic.jump({ count = vim.v.count1, float = false }) + vim.diagnostic.jump({ count = vim.v.count1 }) end, { desc = 'Jump to the next diagnostic in the current buffer' }) vim.keymap.set('n', '[d', function() - vim.diagnostic.jump({ count = -vim.v.count1, float = false }) + vim.diagnostic.jump({ count = -vim.v.count1 }) end, { desc = 'Jump to the previous diagnostic in the current buffer' }) vim.keymap.set('n', ']D', function() - vim.diagnostic.jump({ count = math.huge, wrap = false, float = false }) + vim.diagnostic.jump({ count = math.huge, wrap = false }) end, { desc = 'Jump to the last diagnostic in the current buffer' }) vim.keymap.set('n', '[D', function() - vim.diagnostic.jump({ count = -math.huge, wrap = false, float = false }) + vim.diagnostic.jump({ count = -math.huge, wrap = false }) end, { desc = 'Jump to the first diagnostic in the current buffer' }) vim.keymap.set('n', 'd', function() diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 8e68e9608a..dca7698356 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -42,7 +42,7 @@ local M = {} --- --- @field namespace? integer ---- Each of the configuration options below accepts one of the following: +--- Many of the configuration options below accept one of the following: --- - `false`: Disable this feature --- - `true`: Enable this feature, use default settings. --- - `table`: Enable this feature with overrides. Use an empty table to use default values. @@ -78,6 +78,9 @@ local M = {} --- - {reverse}? (boolean) Reverse sort order --- (default: `false`) --- @field severity_sort? boolean|{reverse?:boolean} +--- +--- Default values for |vim.diagnostic.jump()|. See |vim.diagnostic.Opts.Jump|. +--- @field jump? vim.diagnostic.Opts.Jump --- @class (private) vim.diagnostic.OptsResolved --- @field float vim.diagnostic.Opts.Float @@ -241,6 +244,20 @@ local M = {} --- whole line the sign is placed in. --- @field linehl? table +--- @class vim.diagnostic.Opts.Jump +--- +--- Default value of the {float} parameter of |vim.diagnostic.jump()|. +--- @field float? boolean|vim.diagnostic.Opts.Float +--- +--- Default value of the {wrap} parameter of |vim.diagnostic.jump()|. +--- @field wrap? boolean +--- +--- Default value of the {severity} parameter of |vim.diagnostic.jump()|. +--- @field severity? vim.diagnostic.SeverityFilter +--- +--- Default value of the {_highest} parameter of |vim.diagnostic.jump()|. +--- @field package _highest? boolean + -- TODO: inherit from `vim.diagnostic.Opts`, implement its fields. --- Optional filters |kwargs|, or `nil` for all. --- @class vim.diagnostic.Filter @@ -284,6 +301,13 @@ local global_diagnostic_options = { float = true, update_in_insert = false, severity_sort = false, + jump = { + -- Do not show floating window + float = false, + + -- Wrap around buffer + wrap = true, + }, } --- @class (private) vim.diagnostic.Handler @@ -1212,7 +1236,8 @@ end --- See |diagnostic-severity|. --- @field severity? vim.diagnostic.SeverityFilter ---- Configuration table with the following keys: +--- Configuration table with the keys listed below. Some parameters can have their default values +--- changed with |vim.diagnostic.config()|. --- @class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts --- --- The diagnostic to jump to. Mutually exclusive with {count}, {namespace}, @@ -1256,12 +1281,17 @@ end --- @param opts vim.diagnostic.JumpOpts --- @return vim.Diagnostic? # The diagnostic that was moved to. function M.jump(opts) + vim.validate('opts', opts, 'table') + -- One of "diagnostic" or "count" must be provided assert( opts.diagnostic or opts.count, 'One of "diagnostic" or "count" must be specified in the options to vim.diagnostic.jump()' ) + -- Apply configuration options from vim.diagnostic.config() + opts = vim.tbl_deep_extend('keep', opts, global_diagnostic_options.jump) + if opts.diagnostic then goto_diagnostic(opts.diagnostic, opts) return opts.diagnostic @@ -1279,18 +1309,15 @@ function M.jump(opts) opts.cursor_position = nil end - -- Copy the opts table so that we can modify it - local opts_ = vim.deepcopy(opts, true) - local diag = nil while count ~= 0 do - local next = next_diagnostic(count > 0, opts_) + local next = next_diagnostic(count > 0, opts) if not next then break end -- Update cursor position - opts_.pos = { next.lnum + 1, next.col } + opts.pos = { next.lnum + 1, next.col } if count > 0 then count = count - 1 diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 2641d1feb0..0ec79e1dc7 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -379,7 +379,7 @@ local function tbl_extend(behavior, deep_extend, ...) for i = 1, select('#', ...) do local tbl = select(i, ...) - vim.validate({ ['after the second argument'] = { tbl, 't' } }) + vim.validate('after the second argument', tbl, 'table') --- @cast tbl table if tbl then for k, v in pairs(tbl) do -- cgit From 40679c764a675d8039d0ae5c72cbde5f0dbe6db5 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 30 May 2024 14:39:48 +0800 Subject: vim-patch:8.2.3061: testing the shell option is incomplete and spread out (#29090) Problem: Testing the shell option is incomplete and spread out. Solution: Move shell tests to one file and increase coverage. (Yegappan Lakshmanan, closes vim/vim#8464) https://github.com/vim/vim/commit/054794c20f6322bbd9482c4124041dc0a140c78e Co-authored-by: Yegappan Lakshmanan --- test/old/testdir/test_functions.vim | 48 ------------------------------------- test/old/testdir/test_options.vim | 29 ---------------------- test/old/testdir/test_shell.vim | 23 ++++++++++++++++++ 3 files changed, 23 insertions(+), 77 deletions(-) diff --git a/test/old/testdir/test_functions.vim b/test/old/testdir/test_functions.vim index 18d0d9aa5d..fa9ae63381 100644 --- a/test/old/testdir/test_functions.vim +++ b/test/old/testdir/test_functions.vim @@ -2143,54 +2143,6 @@ func Test_balloon_show() endif endfunc -func Test_shellescape() - let save_shell = &shell - set shell=bash - call assert_equal("'text'", shellescape('text')) - call assert_equal("'te\"xt'", 'te"xt'->shellescape()) - call assert_equal("'te'\\''xt'", shellescape("te'xt")) - - call assert_equal("'te%xt'", shellescape("te%xt")) - call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) - call assert_equal("'te#xt'", shellescape("te#xt")) - call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) - call assert_equal("'te!xt'", shellescape("te!xt")) - call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) - - call assert_equal("'te\nxt'", shellescape("te\nxt")) - call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) - set shell=tcsh - call assert_equal("'te\\!xt'", shellescape("te!xt")) - call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1)) - call assert_equal("'te\\\nxt'", shellescape("te\nxt")) - call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) - - set shell=fish - call assert_equal("'text'", shellescape('text')) - call assert_equal("'te\"xt'", shellescape('te"xt')) - call assert_equal("'te'\\''xt'", shellescape("te'xt")) - - call assert_equal("'te%xt'", shellescape("te%xt")) - call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) - call assert_equal("'te#xt'", shellescape("te#xt")) - call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) - call assert_equal("'te!xt'", shellescape("te!xt")) - call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) - - call assert_equal("'te\\\\xt'", shellescape("te\\xt")) - call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1)) - call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt")) - call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1)) - call assert_equal("'te\\\\!xt'", shellescape("te\\!xt")) - call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1)) - call assert_equal("'te\\\\%xt'", shellescape("te\\%xt")) - call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1)) - call assert_equal("'te\\\\#xt'", shellescape("te\\#xt")) - call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1)) - - let &shell = save_shell -endfunc - func Test_setbufvar_options() " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the " window layout and cursor position. diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index 7786f82af2..8ffd8f7ef8 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -1400,35 +1400,6 @@ func Test_buftype() bwipe! endfunc -" Test for the 'shell' option -func Test_shell() - throw 'Skipped: Nvim does not have :shell' - CheckUnix - let save_shell = &shell - set shell= - let caught_e91 = 0 - try - shell - catch /E91:/ - let caught_e91 = 1 - endtry - call assert_equal(1, caught_e91) - let &shell = save_shell -endfunc - -" Test for the 'shellquote' option -func Test_shellquote() - CheckUnix - set shellquote=# - set verbose=20 - redir => v - silent! !echo Hello - redir END - set verbose& - set shellquote& - call assert_match(': "#echo Hello#"', v) -endfunc - " Test for the 'rightleftcmd' option func Test_rightleftcmd() CheckFeature rightleft diff --git a/test/old/testdir/test_shell.vim b/test/old/testdir/test_shell.vim index c50161a8ed..baaa327965 100644 --- a/test/old/testdir/test_shell.vim +++ b/test/old/testdir/test_shell.vim @@ -128,6 +128,29 @@ func Test_shellescape() call assert_equal("'te\\\nxt'", shellescape("te\nxt")) call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1)) + set shell=fish + call assert_equal("'text'", shellescape('text')) + call assert_equal("'te\"xt'", shellescape('te"xt')) + call assert_equal("'te'\\''xt'", shellescape("te'xt")) + + call assert_equal("'te%xt'", shellescape("te%xt")) + call assert_equal("'te\\%xt'", shellescape("te%xt", 1)) + call assert_equal("'te#xt'", shellescape("te#xt")) + call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) + call assert_equal("'te!xt'", shellescape("te!xt")) + call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) + + call assert_equal("'te\\\\xt'", shellescape("te\\xt")) + call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1)) + call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt")) + call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1)) + call assert_equal("'te\\\\!xt'", shellescape("te\\!xt")) + call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1)) + call assert_equal("'te\\\\%xt'", shellescape("te\\%xt")) + call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1)) + call assert_equal("'te\\\\#xt'", shellescape("te\\#xt")) + call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1)) + let &shell = save_shell endfunc -- cgit From 025c87441502cf570bad7b71f40bc6fe88989297 Mon Sep 17 00:00:00 2001 From: crwebb85 <51029315+crwebb85@users.noreply.github.com> Date: Thu, 30 May 2024 02:59:23 -0400 Subject: fix(lsp): clear lsp client diagnostics (#29050) Problem: When an lsp client is stopped, the client will only clear the diagnostics for the attached buffers but not the unattached buffers. Solution: Reset the diagnostics for the whole namespace rather than for only the attached buffers. --- runtime/lua/vim/lsp.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 94c31359da..96dbf97146 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -391,8 +391,8 @@ end local function on_client_exit(code, signal, client_id) local client = all_clients[client_id] - for bufnr in pairs(client.attached_buffers) do - vim.schedule(function() + vim.schedule(function() + for bufnr in pairs(client.attached_buffers) do if client and client.attached_buffers[bufnr] then api.nvim_exec_autocmds('LspDetach', { buffer = bufnr, @@ -401,15 +401,16 @@ local function on_client_exit(code, signal, client_id) }) end - local namespace = vim.lsp.diagnostic.get_namespace(client_id) - vim.diagnostic.reset(namespace, bufnr) client.attached_buffers[bufnr] = nil if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then reset_defaults(bufnr) end - end) - end + end + + local namespace = vim.lsp.diagnostic.get_namespace(client_id) + vim.diagnostic.reset(namespace) + end) local name = client.name or 'unknown' -- cgit From 0df2c6b5d09fab392dd1a14e4b2e6a3b03203aaa Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 28 May 2024 21:37:46 +0200 Subject: feat(lsp): use fuzzy match on filterText instead of prefix match The `complete()` mechanism matches completion candidates against the typed text, so strict pre-filtering isn't necessary. This is a first step towards supporting postfix snippets (like `items@insert` in luals) --- runtime/lua/vim/lsp/completion.lua | 14 ++++++++++---- test/functional/plugin/lsp/completion_spec.lua | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 25b3d53c8c..f9b0563b86 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -201,11 +201,17 @@ function M._lsp_to_complete_items(result, prefix, client_id) return {} end - local function matches_prefix(item) - return vim.startswith(get_completion_word(item), prefix) - end + if prefix ~= '' then + ---@param item lsp.CompletionItem + local function match_prefix(item) + if item.filterText then + return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) + end + return true + end - items = vim.tbl_filter(matches_prefix, items) --[[@as lsp.CompletionItem[]|]] + items = vim.tbl_filter(match_prefix, items) --[[@as lsp.CompletionItem[]|]] + end table.sort(items, function(a, b) return (a.sortText or a.label) < (b.sortText or b.label) end) diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 5b7232ad7e..078abdf653 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -228,7 +228,7 @@ describe('vim.lsp.completion: item conversion', function() }, }, { - filterText = 'notthis_thread', + filterText = 'no_match', insertText = 'notthis_thread', insertTextFormat = 1, kind = 9, -- cgit From b2bad0ac91ddb9b33c3547b6fd4f7278794818d9 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Tue, 28 May 2024 23:20:25 +0200 Subject: feat(lsp): support postfix snippets in completion --- runtime/lua/vim/lsp/completion.lua | 35 +++++--- test/functional/plugin/lsp/completion_spec.lua | 108 +++++++++++++++++-------- 2 files changed, 98 insertions(+), 45 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index f9b0563b86..39c0c5fa29 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -129,18 +129,33 @@ end --- @param item lsp.CompletionItem --- @return string local function get_completion_word(item) - if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.textEdit.newText - else - return parse_snippet(item.textEdit.newText) - end - elseif item.insertText ~= nil and item.insertText ~= '' then - if item.insertTextFormat == protocol.InsertTextFormat.PlainText then - return item.insertText - else + if item.insertTextFormat == protocol.InsertTextFormat.Snippet then + if item.textEdit then + -- Use label instead of text if text has different starting characters. + -- label is used as abbr (=displayed), but word is used for filtering + -- This is required for things like postfix completion. + -- E.g. in lua: + -- + -- local f = {} + -- f@| + -- ▲ + -- └─ cursor + -- + -- item.textEdit.newText: table.insert(f, $0) + -- label: insert + -- + -- Typing `i` would remove the candidate because newText starts with `t`. + local text = item.insertText or item.textEdit.newText + return #text < #item.label and text or item.label + elseif item.insertText and item.insertText ~= '' then return parse_snippet(item.insertText) + else + return item.label end + elseif item.textEdit then + return item.textEdit.newText + elseif item.insertText and item.insertText ~= '' then + return item.insertText end return item.label end diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index 078abdf653..d7755dd0c4 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -78,32 +78,6 @@ describe('vim.lsp.completion: item conversion', function() textEdit = { newText = 'foobar', range = range0 }, }, { label = 'foocar', sortText = 'f', textEdit = { newText = 'foobar', range = range0 } }, - -- real-world snippet text - { - label = 'foocar', - sortText = 'g', - insertText = 'foodar', - insertTextFormat = 2, - textEdit = { - newText = 'foobar(${1:place holder}, ${2:more ...holder{\\}})', - range = range0, - }, - }, - { - label = 'foocar', - sortText = 'h', - insertText = 'foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', - insertTextFormat = 2, - }, - -- nested snippet tokens - { - label = 'foocar', - sortText = 'i', - insertText = 'foodar(${1:${2|typ1,typ2|}}) {$0\\}', - insertTextFormat = 2, - }, - -- braced tabstop - { label = 'foocar', sortText = 'j', insertText = 'foodar()${0}', insertTextFormat = 2 }, -- plain text { label = 'foocar', @@ -139,23 +113,87 @@ describe('vim.lsp.completion: item conversion', function() }, { abbr = 'foocar', - word = 'foobar(place holder, more ...holder{})', + word = 'foodar(${1:var1})', -- marked as PlainText, text is used as is + }, + } + local result = complete('|', completion_list) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + eq(expected, result) + end) + + it('prefers wordlike components for snippets', function() + -- There are two goals here: + -- + -- 1. The `word` should match what the user started typing, so that vim.fn.complete() doesn't + -- filter it away, preventing snippet expansion + -- + -- For example, if they type `items@ins`, luals returns `table.insert(items, $0)` as + -- textEdit.newText and `insert` as label. + -- There would be no prefix match if textEdit.newText is used as `word` + -- + -- 2. If users do not expand a snippet, but continue typing, they should see a somewhat reasonable + -- `word` getting inserted. + -- + -- For example in: + -- + -- insertText: "testSuites ${1:Env}" + -- label: "testSuites" + -- + -- "testSuites" should have priority as `word`, as long as the full snippet gets expanded on accept () + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } + local completion_list = { + -- luals postfix snippet (typed text: items@ins|) + { + label = 'insert', + insertTextFormat = 2, + textEdit = { + newText = 'table.insert(items, $0)', + range = range0, + }, }, + + -- eclipse.jdt.ls `new` snippet { - abbr = 'foocar', - word = 'foodar(var1 typ1, var2 *typ2) {}', + label = 'new', + insertTextFormat = 2, + textEdit = { + newText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}', + range = range0, + }, + textEditText = '${1:Object} ${2:foo} = new ${1}(${3});\n${0}', }, + + -- eclipse.jdt.ls `List.copyO` function call completion { - abbr = 'foocar', - word = 'foodar(typ1) {}', + label = 'copyOf(Collection coll) : List', + insertTextFormat = 2, + insertText = 'copyOf', + textEdit = { + newText = 'copyOf(${1:coll})', + range = range0, + }, }, + } + local expected = { { - abbr = 'foocar', - word = 'foodar()', + abbr = 'copyOf(Collection coll) : List', + word = 'copyOf', }, { - abbr = 'foocar', - word = 'foodar(${1:var1})', + abbr = 'insert', + word = 'insert', + }, + { + abbr = 'new', + word = 'new', }, } local result = complete('|', completion_list) -- cgit From 5c33815448e11b514678f39cecc74e68131d4628 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 30 May 2024 10:46:26 +0200 Subject: refactor(lsp): replace util.buf_versions with changedtick (#28943) `lsp.util.buf_versions` was already derived from changedtick (`on_lines` from `buf_attach` synced the version) As far as I can tell there is no need to keep track of the state in a separate table. --- runtime/doc/deprecated.txt | 3 +++ runtime/lua/vim/lsp.lua | 5 +--- runtime/lua/vim/lsp/_changetracking.lua | 3 +-- runtime/lua/vim/lsp/client.lua | 5 ++-- runtime/lua/vim/lsp/inlay_hint.lua | 4 +-- runtime/lua/vim/lsp/semantic_tokens.lua | 6 ++--- runtime/lua/vim/lsp/util.lua | 16 ++++++++---- test/functional/fixtures/fake-lsp-server.lua | 14 +++++------ .../functional/plugin/lsp/semantic_tokens_spec.lua | 24 +++++++++--------- test/functional/plugin/lsp_spec.lua | 29 ++++++++-------------- 10 files changed, 52 insertions(+), 57 deletions(-) diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 6c6585d76e..3b3e6afa9e 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -22,6 +22,9 @@ API LUA - vim.region() Use |getregionpos()| instead. +LSP +- *vim.lsp.util.buf_versions* Use |b:changedtick| instead. + DIAGNOSTICS - *vim.diagnostic.goto_next()* Use |vim.diagnostic.jump()| with `{count = 1}` instead. - *vim.diagnostic.goto_prev()* Use |vim.diagnostic.jump()| with `{count = -1}` instead. diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 96dbf97146..c2deac0113 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -484,7 +484,6 @@ local function text_document_did_save_handler(bufnr) text = lsp._buf_get_full_text(bufnr), }, }) - util.buf_versions[bufnr] = 0 end local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save') if save_capability then @@ -520,7 +519,6 @@ local function buf_detach_client(bufnr, client) end client.attached_buffers[bufnr] = nil - util.buf_versions[bufnr] = nil local namespace = lsp.diagnostic.get_namespace(client.id) vim.diagnostic.reset(namespace, bufnr) @@ -576,12 +574,11 @@ local function buf_attach(bufnr) }) -- First time, so attach and set up stuff. api.nvim_buf_attach(bufnr, false, { - on_lines = function(_, _, changedtick, firstline, lastline, new_lastline) + on_lines = function(_, _, _, firstline, lastline, new_lastline) if #lsp.get_clients({ bufnr = bufnr }) == 0 then -- detach if there are no clients return #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 end - util.buf_versions[bufnr] = changedtick changetracking.send_changes(bufnr, firstline, lastline, new_lastline) end, diff --git a/runtime/lua/vim/lsp/_changetracking.lua b/runtime/lua/vim/lsp/_changetracking.lua index b2be53269f..ce701f0772 100644 --- a/runtime/lua/vim/lsp/_changetracking.lua +++ b/runtime/lua/vim/lsp/_changetracking.lua @@ -1,6 +1,5 @@ local protocol = require('vim.lsp.protocol') local sync = require('vim.lsp.sync') -local util = require('vim.lsp.util') local api = vim.api local uv = vim.uv @@ -277,7 +276,7 @@ local function send_changes(bufnr, sync_kind, state, buf_state) client.notify(protocol.Methods.textDocument_didChange, { textDocument = { uri = uri, - version = util.buf_versions[bufnr], + version = vim.b[bufnr].changedtick, }, contentChanges = changes, }) diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua index 327cd19125..b28fe2f797 100644 --- a/runtime/lua/vim/lsp/client.lua +++ b/runtime/lua/vim/lsp/client.lua @@ -673,8 +673,8 @@ function Client:_request(method, params, handler, bufnr) end -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state changetracking.flush(self, bufnr) - local version = lsp.util.buf_versions[bufnr] bufnr = resolve_bufnr(bufnr) + local version = vim.b[bufnr].changedtick log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) local success, request_id = self.rpc.request(method, params, function(err, result) local context = { @@ -922,14 +922,13 @@ function Client:_text_document_did_open_handler(bufnr) local params = { textDocument = { - version = 0, + version = vim.b[bufnr].changedtick, uri = vim.uri_from_bufnr(bufnr), languageId = self.get_language_id(bufnr, filetype), text = lsp._buf_get_full_text(bufnr), }, } self.notify(ms.textDocument_didOpen, params) - lsp.util.buf_versions[bufnr] = params.textDocument.version -- Next chance we get, we should re-do the diagnostics vim.schedule(function() diff --git a/runtime/lua/vim/lsp/inlay_hint.lua b/runtime/lua/vim/lsp/inlay_hint.lua index f98496456b..78f309abf7 100644 --- a/runtime/lua/vim/lsp/inlay_hint.lua +++ b/runtime/lua/vim/lsp/inlay_hint.lua @@ -43,7 +43,7 @@ function M.on_inlayhint(err, result, ctx, _) return end local bufnr = assert(ctx.bufnr) - if util.buf_versions[bufnr] ~= ctx.version then + if vim.b[bufnr].changedtick ~= ctx.version then return end local client_id = ctx.client_id @@ -324,7 +324,7 @@ api.nvim_set_decoration_provider(namespace, { return end - if bufstate.version ~= util.buf_versions[bufnr] then + if bufstate.version ~= vim.b[bufnr].changedtick then return end diff --git a/runtime/lua/vim/lsp/semantic_tokens.lua b/runtime/lua/vim/lsp/semantic_tokens.lua index ef2502b12e..278014a4ea 100644 --- a/runtime/lua/vim/lsp/semantic_tokens.lua +++ b/runtime/lua/vim/lsp/semantic_tokens.lua @@ -116,7 +116,7 @@ local function tokens_to_ranges(data, bufnr, client, request) if elapsed_ns > yield_interval_ns then vim.schedule(function() - coroutine.resume(co, util.buf_versions[bufnr]) + coroutine.resume(co, vim.b[bufnr].changedtick) end) if request.version ~= coroutine.yield() then -- request became stale since the last time the coroutine ran. @@ -275,7 +275,7 @@ end --- ---@package function STHighlighter:send_request() - local version = util.buf_versions[self.bufnr] + local version = vim.b[self.bufnr].changedtick self:reset_timer() @@ -418,7 +418,7 @@ end function STHighlighter:on_win(topline, botline) for client_id, state in pairs(self.client_state) do local current_result = state.current_result - if current_result.version and current_result.version == util.buf_versions[self.bufnr] then + if current_result.version and current_result.version == vim.b[self.bufnr].changedtick then if not current_result.namespace_cleared then api.nvim_buf_clear_namespace(self.bufnr, state.namespace, 0, -1) current_result.namespace_cleared = true diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0099e82f52..d1f0e97065 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -509,8 +509,7 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) and ( text_document.version and text_document.version > 0 - and M.buf_versions[bufnr] - and M.buf_versions[bufnr] > text_document.version + and vim.b[bufnr].changedtick > text_document.version ) then print('Buffer ', text_document.uri, ' newer than edits.') @@ -2200,9 +2199,16 @@ function M._refresh(method, opts) end end -M._get_line_byte_from_position = get_line_byte_from_position - ---@nodoc -M.buf_versions = {} ---@type table +---@deprecated +---@type table +M.buf_versions = setmetatable({}, { + __index = function(_, bufnr) + vim.deprecate('vim.lsp.util.buf_versions', 'vim.b.changedtick', '0.13') + return vim.b[bufnr].changedtick + end, +}) + +M._get_line_byte_from_position = get_line_byte_from_position return M diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index f806869b40..9aafd38d4f 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -471,7 +471,7 @@ function tests.basic_check_buffer_open() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('finish') @@ -498,7 +498,7 @@ function tests.basic_check_buffer_open_and_change() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -534,7 +534,7 @@ function tests.basic_check_buffer_open_and_change_noeol() languageId = '', text = table.concat({ 'testing', '123' }, '\n'), uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -569,7 +569,7 @@ function tests.basic_check_buffer_open_and_change_multi() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -614,7 +614,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -672,7 +672,7 @@ function tests.basic_check_buffer_open_and_change_incremental() languageId = '', text = table.concat({ 'testing', '123' }, '\n') .. '\n', uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { @@ -715,7 +715,7 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() languageId = '', text = table.concat({ 'testing', '123' }, '\n'), uri = 'file://', - version = 0, + version = 2, }, }) expect_notification('textDocument/didChange', { diff --git a/test/functional/plugin/lsp/semantic_tokens_spec.lua b/test/functional/plugin/lsp/semantic_tokens_spec.lua index 7908c5d2e7..9babb080e7 100644 --- a/test/functional/plugin/lsp/semantic_tokens_spec.lua +++ b/test/functional/plugin/lsp/semantic_tokens_spec.lua @@ -111,6 +111,7 @@ describe('semantic token highlighting', function() end) it('buffer is highlighted when attached', function() + insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) @@ -118,8 +119,6 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -141,6 +140,7 @@ describe('semantic token highlighting', function() end) it('use LspTokenUpdate and highlight_token', function() + insert(text) exec_lua([[ vim.api.nvim_create_autocmd("LspTokenUpdate", { callback = function(args) @@ -157,8 +157,6 @@ describe('semantic token highlighting', function() client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -180,14 +178,17 @@ describe('semantic token highlighting', function() end) it('buffer is unhighlighted when client is detached', function() + insert(text) + exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) + vim.wait(1000, function() + return #server.messages > 1 + end) ]]) - insert(text) - exec_lua([[ vim.notify = function() end vim.lsp.buf_detach_client(bufnr, client_id) @@ -331,14 +332,13 @@ describe('semantic token highlighting', function() end) it('buffer is re-highlighted when force refreshed', function() + insert(text) exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) - screen:expect { grid = [[ #include | @@ -412,13 +412,14 @@ describe('semantic token highlighting', function() end) it('updates highlights with delta request on buffer change', function() + insert(text) + exec_lua([[ bufnr = vim.api.nvim_get_current_buf() vim.api.nvim_win_set_buf(0, bufnr) client_id = vim.lsp.start({ name = 'dummy', cmd = server.cmd }) ]]) - insert(text) screen:expect { grid = [[ #include | @@ -597,6 +598,7 @@ describe('semantic token highlighting', function() end) it('does not send delta requests if not supported by server', function() + insert(text) exec_lua( [[ local legend, response, edit_response = ... @@ -625,7 +627,6 @@ describe('semantic token highlighting', function() edit_response ) - insert(text) screen:expect { grid = [[ #include | @@ -1449,6 +1450,7 @@ int main() }, }) do it(test.it, function() + insert(test.text1) exec_lua(create_server_definition) exec_lua( [[ @@ -1485,8 +1487,6 @@ int main() test.response2 ) - insert(test.text1) - test.expected_screen1() local highlights = exec_lua([[ diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 0cf84b50c2..85891e59b5 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -255,7 +255,7 @@ describe('LSP', function() return end local expected_handlers = { - { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'shutdown', bufnr = 1, client_id = 1, version = 2 } }, { NIL, {}, { method = 'test', client_id = 1 } }, } test_rpc_server { @@ -948,7 +948,11 @@ describe('LSP', function() it('should forward ContentModified to callback', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { { code = -32801 }, NIL, { method = 'error_code_test', bufnr = 1, client_id = 1 } }, + { + { code = -32801 }, + NIL, + { method = 'error_code_test', bufnr = 1, client_id = 1, version = 2 }, + }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -978,7 +982,7 @@ describe('LSP', function() it('should track pending requests to the language server', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1045,7 +1049,7 @@ describe('LSP', function() it('should clear pending and cancel requests on reply', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1084,7 +1088,7 @@ describe('LSP', function() it('should trigger LspRequest autocmd when requests table changes', function() local expected_handlers = { { NIL, {}, { method = 'finish', client_id = 1 } }, - { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1 } }, + { NIL, {}, { method = 'slow_request', bufnr = 1, client_id = 1, version = 2 } }, } local client --- @type vim.lsp.Client test_rpc_server { @@ -1364,6 +1368,7 @@ describe('LSP', function() }, bufnr = 2, client_id = 1, + version = 2, }, }, { NIL, {}, { method = 'start', client_id = 1 } }, @@ -2117,7 +2122,6 @@ describe('LSP', function() local args = {...} local bufnr = select(1, ...) local text_edit = select(2, ...) - vim.lsp.util.buf_versions[bufnr] = 10 vim.lsp.util.apply_text_document_edit(text_edit, nil, 'utf-16') ]], target_bufnr, @@ -2134,7 +2138,6 @@ describe('LSP', function() [[ local args = {...} local versionedBuf = args[2] - vim.lsp.util.buf_versions[versionedBuf.bufnr] = versionedBuf.currentVersion vim.lsp.util.apply_text_document_edit(args[1], nil, 'utf-16') ]], edit, @@ -2239,18 +2242,6 @@ describe('LSP', function() } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) - - local update_changed_tick = function() - vim.lsp.util.buf_versions[bufnr] = vim.api.nvim_buf_get_var(bufnr, 'changedtick') - end - - update_changed_tick() - vim.api.nvim_buf_attach(bufnr, false, { - on_changedtick = function() - update_changed_tick() - end - }) - return {bufnr, vim.api.nvim_buf_get_var(bufnr, 'changedtick')} ]] -- cgit From 064483a2b4a3056baf8eee4424bb81127e531991 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 28 May 2024 12:52:24 +0200 Subject: refactor(fileio): use a linear buffer for FileDescriptor Using a ring buffer for buffered synchronous fileio is just unnecessary complexity. - when reading, we always consume the _entire_ buffer before getting into syscalls. Thus we reset the buffer to its initial position before when we actually read. - when writing and buffer is full, we always flush the entire buffer before starting to buffer again. So we can reset the buffer to its initial state. Also no static buffers are needed for writing and skipping. Needing an extra copy for each write completely defeated the purpose of a ring buffer (if there had been one) --- src/nvim/msgpack_rpc/packer.c | 1 - src/nvim/os/fileio.c | 274 +++++++++++++++++++++--------------------- src/nvim/os/fileio_defs.h | 9 +- src/nvim/rbuffer.c | 19 +-- 4 files changed, 144 insertions(+), 159 deletions(-) diff --git a/src/nvim/msgpack_rpc/packer.c b/src/nvim/msgpack_rpc/packer.c index cac68f76f0..9c0d2910fa 100644 --- a/src/nvim/msgpack_rpc/packer.c +++ b/src/nvim/msgpack_rpc/packer.c @@ -113,7 +113,6 @@ void mpack_handle(ObjectType type, handle_T handle, PackerBuffer *packer) mpack_w(&packer->ptr, 0xc7); mpack_w(&packer->ptr, packsize); mpack_w(&packer->ptr, exttype); - // check_buffer(packer); memcpy(packer->ptr, buf, (size_t)packsize); packer->ptr += packsize; } diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index e58eb96c2e..c87b2d359f 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -120,12 +120,9 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags) assert(!ret_fp->wr || !ret_fp->non_blocking); ret_fp->fd = fd; ret_fp->eof = false; - ret_fp->rv = rbuffer_new(kRWBufferSize); - ret_fp->_error = 0; - if (ret_fp->wr) { - ret_fp->rv->data = ret_fp; - ret_fp->rv->full_cb = (rbuffer_callback)&file_rb_write_full_cb; - } + ret_fp->buffer = alloc_block(); + ret_fp->read_pos = ret_fp->buffer; + ret_fp->write_pos = ret_fp->buffer; ret_fp->bytes_read = 0; return 0; } @@ -148,8 +145,9 @@ void file_open_buffer(FileDescriptor *ret_fp, char *data, size_t len) ret_fp->non_blocking = false; ret_fp->fd = -1; ret_fp->eof = true; - ret_fp->rv = rbuffer_new_wrap_buf(data, len); - ret_fp->_error = 0; + ret_fp->buffer = NULL; // we don't take ownership + ret_fp->read_pos = data; + ret_fp->write_pos = data + len; ret_fp->bytes_read = 0; } @@ -163,36 +161,18 @@ int file_close(FileDescriptor *const fp, const bool do_fsync) FUNC_ATTR_NONNULL_ALL { if (fp->fd < 0) { - rbuffer_free(fp->rv); return 0; } const int flush_error = (do_fsync ? file_fsync(fp) : file_flush(fp)); const int close_error = os_close(fp->fd); - rbuffer_free(fp->rv); + free_block(fp->buffer); if (close_error != 0) { return close_error; } return flush_error; } -/// Flush file modifications to disk -/// -/// @param[in,out] fp File to work with. -/// -/// @return 0 or error code. -int file_flush(FileDescriptor *const fp) - FUNC_ATTR_NONNULL_ALL -{ - if (!fp->wr) { - return 0; - } - file_rb_write_full_cb(fp->rv, fp); - const int error = fp->_error; - fp->_error = 0; - return error; -} - /// Flush file modifications to disk and run fsync() /// /// @param[in,out] fp File to work with. @@ -218,36 +198,29 @@ int file_fsync(FileDescriptor *const fp) return 0; } -/// Buffer used for writing -/// -/// Like IObuff, but allows file_\* callers not to care about spoiling it. -static char writebuf[kRWBufferSize]; - -/// Function run when RBuffer is full when writing to a file -/// -/// Actually does writing to the file, may also be invoked directly. +/// Flush file modifications to disk /// -/// @param[in,out] rv RBuffer instance used. /// @param[in,out] fp File to work with. -static void file_rb_write_full_cb(RBuffer *const rv, void *const fp_in) +/// +/// @return 0 or error code. +int file_flush(FileDescriptor *fp) FUNC_ATTR_NONNULL_ALL { - FileDescriptor *const fp = fp_in; - assert(fp->wr); - assert(rv->data == (void *)fp); - if (rbuffer_size(rv) == 0) { - return; + if (!fp->wr) { + return 0; + } + + ptrdiff_t to_write = fp->write_pos - fp->read_pos; + if (to_write == 0) { + return 0; } - const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); - const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes, + const ptrdiff_t wres = os_write(fp->fd, fp->read_pos, (size_t)to_write, fp->non_blocking); - if (wres != (ptrdiff_t)read_bytes) { - if (wres >= 0) { - fp->_error = UV_EIO; - } else { - fp->_error = (int)wres; - } + fp->read_pos = fp->write_pos = fp->buffer; + if (wres != to_write) { + return (wres >= 0) ? UV_EIO : (int)wres; } + return 0; } /// Read from file @@ -262,77 +235,78 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { assert(!fp->wr); - char *buf = ret_buf; - size_t read_remaining = size; - RBuffer *const rv = fp->rv; + size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size); + memcpy(ret_buf, fp->read_pos, from_buffer); + + char *buf = ret_buf + from_buffer; + size_t read_remaining = size - from_buffer; + if (!read_remaining) { + fp->bytes_read += from_buffer; + fp->read_pos += from_buffer; + return (ptrdiff_t)from_buffer; + } + + // at this point, we have consumed all of an existing buffer. restart from the beginning + fp->read_pos = fp->write_pos = fp->buffer; + +#ifdef HAVE_READV bool called_read = false; while (read_remaining) { - const size_t rv_size = rbuffer_size(rv); - if (rv_size > 0) { - const size_t rsize = rbuffer_read(rv, buf, MIN(rv_size, read_remaining)); - buf += rsize; - read_remaining -= rsize; - } - if (fp->eof - // Allow only at most one os_read[v] call. - || (called_read && fp->non_blocking)) { + // Allow only at most one os_read[v] call. + if (fp->eof || (called_read && fp->non_blocking)) { break; } - if (read_remaining) { - assert(rbuffer_size(rv) == 0); - rbuffer_reset(rv); -#ifdef HAVE_READV - // If there is readv() syscall, then take an opportunity to populate - // both target buffer and RBuffer at once, … - size_t write_count; - struct iovec iov[] = { - { .iov_base = buf, .iov_len = read_remaining }, - { .iov_base = rbuffer_write_ptr(rv, &write_count), - .iov_len = kRWBufferSize }, - }; - assert(write_count == kRWBufferSize); - const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, - ARRAY_SIZE(iov), fp->non_blocking); - if (r_ret > 0) { - if (r_ret > (ptrdiff_t)read_remaining) { - rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); - read_remaining = 0; - } else { - buf += (size_t)r_ret; - read_remaining -= (size_t)r_ret; - } - } else if (r_ret < 0) { - return r_ret; - } -#else - if (read_remaining >= kRWBufferSize) { - // …otherwise leave RBuffer empty and populate only target buffer, - // because filtering information through rbuffer will be more syscalls. - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, - fp->non_blocking); - if (r_ret >= 0) { - read_remaining -= (size_t)r_ret; - fp->bytes_read += (size - read_remaining); - return (ptrdiff_t)(size - read_remaining); - } else if (r_ret < 0) { - return r_ret; - } + // If there is readv() syscall, then take an opportunity to populate + // both target buffer and RBuffer at once, … + struct iovec iov[] = { + { .iov_base = buf, .iov_len = read_remaining }, + { .iov_base = fp->write_pos, + .iov_len = ARENA_BLOCK_SIZE }, + }; + const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, + ARRAY_SIZE(iov), fp->non_blocking); + if (r_ret > 0) { + if (r_ret > (ptrdiff_t)read_remaining) { + fp->write_pos += (size_t)(r_ret - (ptrdiff_t)read_remaining); + read_remaining = 0; } else { - size_t write_count; - const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, - rbuffer_write_ptr(rv, &write_count), - kRWBufferSize, fp->non_blocking); - assert(write_count == kRWBufferSize); - if (r_ret > 0) { - rbuffer_produced(rv, (size_t)r_ret); - } else if (r_ret < 0) { - return r_ret; - } + buf += r_ret; + read_remaining -= (size_t)r_ret; } -#endif - called_read = true; + } else if (r_ret < 0) { + return r_ret; + } + called_read = true; + } +#else + if (fp->eof) { + // already eof, cannot read more + } else if (read_remaining >= ARENA_BLOCK_SIZE) { + // …otherwise leave fp->buffer empty and populate only target buffer, + // because filtering information through rbuffer will be more syscalls. + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, + fp->non_blocking); + if (r_ret >= 0) { + read_remaining -= (size_t)r_ret; + } else if (r_ret < 0) { + return r_ret; + } + } else { + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, + fp->write_pos, + ARENA_BLOCK_SIZE, fp->non_blocking); + if (r_ret < 0) { + return r_ret; + } else { + fp->write_pos += r_ret; + size_t to_copy = MIN((size_t)r_ret, read_remaining); + memcpy(ret_buf, fp->read_pos, to_copy); + fp->read_pos += to_copy; + read_remaining -= to_copy; } } +#endif + fp->bytes_read += (size - read_remaining); return (ptrdiff_t)(size - read_remaining); } @@ -348,40 +322,68 @@ ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { assert(fp->wr); - const size_t written = rbuffer_write(fp->rv, buf, size); - if (fp->_error != 0) { - const int error = fp->_error; - fp->_error = 0; - return error; - } else if (written != size) { - return UV_EIO; + ptrdiff_t space = (fp->buffer + ARENA_BLOCK_SIZE) - fp->write_pos; + // includes the trivial case of size==0 + if (size < (size_t)space) { + memcpy(fp->write_pos, buf, size); + fp->write_pos += size; + return (ptrdiff_t)size; + } + + // TODO(bfredl): just as for reading, use iovec to combine fp->buffer with buf + int status = file_flush(fp); + if (status < 0) { + return status; + } + + if (size < ARENA_BLOCK_SIZE) { + memcpy(fp->write_pos, buf, size); + fp->write_pos += size; + return (ptrdiff_t)size; } - return (ptrdiff_t)written; -} -/// Buffer used for skipping. Its contents is undefined and should never be -/// used. -static char skipbuf[kRWBufferSize]; + const ptrdiff_t wres = os_write(fp->fd, buf, size, + fp->non_blocking); + return (wres != (ptrdiff_t)size && wres >= 0) ? UV_EIO : wres; +} /// Skip some bytes /// /// This is like `fseek(fp, size, SEEK_CUR)`, but actual implementation simply -/// reads to a buffer and discards the result. +/// reads to the buffer and discards the result. ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size) FUNC_ATTR_NONNULL_ALL { assert(!fp->wr); - size_t read_bytes = 0; - do { - const ptrdiff_t new_read_bytes = - file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf))); - if (new_read_bytes < 0) { - return new_read_bytes; - } else if (new_read_bytes == 0) { + size_t from_buffer = MIN((size_t)(fp->write_pos - fp->read_pos), size); + size_t skip_remaining = size - from_buffer; + if (skip_remaining == 0) { + fp->read_pos += from_buffer; + fp->bytes_read += from_buffer; + return (ptrdiff_t)from_buffer; + } + + fp->read_pos = fp->write_pos = fp->buffer; + bool called_read = false; + while (skip_remaining > 0) { + // Allow only at most one os_read[v] call. + if (fp->eof || (called_read && fp->non_blocking)) { break; } - read_bytes += (size_t)new_read_bytes; - } while (read_bytes < size && !file_eof(fp)); + const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, fp->buffer, ARENA_BLOCK_SIZE, + fp->non_blocking); + if (r_ret < 0) { + return r_ret; + } else if ((size_t)r_ret > skip_remaining) { + fp->read_pos = fp->buffer + skip_remaining; + fp->write_pos = fp->buffer + r_ret; + fp->bytes_read += size; + return (ptrdiff_t)size; + } + skip_remaining -= (size_t)r_ret; + called_read = true; + } - return (ptrdiff_t)read_bytes; + fp->bytes_read += size - skip_remaining; + return (ptrdiff_t)(size - skip_remaining); } diff --git a/src/nvim/os/fileio_defs.h b/src/nvim/os/fileio_defs.h index 10277d2a7a..63b6f51c17 100644 --- a/src/nvim/os/fileio_defs.h +++ b/src/nvim/os/fileio_defs.h @@ -8,9 +8,10 @@ /// Structure used to read from/write to file typedef struct { - int fd; ///< File descriptor. - int _error; ///< Error code for use with RBuffer callbacks or zero. - RBuffer *rv; ///< Read or write buffer. + int fd; ///< File descriptor. Can be -1 if no backing file (file_open_buffer) + char *buffer; ///< Read or write buffer. always ARENA_BLOCK_SIZE if allocated + char *read_pos; ///< read position in buffer + char *write_pos; ///< write position in buffer bool wr; ///< True if file is in write mode. bool eof; ///< True if end of file was encountered. bool non_blocking; ///< True if EAGAIN should not restart syscalls. @@ -28,7 +29,7 @@ static inline bool file_eof(const FileDescriptor *fp) /// performed. static inline bool file_eof(const FileDescriptor *const fp) { - return fp->eof && rbuffer_size(fp->rv) == 0; + return fp->eof && fp->read_pos == fp->write_pos; } static inline int file_fd(const FileDescriptor *fp) diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index cf2e10f90d..493c079d4c 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -29,23 +29,6 @@ RBuffer *rbuffer_new(size_t capacity) return rv; } -/// Creates a new `RBuffer` instance for reading from a buffer. -/// -/// Must not be used with any write function like rbuffer_write_ptr or rbuffer_produced! -RBuffer *rbuffer_new_wrap_buf(char *data, size_t len) - FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET -{ - RBuffer *rv = xcalloc(1, sizeof(RBuffer)); - rv->full_cb = rv->nonfull_cb = NULL; - rv->data = NULL; - rv->size = len; - rv->read_ptr = data; - rv->write_ptr = data + len; - rv->end_ptr = NULL; - rv->temp = NULL; - return rv; -} - void rbuffer_free(RBuffer *buf) FUNC_ATTR_NONNULL_ALL { xfree(buf->temp); @@ -146,7 +129,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count) assert(count <= buf->size); buf->read_ptr += count; - if (buf->end_ptr && buf->read_ptr >= buf->end_ptr) { + if (buf->read_ptr >= buf->end_ptr) { buf->read_ptr -= rbuffer_capacity(buf); } -- cgit From 783f6079b824539bdc4a168ecfebddab474b2924 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 29 May 2024 15:59:43 +0200 Subject: ci: update labeler configuration and add reviewers --- .github/scripts/labeler_configuration.yml | 20 ++++++++++++++++++++ .github/scripts/reviewers_add.js | 14 +++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.github/scripts/labeler_configuration.yml b/.github/scripts/labeler_configuration.yml index ea670d1dd0..cf3b8f802b 100644 --- a/.github/scripts/labeler_configuration.yml +++ b/.github/scripts/labeler_configuration.yml @@ -2,6 +2,10 @@ build: - changed-files: - any-glob-to-any-file: [ CMakeLists.txt, "**/CMakeLists.txt", "**/Makefile", "**/*.cmake", cmake.deps/**/* ] +checkhealth: + - changed-files: + - any-glob-to-any-file: [ "**/health.lua" ] + ci: - changed-files: - any-glob-to-any-file: [ .github/actions/**, .github/workflows/**, .github/scripts/** ] @@ -14,6 +18,14 @@ column: - changed-files: - any-glob-to-any-file: [ src/nvim/sign* ] +comment: + - changed-files: + - any-glob-to-any-file: [ runtime/lua/vim/_comment.lua ] + +defaults: + - changed-files: + - any-glob-to-any-file: [ runtime/lua/vim/_defaults.lua ] + diagnostic: - changed-files: - any-glob-to-any-file: [ runtime/lua/vim/diagnostic.lua ] @@ -34,6 +46,10 @@ filetype: - changed-files: - any-glob-to-any-file: [ runtime/lua/vim/filetype.lua, runtime/lua/vim/filetype/detect.lua ] +filesystem: + - changed-files: + - any-glob-to-any-file: [ runtime/lua/vim/fs.lua ] + folds: - changed-files: - any-glob-to-any-file: [ src/nvim/fold* ] @@ -46,6 +62,10 @@ mouse: - changed-files: - any-glob-to-any-file: [ src/nvim/mouse* ] +netrw: + - changed-files: + - any-glob-to-any-file: [ runtime/autoload/netrw.vim, runtime/plugin/netrwPlugin.vim ] + snippet: - changed-files: - any-glob-to-any-file: [ runtime/lua/vim/snippet.lua ] diff --git a/.github/scripts/reviewers_add.js b/.github/scripts/reviewers_add.js index a7e0d2e47b..50195497af 100644 --- a/.github/scripts/reviewers_add.js +++ b/.github/scripts/reviewers_add.js @@ -23,6 +23,10 @@ module.exports = async ({ github, context }) => { reviewers.add("lewis6991"); } + if (labels.includes("comment")) { + reviewers.add("echasnovski"); + } + if (labels.includes("defaults")) { reviewers.add("gpanders"); } @@ -43,7 +47,7 @@ module.exports = async ({ github, context }) => { reviewers.add("gpanders"); } - if (labels.includes("extmarks")) { + if (labels.includes("marks")) { reviewers.add("bfredl"); } @@ -52,11 +56,19 @@ module.exports = async ({ github, context }) => { reviewers.add("gpanders"); } + if (labels.includes("inccommand")) { + reviewers.add("famiu"); + } + if (labels.includes("lsp")) { reviewers.add("MariaSolOs"); reviewers.add("mfussenegger"); } + if (labels.includes("netrw")) { + reviewers.add("justinmk"); + } + if (labels.includes("options")) { reviewers.add("famiu"); } -- cgit From df2c3b204b9622687d0cd7dd59cbd3f89d9383ce Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 30 May 2024 13:57:41 +0800 Subject: vim-patch:9.1.0449: MS-Windows: Compiler warnings Problem: MS-Windows: Compiler warnings Solution: Resolve size_t to int warnings closes: vim/vim#14874 A couple of warnings in ex_docmd.c have been resolved by modifying their function argument types, followed by some changes in various function call sites. This also allowed removal of some casts to cope with size_t/int conversion. https://github.com/vim/vim/commit/51024bbc1a9e298b1fb8f2e465fccb5db409551e Co-authored-by: Mike Williams --- src/nvim/strings.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 16ae35272b..485551da6e 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -266,11 +266,11 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli *d++ = *p++; continue; } - if (do_special && find_cmdline_var(p, &l) >= 0) { + if (do_special && find_cmdline_var(p, &l) >= 0 && l > 0) { *d++ = '\\'; // insert backslash - while (--l != SIZE_MAX) { // copy the var + do { // copy the var *d++ = *p++; - } + } while (--l > 0); continue; } if (*p == '\\' && fish_like) { -- cgit From 2de12e9bd7fe72eb4656a3c0f689caf6ce971451 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 31 May 2024 05:50:57 +0800 Subject: vim-patch:9.1.0451: No test for escaping '<' with shellescape() Problem: No test for escaping '<' with shellescape() Solution: Add a test. Use memcpy() in code to make it easier to understand. Fix a typo (zeertzjq). closes: vim/vim#14876 https://github.com/vim/vim/commit/88c8c547d5fc380e5685c2b01ec564ccdf9b259a --- src/nvim/search.h | 2 +- src/nvim/strings.c | 8 ++++---- test/old/testdir/test_shell.vim | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/nvim/search.h b/src/nvim/search.h index 783756b781..92ee5d6854 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -84,7 +84,7 @@ typedef struct { /// Structure containing last search pattern and its attributes. typedef struct { char *pat; ///< The pattern (in allocated memory) or NULL. - size_t patlen; ///< The length of the patten (0 is pat is NULL). + size_t patlen; ///< The length of the pattern (0 if pat is NULL). bool magic; ///< Magicness of the pattern. bool no_scs; ///< No smartcase for this pattern. Timestamp timestamp; ///< Time of the last change. diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 485551da6e..8fef4ba7fd 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -266,11 +266,11 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli *d++ = *p++; continue; } - if (do_special && find_cmdline_var(p, &l) >= 0 && l > 0) { + if (do_special && find_cmdline_var(p, &l) >= 0) { *d++ = '\\'; // insert backslash - do { // copy the var - *d++ = *p++; - } while (--l > 0); + memcpy(d, p, l); // copy the var + d += l; + p += l; continue; } if (*p == '\\' && fish_like) { diff --git a/test/old/testdir/test_shell.vim b/test/old/testdir/test_shell.vim index baaa327965..c2320d8f39 100644 --- a/test/old/testdir/test_shell.vim +++ b/test/old/testdir/test_shell.vim @@ -119,6 +119,10 @@ func Test_shellescape() call assert_equal("'te\\#xt'", shellescape("te#xt", 1)) call assert_equal("'te!xt'", shellescape("te!xt")) call assert_equal("'te\\!xt'", shellescape("te!xt", 1)) + call assert_equal("'text'", shellescape("text")) + call assert_equal("'te\\xt'", shellescape("text", 1)) + call assert_equal("'te%xt'", shellescape("te%xt")) + call assert_equal("'te\\\\%xt'", shellescape("te%xt", 1)) call assert_equal("'te\nxt'", shellescape("te\nxt")) call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1)) -- cgit From a18652ed619b4c94c74080b637f446503e2bc605 Mon Sep 17 00:00:00 2001 From: Luis Calle <53507599+TheLeoP@users.noreply.github.com> Date: Thu, 30 May 2024 23:45:30 -0500 Subject: fix(win-msi): add bin to PATH per-machine after installation (#29099) #22856 made it possible for the msi installer to perform per-user installations, which caused problems for users that already had per-machine installations trying to update (the Windows Installer does not support major upgrades across installation context, see #22933 and https://stackoverflow.com/a/15498911). It was then reverted in #22949, but the scope of the modification to the PATH environment variable was not reverted. --- cmake.packaging/WixPatch.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake.packaging/WixPatch.xml b/cmake.packaging/WixPatch.xml index 1196f4f335..89c47753ce 100644 --- a/cmake.packaging/WixPatch.xml +++ b/cmake.packaging/WixPatch.xml @@ -6,7 +6,7 @@ Name='PATH' Action='set' Permanent='no' - System='no' + System='yes' Part='last' Value='[INSTALL_ROOT]bin' /> -- cgit From 7c48cedf3078648e2a1ab9a4002e8795e8d07f53 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 31 May 2024 11:24:06 +0200 Subject: vim-patch:7129f2a: runtime(java): Improve the matching of lambda expressions (vim/vim#14880) - Distinguish some formal parameters. - Support multi-line definitions. https://github.com/vim/vim/commit/7129f2ad2fd9de3e3812a569ba3ad6bf162fd238 Co-authored-by: Aliaksei Budavei <32549825+zzzyxwvut@users.noreply.github.com> --- runtime/syntax/java.vim | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/runtime/syntax/java.vim b/runtime/syntax/java.vim index 9867b147c2..5ba724d24e 100644 --- a/runtime/syntax/java.vim +++ b/runtime/syntax/java.vim @@ -3,7 +3,7 @@ " Maintainer: Aliaksei Budavei <0x000c70 AT gmail DOT com> " Former Maintainer: Claudio Fleiner " Repository: https://github.com/zzzyxwvut/java-vim.git -" Last Change: 2024 May 10 +" Last Change: 2024 May 30 " Please check :help java.vim for comments on some of the options available. @@ -348,7 +348,6 @@ if exists("java_highlight_functions") exec 'syn region javaFuncDef start=/' . s:ff.Engine('\%#=2', '') . '^\s\+\%(\%(@\%(\K\k*\.\)*\K\k*\>\)\s\+\)*\%(p\%(ublic\|rotected\|rivate\)\s\+\)\=\%(\%(abstract\|default\)\s\+\|\%(\%(final\|\%(native\|strictfp\)\|s\%(tatic\|ynchronized\)\)\s\+\)*\)\=\%(<.*[[:space:]-]\@' . s:ff.Peek('1', '') . '\s\+\)\=\%(void\|\%(b\%(oolean\|yte\)\|char\|short\|int\|long\|float\|double\|\%(\<\K\k*\>\.\)*\<' . s:ff.UpperCase('[$_[:upper:]]', '[^a-z0-9]') . '\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '\)\=\)\%(\[\]\)*\)\s\+\<' . s:ff.LowerCase('[$_[:lower:]]', '[^A-Z0-9]') . '\k*\>\s*(/ end=/)/ skip=/\/\*.\{-}\*\/\|\/\/.*$/ contains=@javaFuncParams' endif - exec 'syn match javaLambdaDef "\<\K\k*\>\%(\\)\@' . s:ff.Peek('7', '') . '"' syn match javaBraces "[{}]" endif @@ -421,9 +420,26 @@ syn match javaParenError "\]" hi def link javaParenError javaError +" Lambda expressions (JLS-17, §15.27). if exists("java_highlight_functions") " Make ()-matching definitions after the parenthesis error catcher. - exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '?\[\]@,.]\)*)\s*->"' + " + " Match: ([@A [@B ...] final] var a[, var b, ...]) -> + " | ([@A [@B ...] final] T[<α>][[][]] a[, T b, ...]) -> + " There is no recognition of expressions interspersed with comments + " or of expressions whose parameterised parameter types are written + " across multiple lines. + exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '\%((\_.\{-1,})\)\{-,1}[[:space:]\n]\+\)*\%(final[[:space:]\n]\+\)\=\%(\<\K\k*\>\.\)*\<\K\k*\>\%(<[^(){}]*[[:space:]-]\@' . s:ff.Peek('1', '') . '\)\=\%(\%(\%(\[\]\)\+\|\.\.\.\)\)\=[[:space:]\n]\+\<\K\k*\>\%(\[\]\)*\%(,[[:space:]\n]*\)\=\)\+)[[:space:]\n]*->" contains=javaAnnotation,javaParamModifier,javaLambdaVarType,javaType,@javaClasses,javaVarArg' + " Match: () -> + " | (a[, b, ...]) -> + exec 'syn match javaLambdaDef "\k\@' . s:ff.Peek('4', '') . '\%(,[[:space:]\n]*\)\=\)*)[[:space:]\n]*->"' + " Match: a -> + exec 'syn match javaLambdaDef "\<\K\k*\>\%(\\)\@' . s:ff.Peek('7', '') . '"' + + syn keyword javaParamModifier contained final + hi def link javaParamModifier javaConceptKind + syn keyword javaLambdaVarType contained var + hi def link javaLambdaVarType javaOperator endif " The @javaTop cluster comprises non-contained Java syntax groups. -- cgit From 07af492f635c51d44d02d8012611cc5e11a4af19 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 31 May 2024 12:07:31 +0200 Subject: vim-patch:9.1.0453: filetype: rasi files are not recognized Problem: filetype: rasi files are not recognized Solution: regonize '*.rasi' files as rasi filetype, include a filetype and syntax plugin (Pierrick Guillaume) ported from: https://github.com/Fymyte/rasi.vim closes: vim/vim#14821 https://github.com/vim/vim/commit/280e5b13ca568ed592a894140bf1ac74356f4b33 Co-authored-by: Pierrick Guillaume --- runtime/doc/syntax.txt | 7 + runtime/ftplugin/rasi.vim | 25 ++++ runtime/lua/vim/filetype.lua | 1 + runtime/syntax/rasi.vim | 298 +++++++++++++++++++++++++++++++++++++ test/old/testdir/test_filetype.vim | 1 + 5 files changed, 332 insertions(+) create mode 100644 runtime/ftplugin/rasi.vim create mode 100644 runtime/syntax/rasi.vim diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index 06d7ad8f7e..fc55569a1c 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -2575,6 +2575,13 @@ To highlight R code in knitr chunk headers, add to your |vimrc|: > let rrst_syn_hl_chunk = 1 +RASI *rasi.vim* *ft-rasi-syntax* + +Rasi stands for Rofi Advanced Style Information. It is used by the program +`rofi` to style the rendering of the search window. The language is heavily +inspired by CSS stylesheet. Files with the following extensions are recognized +as rasi files: .rasi. + READLINE *readline.vim* *ft-readline-syntax* The readline library is primarily used by the BASH shell, which adds quite a diff --git a/runtime/ftplugin/rasi.vim b/runtime/ftplugin/rasi.vim new file mode 100644 index 0000000000..5f8ce862df --- /dev/null +++ b/runtime/ftplugin/rasi.vim @@ -0,0 +1,25 @@ +" Vim filetype plugin file +" Language: RASI +" Maintainer: Pierrick Guillaume +" Last Change: 2024 May 21 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let b:undo_ftplugin = "setl com< cms< isk< inc<" + +setlocal comments=s1:/*,mb:*,ex:*/ +setlocal commentstring=//\ %s +setlocal iskeyword+=- + +let &l:include = '^\s*@import\s\+\%(url(\)\=' + +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: ts=8 diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2ab6cc6059..500632a2b2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -873,6 +873,7 @@ local extension = { t6 = 'raku', p6 = 'raku', raml = 'raml', + rasi = 'rasi', rbs = 'rbs', rego = 'rego', rem = 'remind', diff --git a/runtime/syntax/rasi.vim b/runtime/syntax/rasi.vim new file mode 100644 index 0000000000..40c3393fc5 --- /dev/null +++ b/runtime/syntax/rasi.vim @@ -0,0 +1,298 @@ +" Vim syntax file +" Language: rasi (Rofi Advanced Style Information) +" Maintainer: Pierrick Guillaume +" Last Change: 2024 May 21 +" +" Syntax support for rasi config file + +" This file is based on syntax defined in rofi-theme man page +" https://man.archlinux.org/man/community/rofi/rofi-theme.5.en + +if exists('b:current_syntax') + finish +endif +let b:current_syntax = 'rasi' + +" String {{{ +syn region rasiString start=+"+ skip=+\\"+ end=+"+ oneline contained +syn match rasiCharacter +L\='[^\\]'+ contained + +syn cluster rasiPropertyVals add=rasiString,rasiCharacter +" }}} + +" Integer/Real {{{ +syn match rasiNumber display contained '[+-]\?\d\+\(\.\d\+\)\?' + +syn cluster rasiPropertyVals add=rasiNumber +" }}} + +" Boolean {{{ +syn keyword rasiBool contained true false + +syn cluster rasiPropertyVals add=rasiBool +" }}} + +" Image {{{ +syn match rasiInvImage display contained 'url([^)]*)' +syn keyword rasiImageK contained url linear-gradient + +syn match rasiImage display contained transparent 'url(\s*"\([^"]\|\\"\)\+"\(\s*,\s*\(none\|both\|width\|height\)\)\?\s*)' contains=rasiImageScale,rasiString,rasiImageK +syn keyword rasiImageScale contained none both width height + +syn match rasiImage display contained transparent 'linear-gradient(\s*\(\(top\|left\|right\|bottom\)\s*,\s*\)\?[^,)]\+\s*\(,\s*[^,)]\+\s*\)\+)' contains=rasiImageDirection,@rasiColors,rasiImageK +syn keyword rasiImageDirection contained top left right bottom + +syn match rasiImage display contained transparent 'linear-gradient(\s*\d\+\(rad\|grad\|deg\)\s*,\s*[^,)]\+\s*\(,\s*[^,)]\+\s*\)\+)' contains=rasiImageUnit,@rasiColor,@rasiInvColor,rasiNumber,rasiImageK +syn match rasiImageUnit display contained '\(rad\|grad\|deg\)\>' + +syn cluster rasiPropertyVals add=rasiInvImage,rasiImage +" }}} + +" Reference {{{ +syn match rasiReference display contained '@[a-zA-Z0-9-]\+' + +syn keyword rasiVarReferenceK contained var + +syn match rasiInvVarReference display contained 'var([^)]*)' +syn match rasiVarReference display contained transparent 'var(\s*[a-zA-Z0-9-]\+\s*,\s*\(\a\+\s*([^)]*)\)\?[^),]*)' contains=rasiVarReferenceK,rasiPropertyIdRef,@rasiPropertyVals +syn match rasiPropertyIdRef display contained '\a[a-zA-Z0-9-]*' + +syn cluster rasiPropertyVals add=rasiReference,rasiInvVarReference,rasiVarReference +" }}} + +" Env variable {{{ +syn match rasiInvEnv display contained '${[^}]*}' +syn match rasiEnv display contained '${\w\+}'hs=s+2,he=e-1 + +syn keyword rasiEnvVarK contained env + +syn match rasiInvEnvVar display contained 'env([^)]*)' +syn match rasiEnvVar display contained transparent 'env(\s*\w\+\s*,\s*\(\a\+([^)]*)\)\?[^),]*)' contains=rasiEnvVarK,rasiEnvRef,@rasiPropertyVals +syn match rasiEnvRef display contained '\a\w*' + +syn cluster rasiPropertyVals add=rasiEnv,rasiInvEnv,rasiInvEnvVar,rasiEnvVar +" }}} + +" Color {{{ +syn keyword rasiColorK contained rgb[a] hsl[a] hwb[a] cmyk + +syn match rasiHexColor display contained '#\x\{3,4}' +syn match rasiHexColor display contained '#\x\{6}' +syn match rasiHexColor display contained '#\x\{8}' +syn match rasiInvHexColor display contained '#\x\{5}\X'he=e-1,me=e-1 +syn match rasiInvHexColor display contained '#\x\{7}\X'he=e-1,me=e-1 + +syn match rasiInvRGBColor display contained 'rgb\(a\)\?([^)]*)' +syn match rasiRGBColor display contained transparent 'rgb\(a\)\?(\s*\d\+\s*\(%\)\?\s*,\(\s*\d\+\s*\(%\)\?\s*\){2}\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\?)' contains=rasiColorK,rasiNumber,rasiDistance + +syn match rasiInvHSLColor display contained 'h\(sl\|wb\)\(a\)\?([^)]*)' +syn match rasiHSLColor display contained transparent 'h\(sl\|wb\)\(a\)\?(\s*\d\+\(\.\d*\)\?\(deg\|rad\|grad\|turn\)\?\s*\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\{2,3})' contains=rasiColorK,rasiNumber,rasiDistance + + +"this matches doesn't works properly (too long ?) +syn match rasiInvCMYKColor display contained 'cmyk([^)]*)' +syn match rasiCMYKColor display contained transparent 'cmyk(\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\(,\s*\(\d\(\.\d*\)\?\|\d\{,3}%\)\s*\)\{3,4})' contains=rasiColorK,rasiNumber,rasiDistance + +syn case ignore +syn keyword rasiNamedColor contained + \ AliceBlue AntiqueWhite Aqua Aquamarine Azure Beige Bisque Black BlanchedAlmond Blue + \ BlueViolet Brown BurlyWood CadetBlue Chartreuse Chocolate Coral CornflowerBlue Cornsilk + \ Crimson Cyan DarkBlue DarkCyan DarkGoldenRod DarkGray DarkGrey DarkGreen DarkKhaki DarkMagenta + \ DarkOliveGreen DarkOrange DarkOrchid DarkRed DarkSalmon DarkSeaGreen Dark SlateBlue + \ DarkSlateGray DarkSlateGrey DarkTurquoise DarkViolet DeepPink DeepSkyBlue DimGray DimGrey + \ DodgerBlue FireBrick FloralWhite ForestGreen Fuchsia Gainsboro GhostWhite Gold GoldenRod + \ Gray Grey Green GreenYellow HoneyDew HotPink IndianRed Indigo Ivory Khaki Lavender + \ LavenderBlush LawnGreen LemonChiffon LightBlue LightCoral LightCyan LightGoldenRodYellow + \ LightGray LightGrey LightGreen LightPink LightSalmon LightSeaGreen LightSkyBlue LightSlateGray + \ LightSlateGrey LightSteelBlue LightYellow Lime LimeGreen Linen Magenta Maroon MediumAquaMarine + \ MediumBlue MediumOrchid MediumPurple MediumSeaGreen MediumSlateBlue MediumSpringGreen + \ MediumTurquoise MediumVioletRed MidnightBlue MintCream MistyRose Moccasin NavajoWhite Navy + \ OldLace Olive OliveDrab Orange OrangeRed Orchid PaleGoldenRod PaleGreen PaleTurquoise + \ PaleVioletRed PapayaWhip PeachPuff Peru Pink Plum PowderBlue Purple RebeccaPurple Red + \ RosyBrown RoyalBlue SaddleBrown Salmon SandyBrown SeaGreen SeaShell Sienna Silver SkyBlue + \ SlateBlue SlateGray SlateGrey Snow SpringGreen SteelBlue Tan Teal Thistle Tomato Turquoise + \ Violet Wheat White WhiteSmoke Yellow YellowGreen transparent[] "uses `[]` to escape keyword + +syn cluster rasiColors add=rasiHexColor,rasiRGBColor,rasiHSLColor,rasiCMYKColor,rasiNamedColor +syn cluster rasiColors add=rasiInvHexColor,rasiInvRGBColor,rasiInvHSLColor,rasiInvCMYKColor + +syn cluster rasiPropertyVals add=@rasiColors +" }}} + +" Text-Style {{{ +syn keyword rasiTextStyle contained bold italic underline strikethrough none + +syn cluster rasiPropertyVals add=rasiTextStyle +" }}} + +" Line-Style {{{ +syn keyword rasiLineStyle contained dash solid + +syn cluster rasiPropertyVals add=rasiLineStyle +" }}} + +" Distance {{{ +syn match rasiDistanceUnit display contained '\(px\|em\|ch\|%\|mm\)' + +syn match rasiInvDistance display contained '[+-]\?\d\+\.\d\+\(px\|mm\)' +syn match rasiDistance display contained transparent '[-+]\?\d\+\(px\|mm\)' contains=rasiDistanceUnit,rasiNumber +syn match rasiDistance display contained transparent '[+-]\?\d\+\(\.\d\+\)\?\(em\|ch\|%\)' contains=rasiDistanceUnit,rasiNumber + +syn keyword rasiDistanceCalc contained calc nextgroup=rasiDistanceCalcBody +syn region rasiDistanceCalcBody display contained start=+(+ end=+)+ contains=rasiDistanceCalcOp,rasiDistance,rasiInvDistance +syn match rasiDistanceCalcOp display contained '\(+\|-\|/\|\*\|%\|min\|max\)' + +syn cluster rasiPropertyVals add=rasiInvDistance,rasiDistance,rasiDistanceCalc +" }}} + +" Position {{{ +syn keyword rasiPosition contained center east north west south + +syn cluster rasiPropertyVals add=rasiPosition +" }}} + +" Orientation {{{ +syn keyword rasiOrientation contained horizontal vertical + +syn cluster rasiPropertyVals add=rasiOrientation +" }}} + +" Cursor {{{ +syn keyword rasiCursor contained default pointer text + +syn cluster rasiPropertyVals add=rasiCursor +" }}} + +" Keyword List {{{ +syn region rasiKeywordList contained start=+\[+ end=+\]+ contains=rasiPropertyIdRef + +syn cluster rasiPropertyVals add=rasiKeywordList +" }}} + +" Inherit {{{ +syn keyword rasiInherit contained inherit children + +syn cluster rasiPropertyVals add=rasiInherit +" }}} + +syn match rasiGlobalImport display '^\s*@\(import\|theme\)' nextgroup=rasiString skipwhite + +" Section {{{ +" syn region rasiSection transparent start='^[^{]\+{'me=e-1 end='}' contains=rasiSectionOpenning,rasiSectionContent +syn match rasiSectionOpenning transparent '^[^{]\+{'me=e-1 contains=rasiGlobalSection,rasiWidgetName,rasiGlobalMedia nextgroup=rasiThemeSectionContent +" syn match rasiThemeInnerSectionOpenning transparent '^[^:${]\+{'me=e-1 contains=rasiWidgetName nextgroup=rasiThemeInnerSectionContent contained + +syn match rasiGlobalMedia display contained '^\s*@media' nextgroup=rasiInvMediaBody,rasiMediaBody skipwhite +syn match rasiInvMediaBody display contained '([^)]*)' +syn match rasiMediaBody display contained '(\s*[a-z-]\+\s*:\s*\d\+\(px\|mm\)\?\s*)' contains=rasiMediaK,rasiNumber,rasiDistance +syn keyword rasiMediaK contained min-width max-width min-height max-height min-aspect-ratio max-aspect-ratio monitor-id + +syn match rasiGlobalSection display contained '^*' +syn match rasiWidgetName display contained '[a-zA-Z0-9-]\+' nextgroup=rasiVisibleMod skipwhite + +syn keyword rasiVisibleMod contained normal selected alternate nextgroup=rasiVisibleMod,rasiStateWrapper skipwhite +syn match rasiStateWrapper display contained transparent '\.\(normal\|active\|urgent\)' contains=rasiState +syn keyword rasiState contained normal active urgent + + +syn region rasiThemeSectionContent transparent start="{" end="}" contains=rasiProperty,rasiComment,rasiCommentL,rasiSectionOpenning contained +" syn region rasiThemeInnerSectionContent transparent start="{" end="}" contains=rasiProperty,rasiComment,rasiCommentL,rasiThemeInnerSectionOpenning contained + +syn match rasiProperty transparent '^\s*\S\+\s*:.*;\s*$' keepend contained contains=rasiPropertyId,rasiInvPropertyId,rasiPropertyVal,rasiComment,rasiCommentL +syn match rasiInvPropertyId '^\([^:]\&[^/]\{2}\)*:'me=e-1 contained +syn match rasiPropertyId '^\s*[0-9a-zA-Z-]\+\s*:'me=e-1 contained +syn match rasiInvPropertyVal ':[^;];\s*\S\+\s*$'ms=s+1,hs=s+1 +syn match rasiPropertyVal ':\s*[^;]\+;\s*$'ms=s+1,hs=s+1 contained contains=@rasiPropertyVals +" }}} + +" Comment {{{ +syn cluster rasiCommentGroup contains=rasiTodo,rasiBadContinuation + +syn region rasiCommentL start="//" skip="\\$" end="$" keepend contains=@rasiCommentGroup,@Spell +syn region rasiComment start="/\*" end="\*/" contains=@rasiCommentGroup,rasiCommentStartError,@Spell fold extend + +syn match rasiCommentError display '\*/' + +syn keyword rasiTodo contained TODO FIXME XXX NOTE + +if exists("rasi_minlines") + let b:rasi_minlines = rasi_minlines +else + let b:rasi_minlines = 50 +endif +exec "syn sync ccomment rasiComment minlines=" . b:rasi_minlines +" }}} + + + +" Highlighting: {{{ +hi def link rasiError Error + +hi def link rasiTodo Todo +hi def link rasiComment Comment +hi def link rasiCommentStart rasiComment +hi def link rasiCommentL rasiComment +hi def link rasiCommentError rasiError + +hi def link rasiString String +hi def link rasiNumber Number +hi def link rasiBool Boolean + +hi def link rasiImageK Function +hi def link rasiImageScale Keyword +hi def link rasiImageDirection Keyword +hi def link rasiImageUnit Type +hi def link rasiInvImage rasiError + +hi def link rasiHexColor Number +hi def link rasiColorK Function +hi def link rasiNamedColor Number +hi def link rasiInvColor rasiError +hi def link rasiInvHexColor rasiInvColor +hi def link rasiInvRGBColor rasiInvColor +hi def link rasiInvHSLColor rasiInvColor +hi def link rasiInvCMYKColor rasiInvColor + +hi def link rasiTextStyle Keyword +hi def link rasiLineStyle Keyword + +hi def link rasiDistanceUnit Type +hi def link rasiDistanceCalc Function +hi def link rasiDistanceCalcOp Operator +hi def link rasiInvDistance rasiError + +hi def link rasiPosition Keyword +hi def link rasiOrientation Keyword +hi def link rasiCursor Keyword + +hi def link rasiReference Identifier +hi def link rasiPropertyIdRef Identifier +hi def link rasiVarReferenceK Function +hi def link rasiInvVarReference rasiError + +hi def link rasiEnv Identifier +hi def link rasiEnvRef Identifier +hi def link rasiEnvVarK Function +hi def link rasiInvEnv rasiError +hi def link rasiInvEnvVar rasiError + +hi def link rasiWidgetName StorageClass +hi def link rasiGlobalSection StorageClass +hi def link rasiVisibleMod Type +hi def link rasiState Tag + +hi def link rasiInherit Identifier + +hi def link rasiGlobalImport Include + +hi def link rasiGlobalMedia Preproc +hi def link rasiMediaK Keyword +hi def link rasiInvMediaBody rasiError + +hi def link rasiPropertyId Identifier +hi def link rasiInvProperty rasiError +hi def link rasiInvPropertyId rasiError +hi def link rasiInvPropertyVal rasiError +" }}} + +" vim:ts=8 diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index 16125559cf..c8fd48e064 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -181,6 +181,7 @@ func s:GetFilenameChecks() abort \ 'csdl': ['file.csdl'], \ 'csp': ['file.csp', 'file.fdr'], \ 'css': ['file.css'], + \ 'rasi': ['file.rasi'], \ 'cterm': ['file.con'], \ 'csv': ['file.csv'], \ 'cucumber': ['file.feature'], -- cgit From 9b3dfa3ac0dbc823c00a23ed7bd57dc0f0782a3f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 31 May 2024 12:33:00 +0200 Subject: vim-patch:9.1.0454: minor issues in test_filetype with rasi test Problem: minor issues in test_filetype with rasi test (after 9.1.0453) Solution: re-sort test_filetype, fix wrong syntax.txt help tags https://github.com/vim/vim/commit/f3dd6f617c65a9b939697362efe6833eb2778612 Co-authored-by: Christian Brabandt --- runtime/doc/syntax.txt | 2 +- test/old/testdir/test_filetype.vim | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index fc55569a1c..cf553d6707 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -2578,7 +2578,7 @@ To highlight R code in knitr chunk headers, add to your |vimrc|: > RASI *rasi.vim* *ft-rasi-syntax* Rasi stands for Rofi Advanced Style Information. It is used by the program -`rofi` to style the rendering of the search window. The language is heavily +rofi to style the rendering of the search window. The language is heavily inspired by CSS stylesheet. Files with the following extensions are recognized as rasi files: .rasi. diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index c8fd48e064..88cd8fc416 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -181,7 +181,6 @@ func s:GetFilenameChecks() abort \ 'csdl': ['file.csdl'], \ 'csp': ['file.csp', 'file.fdr'], \ 'css': ['file.css'], - \ 'rasi': ['file.rasi'], \ 'cterm': ['file.con'], \ 'csv': ['file.csv'], \ 'cucumber': ['file.feature'], @@ -594,6 +593,7 @@ func s:GetFilenameChecks() abort \ 'radiance': ['file.rad', 'file.mat'], \ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'], \ 'raml': ['file.raml'], + \ 'rasi': ['file.rasi'], \ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'], \ 'rbs': ['file.rbs'], \ 'rc': ['file.rc', 'file.rch'], -- cgit From 6566a59b3a6c8dabfa40f8debd0de96d875825e9 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 31 May 2024 08:41:10 -0400 Subject: refactor(lsp): use predefined types in util function signatures (#29095) --- runtime/doc/lsp.txt | 44 +++++++++++++++++--------------- runtime/lua/vim/lsp/util.lua | 60 +++++++++++++++++++++++--------------------- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index a78a16968f..c4856c6818 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1832,8 +1832,8 @@ apply_text_document_edit({text_document_edit}, {index}, {offset_encoding}) document. Parameters: ~ - • {text_document_edit} (`table`) a `TextDocumentEdit` object - • {index} (`integer`) Optional index of the edit, if from + • {text_document_edit} (`lsp.TextDocumentEdit`) + • {index} (`integer?`) Optional index of the edit, if from a list of edits (or nil, if not from a list) • {offset_encoding} (`string?`) @@ -1845,7 +1845,7 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding}) Applies a list of text edits to a buffer. Parameters: ~ - • {text_edits} (`table`) list of `TextEdit` objects + • {text_edits} (`lsp.TextEdit[]`) • {bufnr} (`integer`) Buffer id • {offset_encoding} (`string`) utf-8|utf-16|utf-32 @@ -1857,7 +1857,7 @@ apply_workspace_edit({workspace_edit}, {offset_encoding}) Applies a `WorkspaceEdit`. Parameters: ~ - • {workspace_edit} (`table`) `WorkspaceEdit` + • {workspace_edit} (`lsp.WorkspaceEdit`) • {offset_encoding} (`string`) utf-8|utf-16|utf-32 (required) See also: ~ @@ -1875,8 +1875,7 @@ buf_highlight_references({bufnr}, {references}, {offset_encoding}) Parameters: ~ • {bufnr} (`integer`) Buffer id - • {references} (`table`) List of `DocumentHighlight` objects to - highlight + • {references} (`lsp.DocumentHighlight[]`) objects to highlight • {offset_encoding} (`string`) One of "utf-8", "utf-16", "utf-32". See also: ~ @@ -1910,8 +1909,8 @@ convert_input_to_markdown_lines({input}, {contents}) Parameters: ~ • {input} (`lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent`) - • {contents} (`table?`) List of strings to extend with converted lines. - Defaults to {}. + • {contents} (`string[]?`) List of strings to extend with converted + lines. Defaults to {}. Return: ~ (`string[]`) extended with lines of converted markdown. @@ -1924,15 +1923,16 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers}) Converts `textDocument/signatureHelp` response to markdown lines. Parameters: ~ - • {signature_help} (`table`) Response of `textDocument/SignatureHelp` + • {signature_help} (`lsp.SignatureHelp`) Response of + `textDocument/SignatureHelp` • {ft} (`string?`) filetype that will be use as the `lang` for the label markdown code block • {triggers} (`table?`) list of trigger characters from the lsp server. used to better determine parameter offsets Return (multiple): ~ - (`table?`) table list of lines of converted markdown. - (`table?`) table of active hl + (`string[]?`) table list of lines of converted markdown. + (`number[]?`) table of active hl See also: ~ • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp @@ -1954,7 +1954,7 @@ jump_to_location({location}, {offset_encoding}, {reuse_win}) Jumps to a location. Parameters: ~ - • {location} (`table`) (`Location`|`LocationLink`) + • {location} (`lsp.Location|lsp.LocationLink`) • {offset_encoding} (`string?`) utf-8|utf-16|utf-32 • {reuse_win} (`boolean?`) Jump to existing window if buffer is already open. @@ -2019,7 +2019,8 @@ make_formatting_params({options}) cursor position. Parameters: ~ - • {options} (`table?`) with valid `FormattingOptions` entries + • {options} (`lsp.FormattingOptions?`) with valid `FormattingOptions` + entries Return: ~ (`lsp.DocumentFormattingParams`) object @@ -2059,7 +2060,7 @@ make_position_params({window}, {offset_encoding}) `window` Return: ~ - (`table`) `TextDocumentPositionParams` object + (`lsp.TextDocumentPositionParams`) See also: ~ • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams @@ -2090,7 +2091,7 @@ make_text_document_params({bufnr}) • {bufnr} (`integer?`) Buffer handle, defaults to current Return: ~ - (`table`) `TextDocumentIdentifier` + (`lsp.TextDocumentIdentifier`) See also: ~ • https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier @@ -2100,8 +2101,11 @@ make_workspace_params({added}, {removed}) Create the workspace params Parameters: ~ - • {added} (`table`) - • {removed} (`table`) + • {added} (`lsp.WorkspaceFolder[]`) + • {removed} (`lsp.WorkspaceFolder[]`) + + Return: ~ + (`lsp.WorkspaceFoldersChangeEvent`) *vim.lsp.util.open_floating_preview()* open_floating_preview({contents}, {syntax}, {opts}) @@ -2145,7 +2149,7 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()* definition) Parameters: ~ - • {location} (`table`) a single `Location` or `LocationLink` + • {location} (`lsp.Location|lsp.LocationLink`) • {opts} (`table`) Return (multiple): ~ @@ -2175,7 +2179,7 @@ show_document({location}, {offset_encoding}, {opts}) Shows document and optionally jumps to the location. Parameters: ~ - • {location} (`table`) (`Location`|`LocationLink`) + • {location} (`lsp.Location|lsp.LocationLink`) • {offset_encoding} (`string?`) utf-8|utf-16|utf-32 • {opts} (`table?`) options • reuse_win (boolean) Jump to existing window if @@ -2200,7 +2204,7 @@ stylize_markdown({bufnr}, {contents}, {opts}) Parameters: ~ • {bufnr} (`integer`) - • {contents} (`table`) of lines to show in window + • {contents} (`string[]`) of lines to show in window • {opts} (`table`) with optional fields • height of floating window • width of floating window diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d1f0e97065..b33f6ccf69 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -173,11 +173,11 @@ local _str_byteindex_enc = M._str_byteindex_enc --- CAUTION: Changes in-place! --- ---@deprecated ----@param lines (table) Original list of strings ----@param A (table) Start position; a 2-tuple of {line,col} numbers ----@param B (table) End position; a 2-tuple of {line,col} numbers ----@param new_lines (table) list of strings to replace the original ----@return table The modified {lines} object +---@param lines string[] Original list of strings +---@param A [integer, integer] Start position; a 2-tuple of {line,col} numbers +---@param B [integer, integer] End position; a 2-tuple {line,col} numbers +---@param new_lines string[] list of strings to replace the original +---@return string[] The modified {lines} object function M.set_lines(lines, A, B, new_lines) vim.deprecate('vim.lsp.util.set_lines()', 'nil', '0.12') -- 0-indexing to 1-indexing @@ -343,7 +343,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding) end --- Applies a list of text edits to a buffer. ----@param text_edits table list of `TextEdit` objects +---@param text_edits lsp.TextEdit[] ---@param bufnr integer Buffer id ---@param offset_encoding string utf-8|utf-16|utf-32 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit @@ -481,8 +481,8 @@ end --- Applies a `TextDocumentEdit`, which is a list of changes to a single --- document. --- ----@param text_document_edit table: a `TextDocumentEdit` object ----@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) +---@param text_document_edit lsp.TextDocumentEdit +---@param index? integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) ---@param offset_encoding? string ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit function M.apply_text_document_edit(text_document_edit, index, offset_encoding) @@ -533,6 +533,7 @@ local function path_under_prefix(path, prefix) end --- Get list of buffers whose filename matches the given path prefix (normalized full path) +---@param prefix string ---@return integer[] local function get_bufs_with_prefix(prefix) prefix = path_components(prefix) @@ -677,7 +678,7 @@ end --- Applies a `WorkspaceEdit`. --- ----@param workspace_edit table `WorkspaceEdit` +---@param workspace_edit lsp.WorkspaceEdit ---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) @@ -723,8 +724,8 @@ end --- Note that if the input is of type `MarkupContent` and its kind is `plaintext`, --- then the corresponding value is returned without further modifications. --- ----@param input (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent) ----@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}. +---@param input lsp.MarkedString|lsp.MarkedString[]|lsp.MarkupContent +---@param contents string[]|nil List of strings to extend with converted lines. Defaults to {}. ---@return string[] extended with lines of converted markdown. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover function M.convert_input_to_markdown_lines(input, contents) @@ -759,11 +760,11 @@ end --- Converts `textDocument/signatureHelp` response to markdown lines. --- ----@param signature_help table Response of `textDocument/SignatureHelp` +---@param signature_help lsp.SignatureHelp Response of `textDocument/SignatureHelp` ---@param ft string|nil filetype that will be use as the `lang` for the label markdown code block ---@param triggers table|nil list of trigger characters from the lsp server. used to better determine parameter offsets ----@return table|nil table list of lines of converted markdown. ----@return table|nil table of active hl +---@return string[]|nil table list of lines of converted markdown. +---@return number[]|nil table of active hl ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers) if not signature_help.signatures then @@ -960,7 +961,7 @@ end --- Shows document and optionally jumps to the location. --- ----@param location table (`Location`|`LocationLink`) +---@param location lsp.Location|lsp.LocationLink ---@param offset_encoding string|nil utf-8|utf-16|utf-32 ---@param opts table|nil options --- - reuse_win (boolean) Jump to existing window if buffer is already open. @@ -1017,7 +1018,7 @@ end --- Jumps to a location. --- ----@param location table (`Location`|`LocationLink`) +---@param location lsp.Location|lsp.LocationLink ---@param offset_encoding string|nil utf-8|utf-16|utf-32 ---@param reuse_win boolean|nil Jump to existing window if buffer is already open. ---@return boolean `true` if the jump succeeded @@ -1038,7 +1039,7 @@ end --- - for Location, range is shown (e.g., function definition) --- - for LocationLink, targetRange is shown (e.g., body of function definition) --- ----@param location table a single `Location` or `LocationLink` +---@param location lsp.Location|lsp.LocationLink ---@param opts table ---@return integer|nil buffer id of float window ---@return integer|nil window id of float window @@ -1154,7 +1155,7 @@ end --- If you want to open a popup with fancy markdown, use `open_floating_preview` instead --- ---@param bufnr integer ----@param contents table of lines to show in window +---@param contents string[] of lines to show in window ---@param opts table with optional fields --- - height of floating window --- - width of floating window @@ -1669,7 +1670,7 @@ do --[[ References ]] --- Shows a list of document highlights for a certain buffer. --- ---@param bufnr integer Buffer id - ---@param references table List of `DocumentHighlight` objects to highlight + ---@param references lsp.DocumentHighlight[] objects to highlight ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32". ---@see https://microsoft.github.io/language-server-protocol/specification/#textDocumentContentChangeEvent function M.buf_highlight_references(bufnr, references, offset_encoding) @@ -1873,7 +1874,7 @@ end --- CAUTION: Modifies the input in-place! --- ---@deprecated ----@param lines table list of lines +---@param lines string[] list of lines ---@return string filetype or "markdown" if it was unchanged. function M.try_trim_markdown_code_blocks(lines) vim.deprecate('vim.lsp.util.try_trim_markdown_code_blocks()', 'nil', '0.12') @@ -1898,7 +1899,7 @@ function M.try_trim_markdown_code_blocks(lines) end ---@param window integer|nil: window handle or 0 for current, defaults to current ----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` +---@param offset_encoding? string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` local function make_position_param(window, offset_encoding) window = window or 0 local buf = api.nvim_win_get_buf(window) @@ -1919,7 +1920,7 @@ end --- ---@param window integer|nil: window handle or 0 for current, defaults to current ---@param offset_encoding string|nil utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window` ----@return table `TextDocumentPositionParams` object +---@return lsp.TextDocumentPositionParams ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams function M.make_position_params(window, offset_encoding) window = window or 0 @@ -1932,7 +1933,7 @@ function M.make_position_params(window, offset_encoding) end --- Utility function for getting the encoding of the first LSP client on the given buffer. ----@param bufnr (integer) buffer handle or 0 for current, defaults to current +---@param bufnr integer buffer handle or 0 for current, defaults to current ---@return string encoding first client if there is one, nil otherwise function M._get_offset_encoding(bufnr) validate({ @@ -2033,15 +2034,16 @@ end --- Creates a `TextDocumentIdentifier` object for the current buffer. --- ---@param bufnr integer|nil: Buffer handle, defaults to current ----@return table `TextDocumentIdentifier` +---@return lsp.TextDocumentIdentifier ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier function M.make_text_document_params(bufnr) return { uri = vim.uri_from_bufnr(bufnr or 0) } end --- Create the workspace params ----@param added table ----@param removed table +---@param added lsp.WorkspaceFolder[] +---@param removed lsp.WorkspaceFolder[] +---@return lsp.WorkspaceFoldersChangeEvent function M.make_workspace_params(added, removed) return { event = { added = added, removed = removed } } end @@ -2049,8 +2051,8 @@ end --- Returns indentation size. --- ---@see 'shiftwidth' ----@param bufnr (integer|nil): Buffer handle, defaults to current ----@return (integer) indentation size +---@param bufnr integer|nil: Buffer handle, defaults to current +---@return integer indentation size function M.get_effective_tabstop(bufnr) validate({ bufnr = { bufnr, 'n', true } }) local bo = bufnr and vim.bo[bufnr] or vim.bo @@ -2060,7 +2062,7 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ----@param options table|nil with valid `FormattingOptions` entries +---@param options lsp.FormattingOptions|nil with valid `FormattingOptions` entries ---@return lsp.DocumentFormattingParams object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) -- cgit From c13c50b752dca322a5ec77dea6188c9e3694549b Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 30 May 2024 12:59:02 +0200 Subject: refactor(io): separate types for read and write streams This is a structural refactor with no logical changes, yet. Done in preparation for simplifying rstream/rbuffer which will require more state inline in RStream. The initial idea was to have RStream and WStream as sub-types symetrically but that doesn't work, as sockets are both reading and writing. Also there is very little write-specific state to start with, so the benefit of a separate WStream struct is a lot smaller. Just document what fields in `Stream` are write specific. --- src/nvim/channel.c | 32 ++++++++++---------- src/nvim/channel.h | 8 ++--- src/nvim/channel_defs.h | 2 +- src/nvim/event/defs.h | 31 +++++++++++++------- src/nvim/event/libuv_process.c | 8 ++--- src/nvim/event/process.c | 46 +++++++++++++++-------------- src/nvim/event/process.h | 4 +-- src/nvim/event/rstream.c | 66 +++++++++++++++++++++++------------------- src/nvim/event/socket.c | 16 +++++----- src/nvim/event/stream.c | 26 +++++++++-------- src/nvim/event/wstream.c | 7 ++++- src/nvim/msgpack_rpc/channel.c | 4 +-- src/nvim/os/input.c | 12 ++++---- src/nvim/os/pty_process_unix.c | 6 ++-- src/nvim/os/pty_process_win.c | 8 ++--- src/nvim/os/shell.c | 6 ++-- src/nvim/tui/input.c | 4 +-- src/nvim/tui/input.h | 2 +- 18 files changed, 157 insertions(+), 131 deletions(-) diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 41635747f8..e5492caf45 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -126,19 +126,19 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) *error = e_invstream; return false; } - stream_may_close(&chan->stream.socket); + rstream_may_close(&chan->stream.socket); break; case kChannelStreamProc: proc = &chan->stream.proc; if (part == kChannelPartStdin || close_main) { - stream_may_close(&proc->in); + wstream_may_close(&proc->in); } if (part == kChannelPartStdout || close_main) { - stream_may_close(&proc->out); + rstream_may_close(&proc->out); } if (part == kChannelPartStderr || part == kChannelPartAll) { - stream_may_close(&proc->err); + rstream_may_close(&proc->err); } if (proc->type == kProcessTypePty && part == kChannelPartAll) { pty_process_close_master(&chan->stream.pty); @@ -148,10 +148,10 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) case kChannelStreamStdio: if (part == kChannelPartStdin || close_main) { - stream_may_close(&chan->stream.stdio.in); + rstream_may_close(&chan->stream.stdio.in); } if (part == kChannelPartStdout || close_main) { - stream_may_close(&chan->stream.stdio.out); + wstream_may_close(&chan->stream.stdio.out); } if (part == kChannelPartStderr) { *error = e_invstream; @@ -480,9 +480,9 @@ uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader return 0; } - channel->stream.socket.internal_close_cb = close_cb; - channel->stream.socket.internal_data = channel; - wstream_init(&channel->stream.socket, 0); + channel->stream.socket.s.internal_close_cb = close_cb; + channel->stream.socket.s.internal_data = channel; + wstream_init(&channel->stream.socket.s, 0); rstream_init(&channel->stream.socket, 0); if (rpc) { @@ -505,9 +505,9 @@ void channel_from_connection(SocketWatcher *watcher) { Channel *channel = channel_alloc(kChannelStreamSocket); socket_watcher_accept(watcher, &channel->stream.socket); - channel->stream.socket.internal_close_cb = close_cb; - channel->stream.socket.internal_data = channel; - wstream_init(&channel->stream.socket, 0); + channel->stream.socket.s.internal_close_cb = close_cb; + channel->stream.socket.s.internal_data = channel; + wstream_init(&channel->stream.socket.s, 0); rstream_init(&channel->stream.socket, 0); rpc_start(channel); channel_create_event(channel, watcher->addr); @@ -647,19 +647,19 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) return l; } -void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +void on_channel_data(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; on_channel_output(stream, chan, buf, eof, &chan->on_data); } -void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +void on_job_stderr(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; on_channel_output(stream, chan, buf, eof, &chan->on_stderr); } -static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof, +static void on_channel_output(RStream *stream, Channel *chan, RBuffer *buf, bool eof, CallbackReader *reader) { size_t count; @@ -864,7 +864,7 @@ static void term_resize(uint16_t width, uint16_t height, void *data) static inline void term_delayed_free(void **argv) { Channel *chan = argv[0]; - if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.pending_reqs) { + if (chan->stream.proc.in.pending_reqs || chan->stream.proc.out.s.pending_reqs) { multiqueue_put(chan->events, term_delayed_free, chan); return; } diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 35d369e513..72480db0d5 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -30,7 +30,7 @@ struct Channel { Process proc; LibuvProcess uv; PtyProcess pty; - Stream socket; + RStream socket; StdioPair stdio; StderrState err; InternalState internal; @@ -73,7 +73,7 @@ static inline Stream *channel_instream(Channel *chan) return &chan->stream.proc.in; case kChannelStreamSocket: - return &chan->stream.socket; + return &chan->stream.socket.s; case kChannelStreamStdio: return &chan->stream.stdio.out; @@ -85,10 +85,10 @@ static inline Stream *channel_instream(Channel *chan) abort(); } -static inline Stream *channel_outstream(Channel *chan) +static inline RStream *channel_outstream(Channel *chan) REAL_FATTR_NONNULL_ALL; -static inline Stream *channel_outstream(Channel *chan) +static inline RStream *channel_outstream(Channel *chan) { switch (chan->streamtype) { case kChannelStreamProc: diff --git a/src/nvim/channel_defs.h b/src/nvim/channel_defs.h index d4f1895420..2df6edea7a 100644 --- a/src/nvim/channel_defs.h +++ b/src/nvim/channel_defs.h @@ -30,7 +30,7 @@ typedef enum { } ChannelStdinMode; typedef struct { - Stream in; + RStream in; Stream out; } StdioPair; diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h index 9b7d8708be..8563006159 100644 --- a/src/nvim/event/defs.h +++ b/src/nvim/event/defs.h @@ -55,14 +55,15 @@ struct wbuffer { }; typedef struct stream Stream; -/// Type of function called when the Stream buffer is filled with data +typedef struct rstream RStream; +/// Type of function called when the RStream buffer is filled with data /// /// @param stream The Stream instance /// @param buf The associated RBuffer instance /// @param count Number of bytes that was read. /// @param data User-defined data /// @param eof If the stream reached EOF. -typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof); +typedef void (*stream_read_cb)(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof); /// Type of function called when the Stream has information about a write /// request. @@ -71,11 +72,11 @@ typedef void (*stream_read_cb)(Stream *stream, RBuffer *buf, size_t count, void /// @param data User-defined data /// @param status 0 on success, anything else indicates failure typedef void (*stream_write_cb)(Stream *stream, void *data, int status); + typedef void (*stream_close_cb)(Stream *stream, void *data); struct stream { bool closed; - bool did_eof; union { uv_pipe_t pipe; uv_tcp_t tcp; @@ -85,20 +86,27 @@ struct stream { #endif } uv; uv_stream_t *uvstream; - uv_buf_t uvbuf; - RBuffer *buffer; uv_file fd; - stream_read_cb read_cb; - stream_write_cb write_cb; void *cb_data; stream_close_cb close_cb, internal_close_cb; void *close_cb_data, *internal_data; - size_t fpos; + size_t pending_reqs; + MultiQueue *events; + + // only used for writing: + stream_write_cb write_cb; size_t curmem; size_t maxmem; - size_t pending_reqs; +}; + +struct rstream { + Stream s; + bool did_eof; + RBuffer *buffer; + uv_buf_t uvbuf; + stream_read_cb read_cb; size_t num_bytes; - MultiQueue *events; + size_t fpos; }; #define ADDRESS_MAX_SIZE 256 @@ -147,7 +155,8 @@ struct process { char **argv; const char *exepath; dict_T *env; - Stream in, out, err; + Stream in; + RStream out, err; /// Exit handler. If set, user must call process_free(). process_exit_cb cb; internal_process_cb internal_exit_cb, internal_close_cb; diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index f77d686c10..0dead1f9b4 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -70,19 +70,19 @@ int libuv_process_spawn(LibuvProcess *uvproc) uvproc->uvstdio[0].data.stream = (uv_stream_t *)(&proc->in.uv.pipe); } - if (!proc->out.closed) { + if (!proc->out.s.closed) { uvproc->uvstdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; #ifdef MSWIN // pipe must be readable for IOCP to work on Windows. uvproc->uvstdio[1].flags |= proc->overlapped ? (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0; #endif - uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.uv.pipe); + uvproc->uvstdio[1].data.stream = (uv_stream_t *)(&proc->out.s.uv.pipe); } - if (!proc->err.closed) { + if (!proc->err.s.closed) { uvproc->uvstdio[2].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; - uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.uv.pipe); + uvproc->uvstdio[2].data.stream = (uv_stream_t *)(&proc->err.s.uv.pipe); } else if (proc->fwd_err) { uvproc->uvstdio[2].flags = UV_INHERIT_FD; uvproc->uvstdio[2].data.fd = STDERR_FILENO; diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 7460e92766..710376cd62 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -8,7 +8,9 @@ #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/event/process.h" +#include "nvim/event/rstream.h" #include "nvim/event/stream.h" +#include "nvim/event/wstream.h" #include "nvim/globals.h" #include "nvim/log.h" #include "nvim/main.h" @@ -51,15 +53,15 @@ int process_spawn(Process *proc, bool in, bool out, bool err) } if (out) { - uv_pipe_init(&proc->loop->uv, &proc->out.uv.pipe, 0); + uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0); } else { - proc->out.closed = true; + proc->out.s.closed = true; } if (err) { - uv_pipe_init(&proc->loop->uv, &proc->err.uv.pipe, 0); + uv_pipe_init(&proc->loop->uv, &proc->err.s.uv.pipe, 0); } else { - proc->err.closed = true; + proc->err.s.closed = true; } #ifdef USE_GCOV @@ -82,10 +84,10 @@ int process_spawn(Process *proc, bool in, bool out, bool err) uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL); } if (out) { - uv_close((uv_handle_t *)&proc->out.uv.pipe, NULL); + uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL); } if (err) { - uv_close((uv_handle_t *)&proc->err.uv.pipe, NULL); + uv_close((uv_handle_t *)&proc->err.s.uv.pipe, NULL); } if (proc->type == kProcessTypeUv) { @@ -106,16 +108,16 @@ int process_spawn(Process *proc, bool in, bool out, bool err) } if (out) { - stream_init(NULL, &proc->out, -1, (uv_stream_t *)&proc->out.uv.pipe); - proc->out.internal_data = proc; - proc->out.internal_close_cb = on_process_stream_close; + stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe); + proc->out.s.internal_data = proc; + proc->out.s.internal_close_cb = on_process_stream_close; proc->refcount++; } if (err) { - stream_init(NULL, &proc->err, -1, (uv_stream_t *)&proc->err.uv.pipe); - proc->err.internal_data = proc; - proc->err.internal_close_cb = on_process_stream_close; + stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe); + proc->err.s.internal_data = proc; + proc->err.s.internal_close_cb = on_process_stream_close; proc->refcount++; } @@ -148,9 +150,9 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL { - stream_may_close(&proc->in); - stream_may_close(&proc->out); - stream_may_close(&proc->err); + wstream_may_close(&proc->in); + rstream_may_close(&proc->out); + rstream_may_close(&proc->err); } /// Synchronously wait for a process to finish @@ -337,10 +339,10 @@ static void process_close(Process *proc) /// /// @param proc Process, for which an output stream should be flushed. /// @param stream Stream to flush. -static void flush_stream(Process *proc, Stream *stream) +static void flush_stream(Process *proc, RStream *stream) FUNC_ATTR_NONNULL_ARG(1) { - if (!stream || stream->closed) { + if (!stream || stream->s.closed) { return; } @@ -350,7 +352,7 @@ static void flush_stream(Process *proc, Stream *stream) // keeps sending data, we only accept as much data as the system buffer size. // Otherwise this would block cleanup/teardown. int system_buffer_size = 0; - int err = uv_recv_buffer_size((uv_handle_t *)&stream->uv.pipe, + int err = uv_recv_buffer_size((uv_handle_t *)&stream->s.uv.pipe, &system_buffer_size); if (err) { system_buffer_size = (int)rbuffer_capacity(stream->buffer); @@ -359,14 +361,14 @@ static void flush_stream(Process *proc, Stream *stream) size_t max_bytes = stream->num_bytes + (size_t)system_buffer_size; // Read remaining data. - while (!stream->closed && stream->num_bytes < max_bytes) { + while (!stream->s.closed && stream->num_bytes < max_bytes) { // Remember number of bytes before polling size_t num_bytes = stream->num_bytes; // Poll for data and process the generated events. loop_poll_events(proc->loop, 0); - if (stream->events) { - multiqueue_process_events(stream->events); + if (stream->s.events) { + multiqueue_process_events(stream->s.events); } // Stream can be closed if it is empty. @@ -374,7 +376,7 @@ static void flush_stream(Process *proc, Stream *stream) if (stream->read_cb && !stream->did_eof) { // Stream callback could miss EOF handling if a child keeps the stream // open. But only send EOF if we haven't already. - stream->read_cb(stream, stream->buffer, 0, stream->cb_data, true); + stream->read_cb(stream, stream->buffer, 0, stream->s.cb_data, true); } break; } diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h index 421a470244..74b52cbbb1 100644 --- a/src/nvim/event/process.h +++ b/src/nvim/event/process.h @@ -21,8 +21,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data) .argv = NULL, .exepath = NULL, .in = { .closed = false }, - .out = { .closed = false }, - .err = { .closed = false }, + .out = { .s.closed = false }, + .err = { .s.closed = false }, .cb = NULL, .closed = false, .internal_close_cb = NULL, diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index 6b4ab472e4..6c7fa20bd8 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -19,23 +19,26 @@ # include "event/rstream.c.generated.h" #endif -void rstream_init_fd(Loop *loop, Stream *stream, int fd, size_t bufsize) +void rstream_init_fd(Loop *loop, RStream *stream, int fd, size_t bufsize) FUNC_ATTR_NONNULL_ARG(1, 2) { - stream_init(loop, stream, fd, NULL); + stream_init(loop, &stream->s, fd, NULL); rstream_init(stream, bufsize); } -void rstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t bufsize) +void rstream_init_stream(RStream *stream, uv_stream_t *uvstream, size_t bufsize) FUNC_ATTR_NONNULL_ARG(1, 2) { - stream_init(NULL, stream, -1, uvstream); + stream_init(NULL, &stream->s, -1, uvstream); rstream_init(stream, bufsize); } -void rstream_init(Stream *stream, size_t bufsize) +void rstream_init(RStream *stream, size_t bufsize) FUNC_ATTR_NONNULL_ARG(1) { + stream->fpos = 0; + stream->read_cb = NULL; + stream->num_bytes = 0; stream->buffer = rbuffer_new(bufsize); stream->buffer->data = stream; stream->buffer->full_cb = on_rbuffer_full; @@ -45,28 +48,28 @@ void rstream_init(Stream *stream, size_t bufsize) /// Starts watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_start(Stream *stream, stream_read_cb cb, void *data) +void rstream_start(RStream *stream, stream_read_cb cb, void *data) FUNC_ATTR_NONNULL_ARG(1) { stream->read_cb = cb; - stream->cb_data = data; - if (stream->uvstream) { - uv_read_start(stream->uvstream, alloc_cb, read_cb); + stream->s.cb_data = data; + if (stream->s.uvstream) { + uv_read_start(stream->s.uvstream, alloc_cb, read_cb); } else { - uv_idle_start(&stream->uv.idle, fread_idle_cb); + uv_idle_start(&stream->s.uv.idle, fread_idle_cb); } } /// Stops watching for events from a `Stream` instance. /// /// @param stream The `Stream` instance -void rstream_stop(Stream *stream) +void rstream_stop(RStream *stream) FUNC_ATTR_NONNULL_ALL { - if (stream->uvstream) { - uv_read_stop(stream->uvstream); + if (stream->s.uvstream) { + uv_read_stop(stream->s.uvstream); } else { - uv_idle_stop(&stream->uv.idle); + uv_idle_stop(&stream->s.uv.idle); } } @@ -77,9 +80,9 @@ static void on_rbuffer_full(RBuffer *buf, void *data) static void on_rbuffer_nonfull(RBuffer *buf, void *data) { - Stream *stream = data; + RStream *stream = data; assert(stream->read_cb); - rstream_start(stream, stream->read_cb, stream->cb_data); + rstream_start(stream, stream->read_cb, stream->s.cb_data); } // Callbacks used by libuv @@ -87,7 +90,7 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data) /// Called by libuv to allocate memory for reading. static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) { - Stream *stream = handle->data; + RStream *stream = handle->data; // `uv_buf_t.len` happens to have different size on Windows. size_t write_count; buf->base = rbuffer_write_ptr(stream->buffer, &write_count); @@ -99,7 +102,7 @@ static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) /// 0-length buffer. static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) { - Stream *stream = uvstream->data; + RStream *stream = uvstream->data; if (cnt <= 0) { // cnt == 0 means libuv asked for a buffer and decided it wasn't needed: @@ -141,7 +144,7 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) static void fread_idle_cb(uv_idle_t *handle) { uv_fs_t req; - Stream *stream = handle->data; + RStream *stream = handle->data; // `uv_buf_t.len` happens to have different size on Windows. size_t write_count; @@ -160,7 +163,7 @@ static void fread_idle_cb(uv_idle_t *handle) // Synchronous read uv_fs_read(handle->loop, &req, - stream->fd, + stream->s.fd, &stream->uvbuf, 1, (int64_t)stream->fpos, @@ -169,7 +172,7 @@ static void fread_idle_cb(uv_idle_t *handle) uv_fs_req_cleanup(&req); if (req.result <= 0) { - uv_idle_stop(&stream->uv.idle); + uv_idle_stop(&stream->s.uv.idle); invoke_read_cb(stream, 0, true); return; } @@ -183,24 +186,29 @@ static void fread_idle_cb(uv_idle_t *handle) static void read_event(void **argv) { - Stream *stream = argv[0]; + RStream *stream = argv[0]; if (stream->read_cb) { size_t count = (uintptr_t)argv[1]; bool eof = (uintptr_t)argv[2]; stream->did_eof = eof; - stream->read_cb(stream, stream->buffer, count, stream->cb_data, eof); + stream->read_cb(stream, stream->buffer, count, stream->s.cb_data, eof); } - stream->pending_reqs--; - if (stream->closed && !stream->pending_reqs) { - stream_close_handle(stream); + stream->s.pending_reqs--; + if (stream->s.closed && !stream->s.pending_reqs) { + stream_close_handle(&stream->s, true); } } -static void invoke_read_cb(Stream *stream, size_t count, bool eof) +static void invoke_read_cb(RStream *stream, size_t count, bool eof) { // Don't let the stream be closed before the event is processed. - stream->pending_reqs++; + stream->s.pending_reqs++; - CREATE_EVENT(stream->events, read_event, + CREATE_EVENT(stream->s.events, read_event, stream, (void *)(uintptr_t *)count, (void *)(uintptr_t)eof); } + +void rstream_may_close(RStream *stream) +{ + stream_may_close(&stream->s, true); +} diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 4e878a2ecf..017f159fa1 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -135,17 +135,17 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb) return 0; } -int socket_watcher_accept(SocketWatcher *watcher, Stream *stream) +int socket_watcher_accept(SocketWatcher *watcher, RStream *stream) FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) { uv_stream_t *client; if (watcher->stream->type == UV_TCP) { - client = (uv_stream_t *)(&stream->uv.tcp); + client = (uv_stream_t *)(&stream->s.uv.tcp); uv_tcp_init(watcher->uv.tcp.handle.loop, (uv_tcp_t *)client); uv_tcp_nodelay((uv_tcp_t *)client, true); } else { - client = (uv_stream_t *)&stream->uv.pipe; + client = (uv_stream_t *)&stream->s.uv.pipe; uv_pipe_init(watcher->uv.pipe.handle.loop, (uv_pipe_t *)client, 0); } @@ -156,7 +156,7 @@ int socket_watcher_accept(SocketWatcher *watcher, Stream *stream) return result; } - stream_init(NULL, stream, -1, client); + stream_init(NULL, &stream->s, -1, client); return 0; } @@ -197,7 +197,7 @@ static void connect_cb(uv_connect_t *req, int status) } } -bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address, int timeout, +bool socket_connect(Loop *loop, RStream *stream, bool is_tcp, const char *address, int timeout, const char **error) { bool success = false; @@ -206,7 +206,7 @@ bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address req.data = &status; uv_stream_t *uv_stream; - uv_tcp_t *tcp = &stream->uv.tcp; + uv_tcp_t *tcp = &stream->s.uv.tcp; uv_getaddrinfo_t addr_req; addr_req.addrinfo = NULL; const struct addrinfo *addrinfo = NULL; @@ -237,7 +237,7 @@ tcp_retry: uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb); uv_stream = (uv_stream_t *)tcp; } else { - uv_pipe_t *pipe = &stream->uv.pipe; + uv_pipe_t *pipe = &stream->s.uv.pipe; uv_pipe_init(&loop->uv, pipe, 0); uv_pipe_connect(&req, pipe, address, connect_cb); uv_stream = (uv_stream_t *)pipe; @@ -245,7 +245,7 @@ tcp_retry: status = 1; LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1); if (status == 0) { - stream_init(NULL, stream, -1, uv_stream); + stream_init(NULL, &stream->s, -1, uv_stream); success = true; } else if (is_tcp && addrinfo->ai_next) { addrinfo = addrinfo->ai_next; diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 0b9ed4f25b..3d26dd868f 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -85,21 +85,17 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream) } stream->internal_data = NULL; - stream->fpos = 0; stream->curmem = 0; stream->maxmem = 0; stream->pending_reqs = 0; - stream->read_cb = NULL; stream->write_cb = NULL; stream->close_cb = NULL; stream->internal_close_cb = NULL; stream->closed = false; - stream->buffer = NULL; stream->events = NULL; - stream->num_bytes = 0; } -void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) +void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data, bool rstream) FUNC_ATTR_NONNULL_ARG(1) { assert(!stream->closed); @@ -116,18 +112,18 @@ void stream_close(Stream *stream, stream_close_cb on_stream_close, void *data) #endif if (!stream->pending_reqs) { - stream_close_handle(stream); + stream_close_handle(stream, rstream); } } -void stream_may_close(Stream *stream) +void stream_may_close(Stream *stream, bool rstream) { if (!stream->closed) { - stream_close(stream, NULL, NULL); + stream_close(stream, NULL, NULL, rstream); } } -void stream_close_handle(Stream *stream) +void stream_close_handle(Stream *stream, bool rstream) FUNC_ATTR_NONNULL_ALL { uv_handle_t *handle = NULL; @@ -145,16 +141,22 @@ void stream_close_handle(Stream *stream) assert(handle != NULL); if (!uv_is_closing(handle)) { - uv_close(handle, close_cb); + uv_close(handle, rstream ? rstream_close_cb : close_cb); } } -static void close_cb(uv_handle_t *handle) +static void rstream_close_cb(uv_handle_t *handle) { - Stream *stream = handle->data; + RStream *stream = handle->data; if (stream->buffer) { rbuffer_free(stream->buffer); } + close_cb(handle); +} + +static void close_cb(uv_handle_t *handle) +{ + Stream *stream = handle->data; if (stream->close_cb) { stream->close_cb(stream, stream->close_cb_data); } diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c index c67a9b96ed..07aab87e4d 100644 --- a/src/nvim/event/wstream.c +++ b/src/nvim/event/wstream.c @@ -141,7 +141,7 @@ static void write_cb(uv_write_t *req, int status) if (data->stream->closed && data->stream->pending_reqs == 0) { // Last pending write, free the stream; - stream_close_handle(data->stream); + stream_close_handle(data->stream, false); } xfree(data); @@ -158,3 +158,8 @@ void wstream_release_wbuffer(WBuffer *buffer) xfree(buffer); } } + +void wstream_may_close(Stream *stream) +{ + stream_may_close(stream, false); +} diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 5737a0440f..98d5d8c6cb 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -89,7 +89,7 @@ void rpc_start(Channel *channel) kv_init(rpc->call_stack); if (channel->streamtype != kChannelStreamInternal) { - Stream *out = channel_outstream(channel); + RStream *out = channel_outstream(channel); #ifdef NVIM_LOG_DEBUG Stream *in = channel_instream(channel); DLOG("rpc ch %" PRIu64 " in-stream=%p out-stream=%p", channel->id, @@ -202,7 +202,7 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem return frame.errored ? NIL : frame.result; } -static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) +static void receive_msgpack(RStream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) { Channel *channel = data; channel_incref(channel); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 60b5b48745..cfe8696cdd 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -41,7 +41,7 @@ typedef enum { kInputEof, } InbufPollResult; -static Stream read_stream = { .closed = true }; // Input before UI starts. +static RStream read_stream = { .s.closed = true }; // Input before UI starts. static RBuffer *input_buffer = NULL; static bool input_eof = false; static bool blocking = false; @@ -59,7 +59,7 @@ void input_init(void) void input_start(void) { - if (!read_stream.closed) { + if (!read_stream.s.closed) { return; } @@ -70,12 +70,12 @@ void input_start(void) void input_stop(void) { - if (read_stream.closed) { + if (read_stream.s.closed) { return; } rstream_stop(&read_stream); - stream_close(&read_stream, NULL, NULL); + rstream_may_close(&read_stream); } #ifdef EXITFREE @@ -138,7 +138,7 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e uint64_t wait_start = os_hrtime(); cursorhold_time = MIN(cursorhold_time, (int)p_ut); if ((result = inbuf_poll((int)p_ut - cursorhold_time, events)) == kInputNone) { - if (read_stream.closed && silent_mode) { + if (read_stream.s.closed && silent_mode) { // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). read_error_exit(); } @@ -489,7 +489,7 @@ bool input_available(void) return rbuffer_size(input_buffer) != 0; } -static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) +static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) { if (at_eof) { input_eof = true; diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 4d34e8fac4..cfa4dcada7 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -169,7 +169,7 @@ int pty_process_spawn(PtyProcess *ptyproc) int status = 0; // zero or negative error code (libuv convention) Process *proc = (Process *)ptyproc; - assert(proc->err.closed); + assert(proc->err.s.closed); uv_signal_start(&proc->loop->children_watcher, chld_handler, SIGCHLD); ptyproc->winsize = (struct winsize){ ptyproc->height, ptyproc->width, 0, 0 }; uv_disable_stdio_inheritance(); @@ -208,8 +208,8 @@ int pty_process_spawn(PtyProcess *ptyproc) && (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) { goto error; } - if (!proc->out.closed - && (status = set_duplicating_descriptor(master, &proc->out.uv.pipe))) { + if (!proc->out.s.closed + && (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) { goto error; } diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c index 12831ff05f..f73baed490 100644 --- a/src/nvim/os/pty_process_win.c +++ b/src/nvim/os/pty_process_win.c @@ -55,7 +55,7 @@ int pty_process_spawn(PtyProcess *ptyproc) wchar_t *env = NULL; const char *emsg = NULL; - assert(proc->err.closed); + assert(proc->err.s.closed); if (!os_has_conpty_working() || (conpty_object = os_conpty_init(&in_name, &out_name, ptyproc->width, @@ -72,10 +72,10 @@ int pty_process_spawn(PtyProcess *ptyproc) pty_process_connect_cb); } - if (!proc->out.closed) { + if (!proc->out.s.closed) { out_req = xmalloc(sizeof(uv_connect_t)); uv_pipe_connect(out_req, - &proc->out.uv.pipe, + &proc->out.s.uv.pipe, out_name, pty_process_connect_cb); } @@ -216,7 +216,7 @@ static void wait_eof_timer_cb(uv_timer_t *wait_eof_timer) Process *proc = (Process *)ptyproc; assert(ptyproc->finish_wait != NULL); - if (proc->out.closed || proc->out.did_eof || !uv_is_readable(proc->out.uvstream)) { + if (proc->out.s.closed || proc->out.did_eof || !uv_is_readable(proc->out.s.uvstream)) { uv_timer_stop(&ptyproc->wait_eof_timer); pty_process_finish2(ptyproc); } diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 2a10510b0f..958faa4d22 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -987,7 +987,7 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired) buf->data = xrealloc(buf->data, buf->cap); } -static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static void system_data_cb(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { DynamicBuffer *dbuf = data; @@ -1151,7 +1151,7 @@ end: ui_flush(); } -static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) +static void out_data_cb(RStream *stream, RBuffer *buf, size_t count, void *data, bool eof) { size_t cnt; char *ptr = rbuffer_read_ptr(buf, &cnt); @@ -1331,7 +1331,7 @@ static void shell_write_cb(Stream *stream, void *data, int status) msg_schedule_semsg(_("E5677: Error writing input to shell-command: %s"), uv_err_name(status)); } - stream_close(stream, NULL, NULL); + stream_close(stream, NULL, NULL, false); } /// Applies 'shellxescape' (p_sxe) and 'shellxquote' (p_sxq) to a command. diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index f1594dfcb9..588fed2d90 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -167,7 +167,7 @@ void tinput_destroy(TermInput *input) map_destroy(int, &kitty_key_map); rbuffer_free(input->key_buffer); uv_close((uv_handle_t *)&input->timer_handle, NULL); - stream_close(&input->read_stream, NULL, NULL); + rstream_may_close(&input->read_stream); termkey_destroy(input->tk); } @@ -737,7 +737,7 @@ static void handle_raw_buffer(TermInput *input, bool force) } } -static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof) +static void tinput_read_cb(RStream *stream, RBuffer *buf, size_t count_, void *data, bool eof) { TermInput *input = data; diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index bf6d0f2978..646fbdd16a 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -33,7 +33,7 @@ typedef struct { TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook uv_timer_t timer_handle; Loop *loop; - Stream read_stream; + RStream read_stream; RBuffer *key_buffer; TUIData *tui_data; } TermInput; -- cgit From d24f3d055ae7b3e9e47e9eb53a1dafb3ad44760c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 30 May 2024 19:57:47 -0500 Subject: test: do not set termguicolors in test runner It's not clear why this is needed and it has adverse side effects on other tests. --- test/functional/testnvim.lua | 2 +- test/functional/ui/popupmenu_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/testnvim.lua b/test/functional/testnvim.lua index 6b858e4d69..5f24ef3fe6 100644 --- a/test/functional/testnvim.lua +++ b/test/functional/testnvim.lua @@ -22,7 +22,7 @@ local runtime_set = 'set runtimepath^=./build/lib/nvim/' M.nvim_prog = (os.getenv('NVIM_PRG') or t.paths.test_build_dir .. '/bin/nvim') -- Default settings for the test session. M.nvim_set = ( - 'set shortmess+=IS background=light termguicolors noswapfile noautoindent startofline' + 'set shortmess+=IS background=light noswapfile noautoindent startofline' .. ' laststatus=1 undodir=. directory=. viewdir=. backupdir=.' .. ' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid' ) diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua index 8f8604eecb..cc21a797e3 100644 --- a/test/functional/ui/popupmenu_spec.lua +++ b/test/functional/ui/popupmenu_spec.lua @@ -1129,7 +1129,7 @@ describe("builtin popupmenu 'pumblend'", function() [10] = { foreground = tonumber('0x000002') }, }) screen:attach({ rgb = false }) - command('set notermguicolors pumblend=10') + command('set pumblend=10') insert([[ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor -- cgit From 4cff4185647c17b1a397c4c26ff7d8b0738f6396 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 30 May 2024 19:57:47 -0500 Subject: fix(vim.text): remove assert from vim.text.hexdecode Instead, return nil plus an error message if the input is invalid. --- runtime/doc/lua.txt | 5 +++-- runtime/lua/vim/text.lua | 10 +++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 36d6e0d41e..8e600adeb9 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -4385,8 +4385,9 @@ vim.text.hexdecode({enc}) *vim.text.hexdecode()* Parameters: ~ • {enc} (`string`) String to decode - Return: ~ - (`string`) Decoded string + Return (multiple): ~ + (`string?`) Decoded string + (`string?`) Error message, if any vim.text.hexencode({str}) *vim.text.hexencode()* Hex encode a string. diff --git a/runtime/lua/vim/text.lua b/runtime/lua/vim/text.lua index bc90d490aa..0be3396464 100644 --- a/runtime/lua/vim/text.lua +++ b/runtime/lua/vim/text.lua @@ -18,15 +18,19 @@ end --- Hex decode a string. --- --- @param enc string String to decode ---- @return string : Decoded string +--- @return string? : Decoded string +--- @return string? : Error message, if any function M.hexdecode(enc) - assert(#enc % 2 == 0, 'string must have an even number of hex characters') + if #enc % 2 ~= 0 then + return nil, 'string must have an even number of hex characters' + end + local str = {} ---@type string[] for i = 1, #enc, 2 do local n = assert(tonumber(enc:sub(i, i + 1), 16)) str[#str + 1] = string.char(n) end - return table.concat(str) + return table.concat(str), nil end return M -- cgit From d87ecfc8bc3c737e2e7f766d365e67dd08c3b600 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Thu, 30 May 2024 13:11:21 -0400 Subject: docs(luacats): add tuple support --- scripts/luacats_grammar.lua | 3 ++- test/functional/script/luacats_grammar_spec.lua | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/luacats_grammar.lua b/scripts/luacats_grammar.lua index 29f3bda5aa..906f66c18a 100644 --- a/scripts/luacats_grammar.lua +++ b/scripts/luacats_grammar.lua @@ -170,7 +170,7 @@ local grammar = P { ltype = parenOpt(v.ty_union), ty_union = v.ty_opt * rep(Pf('|') * v.ty_opt), - ty = v.ty_fun + ident + v.ty_table + literal + paren(v.ty) + v.ty_generic, + ty = v.ty_fun + ident + v.ty_table + literal + paren(v.ty) + v.ty_generic + v.ty_tuple, ty_param = Pf('<') * comma1(v.ltype) * fill * P('>'), ty_opt = v.ty * opt(v.ty_param) * opt(P('[]')) * opt(P('?')), ty_index = (Pf('[') * (v.ltype + ident + rep1(num)) * fill * P(']')), @@ -180,6 +180,7 @@ local grammar = P { fun_param = lname * opt(colon * v.ltype), ty_fun = Pf('fun') * paren(comma(lname * opt(colon * v.ltype))) * opt(colon * comma1(v.ltype)), ty_generic = P('`') * letter * P('`'), + ty_tuple = Pf('[') * comma(v.ty_opt) * fill * P(']') } return grammar --[[@as nvim.luacats.grammar]] diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua index 6d444e1888..d6fff3f409 100644 --- a/test/functional/script/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -159,4 +159,11 @@ describe('luacats grammar', function() name = 'type', type = '`T`', }) + + test('@param type [number,string] this is a tuple type', { + desc = 'this is a tuple type', + kind = 'param', + name = 'type', + type = '[number,string]', + }) end) -- cgit From 217828b20c9fc224c6892ce1b0129850c280f598 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Thu, 30 May 2024 13:25:06 -0400 Subject: fixup! docs(luacats): add tuple support --- scripts/luacats_grammar.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/luacats_grammar.lua b/scripts/luacats_grammar.lua index 906f66c18a..6742eab5e9 100644 --- a/scripts/luacats_grammar.lua +++ b/scripts/luacats_grammar.lua @@ -180,7 +180,7 @@ local grammar = P { fun_param = lname * opt(colon * v.ltype), ty_fun = Pf('fun') * paren(comma(lname * opt(colon * v.ltype))) * opt(colon * comma1(v.ltype)), ty_generic = P('`') * letter * P('`'), - ty_tuple = Pf('[') * comma(v.ty_opt) * fill * P(']') + ty_tuple = Pf('[') * comma(v.ty_opt) * fill * P(']'), } return grammar --[[@as nvim.luacats.grammar]] -- cgit From d62d181ce065556be51d5eda0425aa42f427cc27 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 31 May 2024 10:48:05 -0400 Subject: refactor(lsp): use tuple syntax in generated protocol types (#29110) --- runtime/lua/vim/lsp/_meta/protocol.lua | 2 +- scripts/gen_lsp.lua | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/lua/vim/lsp/_meta/protocol.lua b/runtime/lua/vim/lsp/_meta/protocol.lua index 9a11972007..cbddd24630 100644 --- a/runtime/lua/vim/lsp/_meta/protocol.lua +++ b/runtime/lua/vim/lsp/_meta/protocol.lua @@ -3235,7 +3235,7 @@ error('Cannot require a meta file') --- ---*Note*: a label of type string should be a substring of its containing signature label. ---Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`. ----@field label string|{ [1]: uinteger, [2]: uinteger } +---@field label string|[uinteger, uinteger] --- ---The human-readable doc-comment of this parameter. Will be shown ---in the UI but can be omitted. diff --git a/scripts/gen_lsp.lua b/scripts/gen_lsp.lua index 04d19f22e6..1706b39864 100644 --- a/scripts/gen_lsp.lua +++ b/scripts/gen_lsp.lua @@ -297,13 +297,13 @@ function M.gen(opt) -- TupleType elseif type.kind == 'tuple' then - local tuple = '{ ' - for i, value in ipairs(type.items) do - tuple = tuple .. '[' .. i .. ']: ' .. parse_type(value, prefix) .. ', ' + local tuple = '[' + for _, value in ipairs(type.items) do + tuple = tuple .. parse_type(value, prefix) .. ', ' end -- remove , at the end tuple = tuple:sub(0, -3) - return tuple .. ' }' + return tuple .. ']' end vim.print('WARNING: Unknown type ', type) -- cgit From 5493fcd52f2eaab4b6a81c366529e80ca3dec535 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Fri, 31 May 2024 08:25:40 -0500 Subject: test: remove checks for failed tests on Windows --- test/functional/core/startup_spec.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index a53625ab1b..1bb4ce2946 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -400,9 +400,6 @@ describe('startup', function() read_file('Xtest_startup_ttyout') ) end) - if is_os('win') then - assert_log('stream write failed. RPC canceled; closing channel', testlog) - end end) it('input from pipe: has("ttyin")==0 has("ttyout")==1', function() @@ -435,9 +432,6 @@ describe('startup', function() read_file('Xtest_startup_ttyout') ) end) - if is_os('win') then - assert_log('stream write failed. RPC canceled; closing channel', testlog) - end end) it('input from pipe (implicit) #7679', function() -- cgit From 50f6d364c661b88a1edc5ffc8e284d1c0ff70810 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 1 Jun 2024 14:47:18 +0800 Subject: vim-patch:0bdc5d8: runtime(doc): Add ft_hare.txt to Reference Manual TOC (#29120) while at it, also re-align ft_context.txt with the rest of the list. closes: vim/vim#14863 https://github.com/vim/vim/commit/0bdc5d8241335c3451f629eed7a3734021d41679 Co-authored-by: h-east --- runtime/doc/help.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index 43f80101ed..685bce2553 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -127,6 +127,7 @@ PROGRAMMING LANGUAGE SUPPORT |filetype| Settings for specific types of files |quickfix| Commands for a quick edit-compile-fix cycle |ft_ada.txt| Ada filetype plugin +|ft_hare.txt| Filetype plugin for Hare |ft_ps1.txt| PowerShell filetype plugin |ft_raku.txt| Raku filetype plugin |ft_rust.txt| Rust filetype plugin -- cgit From 0ba087df5e3c69e1f5a5e6551dc05d6793f5f64f Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 31 May 2024 17:51:52 +0200 Subject: refactor(tui): use a linear buffer for buffered keys This buffer is completely emptied every time it is read from. Thus there is no point in using a ring buffer. --- src/nvim/tui/input.c | 25 ++++++++----------------- src/nvim/tui/input.h | 4 +++- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 588fed2d90..5130678a81 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -28,7 +28,6 @@ #include "nvim/msgpack_rpc/channel.h" #define READ_STREAM_SIZE 0xfff -#define KEY_BUFFER_SIZE 0xfff /// Size of libtermkey's internal input buffer. The buffer may grow larger than /// this when processing very long escape sequences, but will shrink back to @@ -132,7 +131,6 @@ void tinput_init(TermInput *input, Loop *loop) input->key_encoding = kKeyEncodingLegacy; input->ttimeout = (bool)p_ttimeout; input->ttimeoutlen = p_ttm; - input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE); for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) { pmap_put(int)(&kitty_key_map, kitty_key_map_entry[i].key, (ptr_t)kitty_key_map_entry[i].name); @@ -165,7 +163,6 @@ void tinput_init(TermInput *input, Loop *loop) void tinput_destroy(TermInput *input) { map_destroy(int, &kitty_key_map); - rbuffer_free(input->key_buffer); uv_close((uv_handle_t *)&input->timer_handle, NULL); rstream_may_close(&input->read_stream); termkey_destroy(input->tk); @@ -191,44 +188,38 @@ static void tinput_done_event(void **argv) /// Send all pending input in key buffer to Nvim server. static void tinput_flush(TermInput *input) { + String keys = { .data = input->key_buffer, .size = input->key_buffer_len }; if (input->paste) { // produce exactly one paste event - const size_t len = rbuffer_size(input->key_buffer); - String keys = { .data = xmallocz(len), .size = len }; - rbuffer_read(input->key_buffer, keys.data, len); MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, STRING_OBJ(keys)); // 'data' ADD_C(args, BOOLEAN_OBJ(true)); // 'crlf' ADD_C(args, INTEGER_OBJ(input->paste)); // 'phase' rpc_send_event(ui_client_channel_id, "nvim_paste", args); - api_free_string(keys); if (input->paste == 1) { // Paste phase: "continue" input->paste = 2; } - rbuffer_reset(input->key_buffer); } else { // enqueue input - RBUFFER_UNTIL_EMPTY(input->key_buffer, buf, len) { - const String keys = { .data = buf, .size = len }; + if (input->key_buffer_len > 0) { MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, STRING_OBJ(keys)); // NOTE: This is non-blocking and won't check partially processed input, // but should be fine as all big sends are handled with nvim_paste, not nvim_input rpc_send_event(ui_client_channel_id, "nvim_input", args); - rbuffer_consumed(input->key_buffer, len); - rbuffer_reset(input->key_buffer); } } + input->key_buffer_len = 0; } static void tinput_enqueue(TermInput *input, char *buf, size_t size) { - if (rbuffer_size(input->key_buffer) > - rbuffer_capacity(input->key_buffer) - 0xff) { - // don't ever let the buffer get too full or we risk putting incomplete keys - // into it + if (input->key_buffer_len > KEY_BUFFER_SIZE - 0xff) { + // don't ever let the buffer get too full or we risk putting incomplete keys into it tinput_flush(input); } - rbuffer_write(input->key_buffer, buf, size); + size_t to_copy = MIN(size, KEY_BUFFER_SIZE - input->key_buffer_len); + memcpy(input->key_buffer + input->key_buffer_len, buf, to_copy); + input->key_buffer_len += to_copy; } /// Handle TERMKEY_KEYMOD_* modifiers, i.e. Shift, Alt and Ctrl. diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 646fbdd16a..c594228c07 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -17,6 +17,7 @@ typedef enum { kKeyEncodingXterm, ///< Xterm's modifyOtherKeys encoding (XTMODKEYS) } KeyEncoding; +#define KEY_BUFFER_SIZE 0xfff typedef struct { int in_fd; // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk @@ -34,8 +35,9 @@ typedef struct { uv_timer_t timer_handle; Loop *loop; RStream read_stream; - RBuffer *key_buffer; TUIData *tui_data; + char key_buffer[KEY_BUFFER_SIZE]; + size_t key_buffer_len; } TermInput; typedef enum { -- cgit From cc1f2d2ca6caa3da4cb7910f74fed4375202e888 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Thu, 30 May 2024 10:24:54 +0200 Subject: perf(lsp): don't copy completion items in filter pass --- runtime/lua/vim/lsp/completion.lua | 100 ++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 39c0c5fa29..8777947acf 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -201,6 +201,24 @@ local function get_items(result) end end +---@param item lsp.CompletionItem +---@return string +local function get_doc(item) + local doc = item.documentation + if not doc then + return '' + end + if type(doc) == 'string' then + return doc + end + if type(doc) == 'table' and type(doc.value) == 'string' then + return doc.value + end + + vim.notify('invalid documentation value: ' .. vim.inspect(doc), vim.log.levels.WARN) + return '' +end + --- Turns the result of a `textDocument/completion` request into vim-compatible --- |complete-items|. --- @@ -216,58 +234,48 @@ function M._lsp_to_complete_items(result, prefix, client_id) return {} end - if prefix ~= '' then - ---@param item lsp.CompletionItem - local function match_prefix(item) - if item.filterText then - return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) - end - return true + local matches = prefix == '' and function() + return true + end or function(item) + if item.filterText then + return next(vim.fn.matchfuzzy({ item.filterText }, prefix)) end - - items = vim.tbl_filter(match_prefix, items) --[[@as lsp.CompletionItem[]|]] + return true end - table.sort(items, function(a, b) - return (a.sortText or a.label) < (b.sortText or b.label) - end) - - local matches = {} + local candidates = {} for _, item in ipairs(items) do - local info = '' - local documentation = item.documentation - if documentation then - if type(documentation) == 'string' and documentation ~= '' then - info = documentation - elseif type(documentation) == 'table' and type(documentation.value) == 'string' then - info = documentation.value - else - vim.notify( - ('invalid documentation value %s'):format(vim.inspect(documentation)), - vim.log.levels.WARN - ) - end - end - local word = get_completion_word(item) - table.insert(matches, { - word = word, - abbr = item.label, - kind = protocol.CompletionItemKind[item.kind] or 'Unknown', - menu = item.detail or '', - info = #info > 0 and info or '', - icase = 1, - dup = 1, - empty = 1, - user_data = { - nvim = { - lsp = { - completion_item = item, - client_id = client_id, + if matches(item) then + local word = get_completion_word(item) + table.insert(candidates, { + word = word, + abbr = item.label, + kind = protocol.CompletionItemKind[item.kind] or 'Unknown', + menu = item.detail or '', + info = get_doc(item), + icase = 1, + dup = 1, + empty = 1, + user_data = { + nvim = { + lsp = { + completion_item = item, + client_id = client_id, + }, }, }, - }, - }) + }) + end end - return matches + ---@diagnostic disable-next-line: no-unknown + table.sort(candidates, function(a, b) + ---@type lsp.CompletionItem + local itema = a.user_data.nvim.lsp.completion_item + ---@type lsp.CompletionItem + local itemb = b.user_data.nvim.lsp.completion_item + return (itema.sortText or itema.label) < (itemb.sortText or itemb.label) + end) + + return candidates end --- @param lnum integer 0-indexed -- cgit From 4c938f6d72710507db22074951eee23869ed49e0 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Thu, 30 May 2024 10:46:47 +0200 Subject: refactor(lsp): share completion request logic between omnifunc & trigger --- runtime/lua/vim/lsp/completion.lua | 209 +++++++++++++++---------------------- 1 file changed, 85 insertions(+), 124 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index 8777947acf..c514c5ef4d 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -348,78 +348,6 @@ function M._convert_results( return matches, server_start_boundary end ---- Implements 'omnifunc' compatible LSP completion. ---- ---- @see |complete-functions| ---- @see |complete-items| ---- @see |CompleteDone| ---- ---- @param findstart integer 0 or 1, decides behavior ---- @param base integer findstart=0, text to match against ---- ---- @return integer|table Decided by {findstart}: ---- - findstart=0: column where the completion starts, or -2 or -3 ---- - findstart=1: list of matches (actually just calls |complete()|) -function M._omnifunc(findstart, base) - vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) - assert(base) -- silence luals - local bufnr = api.nvim_get_current_buf() - local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) - local remaining = #clients - if remaining == 0 then - return findstart == 1 and -1 or {} - end - - local win = api.nvim_get_current_win() - local cursor = api.nvim_win_get_cursor(win) - local lnum = cursor[1] - 1 - local cursor_col = cursor[2] - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) - local client_start_boundary = vim.fn.match(line_to_cursor, '\\k*$') --[[@as integer]] - local server_start_boundary = nil - local items = {} - - local function on_done() - local mode = api.nvim_get_mode()['mode'] - if mode == 'i' or mode == 'ic' then - vim.fn.complete((server_start_boundary or client_start_boundary) + 1, items) - end - end - - local util = vim.lsp.util - for _, client in ipairs(clients) do - local params = util.make_position_params(win, client.offset_encoding) - client.request(ms.textDocument_completion, params, function(err, result) - if err then - lsp.log.warn(err.message) - end - if result and vim.fn.mode() == 'i' then - local matches - matches, server_start_boundary = M._convert_results( - line, - lnum, - cursor_col, - client.id, - client_start_boundary, - server_start_boundary, - result, - client.offset_encoding - ) - vim.list_extend(items, matches) - end - remaining = remaining - 1 - if remaining == 0 then - vim.schedule(on_done) - end - end, bufnr) - end - - -- Return -2 to signal that we should continue completion so that we can - -- async complete. - return -2 -end - --- @param clients table --- @param bufnr integer --- @param win integer @@ -455,6 +383,64 @@ local function request(clients, bufnr, win, callback) end end +local function trigger(bufnr, clients) + reset_timer() + Context:cancel_pending() + + local win = api.nvim_get_current_win() + local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer + local line = api.nvim_get_current_line() + local line_to_cursor = line:sub(1, cursor_col) + local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') + local start_time = vim.uv.hrtime() + Context.last_request_time = start_time + + local cancel_request = request(clients, bufnr, win, function(responses) + local end_time = vim.uv.hrtime() + rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) + + Context.pending_requests = {} + Context.isIncomplete = false + + local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row + local mode = api.nvim_get_mode().mode + if row_changed or not (mode == 'i' or mode == 'ic') then + return + end + + local matches = {} + local server_start_boundary --- @type integer? + for client_id, response in pairs(responses) do + if response.err then + vim.notify_once(response.err.message, vim.log.levels.warn) + end + + local result = response.result + if result then + Context.isIncomplete = Context.isIncomplete or result.isIncomplete + local client = lsp.get_client_by_id(client_id) + local encoding = client and client.offset_encoding or 'utf-16' + local client_matches + client_matches, server_start_boundary = M._convert_results( + line, + cursor_row - 1, + cursor_col, + client_id, + word_boundary, + nil, + result, + encoding + ) + vim.list_extend(matches, client_matches) + end + end + local start_col = (server_start_boundary or word_boundary) + 1 + vim.fn.complete(start_col, matches) + end) + + table.insert(Context.pending_requests, cancel_request) +end + --- @param handle vim.lsp.completion.BufHandle local function on_insert_char_pre(handle) if tonumber(vim.fn.pumvisible()) == 1 then @@ -701,63 +687,38 @@ end --- Trigger LSP completion in the current buffer. function M.trigger() - reset_timer() - Context:cancel_pending() - - local win = api.nvim_get_current_win() local bufnr = api.nvim_get_current_buf() - local cursor_row, cursor_col = unpack(api.nvim_win_get_cursor(win)) --- @type integer, integer - local line = api.nvim_get_current_line() - local line_to_cursor = line:sub(1, cursor_col) local clients = (buf_handles[bufnr] or {}).clients or {} - local word_boundary = vim.fn.match(line_to_cursor, '\\k*$') - local start_time = vim.uv.hrtime() - Context.last_request_time = start_time - - local cancel_request = request(clients, bufnr, win, function(responses) - local end_time = vim.uv.hrtime() - rtt_ms = compute_new_average((end_time - start_time) * ns_to_ms) - - Context.pending_requests = {} - Context.isIncomplete = false - - local row_changed = api.nvim_win_get_cursor(win)[1] ~= cursor_row - local mode = api.nvim_get_mode().mode - if row_changed or not (mode == 'i' or mode == 'ic') then - return - end + trigger(bufnr, clients) +end - local matches = {} - local server_start_boundary --- @type integer? - for client_id, response in pairs(responses) do - if response.err then - vim.notify_once(response.err.message, vim.log.levels.warn) - end +--- Implements 'omnifunc' compatible LSP completion. +--- +--- @see |complete-functions| +--- @see |complete-items| +--- @see |CompleteDone| +--- +--- @param findstart integer 0 or 1, decides behavior +--- @param base integer findstart=0, text to match against +--- +--- @return integer|table Decided by {findstart}: +--- - findstart=0: column where the completion starts, or -2 or -3 +--- - findstart=1: list of matches (actually just calls |complete()|) +function M._omnifunc(findstart, base) + vim.lsp.log.debug('omnifunc.findstart', { findstart = findstart, base = base }) + assert(base) -- silence luals + local bufnr = api.nvim_get_current_buf() + local clients = lsp.get_clients({ bufnr = bufnr, method = ms.textDocument_completion }) + local remaining = #clients + if remaining == 0 then + return findstart == 1 and -1 or {} + end - local result = response.result - if result then - Context.isIncomplete = Context.isIncomplete or result.isIncomplete - local client = lsp.get_client_by_id(client_id) - local encoding = client and client.offset_encoding or 'utf-16' - local client_matches - client_matches, server_start_boundary = M._convert_results( - line, - cursor_row - 1, - cursor_col, - client_id, - word_boundary, - nil, - result, - encoding - ) - vim.list_extend(matches, client_matches) - end - end - local start_col = (server_start_boundary or word_boundary) + 1 - vim.fn.complete(start_col, matches) - end) + trigger(bufnr, clients) - table.insert(Context.pending_requests, cancel_request) + -- Return -2 to signal that we should continue completion so that we can + -- async complete. + return -2 end return M -- cgit From 138a93a057dabd70673b7466bf5af41bd66f1385 Mon Sep 17 00:00:00 2001 From: Mathias Fussenegger Date: Thu, 30 May 2024 10:51:52 +0200 Subject: perf(lsp): avoid repeated table lookup in completion.enable --- runtime/lua/vim/lsp/completion.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index c514c5ef4d..b77bf3e3c2 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -575,8 +575,10 @@ end ---@param bufnr integer ---@param opts vim.lsp.completion.BufferOpts local function enable_completions(client_id, bufnr, opts) - if not buf_handles[bufnr] then - buf_handles[bufnr] = { clients = {}, triggers = {} } + local buf_handle = buf_handles[bufnr] + if not buf_handle then + buf_handle = { clients = {}, triggers = {} } + buf_handles[bufnr] = buf_handle -- Attach to buffer events. api.nvim_buf_attach(bufnr, false, { @@ -617,12 +619,12 @@ local function enable_completions(client_id, bufnr, opts) end end - if not buf_handles[bufnr].clients[client_id] then + if not buf_handle.clients[client_id] then local client = lsp.get_client_by_id(client_id) assert(client, 'invalid client ID') -- Add the new client to the buffer's clients. - buf_handles[bufnr].clients[client_id] = client + buf_handle.clients[client_id] = client -- Add the new client to the clients that should be triggered by its trigger characters. --- @type string[] @@ -632,10 +634,10 @@ local function enable_completions(client_id, bufnr, opts) 'triggerCharacters' ) or {} for _, char in ipairs(triggers) do - local clients_for_trigger = buf_handles[bufnr].triggers[char] + local clients_for_trigger = buf_handle.triggers[char] if not clients_for_trigger then clients_for_trigger = {} - buf_handles[bufnr].triggers[char] = clients_for_trigger + buf_handle.triggers[char] = clients_for_trigger end local client_exists = vim.iter(clients_for_trigger):any(function(c) return c.id == client_id -- cgit From 6d6974eae685feeccac027287b4dee58730a7464 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 31 May 2024 20:36:16 +0200 Subject: refactor(input): don't use a ring for input Since paste data is handled via a separate channel, the data processed via `input_buffer` is typically just explicit keys as typed in by the user. Therefore it should be fine to use `memmove()` to always put the remaining data in front when refilling the buffer. --- src/nvim/api/vim.c | 2 +- src/nvim/main.c | 1 - src/nvim/memory.c | 1 - src/nvim/os/input.c | 111 ++++++++++++++++++++++++++++------------------------ 4 files changed, 61 insertions(+), 54 deletions(-) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52ab18cbff..ae8f73fa2c 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -313,7 +313,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) keys_esc = keys.data; } if (lowlevel) { - input_enqueue_raw(cstr_as_string(keys_esc)); + input_enqueue_raw(keys_esc, strlen(keys_esc)); } else { ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), insert ? 0 : typebuf.tb_len, !typed, false); diff --git a/src/nvim/main.c b/src/nvim/main.c index cf1324d37f..db7f16131b 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -154,7 +154,6 @@ void event_init(void) loop_init(&main_loop, NULL); resize_events = multiqueue_new_child(main_loop.events); - input_init(); signal_init(); // mspgack-rpc initialization channel_init(); diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 789535e270..6a60ca927e 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -882,7 +882,6 @@ void free_all_mem(void) decor_free_all_mem(); drawline_free_all_mem(); - input_free_all_mem(); if (ui_client_channel_id) { ui_client_free_all_mem(); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index cfe8696cdd..63eca0b6da 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -33,7 +33,7 @@ #include "nvim/state_defs.h" #define READ_BUFFER_SIZE 0xfff -#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4) +#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN) typedef enum { kInputNone, @@ -42,7 +42,10 @@ typedef enum { } InbufPollResult; static RStream read_stream = { .s.closed = true }; // Input before UI starts. -static RBuffer *input_buffer = NULL; +static char input_buffer[INPUT_BUFFER_SIZE]; +static char *input_read_pos = input_buffer; +static char *input_write_pos = input_buffer; + static bool input_eof = false; static bool blocking = false; static int cursorhold_time = 0; ///< time waiting for CursorHold event @@ -52,11 +55,6 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte # include "os/input.c.generated.h" #endif -void input_init(void) -{ - input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); -} - void input_start(void) { if (!read_stream.s.closed) { @@ -78,13 +76,6 @@ void input_stop(void) rstream_may_close(&read_stream); } -#ifdef EXITFREE -void input_free_all_mem(void) -{ - rbuffer_free(input_buffer); -} -#endif - static void cursorhold_event(void **argv) { event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD; @@ -119,9 +110,12 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e restart_cursorhold_wait(tb_change_cnt); } - if (maxlen && rbuffer_size(input_buffer)) { + if (maxlen && input_available()) { restart_cursorhold_wait(tb_change_cnt); - return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); + size_t to_read = MIN((size_t)maxlen, input_available()); + memcpy(buf, input_read_pos, to_read); + input_read_pos += to_read; + return (int)to_read; } // No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped. @@ -161,11 +155,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e return 0; } - if (maxlen && rbuffer_size(input_buffer)) { + if (maxlen && input_available()) { restart_cursorhold_wait(tb_change_cnt); - // Safe to convert rbuffer_read to int, it will never overflow since we use - // relatively small buffers. - return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen); + // Safe to convert rbuffer_read to int, it will never overflow since + // INPUT_BUFFER_SIZE fits in an int + size_t to_read = MIN((size_t)maxlen, input_available()); + memcpy(buf, input_read_pos, to_read); + input_read_pos += to_read; + return (int)to_read; } // If there are events, return the keys directly @@ -247,11 +244,28 @@ bool os_isatty(int fd) return uv_guess_handle(fd) == UV_TTY; } -void input_enqueue_raw(String keys) +size_t input_available(void) +{ + return (size_t)(input_write_pos - input_read_pos); +} + +static size_t input_space(void) +{ + return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos); +} + +void input_enqueue_raw(const char *data, size_t size) { - if (keys.size > 0) { - rbuffer_write(input_buffer, keys.data, keys.size); + if (input_read_pos > input_buffer) { + size_t available = input_available(); + memmove(input_buffer, input_read_pos, available); + input_read_pos = input_buffer; + input_write_pos = input_buffer + available; } + + size_t to_write = MIN(size, input_space()); + memcpy(input_write_pos, data, to_write); + input_write_pos += to_write; } size_t input_enqueue(String keys) @@ -259,7 +273,7 @@ size_t input_enqueue(String keys) const char *ptr = keys.data; const char *end = ptr + keys.size; - while (rbuffer_space(input_buffer) >= 19 && ptr < end) { + while (input_space() >= 19 && ptr < end) { // A "" form occupies at least 1 characters, and produces up // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). // In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed, @@ -272,7 +286,7 @@ size_t input_enqueue(String keys) if (new_size) { new_size = handle_mouse_event(&ptr, buf, new_size); - rbuffer_write(input_buffer, (char *)buf, new_size); + input_enqueue_raw((char *)buf, new_size); continue; } @@ -293,11 +307,11 @@ size_t input_enqueue(String keys) // copy the character, escaping K_SPECIAL if ((uint8_t)(*ptr) == K_SPECIAL) { - rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1); - rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1); + input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1); + input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1); + input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1); } else { - rbuffer_write(input_buffer, ptr, 1); + input_enqueue_raw(ptr, 1); } ptr++; } @@ -422,7 +436,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs return bufsize; } -size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) +void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col) { modifier |= check_multiclick(code, grid, row, col); uint8_t buf[7]; @@ -442,8 +456,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co mouse_col = col; size_t written = 3 + (size_t)(p - buf); - rbuffer_write(input_buffer, (char *)buf, written); - return written; + input_enqueue_raw((char *)buf, written); } /// @return true if the main loop is blocked and waiting for input. @@ -484,20 +497,15 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events) return input_eof ? kInputEof : kInputNone; } -bool input_available(void) -{ - return rbuffer_size(input_buffer) != 0; -} - static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof) { if (at_eof) { input_eof = true; } - assert(rbuffer_space(input_buffer) >= rbuffer_size(buf)); + assert(input_space() >= rbuffer_size(buf)); RBUFFER_UNTIL_EMPTY(buf, ptr, len) { - (void)rbuffer_write(input_buffer, ptr, len); + input_enqueue_raw(ptr, len); rbuffer_consumed(buf, len); } } @@ -508,23 +516,24 @@ static void process_ctrl_c(void) return; } - size_t consume_count = 0; - RBUFFER_EACH_REVERSE(input_buffer, c, i) { - if ((uint8_t)c == Ctrl_C - || ((uint8_t)c == 'C' && i >= 3 - && (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL - && (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER - && (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) { - *rbuffer_get(input_buffer, i) = Ctrl_C; + size_t available = input_available(); + ssize_t i; + for (i = (ssize_t)available - 1; i >= 0; i--) { + uint8_t c = (uint8_t)input_read_pos[i]; + if (c == Ctrl_C + || (c == 'C' && i >= 3 + && (uint8_t)input_read_pos[i - 3] == K_SPECIAL + && (uint8_t)input_read_pos[i - 2] == KS_MODIFIER + && (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) { + input_read_pos[i] = Ctrl_C; got_int = true; - consume_count = i; break; } } - if (got_int && consume_count) { + if (got_int && i > 0) { // Remove all unprocessed input (typeahead) before the CTRL-C. - rbuffer_consumed(input_buffer, consume_count); + input_read_pos += i; } } @@ -548,7 +557,7 @@ static int push_event_key(uint8_t *buf, int maxlen) bool os_input_ready(MultiQueue *events) { return (typebuf_was_filled // API call filled typeahead - || rbuffer_size(input_buffer) // Input buffer filled + || input_available() // Input buffer filled || pending_events(events)); // Events must be processed } -- cgit From f2083bd55cafe861e9dffb1c1658e5b0983c5ef6 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sat, 1 Jun 2024 12:10:35 +0200 Subject: fix(column): crash with 'signcolumn' set to "number" (#29003) Problem: Numberwidth may depend on number of signs with text in the buffer and is not handled correctly for extmark signs. Solution: Move legacy sign code for changed numberwidth so that it is handled properly for legacy and extmark signs alike. --- src/nvim/decoration.c | 18 ++++++++++++++++++ src/nvim/drawline.c | 1 + src/nvim/drawscreen.c | 1 + src/nvim/sign.c | 30 +----------------------------- test/functional/ui/decorations_spec.lua | 20 ++++++++++++++++++++ 5 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 303d0318b5..52a3fa5924 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -15,6 +15,7 @@ #include "nvim/drawscreen.h" #include "nvim/extmark.h" #include "nvim/fold.h" +#include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" #include "nvim/highlight.h" @@ -184,6 +185,21 @@ void buf_put_decor(buf_T *buf, DecorInline decor, int row, int row2) } } +/// When displaying signs in the 'number' column, if the width of the number +/// column is less than 2, then force recomputing the width after placing or +/// unplacing the first sign in "buf". +static void may_force_numberwidth_recompute(buf_T *buf, bool unplace) +{ + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf + && wp->w_minscwidth == SCL_NUM + && (wp->w_p_nu || wp->w_p_rnu) + && (unplace || wp->w_nrwidth_width < 2)) { + wp->w_nrwidth_line_count = 0; + } + } +} + static int sign_add_id = 0; void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) { @@ -191,6 +207,7 @@ void buf_put_decor_sh(buf_T *buf, DecorSignHighlight *sh, int row1, int row2) sh->sign_add_id = sign_add_id++; if (sh->text[0]) { buf_signcols_count_range(buf, row1, row2, 1, kFalse); + may_force_numberwidth_recompute(buf, false); } } } @@ -218,6 +235,7 @@ void buf_remove_decor_sh(buf_T *buf, int row1, int row2, DecorSignHighlight *sh) if (buf_meta_total(buf, kMTMetaSignText)) { buf_signcols_count_range(buf, row1, row2, -1, kFalse); } else { + may_force_numberwidth_recompute(buf, true); buf->b_signcols.resized = true; buf->b_signcols.max = buf->b_signcols.count[0] = 0; } diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 4d534d78a2..3bd00ee3f9 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -465,6 +465,7 @@ static void draw_sign(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, i int fill = nrcol ? number_width(wp) + 1 : SIGN_WIDTH; draw_col_fill(wlv, schar_from_ascii(' '), fill, attr); int sign_pos = wlv->off - SIGN_WIDTH - (int)nrcol; + assert(sign_pos >= 0); linebuf_char[sign_pos] = sattr.text[0]; linebuf_char[sign_pos + 1] = sattr.text[1]; } else { diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 039bbd219c..bd9a834869 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -1548,6 +1548,7 @@ static void win_update(win_T *wp) // Force redraw when width of 'number' or 'relativenumber' column changes. if (wp->w_nrwidth != nrwidth_new) { type = UPD_NOT_VALID; + changed_line_abv_curs_win(wp); wp->w_nrwidth = nrwidth_new; } else { // Set mod_top to the first line that needs displaying because of diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 4e6672c5dd..be7a46b720 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -246,12 +246,6 @@ static int buf_delete_signs(buf_T *buf, char *group, int id, linenr_T atlnum) return FAIL; } - // When deleting the last sign need to redraw the windows to remove the - // sign column. Not when curwin is NULL (this means we're exiting). - if (!buf_meta_total(buf, kMTMetaSignText) && curwin != NULL) { - changed_line_abv_curs(); - } - return OK; } @@ -499,17 +493,6 @@ static void sign_list_by_name(char *name) } } -static void may_force_numberwidth_recompute(buf_T *buf, int unplace) -{ - FOR_ALL_TAB_WINDOWS(tp, wp) - if (wp->w_buffer == buf - && (wp->w_p_nu || wp->w_p_rnu) - && (unplace || wp->w_nrwidth_width < 2) - && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) { - wp->w_nrwidth_line_count = 0; - } -} - /// Place a sign at the specified file location or update a sign. static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_T lnum, int prio) { @@ -531,11 +514,7 @@ static int sign_place(uint32_t *id, char *group, char *name, buf_T *buf, linenr_ // ":sign place {id} file={fname}": change sign type and/or priority lnum = buf_mod_sign(buf, id, group, prio, sp); } - if (lnum > 0) { - // When displaying signs in the 'number' column, if the width of the - // number column is less than 2, then force recomputing the width. - may_force_numberwidth_recompute(buf, false); - } else { + if (lnum <= 0) { semsg(_("E885: Not possible to change sign %s"), name); return FAIL; } @@ -562,13 +541,6 @@ static int sign_unplace_inner(buf_T *buf, int id, char *group, linenr_T atlnum) } } - // When all the signs in a buffer are removed, force recomputing the - // number column width (if enabled) in all the windows displaying the - // buffer if 'signcolumn' is set to 'number' in that window. - if (!buf_meta_total(buf, kMTMetaSignText)) { - may_force_numberwidth_recompute(buf, true); - } - return OK; } diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua index 746bfb3262..3e67e33ddb 100644 --- a/test/functional/ui/decorations_spec.lua +++ b/test/functional/ui/decorations_spec.lua @@ -5497,6 +5497,26 @@ l5 api.nvim_buf_clear_namespace(0, ns, 0, -1) end) + + it([[correct numberwidth with 'signcolumn' set to "number" #28984]], function() + command('set number numberwidth=1 signcolumn=number') + api.nvim_buf_set_extmark(0, ns, 0, 0, { sign_text = 'S1' }) + screen:expect({ + grid = [[ + S1 ^ | + {1:~ }|*8 + | + ]] + }) + api.nvim_buf_del_extmark(0, ns, 1) + screen:expect({ + grid = [[ + {8:1 }^ | + {1:~ }|*8 + | + ]] + }) + end) end) describe('decorations: virt_text', function() -- cgit From 9eb0426002696fba4a7c5b9cadd8799a8ae18e6a Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Fri, 31 May 2024 11:47:32 -0400 Subject: fix(luacats): allow all types inside tuples --- scripts/luacats_grammar.lua | 2 +- test/functional/script/luacats_grammar_spec.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/luacats_grammar.lua b/scripts/luacats_grammar.lua index 6742eab5e9..9360eb9417 100644 --- a/scripts/luacats_grammar.lua +++ b/scripts/luacats_grammar.lua @@ -180,7 +180,7 @@ local grammar = P { fun_param = lname * opt(colon * v.ltype), ty_fun = Pf('fun') * paren(comma(lname * opt(colon * v.ltype))) * opt(colon * comma1(v.ltype)), ty_generic = P('`') * letter * P('`'), - ty_tuple = Pf('[') * comma(v.ty_opt) * fill * P(']'), + ty_tuple = Pf('[') * comma(v.ltype) * fill * P(']'), } return grammar --[[@as nvim.luacats.grammar]] diff --git a/test/functional/script/luacats_grammar_spec.lua b/test/functional/script/luacats_grammar_spec.lua index d6fff3f409..9c6417f7bf 100644 --- a/test/functional/script/luacats_grammar_spec.lua +++ b/test/functional/script/luacats_grammar_spec.lua @@ -160,10 +160,10 @@ describe('luacats grammar', function() type = '`T`', }) - test('@param type [number,string] this is a tuple type', { + test('@param type [number,string,"good"|"bad"] this is a tuple type', { desc = 'this is a tuple type', kind = 'param', name = 'type', - type = '[number,string]', + type = '[number,string,"good"|"bad"]', }) end) -- cgit From bb6190bec5f18c1f9e2c1d29ef1f7cf7912ea625 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sat, 1 Jun 2024 08:19:41 -0700 Subject: refactor: move shared messages to errors.h #26214 --- src/nvim/api/vim.c | 1 + src/nvim/api/win_config.c | 1 + src/nvim/api/window.c | 1 + src/nvim/arglist.c | 1 + src/nvim/autocmd.c | 1 + src/nvim/buffer.c | 1 + src/nvim/bufwrite.c | 1 + src/nvim/channel.c | 1 + src/nvim/cmdexpand.c | 1 + src/nvim/cmdhist.c | 1 + src/nvim/debugger.c | 1 + src/nvim/diff.c | 1 + src/nvim/digraph.c | 1 + src/nvim/edit.c | 1 + src/nvim/errors.h | 193 ++++++++++++++++++++++++++++++ src/nvim/eval.c | 1 + src/nvim/eval/executor.c | 1 + src/nvim/eval/funcs.c | 1 + src/nvim/eval/typval.c | 1 + src/nvim/eval/userfunc.c | 1 + src/nvim/eval/vars.c | 1 + src/nvim/eval/window.c | 1 + src/nvim/ex_cmds.c | 1 + src/nvim/ex_cmds2.c | 1 + src/nvim/ex_docmd.c | 1 + src/nvim/ex_eval.c | 1 + src/nvim/ex_getln.c | 1 + src/nvim/ex_session.c | 1 + src/nvim/fileio.c | 1 + src/nvim/fold.c | 1 + src/nvim/generators/gen_api_dispatch.lua | 1 + src/nvim/getchar.c | 1 + src/nvim/globals.h | 196 +------------------------------ src/nvim/help.c | 1 + src/nvim/highlight_group.c | 1 + src/nvim/indent.c | 1 + src/nvim/insexpand.c | 1 + src/nvim/keycodes.c | 1 + src/nvim/lua/api_wrappers.c | 1 + src/nvim/lua/executor.c | 1 + src/nvim/lua/secure.c | 1 + src/nvim/lua/spell.c | 1 + src/nvim/main.c | 1 + src/nvim/mapping.c | 1 + src/nvim/mark.c | 1 + src/nvim/match.c | 1 + src/nvim/mbyte.c | 1 + src/nvim/memfile.c | 1 + src/nvim/memory.c | 1 + src/nvim/menu.c | 1 + src/nvim/message.c | 1 + src/nvim/move.c | 1 + src/nvim/normal.c | 1 + src/nvim/ops.c | 1 + src/nvim/option.c | 1 + src/nvim/optionstr.c | 1 + src/nvim/os/fs.c | 1 + src/nvim/os/shell.c | 1 + src/nvim/popupmenu.c | 1 + src/nvim/profile.c | 1 + src/nvim/quickfix.c | 1 + src/nvim/regexp.c | 1 + src/nvim/runtime.c | 1 + src/nvim/search.c | 1 + src/nvim/shada.c | 1 + src/nvim/sign.c | 1 + src/nvim/spell.c | 1 + src/nvim/spellfile.c | 1 + src/nvim/spellsuggest.c | 1 + src/nvim/strings.c | 1 + src/nvim/syntax.c | 1 + src/nvim/tag.c | 1 + src/nvim/testing.c | 1 + src/nvim/undo.c | 1 + src/nvim/window.c | 1 + src/nvim/winfloat.c | 1 + 76 files changed, 270 insertions(+), 193 deletions(-) create mode 100644 src/nvim/errors.h diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 52ab18cbff..f5c89fb283 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -28,6 +28,7 @@ #include "nvim/cursor.h" #include "nvim/decoration.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 70235d8db6..f0b90d8512 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -17,6 +17,7 @@ #include "nvim/decoration.h" #include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/window.h" #include "nvim/extmark_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 54a19513db..92dc9dc7e3 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/window.h" #include "nvim/ex_docmd.h" #include "nvim/gettext_defs.h" diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index 4d493c9d03..700bfc1655 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -13,6 +13,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/window.h" diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index c5d81d4cd2..e5872fcc76 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 39d0d24d47..5d0cd66133 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -43,6 +43,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 27de03954a..6fbcb2dbb8 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -18,6 +18,7 @@ #include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/channel.c b/src/nvim/channel.c index e5492caf45..05225cecd0 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -13,6 +13,7 @@ #include "nvim/autocmd_defs.h" #include "nvim/buffer_defs.h" #include "nvim/channel.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 808df44941..bb85620ce6 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -19,6 +19,7 @@ #include "nvim/cmdexpand.h" #include "nvim/cmdhist.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 983ab8b59b..ab05ae1cfc 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -11,6 +11,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cmdhist.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 7d87b61ce5..b71ff23f57 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -13,6 +13,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/diff.c b/src/nvim/diff.c index ea846b46ec..54335fc93e 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -26,6 +26,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index a358a1723a..26fb77df30 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -12,6 +12,7 @@ #include "nvim/charset.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 220b92d099..146e95df87 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -18,6 +18,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/errors.h b/src/nvim/errors.h new file mode 100644 index 0000000000..39095db952 --- /dev/null +++ b/src/nvim/errors.h @@ -0,0 +1,193 @@ +#pragma once + +#include "nvim/gettext_defs.h" +#include "nvim/macros_defs.h" + +// +// Shared error messages. Excludes errors only used once and debugging messages. +// +// uncrustify:off +EXTERN const char e_abort[] INIT(= N_("E470: Command aborted")); +EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup")); +EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job")); +EXTERN const char e_argreq[] INIT(= N_("E471: Argument required")); +EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &")); +EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; executes, CTRL-C quits")); +EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search")); +EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s")); +EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive")); +EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded")); +EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif")); +EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry")); +EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); +EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor")); +EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while")); +EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for")); +EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)")); +EXTERN const char e_failed[] INIT(= N_("E472: Command failed")); +EXTERN const char e_internal[] INIT(= N_("E473: Internal error")); +EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s")); +EXTERN const char e_interr[] INIT(= N_("Interrupted")); +EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument")); +EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); +EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); +EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); +EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); +EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); +EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range")); +EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command")); +EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); +EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); +EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id")); +EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); +EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full")); +EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\"")); +EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty")); +EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); +EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel")); +EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); +EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); +EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); +EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); +EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); +EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number")); +EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set")); +EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); +EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep")); +EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file")); +EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation")); +EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed")); +EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s")); +EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet")); +EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line")); +EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping")); +EXTERN const char e_nomatch[] INIT(= N_("E479: No match")); +EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s")); +EXTERN const char e_noname[] INIT(= N_("E32: No file name")); +EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression")); +EXTERN const char e_noprev[] INIT(= N_("E34: No previous command")); +EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression")); +EXTERN const char e_norange[] INIT(= N_("E481: No range allowed")); +EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room")); +EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name")); +EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s")); +EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s")); +EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s")); +EXTERN const char e_null[] INIT(= N_("E38: Null argument")); +EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected")); +EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s")); +EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!")); +EXTERN const char e_patnotf[] INIT(= N_("Pattern not found")); +EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); +EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive")); +EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); + +EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors")); +EXTERN const char e_loclist[] INIT(= N_("E776: No location list")); +EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string")); +EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program")); +EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)")); +EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s=")); +EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s")); +EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); +EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\"")); +EXTERN const char e_stringreq[] INIT(= N_("E928: String required")); +EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required")); +EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64)); +EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob")); +EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); +EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s")); +EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); +EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\"")); +EXTERN const char e_listreq[] INIT(= N_("E714: List required")); +EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required")); +EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); +EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); +EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); +EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); +EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window")); +EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); +EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size")); +EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); +EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); +EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file")); +EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex")); +EXTERN const char e_longname[] INIT(= N_("E75: Name too long")); +EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many [")); +EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names")); +EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters")); +EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); +EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark")); +EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); +EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); +EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); +EXTERN const char e_write[] INIT(= N_("E80: Error while writing")); +EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required")); +EXTERN const char e_usingsid[] INIT(= N_("E81: Using not in a script context")); +EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); +EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); +EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); + +EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); + +EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); +EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); +EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set")); +EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name")); +EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); +EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); +EXTERN const char e_menu_only_exists_in_another_mode[] +INIT(= N_("E328: Menu only exists in another mode")); +EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window")); +EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); +EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); +EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long")); +EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String")); +EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); +EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); +EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); +EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); + +EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); + +EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); + +EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); +EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); + +EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); + +EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); + +EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); + +EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); + +EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); + +EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); +EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); + +EXTERN const char e_stray_closing_curly_str[] +INIT(= N_("E1278: Stray '}' without a matching '{': %s")); +EXTERN const char e_missing_close_curly_str[] +INIT(= N_("E1279: Missing '}': %s")); + +EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); + +EXTERN const char e_undobang_cannot_redo_or_move_branch[] +INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); + +EXTERN const char e_winfixbuf_cannot_go_to_buffer[] +INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); + +EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); + +EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); + +EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); +EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); + +EXTERN const char line_msg[] INIT(= N_(" line ")); +// uncrustify:on diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 48a58228ae..a8778b9489 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -24,6 +24,7 @@ #include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 1b8c057d7c..3255e78d09 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -1,6 +1,7 @@ #include #include +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/executor.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 8b22c7a797..0165e4af60 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -38,6 +38,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/buffer.h" #include "nvim/eval/decode.h" diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index eb8c89c36e..1ea1fe46d2 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -10,6 +10,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/executor.h" diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 39bd63462c..00fb896797 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 1c15274acc..7b93a291c4 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -15,6 +15,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/funcs.h" diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index 68de40f983..d7485c12a3 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -10,6 +10,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 834cc6698a..2f7673a6f4 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -34,6 +34,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index f4a6e61831..a602719f6d 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -17,6 +17,7 @@ #include "nvim/bufwrite.h" #include "nvim/change.h" #include "nvim/channel.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 1fcfc505df..028ee8f6ae 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -29,6 +29,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 472741d537..2681beb228 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -11,6 +11,7 @@ #include "nvim/ascii_defs.h" #include "nvim/charset.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index cc2608433d..4323a9d221 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -28,6 +28,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 0e5d2fe4f5..50ee197ef4 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -15,6 +15,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index df9c4928c9..05c9114554 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -27,6 +27,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_eval.h" diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 59a4dc6aad..be1b6acf2c 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -22,6 +22,7 @@ #include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_session.h" diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 62c99ce082..61c80a3d2e 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -306,6 +306,7 @@ local keysets_defs = assert(io.open(keysets_outputf, 'wb')) -- so that the dispatcher can find the C functions that you are creating! -- =========================================================================== output:write([[ +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/globals.h" diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 9b19644b7e..ce2c85f174 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -19,6 +19,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 83fef1fe75..410e8f2e7c 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -793,195 +793,7 @@ EXTERN disptick_T display_tick INIT( = 0); // cursor position in Insert mode. EXTERN linenr_T spell_redraw_lnum INIT( = 0); -// uncrustify:off - -// The error messages that can be shared are included here. -// Excluded are errors that are only used once and debugging messages. -EXTERN const char e_abort[] INIT(= N_("E470: Command aborted")); -EXTERN const char e_afterinit[] INIT(= N_("E905: Cannot set this option after startup")); -EXTERN const char e_api_spawn_failed[] INIT(= N_("E903: Could not spawn API job")); -EXTERN const char e_argreq[] INIT(= N_("E471: Argument required")); -EXTERN const char e_backslash[] INIT(= N_("E10: \\ should be followed by /, ? or &")); -EXTERN const char e_cmdwin[] INIT(= N_("E11: Invalid in command-line window; executes, CTRL-C quits")); -EXTERN const char e_curdir[] INIT(= N_("E12: Command not allowed in secure mode in current dir or tag search")); -EXTERN const char e_invalid_buffer_name_str[] INIT(= N_("E158: Invalid buffer name: %s")); -EXTERN const char e_command_too_recursive[] INIT(= N_("E169: Command too recursive")); -EXTERN const char e_buffer_is_not_loaded[] INIT(= N_("E681: Buffer is not loaded")); -EXTERN const char e_endif[] INIT(= N_("E171: Missing :endif")); -EXTERN const char e_endtry[] INIT(= N_("E600: Missing :endtry")); -EXTERN const char e_endwhile[] INIT(= N_("E170: Missing :endwhile")); -EXTERN const char e_endfor[] INIT(= N_("E170: Missing :endfor")); -EXTERN const char e_while[] INIT(= N_("E588: :endwhile without :while")); -EXTERN const char e_for[] INIT(= N_("E588: :endfor without :for")); -EXTERN const char e_exists[] INIT(= N_("E13: File exists (add ! to override)")); -EXTERN const char e_failed[] INIT(= N_("E472: Command failed")); -EXTERN const char e_internal[] INIT(= N_("E473: Internal error")); -EXTERN const char e_intern2[] INIT(= N_("E685: Internal error: %s")); -EXTERN const char e_interr[] INIT(= N_("Interrupted")); -EXTERN const char e_invarg[] INIT(= N_("E474: Invalid argument")); -EXTERN const char e_invarg2[] INIT(= N_("E475: Invalid argument: %s")); -EXTERN const char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); -EXTERN const char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); -EXTERN const char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); -EXTERN const char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); -EXTERN const char e_invrange[] INIT(= N_("E16: Invalid range")); -EXTERN const char e_invcmd[] INIT(= N_("E476: Invalid command")); -EXTERN const char e_isadir2[] INIT(= N_("E17: \"%s\" is a directory")); -EXTERN const char e_no_spell[] INIT(= N_("E756: Spell checking is not possible")); -EXTERN const char e_invchan[] INIT(= N_("E900: Invalid channel id")); -EXTERN const char e_invchanjob[] INIT(= N_("E900: Invalid channel id: not a job")); -EXTERN const char e_jobtblfull[] INIT(= N_("E901: Job table is full")); -EXTERN const char e_jobspawn[] INIT(= N_("E903: Process failed to start: %s: \"%s\"")); -EXTERN const char e_channotpty[] INIT(= N_("E904: channel is not a pty")); -EXTERN const char e_stdiochan2[] INIT(= N_("E905: Couldn't open stdio channel: %s")); -EXTERN const char e_invstream[] INIT(= N_("E906: invalid stream for channel")); -EXTERN const char e_invstreamrpc[] INIT(= N_("E906: invalid stream for rpc channel, use 'rpc'")); -EXTERN const char e_streamkey[] INIT(= N_("E5210: dict key '%s' already set for buffered stream in channel %" PRIu64)); -EXTERN const char e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); -EXTERN const char e_fsync[] INIT(= N_("E667: Fsync failed: %s")); -EXTERN const char e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); -EXTERN const char e_markinval[] INIT(= N_("E19: Mark has invalid line number")); -EXTERN const char e_marknotset[] INIT(= N_("E20: Mark not set")); -EXTERN const char e_modifiable[] INIT(= N_("E21: Cannot make changes, 'modifiable' is off")); -EXTERN const char e_nesting[] INIT(= N_("E22: Scripts nested too deep")); -EXTERN const char e_noalt[] INIT(= N_("E23: No alternate file")); -EXTERN const char e_noabbr[] INIT(= N_("E24: No such abbreviation")); -EXTERN const char e_nobang[] INIT(= N_("E477: No ! allowed")); -EXTERN const char e_nogroup[] INIT(= N_("E28: No such highlight group name: %s")); -EXTERN const char e_noinstext[] INIT(= N_("E29: No inserted text yet")); -EXTERN const char e_nolastcmd[] INIT(= N_("E30: No previous command line")); -EXTERN const char e_nomap[] INIT(= N_("E31: No such mapping")); -EXTERN const char e_nomatch[] INIT(= N_("E479: No match")); -EXTERN const char e_nomatch2[] INIT(= N_("E480: No match: %s")); -EXTERN const char e_noname[] INIT(= N_("E32: No file name")); -EXTERN const char e_nopresub[] INIT(= N_("E33: No previous substitute regular expression")); -EXTERN const char e_noprev[] INIT(= N_("E34: No previous command")); -EXTERN const char e_noprevre[] INIT(= N_("E35: No previous regular expression")); -EXTERN const char e_norange[] INIT(= N_("E481: No range allowed")); -EXTERN const char e_noroom[] INIT(= N_("E36: Not enough room")); -EXTERN const char e_notmp[] INIT(= N_("E483: Can't get temp file name")); -EXTERN const char e_notopen[] INIT(= N_("E484: Can't open file %s")); -EXTERN const char e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s")); -EXTERN const char e_notread[] INIT(= N_("E485: Can't read file %s")); -EXTERN const char e_null[] INIT(= N_("E38: Null argument")); -EXTERN const char e_number_exp[] INIT(= N_("E39: Number expected")); -EXTERN const char e_openerrf[] INIT(= N_("E40: Can't open errorfile %s")); -EXTERN const char e_outofmem[] INIT(= N_("E41: Out of memory!")); -EXTERN const char e_patnotf[] INIT(= N_("Pattern not found")); -EXTERN const char e_patnotf2[] INIT(= N_("E486: Pattern not found: %s")); -EXTERN const char e_positive[] INIT(= N_("E487: Argument must be positive")); -EXTERN const char e_prev_dir[] INIT(= N_("E459: Cannot go back to previous directory")); - -EXTERN const char e_no_errors[] INIT(= N_("E42: No Errors")); -EXTERN const char e_loclist[] INIT(= N_("E776: No location list")); -EXTERN const char e_re_damg[] INIT(= N_("E43: Damaged match string")); -EXTERN const char e_re_corr[] INIT(= N_("E44: Corrupted regexp program")); -EXTERN const char e_readonly[] INIT(= N_("E45: 'readonly' option is set (add ! to override)")); -EXTERN const char e_letwrong[] INIT(= N_("E734: Wrong variable type for %s=")); -EXTERN const char e_illvar[] INIT(= N_("E461: Illegal variable name: %s")); -EXTERN const char e_cannot_mod[] INIT(= N_("E995: Cannot modify existing variable")); -EXTERN const char e_readonlyvar[] INIT(= N_("E46: Cannot change read-only variable \"%.*s\"")); -EXTERN const char e_stringreq[] INIT(= N_("E928: String required")); -EXTERN const char e_dictreq[] INIT(= N_("E715: Dictionary required")); -EXTERN const char e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64)); -EXTERN const char e_invalblob[] INIT(= N_("E978: Invalid operation for Blob")); -EXTERN const char e_toomanyarg[] INIT(= N_("E118: Too many arguments for function: %s")); -EXTERN const char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s")); -EXTERN const char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: \"%s\"")); -EXTERN const char e_dictkey_len[] INIT(= N_("E716: Key not present in Dictionary: \"%.*s\"")); -EXTERN const char e_listreq[] INIT(= N_("E714: List required")); -EXTERN const char e_listblobreq[] INIT(= N_("E897: List or Blob required")); -EXTERN const char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); -EXTERN const char e_listdictblobarg[] INIT(= N_("E896: Argument of %s must be a List, Dictionary or Blob")); -EXTERN const char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); -EXTERN const char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); -EXTERN const char e_secure[] INIT(= N_("E523: Not allowed here")); -EXTERN const char e_textlock[] INIT(= N_("E565: Not allowed to change text or change window")); -EXTERN const char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); -EXTERN const char e_scroll[] INIT(= N_("E49: Invalid scroll size")); -EXTERN const char e_shellempty[] INIT(= N_("E91: 'shell' option is empty")); -EXTERN const char e_signdata[] INIT(= N_("E255: Couldn't read in sign data!")); -EXTERN const char e_swapclose[] INIT(= N_("E72: Close error on swap file")); -EXTERN const char e_toocompl[] INIT(= N_("E74: Command too complex")); -EXTERN const char e_longname[] INIT(= N_("E75: Name too long")); -EXTERN const char e_toomsbra[] INIT(= N_("E76: Too many [")); -EXTERN const char e_toomany[] INIT(= N_("E77: Too many file names")); -EXTERN const char e_trailing[] INIT(= N_("E488: Trailing characters")); -EXTERN const char e_trailing_arg[] INIT(= N_("E488: Trailing characters: %s")); -EXTERN const char e_umark[] INIT(= N_("E78: Unknown mark")); -EXTERN const char e_wildexpand[] INIT(= N_("E79: Cannot expand wildcards")); -EXTERN const char e_winheight[] INIT(= N_("E591: 'winheight' cannot be smaller than 'winminheight'")); -EXTERN const char e_winwidth[] INIT(= N_("E592: 'winwidth' cannot be smaller than 'winminwidth'")); -EXTERN const char e_write[] INIT(= N_("E80: Error while writing")); -EXTERN const char e_zerocount[] INIT(= N_("E939: Positive count required")); -EXTERN const char e_usingsid[] INIT(= N_("E81: Using not in a script context")); -EXTERN const char e_missingparen[] INIT(= N_("E107: Missing parentheses: %s")); -EXTERN const char e_empty_buffer[] INIT(= N_("E749: Empty buffer")); -EXTERN const char e_nobufnr[] INIT(= N_("E86: Buffer %" PRId64 " does not exist")); - -EXTERN const char e_str_not_inside_function[] INIT(= N_("E193: %s not inside a function")); - -EXTERN const char e_invalpat[] INIT(= N_("E682: Invalid search pattern or delimiter")); -EXTERN const char e_bufloaded[] INIT(= N_("E139: File is loaded in another buffer")); -EXTERN const char e_notset[] INIT(= N_("E764: Option '%s' is not set")); -EXTERN const char e_invalidreg[] INIT(= N_("E850: Invalid register name")); -EXTERN const char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\"")); -EXTERN const char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior")); -EXTERN const char e_menu_only_exists_in_another_mode[] -INIT(= N_("E328: Menu only exists in another mode")); -EXTERN const char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window")); -EXTERN const char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); -EXTERN const char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); -EXTERN const char e_fnametoolong[] INIT(= N_("E856: Filename too long")); -EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a String")); -EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); -EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); -EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); -EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); - -EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); - -EXTERN const char e_luv_api_disabled[] INIT(= N_("E5560: %s must not be called in a lua loop callback")); - -EXTERN const char e_floatonly[] INIT(= N_("E5601: Cannot close window, only floating window would remain")); -EXTERN const char e_floatexchange[] INIT(= N_("E5602: Cannot exchange or rotate float")); - -EXTERN const char e_cannot_define_autocommands_for_all_events[] INIT(= N_("E1155: Cannot define autocommands for ALL events")); - -EXTERN const char e_resulting_text_too_long[] INIT(= N_("E1240: Resulting text too long")); - -EXTERN const char e_line_number_out_of_range[] INIT(= N_("E1247: Line number out of range")); - -EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invalid character in group name")); - -EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); - -EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); -EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); - -EXTERN const char e_stray_closing_curly_str[] -INIT(= N_("E1278: Stray '}' without a matching '{': %s")); -EXTERN const char e_missing_close_curly_str[] -INIT(= N_("E1279: Missing '}': %s")); - -EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); - -EXTERN const char e_undobang_cannot_redo_or_move_branch[] -INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); - -EXTERN const char e_winfixbuf_cannot_go_to_buffer[] -INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); - -EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); - -EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); - -EXTERN const char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); -EXTERN const char bot_top_msg[] INIT(= N_("search hit BOTTOM, continuing at TOP")); - -EXTERN const char line_msg[] INIT(= N_(" line ")); - -EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report. +EXTERN FILE *time_fd INIT( = NULL); // Where to write --startuptime report. // Some compilers warn for not using a return value, but in some situations we // can't do anything useful with the value. Assign to this variable to avoid @@ -989,11 +801,9 @@ EXTERN FILE *time_fd INIT(= NULL); // Where to write --startuptime report. EXTERN int vim_ignored; // stdio is an RPC channel (--embed). -EXTERN bool embedded_mode INIT(= false); +EXTERN bool embedded_mode INIT( = false); // Do not start UI (--headless, -l) nor read/write to stdio (unless embedding). -EXTERN bool headless_mode INIT(= false); - -// uncrustify:on +EXTERN bool headless_mode INIT( = false); /// Only filled for Win32. EXTERN char windowsVersion[20] INIT( = { 0 }); diff --git a/src/nvim/help.c b/src/nvim/help.c index e9f67ca3e4..d28f195c00 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -13,6 +13,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index ccb093c116..b5e62e7f31 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -22,6 +22,7 @@ #include "nvim/cursor_shape.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/indent.c b/src/nvim/indent.c index d635c7d7bf..69c95e9038 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -13,6 +13,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 8b1c09b32f..7a652dff2a 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -22,6 +22,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/keycodes.c b/src/nvim/keycodes.c index 44ddfbba00..f7215d3d12 100644 --- a/src/nvim/keycodes.c +++ b/src/nvim/keycodes.c @@ -8,6 +8,7 @@ #include "nvim/ascii_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" #include "nvim/gettext_defs.h" diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c index 2b7b0c6471..36847d1fc9 100644 --- a/src/nvim/lua/api_wrappers.c +++ b/src/nvim/lua/api_wrappers.c @@ -5,6 +5,7 @@ #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" +#include "nvim/errors.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/func_attr.h" diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index a76b8213e5..6246452b92 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -22,6 +22,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/lua/secure.c b/src/nvim/lua/secure.c index f62e0ace04..a84d6c4d65 100644 --- a/src/nvim/lua/secure.c +++ b/src/nvim/lua/secure.c @@ -3,6 +3,7 @@ #include #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c index ba83239dc5..f4dacd7a55 100644 --- a/src/nvim/lua/spell.c +++ b/src/nvim/lua/spell.c @@ -7,6 +7,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/highlight_defs.h" diff --git a/src/nvim/main.c b/src/nvim/main.c index cf1324d37f..ecd3274af4 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -37,6 +37,7 @@ #include "nvim/diff.h" #include "nvim/drawline.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 9320390d68..167111f3ae 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -19,6 +19,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdexpand_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 6ce42bb7fe..16f444a316 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -14,6 +14,7 @@ #include "nvim/cursor.h" #include "nvim/diff.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/match.c b/src/nvim/match.c index 580d7d1069..6ae4e41147 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -10,6 +10,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index a345795bbe..23fdd5eb16 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -43,6 +43,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/getchar.h" diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index a1713edb66..498d212da3 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -46,6 +46,7 @@ #include "nvim/assert_defs.h" #include "nvim/buffer_defs.h" +#include "nvim/errors.h" #include "nvim/fileio.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 789535e270..2afbd262ab 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -19,6 +19,7 @@ #include "nvim/context.h" #include "nvim/decoration_provider.h" #include "nvim/drawline.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" diff --git a/src/nvim/menu.c b/src/nvim/menu.c index ab28eeca1c..a4d49d041e 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -13,6 +13,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/message.c b/src/nvim/message.c index 10b90bde29..9941dcb254 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -18,6 +18,7 @@ #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/move.c b/src/nvim/move.c index 418ece09ed..a2bb1b4685 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -20,6 +20,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" #include "nvim/fold.h" diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 8ba375f29d..879131c9e8 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -28,6 +28,7 @@ #include "nvim/digraph.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 5c1e291ac6..47d302df43 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -24,6 +24,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds2.h" diff --git a/src/nvim/option.c b/src/nvim/option.c index 799513e018..32fabd4141 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -44,6 +44,7 @@ #include "nvim/decoration_provider.h" #include "nvim/diff.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 29433ddbb5..be3bec2256 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -14,6 +14,7 @@ #include "nvim/diff.h" #include "nvim/digraph.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 19bdf30311..13e87a1ca5 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -17,6 +17,7 @@ #endif #include "auto/config.h" +#include "nvim/errors.h" #include "nvim/os/fs.h" #include "nvim/os/os_defs.h" diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 958faa4d22..d572e9b933 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -10,6 +10,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/event/defs.h" diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index 86f3611ec5..bf2fe0f72c 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -19,6 +19,7 @@ #include "nvim/charset.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/profile.c b/src/nvim/profile.c index b88b08d3f0..7ea7061b46 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -10,6 +10,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index e022184f2f..e1d35ab9d5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -20,6 +20,7 @@ #include "nvim/cursor.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/window.h" diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 5600d6a2f8..b743664b69 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -18,6 +18,7 @@ #include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index d913d311db..648e574b97 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -22,6 +22,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/debugger.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" diff --git a/src/nvim/search.c b/src/nvim/search.c index 746c253708..bee124e305 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -18,6 +18,7 @@ #include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 597c7551fd..d5655b1754 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -19,6 +19,7 @@ #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/cmdhist.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/decode.h" #include "nvim/eval/encode.h" diff --git a/src/nvim/sign.c b/src/nvim/sign.c index be7a46b720..be207f58b0 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -21,6 +21,7 @@ #include "nvim/decoration_defs.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/spell.c b/src/nvim/spell.c index d7a6adef58..f6c326075d 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -72,6 +72,7 @@ #include "nvim/decoration.h" #include "nvim/decoration_provider.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" #include "nvim/ex_docmd.h" diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 046a0a56e5..9746c3df91 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -240,6 +240,7 @@ #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/ex_cmds_defs.h" #include "nvim/fileio.h" #include "nvim/garray.h" diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index a7de20d14e..0e674c3178 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -14,6 +14,7 @@ #include "nvim/change.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 8fef4ba7fd..329b66cea1 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -12,6 +12,7 @@ #include "nvim/ascii_defs.h" #include "nvim/assert_defs.h" #include "nvim/charset.h" +#include "nvim/errors.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index b63d2a729d..c13619797a 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -15,6 +15,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/vars.h" diff --git a/src/nvim/tag.c b/src/nvim/tag.c index e7f483dd3d..ca3885b079 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -18,6 +18,7 @@ #include "nvim/cmdexpand_defs.h" #include "nvim/cursor.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" diff --git a/src/nvim/testing.c b/src/nvim/testing.c index 343568d71e..8041cc2e33 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -7,6 +7,7 @@ #include #include "nvim/ascii_defs.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/encode.h" #include "nvim/eval/typval.h" diff --git a/src/nvim/undo.c b/src/nvim/undo.c index ba720c9f6a..ed5c9a508c 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -92,6 +92,7 @@ #include "nvim/decoration.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval/funcs.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" diff --git a/src/nvim/window.c b/src/nvim/window.c index 1a6c3f7263..9203dd1bdb 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -22,6 +22,7 @@ #include "nvim/diff.h" #include "nvim/drawscreen.h" #include "nvim/edit.h" +#include "nvim/errors.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index e3ca0ff139..77bbaed105 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -11,6 +11,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/drawscreen.h" +#include "nvim/errors.h" #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" -- cgit From 7a8f42dc036f3bc6e8b106c580e0cd50dbed465e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 06:06:12 +0800 Subject: vim-patch:e299591: runtime(doc): clarify 'shortmess' flag "S" (#29131) fixes: vim/vim#14893 https://github.com/vim/vim/commit/e299591498a20c5c587364e4df57f947dfc02897 Co-authored-by: Christian Brabandt --- runtime/doc/options.txt | 10 +++++++--- runtime/lua/vim/_meta/options.lua | 10 +++++++--- src/nvim/options.lua | 10 +++++++--- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index edda46e197..a48ebd7199 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -5459,8 +5459,8 @@ A jump table for the options with a short description can be found at |Q_op|. message; also for quickfix message (e.g., ":cn") s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* "search hit TOP, continuing at BOTTOM" messages; when using - the search count do not show "W" after the count message (see - S below) + the search count do not show "W" before the count message + (see |shm-S| below) t truncate file message at the start if it is too long *shm-t* to fit on the command-line, "<" will appear in the left most column; ignored in Ex mode @@ -5482,7 +5482,11 @@ A jump table for the options with a short description can be found at |Q_op|. `:silent` was used for the command; note that this also affects messages from 'autoread' reloading S do not show search count message when searching, e.g. *shm-S* - "[1/5]" + "[1/5]". When the "S" flag is not present (e.g. search count + is shown), the "search hit BOTTOM, continuing at TOP" and + "search hit TOP, continuing at BOTTOM" messages are only + indicated by a "W" (Mnemonic: Wrapped) letter before the + search count statistics. This gives you the opportunity to avoid that a change between buffers requires you to hit , but still gives as useful a message as diff --git a/runtime/lua/vim/_meta/options.lua b/runtime/lua/vim/_meta/options.lua index 428b7c4d4f..2eae0d27a7 100644 --- a/runtime/lua/vim/_meta/options.lua +++ b/runtime/lua/vim/_meta/options.lua @@ -5781,8 +5781,8 @@ vim.bo.sw = vim.bo.shiftwidth --- message; also for quickfix message (e.g., ":cn") --- s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* --- "search hit TOP, continuing at BOTTOM" messages; when using ---- the search count do not show "W" after the count message (see ---- S below) +--- the search count do not show "W" before the count message +--- (see `shm-S` below) --- t truncate file message at the start if it is too long *shm-t* --- to fit on the command-line, "<" will appear in the left most --- column; ignored in Ex mode @@ -5804,7 +5804,11 @@ vim.bo.sw = vim.bo.shiftwidth --- `:silent` was used for the command; note that this also --- affects messages from 'autoread' reloading --- S do not show search count message when searching, e.g. *shm-S* ---- "[1/5]" +--- "[1/5]". When the "S" flag is not present (e.g. search count +--- is shown), the "search hit BOTTOM, continuing at TOP" and +--- "search hit TOP, continuing at BOTTOM" messages are only +--- indicated by a "W" (Mnemonic: Wrapped) letter before the +--- search count statistics. --- --- This gives you the opportunity to avoid that a change between buffers --- requires you to hit , but still gives as useful a message as diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 452cc6876b..0f3cf6c5b4 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7317,8 +7317,8 @@ return { message; also for quickfix message (e.g., ":cn") s don't give "search hit BOTTOM, continuing at TOP" or *shm-s* "search hit TOP, continuing at BOTTOM" messages; when using - the search count do not show "W" after the count message (see - S below) + the search count do not show "W" before the count message + (see |shm-S| below) t truncate file message at the start if it is too long *shm-t* to fit on the command-line, "<" will appear in the left most column; ignored in Ex mode @@ -7340,7 +7340,11 @@ return { `:silent` was used for the command; note that this also affects messages from 'autoread' reloading S do not show search count message when searching, e.g. *shm-S* - "[1/5]" + "[1/5]". When the "S" flag is not present (e.g. search count + is shown), the "search hit BOTTOM, continuing at TOP" and + "search hit TOP, continuing at BOTTOM" messages are only + indicated by a "W" (Mnemonic: Wrapped) letter before the + search count statistics. This gives you the opportunity to avoid that a change between buffers requires you to hit , but still gives as useful a message as -- cgit From c81ad884c754abf91b0c07f4d65f43545a6cf381 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 05:48:50 +0800 Subject: vim-patch:8.2.4436: crash with weird 'vartabstop' value Problem: Crash with weird 'vartabstop' value. Solution: Check for running into the end of the line. https://github.com/vim/vim/commit/4e889f98e95ac05d7c8bd3ee933ab4d47820fdfa Code change is N/A as it's superseded by virtual text changes. Co-authored-by: Bram Moolenaar --- test/old/testdir/test_vartabs.vim | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/old/testdir/test_vartabs.vim b/test/old/testdir/test_vartabs.vim index e12c71d521..04ef211686 100644 --- a/test/old/testdir/test_vartabs.vim +++ b/test/old/testdir/test_vartabs.vim @@ -445,4 +445,16 @@ func Test_shiftwidth_vartabstop() setlocal shiftwidth& vartabstop& tabstop& endfunc +func Test_vartabstop_latin1() + let save_encoding = &encoding + new + set encoding=iso8859 + silent norm :se  + set vartabstop=400 + norm i00  + bwipe! + let &encoding = save_encoding +endfunc + + " vim: shiftwidth=2 sts=2 expandtab -- cgit From 7cbfbd3ae1fea80fd349d703041df480e55aed23 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 05:52:34 +0800 Subject: vim-patch:8.2.4437: vartabs test fails on MS-Windows Problem: Vartabs test fails on MS-Windows. Solution: Use iso8859-1 'encoding'. (Ken Takata, closes vim/vim#9818) https://github.com/vim/vim/commit/0f113e4f7b698fc94c1a8377afdb7249329beaee Co-authored-by: K.Takata --- test/old/testdir/test_vartabs.vim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/old/testdir/test_vartabs.vim b/test/old/testdir/test_vartabs.vim index 04ef211686..5eea75299f 100644 --- a/test/old/testdir/test_vartabs.vim +++ b/test/old/testdir/test_vartabs.vim @@ -448,10 +448,10 @@ endfunc func Test_vartabstop_latin1() let save_encoding = &encoding new - set encoding=iso8859 - silent norm :se  + set encoding=iso8859-1 + silent exe "norm :se \\" set vartabstop=400 - norm i00  + exe "norm i00\t\" bwipe! let &encoding = save_encoding endfunc -- cgit From 6f87779857f1b7a86da9e53c117b5b678a2a3236 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 05:53:31 +0800 Subject: vim-patch:8.2.4452: test for what 8.2.4436 fixes does not check for regression Problem: Test for what 8.2.4436 fixes does not check for regression. Solution: Set several options. (Ken Takata, closes vim/vim#9830) https://github.com/vim/vim/commit/2dada73a4ebffe2582af472ce362abd3116b58c9 Co-authored-by: Bram Moolenaar --- test/old/testdir/test_vartabs.vim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/old/testdir/test_vartabs.vim b/test/old/testdir/test_vartabs.vim index 5eea75299f..274531fdc1 100644 --- a/test/old/testdir/test_vartabs.vim +++ b/test/old/testdir/test_vartabs.vim @@ -446,14 +446,16 @@ func Test_shiftwidth_vartabstop() endfunc func Test_vartabstop_latin1() + throw "Skipped: Nvim does not support 'compatible'" let save_encoding = &encoding new set encoding=iso8859-1 - silent exe "norm :se \\" + set compatible linebreak list revins smarttab set vartabstop=400 exe "norm i00\t\" bwipe! let &encoding = save_encoding + set nocompatible linebreak& list& revins& smarttab& vartabstop& endfunc -- cgit From 0e49c3ad1a599376d0a5c229f304a06d48c56163 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 05:47:47 +0800 Subject: vim-patch:9.1.0456: Left shift is incorrect with vartabstop and shiftwidth=0 Problem: Left shift is incorrect with vartabstop and shiftwidth=0 Solution: make tabstop_at() function aware of shift direction (Gary Johnson) The problem was that with 'vartabstop' set and 'shiftwidth' equal 0, left shifts using << were shifting the line to the wrong column. The tabstop to the right of the first character in the line was being used as the shift amount instead of the tabstop to the left of that first character. The reason was that the tabstop_at() function always returned the value of the tabstop to the right of the given column and was not accounting for the direction of the shift. The solution was to make tabstop_at() aware of the direction of the shift and to choose the tabtop accordingly. A test was added to check this behavior and make sure it doesn't regress. While at it, also fix a few indentation/alignment issues. fixes: vim/vim#14864 closes: vim/vim#14887 https://github.com/vim/vim/commit/88d4f255b7b7a19bb4f6489e0ad0956e47d51fed Co-authored-by: Gary Johnson --- src/nvim/edit.c | 3 +- src/nvim/eval/funcs.c | 2 +- src/nvim/indent.c | 47 +++++++++++++++++++++---------- src/nvim/ops.c | 4 +-- test/old/testdir/test_vartabs.vim | 59 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 146e95df87..595b4da589 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -474,7 +474,8 @@ static int insert_check(VimState *state) if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(), curbuf->b_p_ts, - curbuf->b_p_vts_array) + curbuf->b_p_vts_array, + false) && curwin->w_wrow == curwin->w_height_inner - 1 - get_scrolloff_value(curwin) && (curwin->w_cursor.lnum != curwin->w_topline || curwin->w_topfill > 0)) { diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 0165e4af60..e704135366 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -8302,7 +8302,7 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (col < 0) { return; // type error; errmsg already given } - rettv->vval.v_number = get_sw_value_col(curbuf, col); + rettv->vval.v_number = get_sw_value_col(curbuf, col, false); return; } rettv->vval.v_number = get_sw_value(curbuf); diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 69c95e9038..66cb443e4d 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -147,25 +147,42 @@ int tabstop_padding(colnr_T col, OptInt ts_arg, const colnr_T *vts) } /// Find the size of the tab that covers a particular column. -int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts) +/// +/// If this is being called as part of a shift operation, col is not the cursor +/// column but is the column number to the left of the first non-whitespace +/// character in the line. If the shift is to the left (left == true), then +/// return the size of the tab interval to the left of the column. +int tabstop_at(colnr_T col, OptInt ts, const colnr_T *vts, bool left) { - colnr_T tabcol = 0; - int t; - int tab_size = 0; - if (vts == NULL || vts[0] == 0) { return (int)ts; } - const int tabcount = vts[0]; + colnr_T tabcol = 0; // Column of the tab stop under consideration. + int t; // Tabstop index in the list of variable tab stops. + int tab_size = 0; // Size of the tab stop interval to the right or left of the col. + const int tabcount // Number of tab stops in the list of variable tab stops. + = vts[0]; for (t = 1; t <= tabcount; t++) { tabcol += vts[t]; if (tabcol > col) { - tab_size = vts[t]; + // If shifting left (left == true), and if the column to the left of + // the first first non-blank character (col) in the line is + // already to the left of the first tabstop, set the shift amount + // (tab_size) to just enough to shift the line to the left margin. + // The value doesn't seem to matter as long as it is at least that + // distance. + if (left && (t == 1)) { + tab_size = col; + } else { + tab_size = vts[t - (left ? 1 : 0)]; + } break; } } - if (t > tabcount) { + if (t > tabcount) { // If the value of the index t is beyond the + // end of the list, use the tab stop value at + // the end of the list. tab_size = vts[tabcount]; } @@ -312,35 +329,35 @@ int tabstop_first(colnr_T *ts) /// 'tabstop' value when 'shiftwidth' is zero. int get_sw_value(buf_T *buf) { - int result = get_sw_value_col(buf, 0); + int result = get_sw_value_col(buf, 0, false); return result; } /// Idem, using "pos". -int get_sw_value_pos(buf_T *buf, pos_T *pos) +int get_sw_value_pos(buf_T *buf, pos_T *pos, bool left) { pos_T save_cursor = curwin->w_cursor; curwin->w_cursor = *pos; - int sw_value = get_sw_value_col(buf, get_nolist_virtcol()); + int sw_value = get_sw_value_col(buf, get_nolist_virtcol(), left); curwin->w_cursor = save_cursor; return sw_value; } /// Idem, using the first non-black in the current line. -int get_sw_value_indent(buf_T *buf) +int get_sw_value_indent(buf_T *buf, bool left) { pos_T pos = curwin->w_cursor; pos.col = (colnr_T)getwhitecols_curline(); - return get_sw_value_pos(buf, &pos); + return get_sw_value_pos(buf, &pos, left); } /// Idem, using virtual column "col". -int get_sw_value_col(buf_T *buf, colnr_T col) +int get_sw_value_col(buf_T *buf, colnr_T col, bool left) { return buf->b_p_sw ? (int)buf->b_p_sw - : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array); + : tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array, left); } /// Return the effective softtabstop value for the current buffer, diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 47d302df43..8ae1d70882 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -282,7 +282,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) /// @param call_changed_bytes call changed_bytes() void shift_line(bool left, bool round, int amount, int call_changed_bytes) { - const int sw_val = get_sw_value_indent(curbuf); + const int sw_val = get_sw_value_indent(curbuf, left); int count = get_indent(); // get current indent @@ -328,7 +328,7 @@ static void shift_block(oparg_T *oap, int amount) const int oldstate = State; char *newp; const int oldcol = curwin->w_cursor.col; - const int sw_val = get_sw_value_indent(curbuf); + const int sw_val = get_sw_value_indent(curbuf, left); const int ts_val = (int)curbuf->b_p_ts; struct block_def bd; int incr; diff --git a/test/old/testdir/test_vartabs.vim b/test/old/testdir/test_vartabs.vim index 274531fdc1..82c3a513f9 100644 --- a/test/old/testdir/test_vartabs.vim +++ b/test/old/testdir/test_vartabs.vim @@ -458,5 +458,64 @@ func Test_vartabstop_latin1() set nocompatible linebreak& list& revins& smarttab& vartabstop& endfunc +" Verify that right-shifting and left-shifting adjust lines to the proper +" tabstops. +func Test_vartabstop_shift_right_left() + new + set expandtab + set shiftwidth=0 + set vartabstop=17,11,7 + exe "norm! aword" + let expect = "word" + call assert_equal(expect, getline(1)) + + " Shift to first tabstop. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift to second tabstop. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift to third tabstop. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift to fourth tabstop, repeating the third shift width. + norm! >> + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the third tabstop. + norm! << + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the second tabstop. + norm! << + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the first tabstop. + norm! << + let expect = " word" + call assert_equal(expect, getline(1)) + + " Shift back to the left margin. + norm! << + let expect = "word" + call assert_equal(expect, getline(1)) + + " Shift again back to the left margin. + norm! << + let expect = "word" + call assert_equal(expect, getline(1)) + + bwipeout! +endfunc + " vim: shiftwidth=2 sts=2 expandtab -- cgit From 4374ec83cd49d148fc788bdb43f49d4b0365cf9f Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 14:58:12 +0800 Subject: vim-patch:8.2.0083: text properties wrong when tabs and spaces are exchanged Problem: Text properties wrong when tabs and spaces are exchanged. Solution: Take text properties into account. (Nobuhiro Takasaki, closes vim/vim#5427) https://github.com/vim/vim/commit/5cb0b93d52fa5c12ca50a18509947ee6459bb7a8 Co-authored-by: Bram Moolenaar --- src/nvim/edit.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 595b4da589..436d43a4db 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4421,18 +4421,21 @@ static bool ins_tab(void) // Delete following spaces. int i = cursor->col - fpos.col; if (i > 0) { - STRMOVE(ptr, ptr + i); + if (!(State & VREPLACE_FLAG)) { + memmove(ptr, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - i + - (ptr - curbuf->b_ml.ml_line_ptr))); + curbuf->b_ml.ml_line_len -= i; + inserted_bytes(fpos.lnum, change_col, + cursor->col - change_col, fpos.col - change_col); + } else { + STRMOVE(ptr, ptr + i); + } // correct replace stack. if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { for (temp = i; --temp >= 0;) { replace_join(repl_off); } } - if (!(State & VREPLACE_FLAG)) { - curbuf->b_ml.ml_line_len -= i; - inserted_bytes(fpos.lnum, change_col, - cursor->col - change_col, fpos.col - change_col); - } } cursor->col -= i; -- cgit From 97d9d71bf3ccc156b94acf988f6b2f60fb706fc9 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 15:00:16 +0800 Subject: vim-patch:8.2.0109: corrupted text properties when expanding spaces Problem: Corrupted text properties when expanding spaces. Solution: Reallocate the line. (Nobuhiro Takasaki, closes vim/vim#5457) https://github.com/vim/vim/commit/ac15fd8c6761763c8feedef1a2fbd8309f0a823c Co-authored-by: Bram Moolenaar --- src/nvim/edit.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 436d43a4db..f6e2dbfa4e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -4422,9 +4422,18 @@ static bool ins_tab(void) int i = cursor->col - fpos.col; if (i > 0) { if (!(State & VREPLACE_FLAG)) { - memmove(ptr, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - i - - (ptr - curbuf->b_ml.ml_line_ptr))); + char *newp = xmalloc((size_t)(curbuf->b_ml.ml_line_len - i)); + ptrdiff_t col = ptr - curbuf->b_ml.ml_line_ptr; + if (col > 0) { + memmove(newp, ptr - col, (size_t)col); + } + memmove(newp + col, ptr + i, (size_t)(curbuf->b_ml.ml_line_len - col - i)); + if (curbuf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) { + xfree(curbuf->b_ml.ml_line_ptr); + } + curbuf->b_ml.ml_line_ptr = newp; curbuf->b_ml.ml_line_len -= i; + curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; inserted_bytes(fpos.lnum, change_col, cursor->col - change_col, fpos.col - change_col); } else { -- cgit From 56337310efc765a760b7a1ca0040c7c6ce23574e Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 2 Jun 2024 15:18:30 +0800 Subject: test: add a test for #29119 --- test/functional/lua/buffer_updates_spec.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua index d4af7e4732..6b575ad0ef 100644 --- a/test/functional/lua/buffer_updates_spec.lua +++ b/test/functional/lua/buffer_updates_spec.lua @@ -379,6 +379,25 @@ describe('lua buffer event callbacks: on_lines', function() ]], }) end) + + it('line lengths are correct when pressing TAB with folding #29119', function() + api.nvim_buf_set_lines(0, 0, -1, true, { 'a', 'b' }) + + exec_lua([[ + _G.res = {} + vim.o.foldmethod = 'indent' + vim.o.softtabstop = -1 + vim.api.nvim_buf_attach(0, false, { + on_lines = function(_, bufnr, _, row, _, end_row) + local lines = vim.api.nvim_buf_get_lines(bufnr, row, end_row, true) + table.insert(_G.res, lines) + end + }) + ]]) + + feed('i') + eq({ '\ta' }, exec_lua('return _G.res[#_G.res]')) + end) end) describe('lua: nvim_buf_attach on_bytes', function() -- cgit From 19be3d26830ced203631045f2f622e75e6d857a7 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 2 Jun 2024 09:54:15 +0200 Subject: fix(lsp): trim trailing whitespace from completion words (#29122) the `complete()` mechanism doesn't play nicely with trailing newlines or tabs. A newline causes it to insert a null character, showing up as `^@`. --- runtime/lua/vim/lsp/completion.lua | 3 ++- test/functional/plugin/lsp/completion_spec.lua | 35 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index b77bf3e3c2..f8e17ae2f0 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -153,7 +153,8 @@ local function get_completion_word(item) return item.label end elseif item.textEdit then - return item.textEdit.newText + local word = item.textEdit.newText + return word:match('^(%S*)') or word elseif item.insertText and item.insertText ~= '' then return item.insertText end diff --git a/test/functional/plugin/lsp/completion_spec.lua b/test/functional/plugin/lsp/completion_spec.lua index d7755dd0c4..d8a3e0acbd 100644 --- a/test/functional/plugin/lsp/completion_spec.lua +++ b/test/functional/plugin/lsp/completion_spec.lua @@ -126,6 +126,41 @@ describe('vim.lsp.completion: item conversion', function() eq(expected, result) end) + it('trims trailing newline or tab from textEdit', function() + local range0 = { + start = { line = 0, character = 0 }, + ['end'] = { line = 0, character = 0 }, + } + local items = { + { + detail = 'ansible.builtin', + filterText = 'lineinfile ansible.builtin.lineinfile builtin ansible', + kind = 7, + label = 'ansible.builtin.lineinfile', + sortText = '2_ansible.builtin.lineinfile', + textEdit = { + newText = 'ansible.builtin.lineinfile:\n ', + range = range0, + }, + }, + } + local result = complete('|', items) + result = vim.tbl_map(function(x) + return { + abbr = x.abbr, + word = x.word, + } + end, result.items) + + local expected = { + { + abbr = 'ansible.builtin.lineinfile', + word = 'ansible.builtin.lineinfile:', + }, + } + eq(expected, result) + end) + it('prefers wordlike components for snippets', function() -- There are two goals here: -- -- cgit From 659d3dcd2edf1b178a20015cab399390ffda1a32 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 2 Jun 2024 17:31:37 +0200 Subject: vim-patch:9.1.0460: filetype: lintstagedrc files are not recognized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: filetype: lintstagedrc files are not recognized Solution: recognize '.lintstagedrc' files as json filetype (İlyas Akın) see: https://github.com/lint-staged/lint-staged closes: vim/vim#14897 https://github.com/vim/vim/commit/7577afd5efd0f7ebf0dbbca09713185024263ed7 Co-authored-by: İlyas Akın --- runtime/lua/vim/filetype.lua | 1 + test/old/testdir/test_filetype.vim | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 500632a2b2..c8f9bcfd84 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1451,6 +1451,7 @@ local filename = { ['.firebaserc'] = 'json', ['.prettierrc'] = 'json', ['.stylelintrc'] = 'json', + ['.lintstagedrc'] = 'json', ['flake.lock'] = 'json', ['.babelrc'] = 'jsonc', ['.eslintrc'] = 'jsonc', diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim index 88cd8fc416..fa62765398 100644 --- a/test/old/testdir/test_filetype.vim +++ b/test/old/testdir/test_filetype.vim @@ -365,7 +365,7 @@ func s:GetFilenameChecks() abort \ 'jq': ['file.jq'], \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'], - \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock'], + \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock'], \ 'json5': ['file.json5'], \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.jscsrc', '.vsconfig', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json', '.luaurc'], \ 'jsonl': ['file.jsonl'], -- cgit From 0c9f7f5f96d6fedd2c5d9ec235c8b341f47c06f8 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 3 Jun 2024 05:35:02 +0800 Subject: vim-patch:9.1.0458: Coverity complains about division by zero (#29149) Problem: Coverity complains about division by zero Solution: Check explicitly for sw_val being zero Shouldn't happen, since tabstop value should always be larger than zero. So just add this as a safety measure. https://github.com/vim/vim/commit/7737ce519b9cba8ef135154d76b69f715b1a0b4d Co-authored-by: Christian Brabandt --- src/nvim/ops.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8ae1d70882..74c6e83495 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -282,8 +282,10 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) /// @param call_changed_bytes call changed_bytes() void shift_line(bool left, bool round, int amount, int call_changed_bytes) { - const int sw_val = get_sw_value_indent(curbuf, left); - + int sw_val = get_sw_value_indent(curbuf, left); + if (sw_val == 0) { + sw_val = 1; // shouldn't happen, just in case + } int count = get_indent(); // get current indent if (round) { // round off indent -- cgit From 3a1515bfee59710b4da9bfdf0fc4ecb5b13a00db Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 3 Jun 2024 05:38:06 +0800 Subject: vim-patch:partial:9.1.0461: too many strlen() calls in drawline.c (#29150) Problem: too many strlen() calls in drawline.c Solution: Refactor code to avoid strlen() (John Marriott) closes: vim/vim#14890 https://github.com/vim/vim/commit/f51ff96532ab8f97f779b44d17dccdda9d8ce566 Co-authored-by: John Marriott --- src/nvim/drawline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 3bd00ee3f9..4247705896 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -1422,7 +1422,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s line = ml_get_buf(wp->w_buffer, lnum); ptr = line + linecol; - if (len == 0 || (int)wp->w_cursor.col > ptr - line) { + if (len == 0 || wp->w_cursor.col > linecol) { // no bad word found at line start, don't check until end of a // word spell_hlf = HLF_COUNT; -- cgit From 054a287dbe6fe4308d26ec593da2057641f2bb9b Mon Sep 17 00:00:00 2001 From: Soham Shanbhag Date: Mon, 3 Jun 2024 16:48:43 +0900 Subject: feat(ftplugin): change 'commentstring' to `// %s` for C/C++ (#29085) Problem: The default commentstring for C/C++ can lead to invalid code when commenting and does not match the Nvim codebase. Solution: Change commentstring to `// %s` as used by Neovim. Also set all commentstrings that derive from the default C string explicitly (and correctly). --- runtime/ftplugin/arduino.lua | 1 + runtime/ftplugin/c.lua | 2 +- runtime/ftplugin/calender.lua | 2 +- runtime/ftplugin/ch.lua | 1 + runtime/ftplugin/cs.lua | 2 +- runtime/ftplugin/css.lua | 2 +- runtime/ftplugin/d.lua | 2 +- runtime/ftplugin/indent.lua | 2 +- runtime/ftplugin/objc.lua | 1 + runtime/ftplugin/xdefaults.lua | 2 +- runtime/ftplugin/xs.lua | 1 + test/functional/lua/runtime_spec.lua | 2 +- 12 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 runtime/ftplugin/arduino.lua create mode 100644 runtime/ftplugin/ch.lua create mode 100644 runtime/ftplugin/objc.lua create mode 100644 runtime/ftplugin/xs.lua diff --git a/runtime/ftplugin/arduino.lua b/runtime/ftplugin/arduino.lua new file mode 100644 index 0000000000..f398d66a63 --- /dev/null +++ b/runtime/ftplugin/arduino.lua @@ -0,0 +1 @@ +vim.bo.commentstring = '// %s' diff --git a/runtime/ftplugin/c.lua b/runtime/ftplugin/c.lua index 0ddbf09470..2695b642aa 100644 --- a/runtime/ftplugin/c.lua +++ b/runtime/ftplugin/c.lua @@ -1,5 +1,5 @@ -- These are the default option values in Vim, but not in Nvim, so must be set explicitly. -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' vim.bo.define = '^\\s*#\\s*define' vim.bo.include = '^\\s*#\\s*include' diff --git a/runtime/ftplugin/calender.lua b/runtime/ftplugin/calender.lua index b4e68148f5..984111a08b 100644 --- a/runtime/ftplugin/calender.lua +++ b/runtime/ftplugin/calender.lua @@ -1 +1 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '/* %s */' diff --git a/runtime/ftplugin/ch.lua b/runtime/ftplugin/ch.lua new file mode 100644 index 0000000000..f398d66a63 --- /dev/null +++ b/runtime/ftplugin/ch.lua @@ -0,0 +1 @@ +vim.bo.commentstring = '// %s' diff --git a/runtime/ftplugin/cs.lua b/runtime/ftplugin/cs.lua index b4e68148f5..f398d66a63 100644 --- a/runtime/ftplugin/cs.lua +++ b/runtime/ftplugin/cs.lua @@ -1 +1 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' diff --git a/runtime/ftplugin/css.lua b/runtime/ftplugin/css.lua index b4e68148f5..984111a08b 100644 --- a/runtime/ftplugin/css.lua +++ b/runtime/ftplugin/css.lua @@ -1 +1 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '/* %s */' diff --git a/runtime/ftplugin/d.lua b/runtime/ftplugin/d.lua index b4e68148f5..f398d66a63 100644 --- a/runtime/ftplugin/d.lua +++ b/runtime/ftplugin/d.lua @@ -1 +1 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' diff --git a/runtime/ftplugin/indent.lua b/runtime/ftplugin/indent.lua index b4e68148f5..f398d66a63 100644 --- a/runtime/ftplugin/indent.lua +++ b/runtime/ftplugin/indent.lua @@ -1 +1 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '// %s' diff --git a/runtime/ftplugin/objc.lua b/runtime/ftplugin/objc.lua new file mode 100644 index 0000000000..f398d66a63 --- /dev/null +++ b/runtime/ftplugin/objc.lua @@ -0,0 +1 @@ +vim.bo.commentstring = '// %s' diff --git a/runtime/ftplugin/xdefaults.lua b/runtime/ftplugin/xdefaults.lua index b4e68148f5..e54bf808b0 100644 --- a/runtime/ftplugin/xdefaults.lua +++ b/runtime/ftplugin/xdefaults.lua @@ -1 +1 @@ -vim.bo.commentstring = '/*%s*/' +vim.bo.commentstring = '! %s' diff --git a/runtime/ftplugin/xs.lua b/runtime/ftplugin/xs.lua new file mode 100644 index 0000000000..f398d66a63 --- /dev/null +++ b/runtime/ftplugin/xs.lua @@ -0,0 +1 @@ +vim.bo.commentstring = '// %s' diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua index c6b0577ebe..f63363d6d9 100644 --- a/test/functional/lua/runtime_spec.lua +++ b/test/functional/lua/runtime_spec.lua @@ -406,7 +406,7 @@ describe('runtime:', function() eq('', eval('&commentstring')) eq('', eval('&omnifunc')) exec('edit file.cpp') - eq('/*%s*/', eval('&commentstring')) + eq('// %s', eval('&commentstring')) eq('ccomplete#Complete', eval('&omnifunc')) end) end) -- cgit From a9c89bcbf69a3d0ef47f324a47ff6eb482467e70 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 3 Jun 2024 11:55:20 +0200 Subject: fix(gx): allow `@` in url This will make `gx` work for links for the form https://hachyderm.io/@neovim. --- runtime/lua/vim/ui.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 99b9b78e2a..f168da4955 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -179,7 +179,13 @@ function M._get_url() current_node = current_node:parent() end end - return vim.fn.expand('') + + local old_isfname = vim.o.isfname + vim.cmd [[set isfname+=@-@]] + local url = vim.fn.expand('') + vim.o.isfname = old_isfname + + return url end return M -- cgit From 5aa9906676f3ad040b0ccb75eb5fd560def1e0ec Mon Sep 17 00:00:00 2001 From: ippachi Date: Tue, 4 Jun 2024 01:07:09 +0900 Subject: fix(lsp): use client.id instead of pairs index (#29143) Problem: Completion side effects not working randomly. Solution: When creating the table of LSP responses, the table index was used, but this is not the same as the actual client_id, so it was changed to use the client_id directly. --- runtime/lua/vim/lsp/completion.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/lua/vim/lsp/completion.lua b/runtime/lua/vim/lsp/completion.lua index f8e17ae2f0..c9326a0681 100644 --- a/runtime/lua/vim/lsp/completion.lua +++ b/runtime/lua/vim/lsp/completion.lua @@ -349,7 +349,7 @@ function M._convert_results( return matches, server_start_boundary end ---- @param clients table +--- @param clients table # keys != client_id --- @param bufnr integer --- @param win integer --- @param callback fun(responses: table) @@ -359,7 +359,8 @@ local function request(clients, bufnr, win, callback) local request_ids = {} --- @type table local remaining_requests = vim.tbl_count(clients) - for client_id, client in pairs(clients) do + for _, client in pairs(clients) do + local client_id = client.id local params = lsp.util.make_position_params(win, client.offset_encoding) local ok, request_id = client.request(ms.textDocument_completion, params, function(err, result) responses[client_id] = { err = err, result = result } -- cgit From e20c5fba2c77b7e7ea93363abc987d913e5f9f58 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 4 Jun 2024 06:07:20 +0800 Subject: vim-patch:partial:8.2.3637: typos in test files (#29172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Typos in test files. Solution: Correct the typos. (Dominique Pellé, closes vim/vim#9175) https://github.com/vim/vim/commit/923dce2b07ff185c0ef661f3eca47bc17655f01b Co-authored-by: Dominique Pelle --- test/old/testdir/runtest.vim | 2 +- test/old/testdir/test_debugger.vim | 10 +++++----- test/old/testdir/test_diffmode.vim | 4 ++-- test/old/testdir/test_excmd.vim | 2 +- test/old/testdir/test_flatten.vim | 2 +- test/old/testdir/test_normal.vim | 6 +++--- test/old/testdir/test_options.vim | 2 +- test/old/testdir/test_quickfix.vim | 8 +++----- test/old/testdir/test_spellfile.vim | 2 +- test/old/testdir/test_syntax.vim | 3 +-- test/old/testdir/test_textobjects.vim | 2 +- test/old/testdir/test_trycatch.vim | 2 +- 12 files changed, 21 insertions(+), 24 deletions(-) diff --git a/test/old/testdir/runtest.vim b/test/old/testdir/runtest.vim index 2d8ba60a7e..a1d4011d7e 100644 --- a/test/old/testdir/runtest.vim +++ b/test/old/testdir/runtest.vim @@ -131,7 +131,7 @@ if has('win32') endif if has('mac') - " In MacOS, when starting a shell in a terminal, a bash deprecation warning + " In macOS, when starting a shell in a terminal, a bash deprecation warning " message is displayed. This breaks the terminal test. Disable the warning " message. let $BASH_SILENCE_DEPRECATION_WARNING = 1 diff --git a/test/old/testdir/test_debugger.vim b/test/old/testdir/test_debugger.vim index ad03443cb4..3a469e8a17 100644 --- a/test/old/testdir/test_debugger.vim +++ b/test/old/testdir/test_debugger.vim @@ -524,7 +524,7 @@ func Test_Backtrace_Through_Source() call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) - " step until we have another meaninfgul trace + " step until we have another meaningful trace call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) call RunDbgCmd(buf, 'backtrace', [ @@ -611,7 +611,7 @@ func Test_Backtrace_Autocmd() \ ['cmd: doautocmd User TestGlobalFunction']) call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"']) - " At this point the ontly thing in the stack is the autocommand + " At this point the only thing in the stack is the autocommand call RunDbgCmd(buf, 'backtrace', [ \ '>backtrace', \ '->0 User Autocommands for "TestGlobalFunction"', @@ -741,7 +741,7 @@ func Test_Backtrace_Autocmd() call RunDbgCmd( buf, 'down', [ 'frame is zero' ] ) - " step until we have another meaninfgul trace + " step until we have another meaningful trace call RunDbgCmd(buf, 'step', ['line 5: func File2Function()']) call RunDbgCmd(buf, 'step', ['line 9: call File2Function()']) call RunDbgCmd(buf, 'backtrace', [ @@ -867,7 +867,7 @@ func Test_Backtrace_CmdLine() call CheckDbgOutput(buf, ['command line', \ 'cmd: call GlobalFunction()'], #{msec: 5000}) - " At this point the ontly thing in the stack is the cmdline + " At this point the only thing in the stack is the cmdline call RunDbgCmd(buf, 'backtrace', [ \ '>backtrace', \ '->0 command line', @@ -1285,7 +1285,7 @@ func Test_debug_backtrace_level() \ #{ match: 'pattern' } ) " Expression evaluation in the script frame (not the function frame) - " FIXME: Unexpected in this scope (a: should not be visibnle) + " FIXME: Unexpected in this scope (a: should not be visible) call RunDbgCmd(buf, 'echo a:arg', [ 'arg1' ] ) call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] ) call RunDbgCmd(buf, 'echo g:global_var', [ 'global' ] ) diff --git a/test/old/testdir/test_diffmode.vim b/test/old/testdir/test_diffmode.vim index 71483b7469..85ee5df961 100644 --- a/test/old/testdir/test_diffmode.vim +++ b/test/old/testdir/test_diffmode.vim @@ -276,7 +276,7 @@ func Test_diffget_diffput_empty_buffer() endfunc " :diffput and :diffget completes names of buffers which -" are in diff mode and which are different then current buffer. +" are in diff mode and which are different than current buffer. " No completion when the current window is not in diff mode. func Test_diffget_diffput_completion() e Xdiff1 | diffthis @@ -679,7 +679,7 @@ func Test_diffexpr() call assert_notequal(normattr, screenattr(3, 1)) diffoff! - " Try using an non-existing function for 'diffexpr'. + " Try using a non-existing function for 'diffexpr'. set diffexpr=NewDiffFunc() call assert_fails('windo diffthis', ['E117:', 'E97:']) diffoff! diff --git a/test/old/testdir/test_excmd.vim b/test/old/testdir/test_excmd.vim index 4a780078fd..a9d7c27fe5 100644 --- a/test/old/testdir/test_excmd.vim +++ b/test/old/testdir/test_excmd.vim @@ -665,7 +665,7 @@ func Sandbox_tests() if has('clientserver') call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:') if !has('win32') - " remote_foreground() doesn't thrown an error message on MS-Windows + " remote_foreground() doesn't throw an error message on MS-Windows call assert_fails('call remote_foreground("gvim")', 'E48:') endif call assert_fails('let s=remote_peek("gvim")', 'E48:') diff --git a/test/old/testdir/test_flatten.vim b/test/old/testdir/test_flatten.vim index aa91060313..035ca18f73 100644 --- a/test/old/testdir/test_flatten.vim +++ b/test/old/testdir/test_flatten.vim @@ -53,7 +53,7 @@ func Test_flatten() call test_garbagecollect_now() call assert_equal([1, 2, 3], l:list) - " Tests for checking circular reference list can be flatten. + " Tests for checking circular reference list can be flattened. let l:x = [1] let l:y = [x] let l:z = flatten(l:y) diff --git a/test/old/testdir/test_normal.vim b/test/old/testdir/test_normal.vim index a2ef07193d..47d3e67c5e 100644 --- a/test/old/testdir/test_normal.vim +++ b/test/old/testdir/test_normal.vim @@ -1522,7 +1522,7 @@ func Test_normal18_z_fold() norm! j call assert_equal('52', getline('.')) - " zA on a opened fold when foldenable is not set + " zA on an opened fold when foldenable is not set 50 set nofoldenable norm! zA @@ -1878,7 +1878,7 @@ func Test_normal23_K() let not_gnu_man = has('mac') || has('bsd') if not_gnu_man - " In MacOS and BSD, the option for specifying a pager is different + " In macOS and BSD, the option for specifying a pager is different set keywordprg=man\ -P\ cat else set keywordprg=man\ --pager=cat @@ -2727,7 +2727,7 @@ func Test_normal33_g_cmd2() call assert_equal('foo first line', getline(1)) set virtualedit& - " Test for aboring a g command using CTRL-\ CTRL-G + " Test for aborting a g command using CTRL-\ CTRL-G exe "normal! g\\" call assert_equal('foo first line', getline('.')) diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim index 8ffd8f7ef8..f7eace59c2 100644 --- a/test/old/testdir/test_options.vim +++ b/test/old/testdir/test_options.vim @@ -1732,7 +1732,7 @@ func Test_cmdheight() set cmdheight& endfunc -" To specify a control character as a option value, '^' can be used +" To specify a control character as an option value, '^' can be used func Test_opt_control_char() set wildchar=^v call assert_equal("\", nr2char(&wildchar)) diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim index a708cabc26..791186efe8 100644 --- a/test/old/testdir/test_quickfix.vim +++ b/test/old/testdir/test_quickfix.vim @@ -4353,11 +4353,9 @@ endfunc " Test for shortening/simplifying the file name when opening the " quickfix window or when displaying the quickfix list func Test_shorten_fname() - if !has('unix') - return - endif + CheckUnix %bwipe - " Create a quickfix list with a absolute path filename + " Create a quickfix list with an absolute path filename let fname = getcwd() . '/test_quickfix.vim' call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'}) call assert_equal(fname, bufname('test_quickfix.vim')) @@ -4366,7 +4364,7 @@ func Test_shorten_fname() call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim')) cclose %bwipe - " Create a quickfix list with a absolute path filename + " Create a quickfix list with an absolute path filename call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'}) call assert_equal(fname, bufname('test_quickfix.vim')) " Displaying the quickfix list should simplify the file path diff --git a/test/old/testdir/test_spellfile.vim b/test/old/testdir/test_spellfile.vim index 4d2a6cf35f..509fed11df 100644 --- a/test/old/testdir/test_spellfile.vim +++ b/test/old/testdir/test_spellfile.vim @@ -656,7 +656,7 @@ func Test_aff_file_format_error() let output = execute('mkspell! Xtest.spl Xtest') call assert_match('Different combining flag in continued affix block in Xtest.aff line 3', output) - " Try to reuse a affix used for BAD flag + " Try to reuse an affix used for BAD flag call writefile(['BAD x', 'PFX x Y 1', 'PFX x 0 re x'], 'Xtest.aff') let output = execute('mkspell! Xtest.spl Xtest') call assert_match('Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in Xtest.aff line 2: x', output) diff --git a/test/old/testdir/test_syntax.vim b/test/old/testdir/test_syntax.vim index 35523df17d..8a24c4ae27 100644 --- a/test/old/testdir/test_syntax.vim +++ b/test/old/testdir/test_syntax.vim @@ -549,8 +549,7 @@ endfunc func Test_bg_detection() CheckNotGui - " auto-detection of &bg, make sure sure it isn't set anywhere before - " this test + " auto-detection of &bg, make sure it isn't set anywhere before this test hi Normal ctermbg=0 call assert_equal('dark', &bg) hi Normal ctermbg=4 diff --git a/test/old/testdir/test_textobjects.vim b/test/old/testdir/test_textobjects.vim index 3b86ae97da..a7840860c9 100644 --- a/test/old/testdir/test_textobjects.vim +++ b/test/old/testdir/test_textobjects.vim @@ -232,7 +232,7 @@ func Test_empty_html_tag() normal 0f Date: Tue, 4 Jun 2024 09:39:28 +0200 Subject: vim-patch:9.1.0464: no whitespace padding in commentstring option in ftplugins Problem: no whitespace padding in commentstring option in ftplugins Solution: Change default to include whitespace padding, update existing filetype plugins with the new default value (Riley Bruins) closes: vim/vim#14843 https://github.com/vim/vim/commit/0a0830624a260660c7fa692ecb7e6e5de09114ba Co-authored-by: Riley Bruins --- runtime/doc/options.txt | 4 +- runtime/ftplugin/abaqus.vim | 3 +- runtime/ftplugin/arduino.vim | 3 +- runtime/ftplugin/asm.vim | 3 +- runtime/ftplugin/astro.vim | 7 ++- runtime/ftplugin/bitbake.vim | 3 +- runtime/ftplugin/c.vim | 3 +- runtime/ftplugin/calendar.vim | 3 +- runtime/ftplugin/cgdbrc.vim | 3 +- runtime/ftplugin/csh.vim | 3 +- runtime/ftplugin/css.lua | 1 - runtime/ftplugin/css.vim | 3 +- runtime/ftplugin/desktop.vim | 3 +- runtime/ftplugin/dtd.vim | 3 +- runtime/ftplugin/dtrace.vim | 5 +- runtime/ftplugin/dts.vim | 3 +- runtime/ftplugin/erlang.vim | 5 +- runtime/ftplugin/eruby.vim | 3 +- runtime/ftplugin/fennel.vim | 3 +- runtime/ftplugin/fish.vim | 3 +- runtime/ftplugin/fortran.vim | 3 +- runtime/ftplugin/fstab.vim | 3 +- runtime/ftplugin/gdb.vim | 3 +- runtime/ftplugin/groovy.vim | 3 +- runtime/ftplugin/hamster.vim | 3 +- runtime/ftplugin/html.vim | 3 +- runtime/ftplugin/indent.vim | 3 +- runtime/ftplugin/initex.vim | 3 +- runtime/ftplugin/java.vim | 3 +- runtime/ftplugin/javascript.vim | 3 +- runtime/ftplugin/jq.vim | 3 +- runtime/ftplugin/jsonc.vim | 3 +- runtime/ftplugin/lc.vim | 13 +++++ runtime/ftplugin/ld.vim | 5 +- runtime/ftplugin/liquid.vim | 3 +- runtime/ftplugin/lisp.vim | 3 +- runtime/ftplugin/markdown.vim | 3 +- runtime/ftplugin/mma.vim | 5 +- runtime/ftplugin/modula2.vim | 3 +- runtime/ftplugin/modula3.vim | 3 +- runtime/ftplugin/nroff.vim | 6 +- runtime/ftplugin/obse.vim | 7 ++- runtime/ftplugin/ocaml.vim | 4 +- runtime/ftplugin/odin.vim | 5 +- runtime/ftplugin/openvpn.vim | 3 +- runtime/ftplugin/pascal.vim | 3 +- runtime/ftplugin/pdf.vim | 3 +- runtime/ftplugin/perl.vim | 3 +- runtime/ftplugin/php.vim | 3 +- runtime/ftplugin/ps1.vim | 3 +- runtime/ftplugin/ps1xml.vim | 3 +- runtime/ftplugin/qml.vim | 3 +- runtime/ftplugin/racket.vim | 5 +- runtime/ftplugin/raku.vim | 13 +++-- runtime/ftplugin/rust.vim | 11 ++-- runtime/ftplugin/scdoc.vim | 9 +-- runtime/ftplugin/scheme.vim | 15 ++--- runtime/ftplugin/tcl.vim | 3 +- runtime/ftplugin/typescript.vim | 3 +- runtime/ftplugin/vim.vim | 3 +- runtime/ftplugin/wat.vim | 3 +- runtime/ftplugin/xdefaults.lua | 1 - runtime/ftplugin/xdefaults.vim | 9 +-- runtime/ftplugin/xml.vim | 3 +- runtime/lua/vim/_meta/options.lua | 4 +- runtime/syntax/lc.vim | 2 +- runtime/syntax/mma.vim | 2 +- src/nvim/options.lua | 4 +- test/old/testdir/setup.vim | 2 +- test/old/testdir/test_fold.vim | 70 +++++++++++++++++++++++- test/old/testdir/test_normal.vim | 112 +++++++++++++++++++------------------- 71 files changed, 298 insertions(+), 163 deletions(-) delete mode 100644 runtime/ftplugin/css.lua create mode 100644 runtime/ftplugin/lc.vim delete mode 100644 runtime/ftplugin/xdefaults.lua diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index a48ebd7199..20e825329a 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1442,8 +1442,8 @@ A jump table for the options with a short description can be found at |Q_op|. 'commentstring' 'cms' string (default "") local to buffer A template for a comment. The "%s" in the value is replaced with the - comment text. For example, C uses "/*%s*/". Used for |commenting| and to - add markers for folding, see |fold-marker|. + comment text, and should be padded with a space when possible. + Used for |commenting| and to add markers for folding, see |fold-marker|. *'complete'* *'cpt'* *E535* 'complete' 'cpt' string (default ".,w,b,u,t") diff --git a/runtime/ftplugin/abaqus.vim b/runtime/ftplugin/abaqus.vim index c16e7b032e..d4bb6fe777 100644 --- a/runtime/ftplugin/abaqus.vim +++ b/runtime/ftplugin/abaqus.vim @@ -3,6 +3,7 @@ " Maintainer: Carl Osterwisch " Last Change: 2022 Oct 08 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") | finish | endif @@ -27,7 +28,7 @@ setlocal isfname-=, " Define format of comment lines (see 'formatoptions' for uses) setlocal comments=:** -setlocal commentstring=**%s +setlocal commentstring=**\ %s " Definitions start with a * and assign a NAME, NSET, or ELSET " Used in [d ^wd and other commands diff --git a/runtime/ftplugin/arduino.vim b/runtime/ftplugin/arduino.vim index dae3dd83d3..60b11dab1a 100644 --- a/runtime/ftplugin/arduino.vim +++ b/runtime/ftplugin/arduino.vim @@ -3,6 +3,7 @@ " Maintainer: The Vim Project " Ken Takata " Last Change: 2024 Apr 12 +" 2024 Jun 02 by Riley Bruins ('commentstring') " " Most of the part was copied from c.vim. @@ -32,7 +33,7 @@ setlocal fo-=t fo+=croql " These options have the right value as default, but the user may have " overruled that. -setlocal commentstring& define& include& +setlocal commentstring=/*\ %s\ */ define& include& " Set completion with CTRL-X CTRL-O to autoloaded function. if exists('&ofu') diff --git a/runtime/ftplugin/asm.vim b/runtime/ftplugin/asm.vim index 0ae1610394..4482b90d0b 100644 --- a/runtime/ftplugin/asm.vim +++ b/runtime/ftplugin/asm.vim @@ -4,13 +4,14 @@ " Last Change: 2020 May 23 " 2023 Aug 28 by Vim Project (undo_ftplugin) " 2024 Apr 09 by Vim Project (add Matchit support) +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 setl include=^\\s*%\\s*include setl comments=:;,s1:/*,mb:*,ex:*/,:// -setl commentstring=;%s +setl commentstring=;\ %s let b:undo_ftplugin = "setl commentstring< comments< include<" diff --git a/runtime/ftplugin/astro.vim b/runtime/ftplugin/astro.vim index 0b0e03447b..5d35ba9624 100644 --- a/runtime/ftplugin/astro.vim +++ b/runtime/ftplugin/astro.vim @@ -2,6 +2,7 @@ " Language: Astro " Maintainer: Romain Lafourcade " Last Change: 2024 Apr 21 +" 2024 May 24 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -25,17 +26,17 @@ function! s:AstroComments() abort \ || s:IdentifyScope('^\s*') " ECMAScript comments setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// - setlocal commentstring=//%s + setlocal commentstring=//\ %s elseif s:IdentifyScope('^\s*') " CSS comments setlocal comments=s1:/*,mb:*,ex:*/ - setlocal commentstring=/*%s*/ + setlocal commentstring=/*\ %s\ */ else " HTML comments setlocal comments=s: - setlocal commentstring= + setlocal commentstring= endif endfunction diff --git a/runtime/ftplugin/bitbake.vim b/runtime/ftplugin/bitbake.vim index 99fe334627..4d50a7feb7 100644 --- a/runtime/ftplugin/bitbake.vim +++ b/runtime/ftplugin/bitbake.vim @@ -3,13 +3,14 @@ " Maintainer: Gregory Anders " Repository: https://github.com/openembedded/bitbake " Latest Revision: 2022-07-23 +" 2024-05-23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal comments=:# setlocal suffixesadd=.bb,.bbclass diff --git a/runtime/ftplugin/c.vim b/runtime/ftplugin/c.vim index 716b454675..8b2b784eb4 100644 --- a/runtime/ftplugin/c.vim +++ b/runtime/ftplugin/c.vim @@ -2,6 +2,7 @@ " Language: C " Maintainer: The Vim Project " Last Change: 2023 Aug 22 +" 2024 Jun 02 by Riley Bruins ('commentstring') " Former Maintainer: Bram Moolenaar " Only do this when not done yet for this buffer @@ -24,7 +25,7 @@ setlocal fo-=t fo+=croql " These options have the right value as default, but the user may have " overruled that. -setlocal commentstring& define& include& +setlocal commentstring=/*\ %s\ */ define& include& " Set completion with CTRL-X CTRL-O to autoloaded function. if exists('&ofu') diff --git a/runtime/ftplugin/calendar.vim b/runtime/ftplugin/calendar.vim index f454ba1dc8..c4e683acf6 100644 --- a/runtime/ftplugin/calendar.vim +++ b/runtime/ftplugin/calendar.vim @@ -2,6 +2,7 @@ " Language: calendar(1) input file " Previous Maintainer: Nikolai Weibull " Latest Revision: 2008-07-09 +" 2024-06-02 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring& include& +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ include& setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/cgdbrc.vim b/runtime/ftplugin/cgdbrc.vim index 46cf135c5c..99f9702d26 100644 --- a/runtime/ftplugin/cgdbrc.vim +++ b/runtime/ftplugin/cgdbrc.vim @@ -3,6 +3,7 @@ " Maintainer: Wu, Zhenyu " Documentation: https://cgdb.github.io/docs/Configuring-CGDB.html " Latest Revision: 2024-04-09 +" 2024-05-23 by Riley Bruins ('commentstring') if exists('b:did_ftplugin') finish @@ -14,7 +15,7 @@ set cpoptions&vim let b:undo_ftplugin = 'setl com< cms<' -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal comments=:# let &cpoptions = s:save_cpoptions diff --git a/runtime/ftplugin/csh.vim b/runtime/ftplugin/csh.vim index a22bee3279..74666b9680 100644 --- a/runtime/ftplugin/csh.vim +++ b/runtime/ftplugin/csh.vim @@ -4,6 +4,7 @@ " Previous Maintainer: Dan Sharp " Contributor: Johannes Zellner " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -14,7 +15,7 @@ let s:save_cpo = &cpo set cpo-=C setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions-=t setlocal formatoptions+=crql diff --git a/runtime/ftplugin/css.lua b/runtime/ftplugin/css.lua deleted file mode 100644 index 984111a08b..0000000000 --- a/runtime/ftplugin/css.lua +++ /dev/null @@ -1 +0,0 @@ -vim.bo.commentstring = '/* %s */' diff --git a/runtime/ftplugin/css.vim b/runtime/ftplugin/css.vim index ece2def4ee..778a9e12d6 100644 --- a/runtime/ftplugin/css.vim +++ b/runtime/ftplugin/css.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns " Previous Maintainer: Nikolai Weibull " Last Change: 2020 Dec 21 +" 2024 Jun 02 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -14,7 +15,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo< ofu< isk<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring& +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ setlocal formatoptions-=t formatoptions+=croql setlocal omnifunc=csscomplete#CompleteCSS setlocal iskeyword+=- diff --git a/runtime/ftplugin/desktop.vim b/runtime/ftplugin/desktop.vim index bd6fd7097c..d15afd24b9 100644 --- a/runtime/ftplugin/desktop.vim +++ b/runtime/ftplugin/desktop.vim @@ -2,6 +2,7 @@ " Language: XDG desktop entry " Maintainer: Eisuke Kawashima ( e.kawaschima+vim AT gmail.com ) " Last Change: 2022-07-26 +" 2024-05-24 by Riley Bruins ('commentstring') if exists('b:did_ftplugin') finish @@ -9,5 +10,5 @@ endif let b:did_ftplugin = v:true setl comments=:# -setl commentstring=#%s +setl commentstring=#\ %s let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/dtd.vim b/runtime/ftplugin/dtd.vim index bea8c5c18a..f97014814b 100644 --- a/runtime/ftplugin/dtd.vim +++ b/runtime/ftplugin/dtd.vim @@ -6,6 +6,7 @@ " Former maintainer: Dan Sharp " Last Change: 2009 Jan 20 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 @@ -15,7 +16,7 @@ let b:did_ftplugin = 1 let s:save_cpo = &cpo set cpo-=C -setlocal commentstring= +setlocal commentstring= setlocal comments=s: setlocal formatoptions-=t diff --git a/runtime/ftplugin/dtrace.vim b/runtime/ftplugin/dtrace.vim index 9288097f7f..a276b310a3 100644 --- a/runtime/ftplugin/dtrace.vim +++ b/runtime/ftplugin/dtrace.vim @@ -1,6 +1,7 @@ " Language: D script as described in "Solaris Dynamic Tracing Guide", " http://docs.sun.com/app/docs/doc/817-6223 " Last Change: 2008/03/20 +" 2024/05/23 by Riley Bruins @@ -26,8 +27,8 @@ setlocal fo-=t fo+=croql setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/ " dtrace uses /* */ comments. Set this explicitly, just in case the user -" changed this (/*%s*/ is the default) -setlocal commentstring=/*%s*/ +" changed this (/*\ %s\ */ is the default) +setlocal commentstring=/*\ %s\ */ setlocal iskeyword+=@,$ diff --git a/runtime/ftplugin/dts.vim b/runtime/ftplugin/dts.vim index 42e38338b7..346ff94704 100644 --- a/runtime/ftplugin/dts.vim +++ b/runtime/ftplugin/dts.vim @@ -2,6 +2,7 @@ " Language: dts/dtsi (device tree files) " Maintainer: Wu, Zhenyu " Latest Revision: 2024 Apr 12 +" 2024 Jun 02 by Riley Bruins ('commentstring') if exists('b:did_ftplugin') finish @@ -12,5 +13,5 @@ let b:undo_ftplugin = 'setl inc< cms< com<' setlocal include=^\\%(#include\\\|/include/\\) " same as C -setlocal commentstring& +setlocal commentstring=/*\ %s\ */ setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:///,:// diff --git a/runtime/ftplugin/erlang.vim b/runtime/ftplugin/erlang.vim index 1cb57f4c85..5a3ab717d9 100644 --- a/runtime/ftplugin/erlang.vim +++ b/runtime/ftplugin/erlang.vim @@ -6,7 +6,8 @@ " Eduardo Lopez (http://github.com/tapichu) " Arvid Bjurklint (http://github.com/slarwise) " Paweł Zacharek (http://github.com/subc2) -" Last Update: 2023-Dec-20 +" Riley Bruins (http://github.com/ribru17) ('commentstring') +" Last Update: 2024 May 23 " License: Vim license " URL: https://github.com/vim-erlang/vim-erlang-runtime @@ -27,7 +28,7 @@ if get(g:, 'erlang_folding', 0) endif setlocal comments=:%%%,:%%,:% -setlocal commentstring=%%s +setlocal commentstring=%\ %s setlocal formatoptions+=ro diff --git a/runtime/ftplugin/eruby.vim b/runtime/ftplugin/eruby.vim index b5c4665d24..b3e074aa20 100644 --- a/runtime/ftplugin/eruby.vim +++ b/runtime/ftplugin/eruby.vim @@ -5,6 +5,7 @@ " Release Coordinator: Doug Kearns " Last Change: 2022 May 15 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -125,7 +126,7 @@ if exists("loaded_matchit") endif " TODO: comments= -setlocal commentstring=<%#%s%> +setlocal commentstring=<%#\ %s\ %> let b:undo_ftplugin = "setl cms< " . \ " | unlet! b:browsefilter b:match_words | " . b:undo_ftplugin diff --git a/runtime/ftplugin/fennel.vim b/runtime/ftplugin/fennel.vim index 93cf366726..2a9623faff 100644 --- a/runtime/ftplugin/fennel.vim +++ b/runtime/ftplugin/fennel.vim @@ -2,13 +2,14 @@ " Language: Fennel " Maintainer: Gregory Anders " Last Update: 2023 Jun 9 +" 2024 May 24 by Riley Bruins ('commentstring') if exists('b:did_ftplugin') finish endif let b:did_ftplugin = 1 -setlocal commentstring=;%s +setlocal commentstring=;\ %s setlocal comments=:;;,:; setlocal formatoptions-=t setlocal suffixesadd=.fnl diff --git a/runtime/ftplugin/fish.vim b/runtime/ftplugin/fish.vim index f06ad3a0bf..55d7ea8dd9 100644 --- a/runtime/ftplugin/fish.vim +++ b/runtime/ftplugin/fish.vim @@ -4,6 +4,7 @@ " Repository: https://github.com/nickeb96/fish.vim " Last Change: February 1, 2023 " 2023 Aug 28 by Vim Project (undo_ftplugin) +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -12,7 +13,7 @@ let b:did_ftplugin = 1 setlocal iskeyword=@,48-57,_,192-255,-,. setlocal comments=:# -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal formatoptions+=crjq let b:undo_ftplugin = "setl cms< com< fo< isk<" diff --git a/runtime/ftplugin/fortran.vim b/runtime/ftplugin/fortran.vim index 3c325818d3..19a4c1e62b 100644 --- a/runtime/ftplugin/fortran.vim +++ b/runtime/ftplugin/fortran.vim @@ -11,6 +11,7 @@ " Doug Kearns, and Fritz Reese. " Last Change: 2023 Dec 22 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins ('commentstring') " Only do these settings when not done yet for this buffer if exists("b:did_ftplugin") @@ -89,7 +90,7 @@ else endif " Set commentstring for foldmethod=marker -setlocal cms=!%s +setlocal cms=!\ %s " Tabs are not a good idea in Fortran so the default is to expand tabs if !exists("fortran_have_tabs") diff --git a/runtime/ftplugin/fstab.vim b/runtime/ftplugin/fstab.vim index 99805322cd..0e7ffda498 100644 --- a/runtime/ftplugin/fstab.vim +++ b/runtime/ftplugin/fstab.vim @@ -3,6 +3,7 @@ " Maintainer: Radu Dineiu " URL: https://raw.github.com/rid9/vim-fstab/master/ftplugin/fstab.vim " Last Change: 2021 Jan 02 +" 2024 May 23 by Riley Bruins ('commentstring') " Version: 1.0 " " Credits: @@ -13,7 +14,7 @@ if exists("b:did_ftplugin") endif let b:did_ftplugin = 1 -setlocal commentstring=#%s +setlocal commentstring=#\ %s let b:undo_ftplugin = "setlocal commentstring<" " vim: ts=8 ft=vim diff --git a/runtime/ftplugin/gdb.vim b/runtime/ftplugin/gdb.vim index 7c10633be4..af88a04d54 100644 --- a/runtime/ftplugin/gdb.vim +++ b/runtime/ftplugin/gdb.vim @@ -3,11 +3,12 @@ " Maintainer: Michaël Peeters " Last Changed: 2017-10-26 " 2024-04-10: - add Matchit support (by Vim Project) +" 2024-04-23: - add space to commentstring (by Riley Bruins) ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 -setlocal commentstring=#%s +setlocal commentstring=#\ %s setlocal include=^\\s*source " Undo the stuff we changed. diff --git a/runtime/ftplugin/groovy.vim b/runtime/ftplugin/groovy.vim index cc7d6e35eb..a2e2b2f93e 100644 --- a/runtime/ftplugin/groovy.vim +++ b/runtime/ftplugin/groovy.vim @@ -2,6 +2,7 @@ " Language: groovy " Maintainer: Justin M. Keyes " Last Change: 2016 May 22 +" 2024 May 24 by Riley Bruins ('commentstring') if exists('b:did_ftplugin') finish @@ -13,7 +14,7 @@ set cpo-=C let b:undo_ftplugin = 'setlocal commentstring<' -setlocal commentstring=//%s +setlocal commentstring=//\ %s let &cpo = s:cpo_save unlet s:cpo_save diff --git a/runtime/ftplugin/hamster.vim b/runtime/ftplugin/hamster.vim index 5446e72286..904f267fdc 100644 --- a/runtime/ftplugin/hamster.vim +++ b/runtime/ftplugin/hamster.vim @@ -3,6 +3,7 @@ " Version: 2.0.6.0 " Maintainer: David Fishburn " Last Change: 2021 Jan 19 +" 2024 May 23 by Riley Bruins ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -31,7 +32,7 @@ if &tw == 0 endif " Comments start with a double quote -setlocal commentstring=#%s +setlocal commentstring=#\ %s " Move around functions. noremap [[ :call search('^\s*sub\>', "bW") diff --git a/runtime/ftplugin/html.vim b/runtime/ftplugin/html.vim index 3aa60a873e..5495f859de 100644 --- a/runtime/ftplugin/html.vim +++ b/runtime/ftplugin/html.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns " Previous Maintainer: Dan Sharp " Last Change: 2024 Jan 14 +" 2024 May 24 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ let s:save_cpo = &cpo set cpo-=C setlocal matchpairs+=<:> -setlocal commentstring= +setlocal commentstring= setlocal comments=s: let b:undo_ftplugin = "setlocal comments< commentstring< matchpairs<" diff --git a/runtime/ftplugin/indent.vim b/runtime/ftplugin/indent.vim index 64a650ad7b..32208d38d8 100644 --- a/runtime/ftplugin/indent.vim +++ b/runtime/ftplugin/indent.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns " Previous Maintainer: Nikolai Weibull " Latest Revision: 2008-07-09 +" 2024-06-02 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -14,7 +15,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< fo<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring& +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/initex.vim b/runtime/ftplugin/initex.vim index 0ee3e8d899..71049df6bd 100644 --- a/runtime/ftplugin/initex.vim +++ b/runtime/ftplugin/initex.vim @@ -3,6 +3,7 @@ " Maintainer: Benji Fisher, Ph.D. " Version: 1.0 " Last Change: Wed 19 Apr 2006 +" Last Change: Thu 23 May 2024 by Riley Bruins ('commentstring') " Only do this when not done yet for this buffer. if exists("b:did_ftplugin") @@ -23,7 +24,7 @@ setlocal com=sO:%\ -,mO:%\ \ ,eO:%%,:% " Set 'commentstring' to recognize the % comment character: " (Thanks to Ajit Thakkar.) -setlocal cms=%%s +setlocal cms=%\ %s " Allow "[d" to be used to find a macro definition: let &l:define='\\\([egx]\|char\|mathchar\|count\|dimen\|muskip\|skip\|toks\)\=' diff --git a/runtime/ftplugin/java.vim b/runtime/ftplugin/java.vim index fa2b61075f..eee7ef0153 100644 --- a/runtime/ftplugin/java.vim +++ b/runtime/ftplugin/java.vim @@ -5,6 +5,7 @@ " Repository: https://github.com/zzzyxwvut/java-vim.git " Last Change: 2024 Apr 18 " 2024 Jan 14 by Vim Project (browsefilter) +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 @@ -61,7 +62,7 @@ setlocal formatoptions-=t formatoptions+=croql " Set 'comments' to format dashed lists in comments. Behaves just like C. setlocal comments& comments^=sO:*\ -,mO:*\ \ ,exO:*/ -setlocal commentstring=//%s +setlocal commentstring=//\ %s " Change the :browse e filter to primarily show Java-related files. if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") diff --git a/runtime/ftplugin/javascript.vim b/runtime/ftplugin/javascript.vim index 2633954903..455b794cf0 100644 --- a/runtime/ftplugin/javascript.vim +++ b/runtime/ftplugin/javascript.vim @@ -3,6 +3,7 @@ " Maintainer: Doug Kearns " Contributor: Romain Lafourcade " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -24,7 +25,7 @@ endif " Set 'comments' to format dashed lists in comments. setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// -setlocal commentstring=//%s +setlocal commentstring=//\ %s " Change the :browse e filter to primarily show JavaScript-related files. if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter") diff --git a/runtime/ftplugin/jq.vim b/runtime/ftplugin/jq.vim index 88958e80dd..d25883640b 100644 --- a/runtime/ftplugin/jq.vim +++ b/runtime/ftplugin/jq.vim @@ -2,6 +2,7 @@ " Language: jq " Maintainer: Vito " Last Change: 2024 Apr 29 +" 2024 May 23 by Riley Bruins ('commentstring') " Upstream: https://github.com/vito-c/jq.vim if exists('b:did_ftplugin') @@ -10,7 +11,7 @@ endif let b:did_ftplugin = 1 setlocal include=^\\s*\\%(import\\\|include\\) -setlocal commentstring=#%s +setlocal commentstring=#\ %s compiler jq let b:undo_ftplugin = 'setl commentstring< include<' diff --git a/runtime/ftplugin/jsonc.vim b/runtime/ftplugin/jsonc.vim index e47a75f574..ec3268492c 100644 --- a/runtime/ftplugin/jsonc.vim +++ b/runtime/ftplugin/jsonc.vim @@ -5,6 +5,7 @@ " https://github.com/kevinoid/vim-jsonc " License: MIT " Last Change: 2021 Nov 22 +" 2024 May 23 by Riley Bruins ('commentstring') runtime! ftplugin/json.vim @@ -15,7 +16,7 @@ else endif " Set comment (formatting) related options. {{{1 -setlocal commentstring=//%s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// +setlocal commentstring=//\ %s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,:// " Let Vim know how to disable the plug-in. let b:undo_ftplugin = 'setlocal commentstring< comments<' diff --git a/runtime/ftplugin/lc.vim b/runtime/ftplugin/lc.vim new file mode 100644 index 0000000000..e818f1aecb --- /dev/null +++ b/runtime/ftplugin/lc.vim @@ -0,0 +1,13 @@ +" Vim filetype plugin +" Language: Elsa +" Maintainer: Riley Bruins +" Last Change: 2024 May 25 + +if exists('b:did_ftplugin') + finish +endif +let b:did_ftplugin = 1 + +setl comments=:-- commentstring=--\ %s + +let b:undo_ftplugin = 'setl com< cms<' diff --git a/runtime/ftplugin/ld.vim b/runtime/ftplugin/ld.vim index 1ab80d533c..9cc70bd94d 100644 --- a/runtime/ftplugin/ld.vim +++ b/runtime/ftplugin/ld.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: ld(1) script " Previous Maintainer: Nikolai Weibull -" Latest Revision: 2008-07-09 +" Latest Revision: 2008 Jul 09 +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -13,7 +14,7 @@ set cpo&vim let b:undo_ftplugin = "setl com< cms< inc< fo<" -setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*%s*/ include=^\\s*INCLUDE +setlocal comments=s1:/*,mb:*,ex:*/ commentstring=/*\ %s\ */ include=^\\s*INCLUDE setlocal formatoptions-=t formatoptions+=croql let &cpo = s:cpo_save diff --git a/runtime/ftplugin/liquid.vim b/runtime/ftplugin/liquid.vim index f24ec4cbb2..dbd8abe457 100644 --- a/runtime/ftplugin/liquid.vim +++ b/runtime/ftplugin/liquid.vim @@ -2,6 +2,7 @@ " Language: Liquid " Maintainer: Tim Pope " Last Change: 2022 Mar 15 +" 2024 May 23 by Riley Bruins ('commentstring') if exists('b:did_ftplugin') finish @@ -56,6 +57,6 @@ if exists('loaded_matchit') let b:match_words .= '\<\%(if\w*\|unless\|case\)\>:\<\%(elsif\|else\|when\)\>:\,\<\%(for\|tablerow\)\>:\%({%\s*\)\@<=empty\>:\,\<\(capture\|comment\|highlight\)\>:\' endif -setlocal commentstring={%\ comment\ %}%s{%\ endcomment\ %} +setlocal commentstring={%\ comment\ %}\ %s\ {%\ endcomment\ %} let b:undo_ftplugin .= 'setl cms< | unlet! b:browsefilter b:match_words' diff --git a/runtime/ftplugin/lisp.vim b/runtime/ftplugin/lisp.vim index db3ac96631..fe3c6fe996 100644 --- a/runtime/ftplugin/lisp.vim +++ b/runtime/ftplugin/lisp.vim @@ -5,6 +5,7 @@ " Original author: Dorai Sitaram " Original URL: http://www.ccs.neu.edu/~dorai/vimplugins/vimplugins.html " Last Change: Mar 10, 2021 +" May 23, 2024 by Riley Bruins ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -19,6 +20,6 @@ setl define=^\\s*(def\\k* setl formatoptions-=t setl iskeyword+=+,-,*,/,%,<,=,>,:,$,?,!,@-@,94 setl lisp -setl commentstring=;%s +setl commentstring=;\ %s let b:undo_ftplugin = "setlocal comments< define< formatoptions< iskeyword< lisp< commentstring<" diff --git a/runtime/ftplugin/markdown.vim b/runtime/ftplugin/markdown.vim index 022dd0d601..d4ee5ac242 100644 --- a/runtime/ftplugin/markdown.vim +++ b/runtime/ftplugin/markdown.vim @@ -2,6 +2,7 @@ " Language: Markdown " Maintainer: Tim Pope " Last Change: 2023 Dec 28 +" 2024 May 24 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -12,7 +13,7 @@ runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim let s:keepcpo= &cpo set cpo&vim -setlocal comments=fb:*,fb:-,fb:+,n:> commentstring= +setlocal comments=fb:*,fb:-,fb:+,n:> commentstring= setlocal formatoptions+=tcqln formatoptions-=r formatoptions-=o setlocal formatlistpat=^\\s*\\d\\+\\.\\s\\+\\\|^\\s*[-*+]\\s\\+\\\|^\\[^\\ze[^\\]]\\+\\]:\\&^.\\{4\\} diff --git a/runtime/ftplugin/mma.vim b/runtime/ftplugin/mma.vim index ce4cee18ae..91a8111bcb 100644 --- a/runtime/ftplugin/mma.vim +++ b/runtime/ftplugin/mma.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: Mathematica " Maintainer: Ian Ford -" Last Change: 22 January 2019 +" Last Change: 2019 Jan 22 +" 2024 May 23 by Riley Bruins ('commentstring') " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -13,4 +14,4 @@ let b:did_ftplugin = 1 let b:undo_ftplugin = "setlocal commentstring<" -setlocal commentstring=\(*%s*\) +setlocal commentstring=\(*\ %s\ *\) diff --git a/runtime/ftplugin/modula2.vim b/runtime/ftplugin/modula2.vim index 9c1acc276a..306688da05 100644 --- a/runtime/ftplugin/modula2.vim +++ b/runtime/ftplugin/modula2.vim @@ -2,6 +2,7 @@ " Language: Modula-2 " Maintainer: Doug Kearns " Last Change: 2024 Jan 14 +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -17,7 +18,7 @@ if s:dialect ==# "r10" setlocal comments=s:(*,m:\ ,e:*),:! setlocal commentstring=!\ %s else - setlocal commentstring=(*%s*) + setlocal commentstring=(*\ %s\ *) setlocal comments=s:(*,m:\ ,e:*) endif setlocal formatoptions-=t formatoptions+=croql diff --git a/runtime/ftplugin/modula3.vim b/runtime/ftplugin/modula3.vim index 45dd7ca01c..f899d1d103 100644 --- a/runtime/ftplugin/modula3.vim +++ b/runtime/ftplugin/modula3.vim @@ -2,6 +2,7 @@ " Language: Modula-3 " Maintainer: Doug Kearns " Last Change: 2024 Jan 14 +" 2024 May 24 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -12,7 +13,7 @@ let s:cpo_save = &cpo set cpo&vim setlocal comments=s0:(*,mb:\ ,ex:*) -setlocal commentstring=(*%s*) +setlocal commentstring=(*\ %s\ *) setlocal formatoptions-=t formatoptions+=croql setlocal suffixesadd+=.m3 setlocal formatprg=m3pp diff --git a/runtime/ftplugin/nroff.vim b/runtime/ftplugin/nroff.vim index cf62d02daa..ed0b32f5f3 100644 --- a/runtime/ftplugin/nroff.vim +++ b/runtime/ftplugin/nroff.vim @@ -2,15 +2,15 @@ " Language: roff(7) " Maintainer: Aman Verma " Homepage: https://github.com/a-vrma/vim-nroff-ftplugin -" Previous Maintainer: Chris Spiegel -" Last Change: 2020 Nov 21 +" Previous Maintainer: Chris Spiegel +" 2024 May 24 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 -setlocal commentstring=.\\\"%s +setlocal commentstring=.\\\"\ %s setlocal comments=:.\\\" setlocal sections+=Sh diff --git a/runtime/ftplugin/obse.vim b/runtime/ftplugin/obse.vim index 6d865f05ee..bf5076f41f 100644 --- a/runtime/ftplugin/obse.vim +++ b/runtime/ftplugin/obse.vim @@ -2,8 +2,9 @@ " Language: Oblivion Language (obl) " Original Creator: Kat " Maintainer: Kat -" Created: August 08, 2021 -" Last Change: 13 November 2022 +" Created: 2021 Aug 08 +" Last Change: 2022 Nov 13 +" 2024 May 23 by Riley Bruins ('commentstring') if exists("b:did_ftplugin") finish @@ -20,7 +21,7 @@ noremap