aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml2
-rw-r--r--CMakeLists.txt9
-rw-r--r--cmake/Util.cmake13
-rw-r--r--contrib/luarc.json3
-rw-r--r--runtime/lua/vim/filetype.lua3
-rw-r--r--runtime/lua/vim/lsp.lua4
-rw-r--r--runtime/lua/vim/lsp/_inlay_hint.lua61
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim55
-rw-r--r--src/nvim/drawline.c31
-rw-r--r--test/functional/ui/decorations_spec.lua58
-rw-r--r--test/old/testdir/test_filetype.vim4
11 files changed, 180 insertions, 63 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 14546cb371..bdec96babb 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -48,7 +48,7 @@ jobs:
cmake --build .deps
- if: success() || failure() && steps.abort_job.outputs.status == 'success'
- run: cmake -B build -G Ninja
+ run: cmake -B build -G Ninja -D CI_LINT=ON
- if: "!cancelled()"
name: Determine if run should be aborted
diff --git a/CMakeLists.txt b/CMakeLists.txt
index abd3a57fc0..d0534731b0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -229,11 +229,14 @@ endif()
#
# Lint
#
-find_program(SHELLCHECK_PRG shellcheck)
-find_program(STYLUA_PRG stylua)
+option(CI_LINT "Abort if lint programs not found" OFF)
+if(CI_LINT)
+ set(LINT_REQUIRED "REQUIRED")
+endif()
+find_program(SHELLCHECK_PRG shellcheck ${LINT_REQUIRED})
+find_program(STYLUA_PRG stylua ${LINT_REQUIRED})
add_glob_target(
- REQUIRED
TARGET lintlua-luacheck
COMMAND ${DEPS_BIN_DIR}/luacheck
FLAGS -q
diff --git a/cmake/Util.cmake b/cmake/Util.cmake
index b70f33a302..0d6fa2a4ce 100644
--- a/cmake/Util.cmake
+++ b/cmake/Util.cmake
@@ -4,7 +4,6 @@
# depends on the value of TOUCH_STRATEGY.
#
# Options:
-# REQUIRED - Abort if COMMAND doesn't exist.
#
# Single value arguments:
# TARGET - Name of the target
@@ -53,7 +52,7 @@
# files.
function(add_glob_target)
cmake_parse_arguments(ARG
- "REQUIRED"
+ ""
"TARGET;COMMAND;GLOB_PAT;TOUCH_STRATEGY"
"FLAGS;FILES;GLOB_DIRS;EXCLUDE"
${ARGN}
@@ -61,14 +60,8 @@ function(add_glob_target)
if(NOT ARG_COMMAND)
add_custom_target(${ARG_TARGET})
- if(ARG_REQUIRED)
- add_custom_command(TARGET ${ARG_TARGET}
- COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET}: ${ARG_COMMAND} not found"
- COMMAND false)
- else()
- add_custom_command(TARGET ${ARG_TARGET}
- COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET} SKIP: ${ARG_COMMAND} not found")
- endif()
+ add_custom_command(TARGET ${ARG_TARGET}
+ COMMAND ${CMAKE_COMMAND} -E echo "${ARG_TARGET} SKIP: ${ARG_COMMAND} not found")
return()
endif()
diff --git a/contrib/luarc.json b/contrib/luarc.json
index ebad0581b9..31126e4215 100644
--- a/contrib/luarc.json
+++ b/contrib/luarc.json
@@ -13,6 +13,9 @@
"teardown",
"finally",
"lfs"
+ ],
+ "disable": [
+ "luadoc-miss-see-name"
]
},
"workspace": {
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 08a042d376..7bcc67313d 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1372,6 +1372,7 @@ local filename = {
['named.root'] = 'bindzone',
WORKSPACE = 'bzl',
['WORKSPACE.bzlmod'] = 'bzl',
+ BUCK = 'bzl',
BUILD = 'bzl',
['cabal.project'] = 'cabalproject',
['cabal.config'] = 'cabalconfig',
@@ -2189,7 +2190,7 @@ local pattern = {
['.*/etc/profile'] = function(path, bufnr)
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
- ['bash%-fc[%-%.]'] = function(path, bufnr)
+ ['bash%-fc[%-%.].*'] = function(path, bufnr)
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['%.tcshrc.*'] = function(path, bufnr)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index a8e75c4dc9..1e5ce8fa10 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1183,7 +1183,7 @@ function lsp.start_client(config)
---
---@param code (integer) Error code
---@param err (...) Other arguments may be passed depending on the error kind
- ---@see `vim.lsp.rpc.client_errors` for possible errors. Use
+ ---@see vim.lsp.rpc.client_errors for possible errors. Use
---`vim.lsp.rpc.client_errors[code]` to get a human-friendly name.
function dispatch.on_error(code, err)
if log.error() then
@@ -2366,7 +2366,7 @@ function lsp.formatexpr(opts)
}
local response =
client.request_sync('textDocument/rangeFormatting', params, timeout_ms, bufnr)
- if response.result then
+ if response and response.result then
lsp.util.apply_text_edits(response.result, 0, client.offset_encoding)
return 0
end
diff --git a/runtime/lua/vim/lsp/_inlay_hint.lua b/runtime/lua/vim/lsp/_inlay_hint.lua
index 8edf14e707..84794841ae 100644
--- a/runtime/lua/vim/lsp/_inlay_hint.lua
+++ b/runtime/lua/vim/lsp/_inlay_hint.lua
@@ -8,6 +8,7 @@ local M = {}
---@field client_hint table<integer, table<integer, lsp.InlayHint[]>> client_id -> (lnum -> hints)
---@field enabled boolean Whether inlay hints are enabled for the buffer
---@field timer uv.uv_timer_t? Debounce timer associated with the buffer
+---@field applied table<integer, integer> Last version of hints applied to this line
---@type table<integer, lsp._inlay_hint.bufstate>
local bufstates = {}
@@ -143,6 +144,9 @@ end
---@private
local function clear(bufnr)
bufnr = resolve_bufnr(bufnr)
+ if not bufstates[bufnr] then
+ return
+ end
reset_timer(bufnr)
local bufstate = bufstates[bufnr]
local client_lens = (bufstate or {}).client_hint or {}
@@ -169,7 +173,7 @@ function M.enable(bufnr)
bufnr = resolve_bufnr(bufnr)
local bufstate = bufstates[bufnr]
if not (bufstate and bufstate.enabled) then
- bufstates[bufnr] = { enabled = true, timer = nil }
+ bufstates[bufnr] = { enabled = true, timer = nil, applied = {} }
M.refresh({ bufnr = bufnr })
api.nvim_buf_attach(bufnr, true, {
on_lines = function(_, cb_bufnr)
@@ -183,7 +187,9 @@ function M.enable(bufnr)
end,
on_reload = function(_, cb_bufnr)
clear(cb_bufnr)
- bufstates[cb_bufnr] = nil
+ if bufstates[cb_bufnr] and bufstates[cb_bufnr].enabled then
+ bufstates[cb_bufnr] = { enabled = true }
+ end
M.refresh({ bufnr = cb_bufnr })
end,
on_detach = function(_, cb_bufnr)
@@ -238,35 +244,38 @@ api.nvim_set_decoration_provider(namespace, {
return
end
local hints_by_client = bufstate.client_hint
- api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
for lnum = topline, botline do
- for _, hints_by_lnum in pairs(hints_by_client) do
- local line_hints = hints_by_lnum[lnum] or {}
- for _, hint in pairs(line_hints) do
- local text = ''
- if type(hint.label) == 'string' then
- text = hint.label
- else
- for _, part in ipairs(hint.label) do
- text = text .. part.value
+ if bufstate.applied[lnum] ~= bufstate.version then
+ api.nvim_buf_clear_namespace(bufnr, namespace, lnum, lnum + 1)
+ for _, hints_by_lnum in pairs(hints_by_client) do
+ local line_hints = hints_by_lnum[lnum] or {}
+ for _, hint in pairs(line_hints) do
+ local text = ''
+ if type(hint.label) == 'string' then
+ text = hint.label
+ else
+ for _, part in ipairs(hint.label) do
+ text = text .. part.value
+ end
end
+ local vt = {}
+ if hint.paddingLeft then
+ vt[#vt + 1] = { ' ' }
+ end
+ vt[#vt + 1] = { text, 'LspInlayHint' }
+ if hint.paddingRight then
+ vt[#vt + 1] = { ' ' }
+ end
+ api.nvim_buf_set_extmark(bufnr, namespace, lnum, hint.position.character, {
+ virt_text_pos = 'inline',
+ ephemeral = false,
+ virt_text = vt,
+ hl_mode = 'combine',
+ })
end
- local vt = {}
- if hint.paddingLeft then
- vt[#vt + 1] = { ' ' }
- end
- vt[#vt + 1] = { text, 'LspInlayHint' }
- if hint.paddingRight then
- vt[#vt + 1] = { ' ' }
- end
- api.nvim_buf_set_extmark(bufnr, namespace, lnum, hint.position.character, {
- virt_text_pos = 'inline',
- ephemeral = false,
- virt_text = vt,
- hl_mode = 'combine',
- })
end
+ bufstate.applied[lnum] = bufstate.version
end
end
end,
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 43c3d7541f..d4b49e85c8 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -2,7 +2,7 @@
"
" Author: Bram Moolenaar
" Copyright: Vim license applies, see ":help license"
-" Last Change: 2022 Nov 10
+" Last Change: 2023 Jun 24
"
" WORK IN PROGRESS - The basics works stable, more to come
" Note: In general you need at least GDB 7.12 because this provides the
@@ -87,6 +87,8 @@ func s:Breakpoint2SignNumber(id, subid)
return s:break_id + a:id * 1000 + a:subid
endfunction
+" Define or adjust the default highlighting, using background "new".
+" When the 'background' option is set then "old" has the old value.
func s:Highlight(init, old, new)
let default = a:init ? 'default ' : ''
if a:new ==# 'light' && a:old !=# 'light'
@@ -96,9 +98,21 @@ func s:Highlight(init, old, new)
endif
endfunc
-call s:Highlight(1, '', &background)
-hi default debugBreakpoint term=reverse ctermbg=red guibg=red
-hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
+" Define the default highlighting, using the current 'background' value.
+func s:InitHighlight()
+ call s:Highlight(1, '', &background)
+ hi default debugBreakpoint term=reverse ctermbg=red guibg=red
+ hi default debugBreakpointDisabled term=reverse ctermbg=gray guibg=gray
+endfunc
+
+" Setup an autocommand to redefine the default highlight when the colorscheme
+" is changed.
+func s:InitAutocmd()
+ augroup TermDebug
+ autocmd!
+ autocmd ColorScheme * call s:InitHighlight()
+ augroup END
+endfunc
" Get the command to execute the debugger as a list, defaults to ["gdb"].
func s:GetCommand()
@@ -626,7 +640,7 @@ func s:GdbOutCallback(job_id, msgs, event)
for msg in a:msgs
if msg =~ '^\^error,msg='
if exists('s:evalexpr')
- \ && s:DecodeMessage(msg[11:])
+ \ && s:DecodeMessage(msg[11:], v:false)
\ =~ 'A syntax error in expression, near\|No symbol .* in current context'
" Silently drop evaluation errors.
call remove(a:msgs, index)
@@ -634,7 +648,7 @@ func s:GdbOutCallback(job_id, msgs, event)
continue
endif
elseif msg[0] == '~'
- call add(lines, s:DecodeMessage(msg[1:]))
+ call add(lines, s:DecodeMessage(msg[1:], v:false))
call remove(a:msgs, index)
continue
endif
@@ -656,21 +670,20 @@ func s:GdbOutCallback(job_id, msgs, event)
call s:CommOutput(a:job_id, a:msgs, a:event)
endfunc
-" Decode a message from gdb. quotedText starts with a ", return the text up
+" Decode a message from gdb. "quotedText" starts with a ", return the text up
" to the next ", unescaping characters:
-" - remove line breaks
-" - change \\t to \t
+" - remove line breaks (unless "literal" is v:true)
+" - change \\t to \t (unless "literal" is v:true)
" - change \0xhh to \xhh (disabled for now)
" - change \ooo to octal
" - change \\ to \
-func s:DecodeMessage(quotedText)
+func s:DecodeMessage(quotedText, literal)
if a:quotedText[0] != '"'
echoerr 'DecodeMessage(): missing quote in ' . a:quotedText
return
endif
- return a:quotedText
- \ ->substitute('^"\|".*\|\\n', '', 'g')
- \ ->substitute('\\t', "\t", 'g')
+ let msg = a:quotedText
+ \ ->substitute('^"\|".*', '', 'g')
" multi-byte characters arrive in octal form
" NULL-values must be kept encoded as those break the string otherwise
\ ->substitute('\\000', s:NullRepl, 'g')
@@ -682,6 +695,13 @@ func s:DecodeMessage(quotedText)
" \ ->substitute('\\0x00', s:NullRepl, 'g')
\ ->substitute('\\\\', '\', 'g')
\ ->substitute(s:NullRepl, '\\000', 'g')
+ if !a:literal
+ return msg
+ \ ->substitute('\\t', "\t", 'g')
+ \ ->substitute('\\n', '', 'g')
+ else
+ return msg
+ endif
endfunc
const s:NullRepl = 'XXXNULLXXX'
@@ -690,7 +710,7 @@ func s:GetFullname(msg)
if a:msg !~ 'fullname'
return ''
endif
- let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', ''))
+ let name = s:DecodeMessage(substitute(a:msg, '.*fullname=', '', ''), v:true)
if has('win32') && name =~ ':\\\\'
" sometimes the name arrives double-escaped
let name = substitute(name, '\\\\', '\\', 'g')
@@ -703,11 +723,11 @@ func s:GetAsmAddr(msg)
if a:msg !~ 'addr='
return ''
endif
- let addr = s:DecodeMessage(substitute(a:msg, '.*addr=', '', ''))
+ let addr = s:DecodeMessage(substitute(a:msg, '.*addr=', '', ''), v:false)
return addr
endfunc
-function s:EndTermDebug(job_id, exit_code, event)
+func s:EndTermDebug(job_id, exit_code, event)
let s:running = v:false
if s:starting
return
@@ -1664,5 +1684,8 @@ func s:BufUnloaded()
endfor
endfunc
+call s:InitHighlight()
+call s:InitAutocmd()
+
let &cpo = s:keepcpo
unlet s:keepcpo
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 9728804ed7..b8dc1297cc 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -134,6 +134,7 @@ typedef struct {
int skip_cells; // nr of cells to skip for virtual text
int skipped_cells; // nr of skipped virtual text cells
+ bool more_virt_inline_chunks; // indicates if there is more inline virtual text after n_extra
} winlinevars_T;
/// for line_putchar. Contains the state that needs to be remembered from
@@ -870,6 +871,25 @@ static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv)
}
}
+// Checks if there is more inline virtual text that need to be drawn
+// and sets has_more_virt_inline_chunks to reflect that.
+static bool has_more_inline_virt(winlinevars_T *wlv, ptrdiff_t v)
+{
+ DecorState *state = &decor_state;
+ for (size_t i = 0; i < kv_size(state->active); i++) {
+ DecorRange *item = &kv_A(state->active, i);
+ if (item->start_row != state->row
+ || !kv_size(item->decor.virt_text)
+ || item->decor.virt_text_pos != kVTInline) {
+ continue;
+ }
+ if (item->draw_col >= -1 && item->start_col >= v) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t v)
{
while (wlv->n_extra == 0) {
@@ -892,6 +912,7 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
break;
}
}
+ wlv->more_virt_inline_chunks = has_more_inline_virt(wlv, v);
if (!kv_size(wlv->virt_inline)) {
// no more inline virtual text here
break;
@@ -909,6 +930,11 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t
wlv->c_final = NUL;
wlv->extra_attr = vtc.hl_id ? syn_id2attr(vtc.hl_id) : 0;
wlv->n_attr = mb_charlen(vtc.text);
+
+ // Checks if there is more inline virtual text chunks that need to be drawn.
+ wlv->more_virt_inline_chunks = has_more_inline_virt(wlv, v)
+ || wlv->virt_inline_i < kv_size(wlv->virt_inline);
+
// If the text didn't reach until the first window
// column we need to skip cells.
if (wlv->skip_cells > 0) {
@@ -2874,7 +2900,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& !has_fold
&& (*ptr != NUL
|| lcs_eol_one > 0
- || (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
+ || (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL))
+ || wlv.more_virt_inline_chunks)) {
c = wp->w_p_lcs_chars.ext;
wlv.char_attr = win_hl_attr(wp, HLF_AT);
mb_c = c;
@@ -3064,7 +3091,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
&& wlv.p_extra != at_end_str)
|| (wlv.n_extra != 0
- && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) {
+ && (wlv.c_extra != NUL || *wlv.p_extra != NUL)) || wlv.more_virt_inline_chunks)) {
bool wrap = wp->w_p_wrap // Wrapping enabled.
&& wlv.filler_todo <= 0 // Not drawing diff filler lines.
&& lcs_eol_one != -1 // Haven't printed the lcs_eol character.
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 5de0106a8c..4c04bad3a0 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2506,6 +2506,64 @@ bbbbbbb]])
|
]]}
end)
+
+ it('does not crash at right edge of wide window #23848', function()
+ screen:try_resize(82, 5)
+ meths.buf_set_extmark(0, ns, 0, 0, {virt_text = {{('a'):rep(82)}, {'b'}}, virt_text_pos = 'inline'})
+ screen:expect{grid=[[
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ b |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ command('set nowrap')
+ screen:expect{grid=[[
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ feed('82i0<Esc>0')
+ screen:expect{grid=[[
+ ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ command('set wrap')
+ screen:expect{grid=[[
+ ^0000000000000000000000000000000000000000000000000000000000000000000000000000000000|
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+ b |
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('list "extends" is drawn with only inline virtual text offscreen', function()
+ command('set nowrap')
+ command('set list')
+ command('set listchars+=extends:c')
+ meths.buf_set_extmark(0, ns, 0, 0,
+ { virt_text = { { 'test', 'Special' } }, virt_text_pos = 'inline' })
+ insert(string.rep('a', 50))
+ feed('gg0')
+ screen:expect { grid = [[
+ ^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa{1:c}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
end)
describe('decorations: virtual lines', function()
diff --git a/test/old/testdir/test_filetype.vim b/test/old/testdir/test_filetype.vim
index fe23bd73b7..8004c35d97 100644
--- a/test/old/testdir/test_filetype.vim
+++ b/test/old/testdir/test_filetype.vim
@@ -535,7 +535,7 @@ let s:filename_checks = {
\ 'services': ['/etc/services', 'any/etc/services'],
\ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'],
\ 'sexplib': ['file.sexp'],
- \ 'sh': ['.bashrc', 'file.bash', '/usr/share/doc/bash-completion/filter.sh','/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'],
+ \ 'sh': ['.bashrc', '.bash_profile', '.bash-profile', '.bash_logout', '.bash-logout', '.bash_aliases', '.bash-aliases', '/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh', '/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'],
\ 'sieve': ['file.siv', 'file.sieve'],
\ 'sil': ['file.sil'],
\ 'simula': ['file.sim'],
@@ -705,7 +705,7 @@ let s:filename_checks = {
let s:filename_case_checks = {
\ 'modula2': ['file.DEF'],
- \ 'bzl': ['file.BUILD', 'BUILD'],
+ \ 'bzl': ['file.BUILD', 'BUILD', 'BUCK'],
\ }
func CheckItems(checks)