aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci/before_script.sh6
-rw-r--r--ci/common/build.sh9
-rw-r--r--runtime/doc/lsp.txt43
-rw-r--r--runtime/lua/vim/lsp.lua18
-rw-r--r--runtime/lua/vim/lsp/buf.lua6
-rw-r--r--runtime/lua/vim/lsp/callbacks.lua97
-rw-r--r--runtime/lua/vim/lsp/rpc.lua17
-rw-r--r--runtime/lua/vim/lsp/util.lua211
-rwxr-xr-xscripts/vim-patch.sh6
-rw-r--r--src/nvim/api/private/helpers.h4
-rw-r--r--src/nvim/ascii.h2
-rw-r--r--src/nvim/change.c4
-rw-r--r--src/nvim/event/stream.c5
-rw-r--r--src/nvim/ex_cmds.c4
-rw-r--r--src/nvim/extmark.c9
-rw-r--r--src/nvim/fileio.c5
-rw-r--r--src/nvim/fold.c219
-rw-r--r--src/nvim/lua/treesitter.c27
-rw-r--r--src/nvim/memline.c54
-rw-r--r--src/nvim/option.c393
-rw-r--r--src/nvim/os/signal.c33
-rw-r--r--src/nvim/syntax.c2
-rw-r--r--src/nvim/terminal.c5
-rw-r--r--src/nvim/testdir/test_messages.vim3
-rw-r--r--src/nvim/tui/tui.c170
-rw-r--r--src/nvim/version.c6
-rw-r--r--test/functional/plugin/lsp_spec.lua74
-rw-r--r--test/functional/terminal/mouse_spec.lua34
28 files changed, 832 insertions, 634 deletions
diff --git a/ci/before_script.sh b/ci/before_script.sh
index a0e87adb9e..1759dbe942 100755
--- a/ci/before_script.sh
+++ b/ci/before_script.sh
@@ -10,6 +10,12 @@ fi
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/build.sh"
+# Enable ipv6 on Travis. ref: a39c8b7ce30d
+if ! test "${TRAVIS_OS_NAME}" = osx ; then
+ echo "before_script.sh: enable ipv6"
+ sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0
+fi
+
# Test some of the configuration variables.
if [[ -n "${GCOV}" ]] && [[ ! $(type -P "${GCOV}") ]]; then
echo "\$GCOV: '${GCOV}' is not executable."
diff --git a/ci/common/build.sh b/ci/common/build.sh
index 02e1110a15..0024f2cbd5 100644
--- a/ci/common/build.sh
+++ b/ci/common/build.sh
@@ -86,12 +86,3 @@ build_nvim() {
cd "${TRAVIS_BUILD_DIR}"
}
-
-macos_rvm_dance() {
- # neovim-ruby gem requires a ruby newer than the macOS default.
- source ~/.rvm/scripts/rvm
- rvm get stable --auto-dotfiles
- rvm reload
- rvm use 2.2.5
- rvm use
-}
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 2f5427f6fc..2d0bba0ffb 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -64,7 +64,7 @@ FAQ *lsp-faq*
- Q: How to force-reload LSP?
A: Stop all clients, then reload the buffer. >
- :lua vim.lsp.stop_all_clients()
+ :lua vim.lsp.stop_client(vim.lsp.get_active_clients())
:edit
- Q: Why isn't completion working?
@@ -752,9 +752,6 @@ npcall({fn}, {...}) *vim.lsp.buf.npcall()*
ok_or_nil({status}, {...}) *vim.lsp.buf.ok_or_nil()*
TODO: Documentation
-peek_definition() *vim.lsp.buf.peek_definition()*
- TODO: Documentation
-
*vim.lsp.buf.range_formatting()*
range_formatting({options}, {start_pos}, {end_pos})
TODO: Documentation
@@ -915,6 +912,21 @@ apply_text_edits({text_edits}, {bufnr})
apply_workspace_edit({workspace_edit})
TODO: Documentation
+ *vim.lsp.util.diagnostics_by_buf*
+diagnostics_by_buf
+ A table containing diagnostics grouped by buf.
+
+ {<bufnr>: {diagnostics}}
+
+ {diagnostics} is an array of diagnostics.
+
+ By default this is populated by the
+ `textDocument/publishDiagnostics` callback via
+ |vim.lsp.util.buf_diagnostics_save_positions|.
+
+ It contains entries for active buffers. Once a buffer is
+ detached the entries for it are discarded.
+
buf_clear_diagnostics({bufnr}) *vim.lsp.util.buf_clear_diagnostics()*
TODO: Documentation
@@ -945,9 +957,14 @@ buf_diagnostics_count({kind})
buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
TODO: Documentation
- *vim.lsp.util.buf_diagnostics_save_positions()*
+ *vim.lsp.util.buf_diagnostics_save()*
buf_diagnostics_save_positions({bufnr}, {diagnostics})
- TODO: Documentation
+ Stores the diagnostics into |vim.lsp.util.diagnostics_by_buf|
+
+ Parameters: ~
+ {bufr} bufnr for which the diagnostics are for.
+ {diagnostics} Diagnostics[] received from the
+ langauge server.
*vim.lsp.util.buf_diagnostics_underline()*
buf_diagnostics_underline({bufnr}, {diagnostics})
@@ -960,12 +977,12 @@ buf_diagnostics_virtual_text({bufnr}, {diagnostics})
*vim.lsp.util.buf_diagnostics_signs()*
buf_diagnostics_signs({bufnr}, {diagnostics})
Place signs for each diagnostic in the sign column.
- Sign characters can be customized with the following options:
+ Sign characters can be customized with the following commands:
>
-let g:LspDiagnosticsErrorSign = 'E'
-let g:LspDiagnosticsWarningSign = 'W'
-let g:LspDiagnosticsInformationSign = 'I'
-let g:LspDiagnosticsHintSign = 'H'
+sign define LspDiagnosticsErrorSign text=E texthl=LspDiagnosticsError linehl= numhl=
+sign define LspDiagnosticsWarningSign text=W texthl=LspDiagnosticsWarning linehl= numhl=
+sign define LspDiagnosticsInformationSign text=I texthl=LspDiagnosticsInformation linehl= numhl=
+sign define LspDiagnosticsHintSign text=H texthl=LspDiagnosticsHint linehl= numhl=
<
@@ -1033,10 +1050,6 @@ npcall({fn}, {...}) *vim.lsp.util.npcall()*
ok_or_nil({status}, {...}) *vim.lsp.util.ok_or_nil()*
TODO: Documentation
- *vim.lsp.util.open_floating_peek_preview()*
-open_floating_peek_preview({bufnr}, {start}, {finish}, {opts})
- TODO: Documentation
-
*vim.lsp.util.open_floating_preview()*
open_floating_preview({contents}, {filetype}, {opts})
TODO: Documentation
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index afff4d9900..c7de2df25f 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -198,6 +198,7 @@ local function text_document_did_open_handler(bufnr, client)
}
}
client.notify('textDocument/didOpen', params)
+ util.buf_versions[bufnr] = params.textDocument.version
end
--- LSP client object.
@@ -722,6 +723,7 @@ function lsp.buf_attach_client(bufnr, client_id)
client.notify('textDocument/didClose', params)
end
end)
+ util.buf_versions[bufnr] = nil
all_buffer_active_clients[bufnr] = nil
end;
-- TODO if we know all of the potential clients ahead of time, then we
@@ -1015,5 +1017,21 @@ function lsp.get_log_path()
return log.get_filename()
end
+local function define_default_sign(name, properties)
+ if not vim.fn.sign_getdefined(name) then
+ vim.fn.sign_define(name, properties)
+ end
+end
+
+-- Define the LspDiagnostics signs if they're not defined already.
+local function define_default_lsp_diagnostics_signs()
+ define_default_sign('LspDiagnosticsErrorSign', {text='E', texthl='LspDiagnosticsError', linehl='', numhl=''})
+ define_default_sign('LspDiagnosticsWarningSign', {text='W', texthl='LspDiagnosticsWarning', linehl='', numhl=''})
+ define_default_sign('LspDiagnosticsInformationSign', {text='I', texthl='LspDiagnosticsInformation', linehl='', numhl=''})
+ define_default_sign('LspDiagnosticsHintSign', {text='H', texthl='LspDiagnosticsHint', linehl='', numhl=''})
+end
+
+define_default_lsp_diagnostics_signs()
+
return lsp
-- vim:sw=2 ts=2 et
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index fc9e10cb73..587d1f52e9 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -32,12 +32,6 @@ function M.hover()
request('textDocument/hover', params)
end
-function M.peek_definition()
- local params = util.make_position_params()
- request('textDocument/peekDefinition', params)
-end
-
-
function M.declaration()
local params = util.make_position_params()
request('textDocument/declaration', params)
diff --git a/runtime/lua/vim/lsp/callbacks.lua b/runtime/lua/vim/lsp/callbacks.lua
index c403a3fd51..bd2cbf1ea7 100644
--- a/runtime/lua/vim/lsp/callbacks.lua
+++ b/runtime/lua/vim/lsp/callbacks.lua
@@ -50,6 +50,8 @@ end
M['textDocument/references'] = function(_, _, result)
if not result then return end
util.set_qflist(util.locations_to_items(result))
+ api.nvim_command("copen")
+ api.nvim_command("wincmd p")
end
M['textDocument/documentSymbol'] = function(_, _, result, _, bufnr)
@@ -112,11 +114,20 @@ local function location_callback(_, method, result)
local _ = log.info() and log.info(method, 'No location found')
return nil
end
- util.jump_to_location(result[1])
- if #result > 1 then
- util.set_qflist(util.locations_to_items(result))
- api.nvim_command("copen")
- api.nvim_command("wincmd p")
+
+ -- textDocument/definition can return Location or Location[]
+ -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
+
+ if vim.tbl_islist(result) then
+ util.jump_to_location(result[1])
+
+ if #result > 1 then
+ util.set_qflist(util.locations_to_items(result))
+ api.nvim_command("copen")
+ api.nvim_command("wincmd p")
+ end
+ else
+ util.jump_to_location(result)
end
end
@@ -125,72 +136,13 @@ M['textDocument/definition'] = location_callback
M['textDocument/typeDefinition'] = location_callback
M['textDocument/implementation'] = location_callback
---- Convert SignatureHelp response to preview contents.
--- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
-local function signature_help_to_preview_contents(input)
- if not input.signatures then
- return
- end
- --The active signature. If omitted or the value lies outside the range of
- --`signatures` the value defaults to zero or is ignored if `signatures.length
- --=== 0`. Whenever possible implementors should make an active decision about
- --the active signature and shouldn't rely on a default value.
- local contents = {}
- local active_signature = input.activeSignature or 0
- -- If the activeSignature is not inside the valid range, then clip it.
- if active_signature >= #input.signatures then
- active_signature = 0
- end
- local signature = input.signatures[active_signature + 1]
- if not signature then
- return
- end
- vim.list_extend(contents, vim.split(signature.label, '\n', true))
- if signature.documentation then
- util.convert_input_to_markdown_lines(signature.documentation, contents)
- end
- if input.parameters then
- local active_parameter = input.activeParameter or 0
- -- If the activeParameter is not inside the valid range, then clip it.
- if active_parameter >= #input.parameters then
- active_parameter = 0
- end
- local parameter = signature.parameters and signature.parameters[active_parameter]
- if parameter then
- --[=[
- --Represents a parameter of a callable-signature. A parameter can
- --have a label and a doc-comment.
- interface ParameterInformation {
- --The label of this parameter information.
- --
- --Either a string or an inclusive start and exclusive end offsets within its containing
- --signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
- --string representation as `Position` and `Range` does.
- --
- --*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`.
- label: string | [number, number];
- --The human-readable doc-comment of this parameter. Will be shown
- --in the UI but can be omitted.
- documentation?: string | MarkupContent;
- }
- --]=]
- -- TODO highlight parameter
- if parameter.documentation then
- util.convert_input_to_markdown_lines(parameter.documentation, contents)
- end
- end
- end
- return contents
-end
-
M['textDocument/signatureHelp'] = function(_, method, result)
util.focusable_preview(method, function()
if not (result and result.signatures and result.signatures[1]) then
return { 'No signature available' }
end
-- TODO show popup when signatures is empty?
- local lines = signature_help_to_preview_contents(result)
+ local lines = util.convert_signature_help_to_markdown_lines(result)
lines = util.trim_empty_lines(lines)
if vim.tbl_isempty(lines) then
return { 'No signature available' }
@@ -199,21 +151,6 @@ M['textDocument/signatureHelp'] = function(_, method, result)
end)
end
-M['textDocument/peekDefinition'] = function(_, _, result, _)
- if not (result and result[1]) then return end
- local loc = result[1]
- local bufnr = vim.uri_to_bufnr(loc.uri) or error("not found: "..tostring(loc.uri))
- local start = loc.range.start
- local finish = loc.range["end"]
- util.open_floating_peek_preview(bufnr, start, finish, { offset_x = 1 })
- local headbuf = util.open_floating_preview({"Peek:"}, nil, {
- offset_y = -(finish.line - start.line);
- width = finish.character - start.character + 2;
- })
- -- TODO(ashkan) change highlight group?
- api.nvim_buf_add_highlight(headbuf, -1, 'Keyword', 0, -1)
-end
-
M['textDocument/documentHighlight'] = function(_, _, result, _)
if not result then return end
local bufnr = api.nvim_get_current_buf()
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 74d73da31f..dad1dc11f1 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -140,14 +140,23 @@ local function format_rpc_error(err)
validate {
err = { err, 't' };
}
- local code_name = assert(protocol.ErrorCodes[err.code], "err.code is invalid")
- local message_parts = {"RPC", code_name}
+
+ -- There is ErrorCodes in the LSP specification,
+ -- but in ResponseError.code it is not used and the actual type is number.
+ local code
+ if protocol.ErrorCodes[err.code] then
+ code = string.format("code_name = %s,", protocol.ErrorCodes[err.code])
+ else
+ code = string.format("code_name = unknown, code = %s,", err.code)
+ end
+
+ local message_parts = {"RPC[Error]", code}
if err.message then
- table.insert(message_parts, "message = ")
+ table.insert(message_parts, "message =")
table.insert(message_parts, string.format("%q", err.message))
end
if err.data then
- table.insert(message_parts, "data = ")
+ table.insert(message_parts, "data =")
table.insert(message_parts, vim.inspect(err.data))
end
return table.concat(message_parts, ' ')
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 763e9719a7..53e2240ff5 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -6,6 +6,31 @@ local list_extend = vim.list_extend
local M = {}
+--- Diagnostics received from the server via `textDocument/publishDiagnostics`
+-- by buffer.
+--
+-- {<bufnr>: {diagnostics}}
+--
+-- This contains only entries for active buffers. Entries for detached buffers
+-- are discarded.
+--
+-- If you override the `textDocument/publishDiagnostic` callback,
+-- this will be empty unless you call `buf_diagnostics_save_positions`.
+--
+--
+-- Diagnostic is:
+--
+-- {
+-- range: Range
+-- message: string
+-- severity?: DiagnosticSeverity
+-- code?: number | string
+-- source?: string
+-- tags?: DiagnosticTag[]
+-- relatedInformation?: DiagnosticRelatedInformation[]
+-- }
+M.diagnostics_by_buf = {}
+
local split = vim.split
local function split_lines(value)
return split(value, '\n', true)
@@ -134,8 +159,8 @@ end
function M.apply_text_document_edit(text_document_edit)
local text_document = text_document_edit.textDocument
local bufnr = vim.uri_to_bufnr(text_document.uri)
- -- TODO(ashkan) check this is correct.
- if (M.buf_versions[bufnr] or 0) > text_document.version then
+ -- `VersionedTextDocumentIdentifier`s version may be nil https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier
+ if text_document.version ~= nil and M.buf_versions[bufnr] > text_document.version then
print("Buffer ", text_document.uri, " newer than edits.")
return
end
@@ -157,11 +182,23 @@ local function sort_completion_items(items)
end
end
+-- Returns text that should be inserted when selecting completion item. The precedence is as follows:
+-- textEdit.newText > insertText > label
+-- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+local function get_completion_word(item)
+ if item.textEdit ~= nil and item.textEdit.newText ~= nil then
+ return item.textEdit.newText
+ elseif item.insertText ~= nil then
+ return item.insertText
+ end
+ return item.label
+end
+
-- Some lanuguage servers return complementary candidates whose prefixes do not match are also returned.
-- So we exclude completion candidates whose prefix does not match.
local function remove_unmatch_completion_items(items, prefix)
return vim.tbl_filter(function(item)
- local word = item.insertText or item.label
+ local word = get_completion_word(item)
return vim.startswith(word, prefix)
end, items)
end
@@ -193,7 +230,7 @@ function M.text_document_completion_list_to_complete_items(result, prefix)
end
end
- local word = completion_item.insertText or completion_item.label
+ local word = get_completion_word(completion_item)
table.insert(matches, {
word = word,
abbr = completion_item.label,
@@ -275,6 +312,65 @@ function M.convert_input_to_markdown_lines(input, contents)
return contents
end
+--- Convert SignatureHelp response to markdown lines.
+-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
+function M.convert_signature_help_to_markdown_lines(signature_help)
+ if not signature_help.signatures then
+ return
+ end
+ --The active signature. If omitted or the value lies outside the range of
+ --`signatures` the value defaults to zero or is ignored if `signatures.length
+ --=== 0`. Whenever possible implementors should make an active decision about
+ --the active signature and shouldn't rely on a default value.
+ local contents = {}
+ local active_signature = signature_help.activeSignature or 0
+ -- If the activeSignature is not inside the valid range, then clip it.
+ if active_signature >= #signature_help.signatures then
+ active_signature = 0
+ end
+ local signature = signature_help.signatures[active_signature + 1]
+ if not signature then
+ return
+ end
+ vim.list_extend(contents, vim.split(signature.label, '\n', true))
+ if signature.documentation then
+ M.convert_input_to_markdown_lines(signature.documentation, contents)
+ end
+ if signature_help.parameters then
+ local active_parameter = signature_help.activeParameter or 0
+ -- If the activeParameter is not inside the valid range, then clip it.
+ if active_parameter >= #signature_help.parameters then
+ active_parameter = 0
+ end
+ local parameter = signature.parameters and signature.parameters[active_parameter]
+ if parameter then
+ --[=[
+ --Represents a parameter of a callable-signature. A parameter can
+ --have a label and a doc-comment.
+ interface ParameterInformation {
+ --The label of this parameter information.
+ --
+ --Either a string or an inclusive start and exclusive end offsets within its containing
+ --signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
+ --string representation as `Position` and `Range` does.
+ --
+ --*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`.
+ label: string | [number, number];
+ --The human-readable doc-comment of this parameter. Will be shown
+ --in the UI but can be omitted.
+ documentation?: string | MarkupContent;
+ }
+ --]=]
+ -- TODO highlight parameter
+ if parameter.documentation then
+ M.convert_input_help_to_markdown_lines(parameter.documentation, contents)
+ end
+ end
+ end
+ return contents
+end
+
function M.make_floating_popup_options(width, height, opts)
validate {
opts = { opts, 't', true };
@@ -526,31 +622,6 @@ function M.open_floating_preview(contents, filetype, opts)
return floating_bufnr, floating_winnr
end
-local function validate_lsp_position(pos)
- validate { pos = {pos, 't'} }
- validate {
- line = {pos.line, 'n'};
- character = {pos.character, 'n'};
- }
- return true
-end
-
-function M.open_floating_peek_preview(bufnr, start, finish, opts)
- validate {
- bufnr = {bufnr, 'n'};
- start = {start, validate_lsp_position, 'valid start Position'};
- finish = {finish, validate_lsp_position, 'valid finish Position'};
- opts = { opts, 't', true };
- }
- local width = math.max(finish.character - start.character + 1, 1)
- local height = math.max(finish.line - start.line + 1, 1)
- local floating_winnr = api.nvim_open_win(bufnr, false, M.make_floating_popup_options(width, height, opts))
- api.nvim_win_set_cursor(floating_winnr, {start.line+1, start.character})
- api.nvim_command("autocmd CursorMoved * ++once lua pcall(vim.api.nvim_win_close, "..floating_winnr..", true)")
- return floating_winnr
-end
-
-
local function highlight_range(bufnr, ns, hiname, start, finish)
if start[1] == finish[1] then
-- TODO care about encoding here since this is in byte index?
@@ -565,8 +636,6 @@ local function highlight_range(bufnr, ns, hiname, start, finish)
end
do
- local all_buffer_diagnostics = {}
-
local diagnostic_ns = api.nvim_create_namespace("vim_lsp_diagnostics")
local reference_ns = api.nvim_create_namespace("vim_lsp_references")
local sign_ns = 'vim_lsp_signs'
@@ -622,13 +691,12 @@ do
-- if #marks == 0 then
-- return
-- end
- -- local buffer_diagnostics = all_buffer_diagnostics[bufnr]
local lines = {"Diagnostics:"}
local highlights = {{0, "Bold"}}
- local buffer_diagnostics = all_buffer_diagnostics[bufnr]
+ local buffer_diagnostics = M.diagnostics_by_buf[bufnr]
if not buffer_diagnostics then return end
- local line_diagnostics = buffer_diagnostics[line]
+ local line_diagnostics = M.diagnostics_group_by_line(buffer_diagnostics)[line]
if not line_diagnostics then return end
for i, diagnostic in ipairs(line_diagnostics) do
@@ -639,6 +707,7 @@ do
-- TODO(ashkan) make format configurable?
local prefix = string.format("%d. ", i)
local hiname = severity_highlights[diagnostic.severity]
+ assert(hiname, 'unknown severity: ' .. tostring(diagnostic.severity))
local message_lines = split_lines(diagnostic.message)
table.insert(lines, prefix..message_lines[1])
table.insert(highlights, {#prefix + 1, hiname})
@@ -656,6 +725,8 @@ do
return popup_bufnr, winnr
end
+ --- Saves the diagnostics (Diagnostic[]) into diagnostics_by_buf
+ --
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
validate {
bufnr = {bufnr, 'n', true};
@@ -664,28 +735,15 @@ do
if not diagnostics then return end
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
- if not all_buffer_diagnostics[bufnr] then
+ if not M.diagnostics_by_buf[bufnr] then
-- Clean up our data when the buffer unloads.
api.nvim_buf_attach(bufnr, false, {
on_detach = function(b)
- all_buffer_diagnostics[b] = nil
+ M.diagnostics_by_buf[b] = nil
end
})
end
- all_buffer_diagnostics[bufnr] = {}
- local buffer_diagnostics = all_buffer_diagnostics[bufnr]
-
- for _, diagnostic in ipairs(diagnostics) do
- local start = diagnostic.range.start
- -- local mark_id = api.nvim_buf_set_extmark(bufnr, diagnostic_ns, 0, start.line, 0, {})
- -- buffer_diagnostics[mark_id] = diagnostic
- local line_diagnostics = buffer_diagnostics[start.line]
- if not line_diagnostics then
- line_diagnostics = {}
- buffer_diagnostics[start.line] = line_diagnostics
- end
- table.insert(line_diagnostics, diagnostic)
- end
+ M.diagnostics_by_buf[bufnr] = diagnostics
end
function M.buf_diagnostics_underline(bufnr, diagnostics)
@@ -729,15 +787,26 @@ do
end
end
- function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
- local buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
- if not buffer_line_diagnostics then
- M.buf_diagnostics_save_positions(bufnr, diagnostics)
+ function M.diagnostics_group_by_line(diagnostics)
+ if not diagnostics then return end
+ local diagnostics_by_line = {}
+ for _, diagnostic in ipairs(diagnostics) do
+ local start = diagnostic.range.start
+ local line_diagnostics = diagnostics_by_line[start.line]
+ if not line_diagnostics then
+ line_diagnostics = {}
+ diagnostics_by_line[start.line] = line_diagnostics
+ end
+ table.insert(line_diagnostics, diagnostic)
end
- buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
- if not buffer_line_diagnostics then
+ return diagnostics_by_line
+ end
+
+ function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
+ if not diagnostics then
return
end
+ local buffer_line_diagnostics = M.diagnostics_group_by_line(diagnostics)
for line, line_diags in pairs(buffer_line_diagnostics) do
local virt_texts = {}
for i = 1, #line_diags - 1 do
@@ -749,31 +818,29 @@ do
api.nvim_buf_set_virtual_text(bufnr, diagnostic_ns, line, virt_texts, {})
end
end
+
function M.buf_diagnostics_count(kind)
local bufnr = vim.api.nvim_get_current_buf()
- local buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
- if not buffer_line_diagnostics then return end
+ local diagnostics = M.diagnostics_by_buf[bufnr]
+ if not diagnostics then return end
local count = 0
- for _, line_diags in pairs(buffer_line_diagnostics) do
- for _, diag in ipairs(line_diags) do
- if protocol.DiagnosticSeverity[kind] == diag.severity then count = count + 1 end
+ for _, diagnostic in pairs(diagnostics) do
+ if protocol.DiagnosticSeverity[kind] == diagnostic.severity then
+ count = count + 1
end
end
return count
end
- function M.buf_diagnostics_signs(bufnr, diagnostics)
- vim.fn.sign_define('LspDiagnosticsErrorSign', {text=vim.g['LspDiagnosticsErrorSign'] or 'E', texthl='LspDiagnosticsError', linehl='', numhl=''})
- vim.fn.sign_define('LspDiagnosticsWarningSign', {text=vim.g['LspDiagnosticsWarningSign'] or 'W', texthl='LspDiagnosticsWarning', linehl='', numhl=''})
- vim.fn.sign_define('LspDiagnosticsInformationSign', {text=vim.g['LspDiagnosticsInformationSign'] or 'I', texthl='LspDiagnosticsInformation', linehl='', numhl=''})
- vim.fn.sign_define('LspDiagnosticsHintSign', {text=vim.g['LspDiagnosticsHintSign'] or 'H', texthl='LspDiagnosticsHint', linehl='', numhl=''})
+ local diagnostic_severity_map = {
+ [protocol.DiagnosticSeverity.Error] = "LspDiagnosticsErrorSign";
+ [protocol.DiagnosticSeverity.Warning] = "LspDiagnosticsWarningSign";
+ [protocol.DiagnosticSeverity.Information] = "LspDiagnosticsInformationSign";
+ [protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
+ }
+
+ function M.buf_diagnostics_signs(bufnr, diagnostics)
for _, diagnostic in ipairs(diagnostics) do
- local diagnostic_severity_map = {
- [protocol.DiagnosticSeverity.Error] = "LspDiagnosticsErrorSign";
- [protocol.DiagnosticSeverity.Warning] = "LspDiagnosticsWarningSign";
- [protocol.DiagnosticSeverity.Information] = "LspDiagnosticsInformationSign";
- [protocol.DiagnosticSeverity.Hint] = "LspDiagnosticsHintSign";
- }
vim.fn.sign_place(0, sign_ns, diagnostic_severity_map[diagnostic.severity], bufnr, {lnum=(diagnostic.range.start.line+1)})
end
end
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index e50eb307e5..dc62c9e744 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -5,6 +5,12 @@ set -u
# Use privileged mode, which e.g. skips using CDPATH.
set -p
+# Ensure that the user has a bash that supports -A
+if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
+ echo "This script requires bash version 3 or later (you have ${BASH_VERSION})." >&2
+ exit 1
+fi
+
readonly NVIM_SOURCE_DIR="${NVIM_SOURCE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
readonly VIM_SOURCE_DIR_DEFAULT="${NVIM_SOURCE_DIR}/.vim-src"
readonly VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}"
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 048b937136..df3a263dcf 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -63,8 +63,8 @@
#define FIXED_TEMP_ARRAY(name, fixsize) \
Array name = ARRAY_DICT_INIT; \
Object name##__items[fixsize]; \
- args.size = fixsize; \
- args.items = name##__items; \
+ name.size = fixsize; \
+ name.items = name##__items; \
#define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1})
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 2397af27cc..31423e79af 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -31,7 +31,9 @@
#define CSI 0x9b // Control Sequence Introducer
#define CSI_STR "\233"
#define DCS 0x90 // Device Control String
+#define DCS_STR "\033P"
#define STERM 0x9c // String Terminator
+#define STERM_STR "\033\\"
#define POUND 0xA3
diff --git a/src/nvim/change.c b/src/nvim/change.c
index a341b8fce1..51afb40b40 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -361,8 +361,8 @@ void changed_bytes(linenr_T lnum, colnr_T col)
/// insert/delete bytes at column
///
-/// Like changed_bytes() but also adjust extmark for "added" bytes.
-/// When "added" is negative text was deleted.
+/// Like changed_bytes() but also adjust extmark for "new" bytes.
+/// When "new" is negative text was deleted.
static void inserted_bytes(linenr_T lnum, colnr_T col, int old, int new)
{
if (curbuf_splice_pending == 0) {
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index d1a53fa4b6..0e87f7c6c1 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -16,6 +16,11 @@
# include "event/stream.c.generated.h"
#endif
+// For compatbility with libuv < 1.19.0 (tested on 1.18.0)
+#if UV_VERSION_MINOR < 19
+#define uv_stream_get_write_queue_size(stream) stream->write_queue_size
+#endif
+
/// Sets the stream associated with `fd` to "blocking" mode.
///
/// @return `0` on success, or libuv error code on failure.
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index f18395e6cc..8a0f2e634a 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -882,7 +882,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, kExtmarkNOOP);
FOR_ALL_TAB_WINDOWS(tab, win) {
if (win->w_buffer == curbuf) {
- foldMoveRange(&win->w_folds, line1, line2, dest);
+ foldMoveRange(win, &win->w_folds, line1, line2, dest);
}
}
curbuf->b_op_start.lnum = dest - num_lines + 1;
@@ -891,7 +891,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, kExtmarkNOOP);
FOR_ALL_TAB_WINDOWS(tab, win) {
if (win->w_buffer == curbuf) {
- foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
+ foldMoveRange(win, &win->w_folds, dest + 1, line1 - 1, line2);
}
}
curbuf->b_op_start.lnum = dest + 1;
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 38d111f2aa..1457a1172d 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -578,6 +578,15 @@ void extmark_splice(buf_T *buf,
}
}
+void extmark_splice_cols(buf_T *buf,
+ int start_row, colnr_T start_col,
+ colnr_T old_col, colnr_T new_col,
+ ExtmarkOp undo)
+{
+ extmark_splice(buf, start_row, start_col,
+ 0, old_col,
+ 0, new_col, undo);
+}
void extmark_move_region(buf_T *buf,
int start_row, colnr_T start_col,
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 88e9390c65..8da1c94219 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -62,6 +62,11 @@
#define BUFSIZE 8192 /* size of normal write buffer */
#define SMBUFSIZE 256 /* size of emergency write buffer */
+// For compatibility with libuv < 1.20.0 (tested on 1.18.0)
+#ifndef UV_FS_COPYFILE_FICLONE
+#define UV_FS_COPYFILE_FICLONE 0
+#endif
+
//
// The autocommands are stored in a list for each event.
// Autocommands for the same pattern, that are consecutive, are joined
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 405f15d751..61a85171e8 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -642,15 +642,17 @@ void foldCreate(win_T *wp, linenr_T start, linenr_T end)
/* We want the new fold to be closed. If it would remain open because
* of using 'foldlevel', need to adjust fd_flags of containing folds.
*/
- if (use_level && !closed && level < curwin->w_p_fdl)
+ if (use_level && !closed && level < wp->w_p_fdl) {
closeFold(start, 1L);
- if (!use_level)
- curwin->w_fold_manual = true;
+ }
+ if (!use_level) {
+ wp->w_fold_manual = true;
+ }
fp->fd_flags = FD_CLOSED;
fp->fd_small = kNone;
- /* redraw */
- changed_window_setting();
+ // redraw
+ changed_window_setting_win(wp);
}
}
@@ -711,7 +713,7 @@ void deleteFold(
lnum = found_fp->fd_top + found_fp->fd_len + found_off;
if (foldmethodIsManual(wp)) {
- deleteFoldEntry(found_ga,
+ deleteFoldEntry(wp, found_ga,
(int)(found_fp - (fold_T *)found_ga->ga_data),
recursive);
} else {
@@ -724,22 +726,24 @@ void deleteFold(
if (!did_one) {
parseMarker(wp);
}
- deleteFoldMarkers(found_fp, recursive, found_off);
+ deleteFoldMarkers(wp, found_fp, recursive, found_off);
}
did_one = true;
- /* redraw window */
- changed_window_setting();
+ // redraw window
+ changed_window_setting_win(wp);
}
}
if (!did_one) {
EMSG(_(e_nofold));
- /* Force a redraw to remove the Visual highlighting. */
- if (had_visual)
- redraw_curbuf_later(INVERTED);
- } else
- /* Deleting markers may make cursor column invalid. */
- check_cursor_col();
+ // Force a redraw to remove the Visual highlighting.
+ if (had_visual) {
+ redraw_buf_later(wp->w_buffer, INVERTED);
+ }
+ } else {
+ // Deleting markers may make cursor column invalid
+ check_cursor_col_win(wp);
+ }
if (last_lnum > 0) {
// TODO(teto): pass the buffer
@@ -751,7 +755,7 @@ void deleteFold(
// the modification of the *first* line of the fold, but we send through a
// notification that includes every line that was part of the fold
int64_t num_changed = last_lnum - first_lnum;
- buf_updates_send_changes(curbuf, first_lnum, num_changed,
+ buf_updates_send_changes(wp->w_buffer, first_lnum, num_changed,
num_changed, true);
}
}
@@ -1303,7 +1307,7 @@ static void foldOpenNested(fold_T *fpr)
// Delete fold "idx" from growarray "gap".
// When "recursive" is true also delete all the folds contained in it.
// When "recursive" is false contained folds are moved one level up.
-static void deleteFoldEntry(garray_T *const gap, const int idx,
+static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
const bool recursive)
{
fold_T *fp = (fold_T *)gap->ga_data + idx;
@@ -1369,13 +1373,17 @@ void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long
line2 = line1 - amount_after - 1;
/* If appending a line in Insert mode, it should be included in the fold
* just above the line. */
- if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM)
- --line1;
- foldMarkAdjustRecurse(&wp->w_folds, line1, line2, amount, amount_after);
+ if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) {
+ line1--;
+ }
+ foldMarkAdjustRecurse(wp, &wp->w_folds, line1, line2, amount, amount_after);
}
-/* foldMarkAdjustRecurse() {{{2 */
-static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, long amount, long amount_after)
+// foldMarkAdjustRecurse() {{{2
+static void foldMarkAdjustRecurse(
+ win_T *wp, garray_T *gap,
+ linenr_T line1, linenr_T line2, long amount, long amount_after
+)
{
fold_T *fp;
linenr_T last;
@@ -1423,7 +1431,7 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2,
// 4. fold completely contained in range
if (amount == MAXLNUM) {
// Deleting lines: delete the fold completely
- deleteFoldEntry(gap, i, true);
+ deleteFoldEntry(wp, gap, i, true);
i--; // adjust index for deletion
fp--;
} else {
@@ -1431,9 +1439,9 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2,
}
} else {
if (fp->fd_top < top) {
- /* 2 or 3: need to correct nested folds too */
- foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top,
- line2 - fp->fd_top, amount, amount_after);
+ // 2 or 3: need to correct nested folds too
+ foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top,
+ line2 - fp->fd_top, amount, amount_after);
if (last <= line2) {
/* 2. fold contains line1, line2 is below fold */
if (amount == MAXLNUM)
@@ -1448,13 +1456,13 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2,
/* 5. fold is below line1 and contains line2; need to
* correct nested folds too */
if (amount == MAXLNUM) {
- foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top,
+ foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top,
line2 - fp->fd_top, amount,
amount_after + (fp->fd_top - top));
fp->fd_len -= line2 - fp->fd_top + 1;
fp->fd_top = line1;
} else {
- foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top,
+ foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top,
line2 - fp->fd_top, amount,
amount_after - amount);
fp->fd_len += amount_after - amount;
@@ -1497,16 +1505,18 @@ static int getDeepestNestingRecurse(garray_T *gap)
/// Check if a fold is closed and update the info needed to check nested folds.
///
/// @param[in,out] use_levelp true: outer fold had FD_LEVEL
+/// @param[in,out] fp fold to check
/// @param level folding depth
-/// @param[out] maybe_smallp TRUE: outer this had fd_small == kNone
+/// @param[out] maybe_smallp true: outer this had fd_small == kNone
/// @param lnum_off line number offset for fp->fd_top
+/// @return true if fold is closed
static bool check_closed(
win_T *const wp,
fold_T *const fp,
- bool *const use_levelp, // true: outer fold had FD_LEVEL
- const int level, // folding depth
- bool *const maybe_smallp, // true: outer this had fd_small == kNone
- const linenr_T lnum_off // line number offset for fp->fd_top
+ bool *const use_levelp,
+ const int level,
+ bool *const maybe_smallp,
+ const linenr_T lnum_off
)
{
bool closed = false;
@@ -1552,13 +1562,13 @@ checkSmall(
// Mark any nested folds to maybe-small
setSmallMaybe(&fp->fd_nested);
- if (fp->fd_len > curwin->w_p_fml) {
+ if (fp->fd_len > wp->w_p_fml) {
fp->fd_small = kFalse;
} else {
int count = 0;
for (int n = 0; n < fp->fd_len; n++) {
count += plines_win_nofold(wp, fp->fd_top + lnum_off + n);
- if (count > curwin->w_p_fml) {
+ if (count > wp->w_p_fml) {
fp->fd_small = kFalse;
return;
}
@@ -1604,7 +1614,7 @@ static void foldCreateMarkers(win_T *wp, linenr_T start, linenr_T end)
// u_save() is unable to save the buffer line, but we send the
// nvim_buf_lines_event anyway since it won't do any harm.
int64_t num_changed = 1 + end - start;
- buf_updates_send_changes(curbuf, start, num_changed, num_changed, true);
+ buf_updates_send_changes(buf, start, num_changed, num_changed, true);
}
/* foldAddMarker() {{{2 */
@@ -1621,7 +1631,7 @@ static void foldAddMarker(
bool line_is_comment = false;
// Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end
- line = ml_get(lnum);
+ line = ml_get_buf(buf, lnum, false);
size_t line_len = STRLEN(line);
size_t added = 0;
@@ -1640,11 +1650,10 @@ static void foldAddMarker(
STRCPY(newline + line_len + (p - cms) + markerlen, p + 2);
added = markerlen + STRLEN(cms)-2;
}
- ml_replace(lnum, newline, false);
+ ml_replace_buf(buf, lnum, newline, false);
if (added) {
- extmark_splice(buf, (int)lnum-1, (int)line_len,
- 0, 0,
- 0, (int)added, kExtmarkUndo);
+ extmark_splice_cols(buf, (int)lnum-1, (int)line_len,
+ 0, (int)added, kExtmarkUndo);
}
}
}
@@ -1655,20 +1664,22 @@ static void foldAddMarker(
*/
static void
deleteFoldMarkers(
+ win_T *wp,
fold_T *fp,
int recursive,
linenr_T lnum_off // offset for fp->fd_top
)
{
if (recursive) {
- for (int i = 0; i < fp->fd_nested.ga_len; ++i) {
- deleteFoldMarkers((fold_T *)fp->fd_nested.ga_data + i, TRUE,
+ for (int i = 0; i < fp->fd_nested.ga_len; i++) {
+ deleteFoldMarkers(wp, (fold_T *)fp->fd_nested.ga_data + i, true,
lnum_off + fp->fd_top);
}
}
- foldDelMarker(fp->fd_top + lnum_off, curwin->w_p_fmr, foldstartmarkerlen);
- foldDelMarker(fp->fd_top + lnum_off + fp->fd_len - 1, foldendmarker,
- foldendmarkerlen);
+ foldDelMarker(wp->w_buffer, fp->fd_top+lnum_off, wp->w_p_fmr,
+ foldstartmarkerlen);
+ foldDelMarker(wp->w_buffer, fp->fd_top + lnum_off + fp->fd_len - 1,
+ foldendmarker, foldendmarkerlen);
}
// foldDelMarker() {{{2
@@ -1677,18 +1688,20 @@ deleteFoldMarkers(
// Delete 'commentstring' if it matches.
// If the marker is not found, there is no error message. Could be a missing
// close-marker.
-static void foldDelMarker(linenr_T lnum, char_u *marker, size_t markerlen)
+static void foldDelMarker(
+ buf_T *buf, linenr_T lnum, char_u *marker, size_t markerlen
+)
{
char_u *newline;
- char_u *cms = curbuf->b_p_cms;
+ char_u *cms = buf->b_p_cms;
char_u *cms2;
// end marker may be missing and fold extends below the last line
- if (lnum > curbuf->b_ml.ml_line_count) {
+ if (lnum > buf->b_ml.ml_line_count) {
return;
}
- char_u *line = ml_get(lnum);
- for (char_u *p = line; *p != NUL; ++p) {
+ char_u *line = ml_get_buf(buf, lnum, false);
+ for (char_u *p = line; *p != NUL; p++) {
if (STRNCMP(p, marker, markerlen) != 0) {
continue;
}
@@ -1712,10 +1725,10 @@ static void foldDelMarker(linenr_T lnum, char_u *marker, size_t markerlen)
assert(p >= line);
memcpy(newline, line, (size_t)(p - line));
STRCPY(newline + (p - line), p + len);
- ml_replace(lnum, newline, false);
- extmark_splice(curbuf, (int)lnum-1, (int)(p - line),
- 0, (int)len,
- 0, 0, kExtmarkUndo);
+ ml_replace_buf(buf, lnum, newline, false);
+ extmark_splice_cols(buf, (int)lnum-1, (int)(p - line),
+ (int)len,
+ 0, kExtmarkUndo);
}
break;
}
@@ -1903,13 +1916,12 @@ void foldtext_cleanup(char_u *str)
/* foldUpdateIEMS() {{{2 */
/*
* Update the folding for window "wp", at least from lines "top" to "bot".
- * Return TRUE if any folds did change.
* IEMS = "Indent Expr Marker Syntax"
*/
static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
{
fline_T fline;
- void (*getlevel)(fline_T *);
+ LevelGetter getlevel = NULL;
fold_T *fp;
/* Avoid problems when being called recursively. */
@@ -2091,8 +2103,8 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
}
}
- /* There can't be any folds from start until end now. */
- foldRemove(&wp->w_folds, start, end);
+ // There can't be any folds from start until end now.
+ foldRemove(wp, &wp->w_folds, start, end);
/* If some fold changed, need to redraw and position cursor. */
if (fold_changed && wp->w_p_fen)
@@ -2272,12 +2284,12 @@ static linenr_T foldUpdateIEMSRecurse(
if (fp->fd_top > firstlnum) {
// We will move the start of this fold up, hence we move all
// nested folds (with relative line numbers) down.
- foldMarkAdjustRecurse(&fp->fd_nested,
+ foldMarkAdjustRecurse(flp->wp, &fp->fd_nested,
(linenr_T)0, (linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum), 0L);
} else {
// Will move fold down, move nested folds relatively up.
- foldMarkAdjustRecurse(&fp->fd_nested,
+ foldMarkAdjustRecurse(flp->wp, &fp->fd_nested,
(linenr_T)0,
(long)(firstlnum - fp->fd_top - 1),
(linenr_T)MAXLNUM,
@@ -2307,10 +2319,10 @@ static linenr_T foldUpdateIEMSRecurse(
breakstart = flp->lnum;
breakend = flp->lnum;
}
- foldRemove(&fp->fd_nested, breakstart - fp->fd_top,
+ foldRemove(flp->wp, &fp->fd_nested, breakstart - fp->fd_top,
breakend - fp->fd_top);
i = (int)(fp - (fold_T *)gap->ga_data);
- foldSplit(gap, i, breakstart, breakend - 1);
+ foldSplit(flp->wp->w_buffer, gap, i, breakstart, breakend - 1);
fp = (fold_T *)gap->ga_data + i + 1;
/* If using the "marker" or "syntax" method, we
* need to continue until the end of the fold is
@@ -2326,7 +2338,7 @@ static linenr_T foldUpdateIEMSRecurse(
if (i != 0) {
fp2 = fp - 1;
if (fp2->fd_top + fp2->fd_len == fp->fd_top) {
- foldMerge(fp2, gap, fp);
+ foldMerge(flp->wp, fp2, gap, fp);
fp = fp2;
}
}
@@ -2337,12 +2349,13 @@ static linenr_T foldUpdateIEMSRecurse(
// A fold that starts at or after startlnum and stops
// before the new fold must be deleted. Continue
// looking for the next one.
- deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), true);
+ deleteFoldEntry(flp->wp, gap,
+ (int)(fp - (fold_T *)gap->ga_data), true);
} else {
/* A fold has some lines above startlnum, truncate it
* to stop just above startlnum. */
fp->fd_len = startlnum - fp->fd_top;
- foldMarkAdjustRecurse(&fp->fd_nested,
+ foldMarkAdjustRecurse(flp->wp, &fp->fd_nested,
(linenr_T)fp->fd_len, (linenr_T)MAXLNUM,
(linenr_T)MAXLNUM, 0L);
fold_changed = true;
@@ -2471,8 +2484,8 @@ static linenr_T foldUpdateIEMSRecurse(
// Delete contained folds from the end of the last one found until where
// we stopped looking.
- foldRemove(&fp->fd_nested, startlnum2 - fp->fd_top,
- flp->lnum - 1 - fp->fd_top);
+ foldRemove(flp->wp, &fp->fd_nested, startlnum2 - fp->fd_top,
+ flp->lnum - 1 - fp->fd_top);
if (lvl < level) {
// End of fold found, update the length when it got shorter.
@@ -2490,7 +2503,7 @@ static linenr_T foldUpdateIEMSRecurse(
// indent or expr method: split fold to create a new one
// below bot
i = (int)(fp - (fold_T *)gap->ga_data);
- foldSplit(gap, i, flp->lnum, bot);
+ foldSplit(flp->wp->w_buffer, gap, i, flp->lnum, bot);
fp = (fold_T *)gap->ga_data + i;
}
} else {
@@ -2508,23 +2521,23 @@ static linenr_T foldUpdateIEMSRecurse(
break;
if (fp2->fd_top + fp2->fd_len > flp->lnum) {
if (fp2->fd_top < flp->lnum) {
- /* Make fold that includes lnum start at lnum. */
- foldMarkAdjustRecurse(&fp2->fd_nested,
- (linenr_T)0, (long)(flp->lnum - fp2->fd_top - 1),
- (linenr_T)MAXLNUM, (long)(fp2->fd_top - flp->lnum));
+ // Make fold that includes lnum start at lnum.
+ foldMarkAdjustRecurse(flp->wp, &fp2->fd_nested,
+ (linenr_T)0, (long)(flp->lnum - fp2->fd_top - 1),
+ (linenr_T)MAXLNUM, (long)(fp2->fd_top-flp->lnum));
fp2->fd_len -= flp->lnum - fp2->fd_top;
fp2->fd_top = flp->lnum;
fold_changed = true;
}
if (lvl >= level) {
- /* merge new fold with existing fold that follows */
- foldMerge(fp, gap, fp2);
+ // merge new fold with existing fold that follows
+ foldMerge(flp->wp, fp, gap, fp2);
}
break;
}
fold_changed = true;
- deleteFoldEntry(gap, (int)(fp2 - (fold_T *)gap->ga_data), true);
+ deleteFoldEntry(flp->wp, gap, (int)(fp2 - (fold_T *)gap->ga_data), true);
}
/* Need to redraw the lines we inspected, which might be further down than
@@ -2560,8 +2573,10 @@ static void foldInsert(garray_T *gap, int i)
* The caller must first have taken care of any nested folds from "top" to
* "bot"!
*/
-static void foldSplit(garray_T *const gap, const int i, const linenr_T top,
- const linenr_T bot)
+static void foldSplit(buf_T *buf, garray_T *const gap,
+ const int i, const linenr_T top,
+ const linenr_T bot
+ )
{
fold_T *fp2;
@@ -2616,7 +2631,9 @@ static void foldSplit(garray_T *const gap, const int i, const linenr_T top,
* 5: made to start below "bot".
* 6: not changed
*/
-static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
+static void foldRemove(
+ win_T *const wp, garray_T *gap, linenr_T top, linenr_T bot
+)
{
fold_T *fp = NULL;
@@ -2628,10 +2645,11 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
// Find fold that includes top or a following one.
if (foldFind(gap, top, &fp) && fp->fd_top < top) {
// 2: or 3: need to delete nested folds
- foldRemove(&fp->fd_nested, top - fp->fd_top, bot - fp->fd_top);
+ foldRemove(wp, &fp->fd_nested, top - fp->fd_top, bot - fp->fd_top);
if (fp->fd_top + fp->fd_len - 1 > bot) {
// 3: need to split it.
- foldSplit(gap, (int)(fp - (fold_T *)gap->ga_data), top, bot);
+ foldSplit(wp->w_buffer, gap,
+ (int)(fp - (fold_T *)gap->ga_data), top, bot);
} else {
// 2: truncate fold at "top".
fp->fd_len = top - fp->fd_top;
@@ -2649,7 +2667,8 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
fold_changed = true;
if (fp->fd_top + fp->fd_len - 1 > bot) {
// 5: Make fold that includes bot start below bot.
- foldMarkAdjustRecurse(&fp->fd_nested,
+ foldMarkAdjustRecurse(
+ wp, &fp->fd_nested,
(linenr_T)0, (long)(bot - fp->fd_top),
(linenr_T)MAXLNUM, (long)(fp->fd_top - bot - 1));
fp->fd_len -= bot - fp->fd_top + 1;
@@ -2658,7 +2677,7 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot)
}
// 4: Delete completely contained fold.
- deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), true);
+ deleteFoldEntry(wp, gap, (int)(fp - (fold_T *)gap->ga_data), true);
}
}
}
@@ -2710,19 +2729,22 @@ static void foldReverseOrder(
// 8. truncated below dest and shifted up.
// 9. shifted up
// 10. not changed
-static void truncate_fold(fold_T *fp, linenr_T end)
+static void truncate_fold(win_T *const wp, fold_T *fp, linenr_T end)
{
// I want to stop *at here*, foldRemove() stops *above* top
end += 1;
- foldRemove(&fp->fd_nested, end - fp->fd_top, MAXLNUM);
+ foldRemove(wp, &fp->fd_nested, end - fp->fd_top, MAXLNUM);
fp->fd_len = end - fp->fd_top;
}
#define FOLD_END(fp) ((fp)->fd_top + (fp)->fd_len - 1)
#define VALID_FOLD(fp, gap) ((fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
#define FOLD_INDEX(fp, gap) ((size_t)(fp - ((fold_T *)(gap)->ga_data)))
-void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
- const linenr_T dest)
+void foldMoveRange(
+ win_T *const wp, garray_T *gap,
+ const linenr_T line1, const linenr_T line2,
+ const linenr_T dest
+)
{
fold_T *fp;
const linenr_T range_len = line2 - line1 + 1;
@@ -2733,20 +2755,20 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
if (FOLD_END(fp) > dest) {
// Case 4 -- don't have to change this fold, but have to move nested
// folds.
- foldMoveRange(&fp->fd_nested, line1 - fp->fd_top, line2 -
+ foldMoveRange(wp, &fp->fd_nested, line1 - fp->fd_top, line2 -
fp->fd_top, dest - fp->fd_top);
return;
} else if (FOLD_END(fp) > line2) {
// Case 3 -- Remove nested folds between line1 and line2 & reduce the
// length of fold by "range_len".
// Folds after this one must be dealt with.
- foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top,
+ foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top,
line2 - fp->fd_top, MAXLNUM, -range_len);
fp->fd_len -= range_len;
} else {
// Case 2 -- truncate fold *above* line1.
// Folds after this one must be dealt with.
- truncate_fold(fp, line1 - 1);
+ truncate_fold(wp, fp, line1 - 1);
}
// Look at the next fold, and treat that one as if it were the first after
// "line1" (because now it is).
@@ -2764,13 +2786,13 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
}
if (VALID_FOLD(fp, gap) && fp->fd_top <= dest) {
// Case 8. -- ensure truncated at dest, shift up
- truncate_fold(fp, dest);
+ truncate_fold(wp, fp, dest);
fp->fd_top -= range_len;
}
return;
} else if (FOLD_END(fp) > dest) {
// Case 7 -- remove nested folds and shrink
- foldMarkAdjustRecurse(&fp->fd_nested, line2 + 1 - fp->fd_top,
+ foldMarkAdjustRecurse(wp, &fp->fd_nested, line2 + 1 - fp->fd_top,
dest - fp->fd_top, MAXLNUM, -move_len);
fp->fd_len -= move_len;
fp->fd_top += move_len;
@@ -2786,7 +2808,7 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
// 5, or 6
if (FOLD_END(fp) > line2) {
// 6, truncate before moving
- truncate_fold(fp, line2);
+ truncate_fold(wp, fp, line2);
}
fp->fd_top += move_len;
continue;
@@ -2798,7 +2820,7 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
}
if (FOLD_END(fp) > dest) {
- truncate_fold(fp, dest);
+ truncate_fold(wp, fp, dest);
}
fp->fd_top -= range_len;
@@ -2830,7 +2852,7 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2,
* The resulting fold is "fp1", nested folds are moved from "fp2" to "fp1".
* Fold entry "fp2" in "gap" is deleted.
*/
-static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2)
+static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
{
fold_T *fp3;
fold_T *fp4;
@@ -2840,8 +2862,9 @@ static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2)
/* If the last nested fold in fp1 touches the first nested fold in fp2,
* merge them recursively. */
- if (foldFind(gap1, fp1->fd_len - 1L, &fp3) && foldFind(gap2, 0L, &fp4))
- foldMerge(fp3, gap2, fp4);
+ if (foldFind(gap1, fp1->fd_len - 1L, &fp3) && foldFind(gap2, 0L, &fp4)) {
+ foldMerge(wp, fp3, gap2, fp4);
+ }
/* Move nested folds in fp2 to the end of fp1. */
if (!GA_EMPTY(gap2)) {
@@ -2856,7 +2879,7 @@ static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2)
}
fp1->fd_len += fp2->fd_len;
- deleteFoldEntry(gap, (int)(fp2 - (fold_T *)gap->ga_data), true);
+ deleteFoldEntry(wp, gap, (int)(fp2 - (fold_T *)gap->ga_data), true);
fold_changed = true;
}
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index 4753df7b87..51d9549033 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -271,17 +271,22 @@ static const char *input_cb(void *payload, uint32_t byte_index,
}
char_u *line = ml_get_buf(bp, position.row+1, false);
size_t len = STRLEN(line);
- size_t tocopy = MIN(len-position.column, BUFSIZE);
-
- memcpy(buf, line+position.column, tocopy);
- // Translate embedded \n to NUL
- memchrsub(buf, '\n', '\0', tocopy);
- *bytes_read = (uint32_t)tocopy;
- if (tocopy < BUFSIZE) {
- // now add the final \n. If it didn't fit, input_cb will be called again
- // on the same line with advanced column.
- buf[tocopy] = '\n';
- (*bytes_read)++;
+
+ if (position.column > len) {
+ *bytes_read = 0;
+ } else {
+ size_t tocopy = MIN(len-position.column, BUFSIZE);
+
+ memcpy(buf, line+position.column, tocopy);
+ // Translate embedded \n to NUL
+ memchrsub(buf, '\n', '\0', tocopy);
+ *bytes_read = (uint32_t)tocopy;
+ if (tocopy < BUFSIZE) {
+ // now add the final \n. If it didn't fit, input_cb will be called again
+ // on the same line with advanced column.
+ buf[tocopy] = '\n';
+ (*bytes_read)++;
+ }
}
return buf;
#undef BUFSIZE
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index b695d0e139..6e074b3249 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -2390,21 +2390,32 @@ static int ml_append_int(
void ml_add_deleted_len(char_u *ptr, ssize_t len)
{
+ ml_add_deleted_len_buf(curbuf, ptr, len);
+}
+
+void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len)
+{
if (inhibit_delete_count) {
return;
}
if (len == -1) {
len = STRLEN(ptr);
}
- curbuf->deleted_bytes += len+1;
- if (curbuf->update_need_codepoints) {
- mb_utflen(ptr, len, &curbuf->deleted_codepoints,
- &curbuf->deleted_codeunits);
- curbuf->deleted_codepoints++; // NL char
- curbuf->deleted_codeunits++;
+ buf->deleted_bytes += len+1;
+ if (buf->update_need_codepoints) {
+ mb_utflen(ptr, len, &buf->deleted_codepoints,
+ &buf->deleted_codeunits);
+ buf->deleted_codepoints++; // NL char
+ buf->deleted_codeunits++;
}
}
+
+int ml_replace(linenr_T lnum, char_u *line, bool copy)
+{
+ return ml_replace_buf(curbuf, lnum, line, copy);
+}
+
/*
* Replace line lnum, with buffering, in current buffer.
*
@@ -2416,36 +2427,37 @@ void ml_add_deleted_len(char_u *ptr, ssize_t len)
*
* return FAIL for failure, OK otherwise
*/
-int ml_replace(linenr_T lnum, char_u *line, bool copy)
+int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy)
{
if (line == NULL) /* just checking... */
return FAIL;
- /* When starting up, we might still need to create the memfile */
- if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
+ // When starting up, we might still need to create the memfile
+ if (buf->b_ml.ml_mfp == NULL && open_buffer(false, NULL, 0) == FAIL) {
return FAIL;
+ }
bool readlen = true;
if (copy) {
line = vim_strsave(line);
}
- if (curbuf->b_ml.ml_line_lnum != lnum) { // other line buffered
- ml_flush_line(curbuf); // flush it
- } else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated
- ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, -1);
+ if (buf->b_ml.ml_line_lnum != lnum) { // other line buffered
+ ml_flush_line(buf); // flush it
+ } else if (buf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated
+ ml_add_deleted_len(buf->b_ml.ml_line_ptr, -1);
readlen = false; // already added the length
- xfree(curbuf->b_ml.ml_line_ptr); // free it
+ xfree(buf->b_ml.ml_line_ptr); // free it
}
- if (readlen && kv_size(curbuf->update_callbacks)) {
- ml_add_deleted_len(ml_get_buf(curbuf, lnum, false), -1);
+ if (readlen && kv_size(buf->update_callbacks)) {
+ ml_add_deleted_len(ml_get_buf(buf, lnum, false), -1);
}
- curbuf->b_ml.ml_line_ptr = line;
- curbuf->b_ml.ml_line_lnum = lnum;
- curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
+ buf->b_ml.ml_line_ptr = line;
+ buf->b_ml.ml_line_lnum = lnum;
+ buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
return OK;
}
@@ -3989,8 +4001,8 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
int ffdos = !no_ff && (get_fileformat(buf) == EOL_DOS);
int extra = 0;
- /* take care of cached line first */
- ml_flush_line(curbuf);
+ // take care of cached line first
+ ml_flush_line(buf);
if (buf->b_ml.ml_usedchunks == -1
|| buf->b_ml.ml_chunksize == NULL
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 4eb1107cd4..eae52ff260 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -619,11 +619,9 @@ static void set_runtimepath_default(void)
#undef NVIM_SIZE
-/*
- * Initialize the options, first part.
- *
- * Called only once from main(), just after creating the first buffer.
- */
+/// Initialize the options, first part.
+///
+/// Called only once from main(), just after creating the first buffer.
void set_init_1(void)
{
int opt_idx;
@@ -868,10 +866,8 @@ void set_init_1(void)
set_helplang_default(get_mess_lang());
}
-/*
- * Set an option to its default value.
- * This does not take care of side effects!
- */
+/// Set an option to its default value.
+/// This does not take care of side effects!
static void
set_option_default(
int opt_idx,
@@ -942,9 +938,7 @@ set_option_default(
set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
}
-/*
- * Set all options (except terminal options) to their default value.
- */
+/// Set all options (except terminal options) to their default value.
static void
set_options_default(
int opt_flags // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
@@ -987,10 +981,8 @@ static void set_string_default(const char *name, char *val, bool allocated)
}
}
-/*
- * Set the Vi-default value of a number option.
- * Used for 'lines' and 'columns'.
- */
+/// Set the Vi-default value of a number option.
+/// Used for 'lines' and 'columns'.
void set_number_default(char *name, long val)
{
int opt_idx;
@@ -1117,10 +1109,8 @@ void set_init_3(void)
set_title_defaults(); // 'title', 'icon'
}
-/*
- * When 'helplang' is still at its default value, set it to "lang".
- * Only the first two characters of "lang" are used.
- */
+/// When 'helplang' is still at its default value, set it to "lang".
+/// Only the first two characters of "lang" are used.
void set_helplang_default(const char *lang)
{
if (lang == NULL) {
@@ -1152,13 +1142,11 @@ void set_helplang_default(const char *lang)
}
-/*
- * 'title' and 'icon' only default to true if they have not been set or reset
- * in .vimrc and we can read the old value.
- * When 'title' and 'icon' have been reset in .vimrc, we won't even check if
- * they can be reset. This reduces startup time when using X on a remote
- * machine.
- */
+/// 'title' and 'icon' only default to true if they have not been set or reset
+/// in .vimrc and we can read the old value.
+/// When 'title' and 'icon' have been reset in .vimrc, we won't even check if
+/// they can be reset. This reduces startup time when using X on a remote
+/// machine.
void set_title_defaults(void)
{
int idx1;
@@ -2023,10 +2011,8 @@ static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c)
return errbuf;
}
-/*
- * Convert a key name or string into a key value.
- * Used for 'wildchar' and 'cedit' options.
- */
+/// Convert a key name or string into a key value.
+/// Used for 'wildchar' and 'cedit' options.
static int string_to_key(char_u *arg)
{
if (*arg == '<') {
@@ -2038,10 +2024,8 @@ static int string_to_key(char_u *arg)
return *arg;
}
-/*
- * Check value of 'cedit' and set cedit_key.
- * Returns NULL if value is OK, error message otherwise.
- */
+/// Check value of 'cedit' and set cedit_key.
+/// Returns NULL if value is OK, error message otherwise.
static char_u *check_cedit(void)
{
int n;
@@ -2125,13 +2109,11 @@ void set_options_bin(
}
}
-/*
- * Find the parameter represented by the given character (eg ', :, ", or /),
- * and return its associated value in the 'shada' string.
- * Only works for number parameters, not for 'r' or 'n'.
- * If the parameter is not specified in the string or there is no following
- * number, return -1.
- */
+/// Find the parameter represented by the given character (eg ', :, ", or /),
+/// and return its associated value in the 'shada' string.
+/// Only works for number parameters, not for 'r' or 'n'.
+/// If the parameter is not specified in the string or there is no following
+/// number, return -1.
int get_shada_parameter(int type)
{
char_u *p;
@@ -2143,11 +2125,9 @@ int get_shada_parameter(int type)
return -1;
}
-/*
- * Find the parameter represented by the given character (eg ''', ':', '"', or
- * '/') in the 'shada' option and return a pointer to the string after it.
- * Return NULL if the parameter is not specified in the string.
- */
+/// Find the parameter represented by the given character (eg ''', ':', '"', or
+/// '/') in the 'shada' option and return a pointer to the string after it.
+/// Return NULL if the parameter is not specified in the string.
char_u *find_shada_parameter(int type)
{
char_u *p;
@@ -2167,12 +2147,10 @@ char_u *find_shada_parameter(int type)
return NULL;
}
-/*
- * Expand environment variables for some string options.
- * These string options cannot be indirect!
- * If "val" is NULL expand the current value of the option.
- * Return pointer to NameBuff, or NULL when not expanded.
- */
+/// Expand environment variables for some string options.
+/// These string options cannot be indirect!
+/// If "val" is NULL expand the current value of the option.
+/// Return pointer to NameBuff, or NULL when not expanded.
static char_u *option_expand(int opt_idx, char_u *val)
{
// if option doesn't need expansion nothing to do
@@ -2256,9 +2234,7 @@ static void didset_options2(void)
check_opt_wim();
}
-/*
- * Check for string options that are NULL (normally only termcap options).
- */
+/// Check for string options that are NULL (normally only termcap options).
void check_options(void)
{
int opt_idx;
@@ -2270,9 +2246,7 @@ void check_options(void)
}
}
-/*
- * Check string options in a buffer for NULL value.
- */
+/// Check string options in a buffer for NULL value.
void check_buf_options(buf_T *buf)
{
check_string_option(&buf->b_p_bh);
@@ -2325,13 +2299,11 @@ void check_buf_options(buf_T *buf)
check_string_option(&buf->b_p_menc);
}
-/*
- * Free the string allocated for an option.
- * Checks for the string being empty_option. This may happen if we're out of
- * memory, vim_strsave() returned NULL, which was replaced by empty_option by
- * check_options().
- * Does NOT check for P_ALLOCED flag!
- */
+/// Free the string allocated for an option.
+/// Checks for the string being empty_option. This may happen if we're out of
+/// memory, vim_strsave() returned NULL, which was replaced by empty_option by
+/// check_options().
+/// Does NOT check for P_ALLOCED flag!
void free_string_option(char_u *p)
{
if (p != empty_option) {
@@ -2369,10 +2341,8 @@ int was_set_insecurely(char_u *opt, int opt_flags)
return -1;
}
-/*
- * Get a pointer to the flags used for the P_INSECURE flag of option
- * "opt_idx". For some local options a local flags field is used.
- */
+/// Get a pointer to the flags used for the P_INSECURE flag of option
+/// "opt_idx". For some local options a local flags field is used.
static uint32_t *insecure_flag(int opt_idx, int opt_flags)
{
if (opt_flags & OPT_LOCAL)
@@ -2390,9 +2360,7 @@ static uint32_t *insecure_flag(int opt_idx, int opt_flags)
}
-/*
- * Redraw the window title and/or tab page text later.
- */
+/// Redraw the window title and/or tab page text later.
static void redraw_titles(void)
{
need_maketitle = true;
@@ -2473,9 +2441,7 @@ set_string_option_direct(
}
}
-/*
- * Set global value for string option when it's a local option.
- */
+/// Set global value for string option when it's a local option.
static void
set_string_option_global(
int opt_idx, // option index
@@ -3742,10 +3708,8 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
return NULL; // no error
}
-/*
- * Check validity of options with the 'statusline' format.
- * Return error message or NULL.
- */
+/// Check validity of options with the 'statusline' format.
+/// Return error message or NULL.
char_u *check_stl_option(char_u *s)
{
int itemcnt = 0;
@@ -3838,10 +3802,8 @@ static char_u *did_set_spell_option(bool is_spellfile)
return errmsg;
}
-/*
- * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
- * Return error message when failed, NULL when OK.
- */
+/// Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'.
+/// Return error message when failed, NULL when OK.
static char_u *compile_cap_prog(synblock_T *synblock)
FUNC_ATTR_NONNULL_ALL
{
@@ -4683,9 +4645,7 @@ static void trigger_optionsset_string(int opt_idx, int opt_flags,
}
}
-/*
- * Called after an option changed: check if something needs to be redrawn.
- */
+/// Called after an option changed: check if something needs to be redrawn.
static void check_redraw(uint32_t flags)
{
// Careful: P_RCLR and P_RALL are a combination of other P_ flags
@@ -5140,10 +5100,8 @@ static int find_key_option(const char_u *arg, bool has_lt)
return find_key_option_len(arg, STRLEN(arg), has_lt);
}
-/*
- * if 'all' == 0: show changed options
- * if 'all' == 1: show all normal options
- */
+/// if 'all' == 0: show changed options
+/// if 'all' == 1: show all normal options
static void
showoptions(
int all,
@@ -5292,10 +5250,8 @@ void ui_refresh_options(void)
}
}
-/*
- * showoneopt: show the value of one option
- * must not be called with a hidden option!
- */
+/// showoneopt: show the value of one option
+/// must not be called with a hidden option!
static void
showoneopt(
vimoption_T *p,
@@ -5331,28 +5287,26 @@ showoneopt(
info_message = false;
}
-/*
- * Write modified options as ":set" commands to a file.
- *
- * There are three values for "opt_flags":
- * OPT_GLOBAL: Write global option values and fresh values of
- * buffer-local options (used for start of a session
- * file).
- * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for
- * curwin (used for a vimrc file).
- * OPT_LOCAL: Write buffer-local option values for curbuf, fresh
- * and local values for window-local options of
- * curwin. Local values are also written when at the
- * default value, because a modeline or autocommand
- * may have set them when doing ":edit file" and the
- * user has set them back at the default or fresh
- * value.
- * When "local_only" is true, don't write fresh
- * values, only local values (for ":mkview").
- * (fresh value = value used for a new buffer or window for a local option).
- *
- * Return FAIL on error, OK otherwise.
- */
+/// Write modified options as ":set" commands to a file.
+///
+/// There are three values for "opt_flags":
+/// OPT_GLOBAL: Write global option values and fresh values of
+/// buffer-local options (used for start of a session
+/// file).
+/// OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for
+/// curwin (used for a vimrc file).
+/// OPT_LOCAL: Write buffer-local option values for curbuf, fresh
+/// and local values for window-local options of
+/// curwin. Local values are also written when at the
+/// default value, because a modeline or autocommand
+/// may have set them when doing ":edit file" and the
+/// user has set them back at the default or fresh
+/// value.
+/// When "local_only" is true, don't write fresh
+/// values, only local values (for ":mkview").
+/// (fresh value = value used for a new buffer or window for a local option).
+///
+/// Return FAIL on error, OK otherwise.
int makeset(FILE *fd, int opt_flags, int local_only)
{
vimoption_T *p;
@@ -5463,10 +5417,8 @@ int makeset(FILE *fd, int opt_flags, int local_only)
return OK;
}
-/*
- * Generate set commands for the local fold options only. Used when
- * 'sessionoptions' or 'viewoptions' contains "folds" but not "options".
- */
+/// Generate set commands for the local fold options only. Used when
+/// 'sessionoptions' or 'viewoptions' contains "folds" but not "options".
int makefoldset(FILE *fd)
{
if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, false) == FAIL
@@ -5559,12 +5511,10 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value)
return OK;
}
-/*
- * Compute columns for ruler and shown command. 'sc_col' is also used to
- * decide what the maximum length of a message on the status line can be.
- * If there is a status line for the last window, 'sc_col' is independent
- * of 'ru_col'.
- */
+/// Compute columns for ruler and shown command. 'sc_col' is also used to
+/// decide what the maximum length of a message on the status line can be.
+/// If there is a status line for the last window, 'sc_col' is independent
+/// of 'ru_col'.
#define COL_RULER 17 // columns needed by standard ruler
@@ -5698,9 +5648,7 @@ void unset_global_local_option(char *name, void *from)
}
}
-/*
- * Get pointer to option variable, depending on local or global scope.
- */
+/// Get pointer to option variable, depending on local or global scope.
static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
{
if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) {
@@ -5741,9 +5689,7 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
return get_varp(p);
}
-/*
- * Get pointer to option variable.
- */
+/// Get pointer to option variable.
static char_u *get_varp(vimoption_T *p)
{
// hidden option, always return NULL
@@ -5905,9 +5851,7 @@ static char_u *get_varp(vimoption_T *p)
return (char_u *)&(curbuf->b_p_wm);
}
-/*
- * Get the value of 'equalprg', either the buffer-local one or the global one.
- */
+/// Get the value of 'equalprg', either the buffer-local one or the global one.
char_u *get_equalprg(void)
{
if (*curbuf->b_p_ep == NUL) {
@@ -5916,22 +5860,18 @@ char_u *get_equalprg(void)
return curbuf->b_p_ep;
}
-/*
- * Copy options from one window to another.
- * Used when splitting a window.
- */
+/// Copy options from one window to another.
+/// Used when splitting a window.
void win_copy_options(win_T *wp_from, win_T *wp_to)
{
copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt);
copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt);
}
-/*
- * Copy the options from one winopt_T to another.
- * Doesn't free the old option values in "to", use clear_winopt() for that.
- * The 'scroll' option is not copied, because it depends on the window height.
- * The 'previewwindow' option is reset, there can be only one preview window.
- */
+/// Copy the options from one winopt_T to another.
+/// Doesn't free the old option values in "to", use clear_winopt() for that.
+/// The 'scroll' option is not copied, because it depends on the window height.
+/// The 'previewwindow' option is reset, there can be only one preview window.
void copy_winopt(winopt_T *from, winopt_T *to)
{
to->wo_arab = from->wo_arab;
@@ -5983,18 +5923,14 @@ void copy_winopt(winopt_T *from, winopt_T *to)
check_winopt(to); // don't want NULL pointers
}
-/*
- * Check string options in a window for a NULL value.
- */
+/// Check string options in a window for a NULL value.
void check_win_options(win_T *win)
{
check_winopt(&win->w_onebuf_opt);
check_winopt(&win->w_allbuf_opt);
}
-/*
- * Check for NULL pointers in a winopt_T and replace them with empty_option.
- */
+/// Check for NULL pointers in a winopt_T and replace them with empty_option.
static void check_winopt(winopt_T *wop)
{
check_string_option(&wop->wo_fdc);
@@ -6016,9 +5952,7 @@ static void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_lcs);
}
-/*
- * Free the allocated memory inside a winopt_T.
- */
+/// Free the allocated memory inside a winopt_T.
void clear_winopt(winopt_T *wop)
{
clear_string_option(&wop->wo_fdc);
@@ -6051,15 +5985,13 @@ void didset_window_options(win_T *wp)
}
-/*
- * Copy global option values to local options for one buffer.
- * Used when creating a new buffer and sometimes when entering a buffer.
- * flags:
- * BCO_ENTER We will enter the buf buffer.
- * BCO_ALWAYS Always copy the options, but only set b_p_initialized when
- * appropriate.
- * BCO_NOHELP Don't copy the values to a help buffer.
- */
+/// Copy global option values to local options for one buffer.
+/// Used when creating a new buffer and sometimes when entering a buffer.
+/// flags:
+/// BCO_ENTER We will enter the buf buffer.
+/// BCO_ALWAYS Always copy the options, but only set b_p_initialized when
+/// appropriate.
+/// BCO_NOHELP Don't copy the values to a help buffer.
void buf_copy_options(buf_T *buf, int flags)
{
int should_copy = true;
@@ -6254,9 +6186,7 @@ void buf_copy_options(buf_T *buf, int flags)
}
}
-/*
- * Reset the 'modifiable' option and its default value.
- */
+/// Reset the 'modifiable' option and its default value.
void reset_modifiable(void)
{
int opt_idx;
@@ -6269,17 +6199,13 @@ void reset_modifiable(void)
}
}
-/*
- * Set the global value for 'iminsert' to the local value.
- */
+/// Set the global value for 'iminsert' to the local value.
void set_iminsert_global(void)
{
p_iminsert = curbuf->b_p_iminsert;
}
-/*
- * Set the global value for 'imsearch' to the local value.
- */
+/// Set the global value for 'imsearch' to the local value.
void set_imsearch_global(void)
{
p_imsearch = curbuf->b_p_imsearch;
@@ -6581,10 +6507,8 @@ void ExpandOldSetting(int *num_file, char_u ***file)
*num_file = 1;
}
-/*
- * Get the value for the numeric or string option *opp in a nice format into
- * NameBuff[]. Must not be called with a hidden option!
- */
+/// Get the value for the numeric or string option///opp in a nice format into
+/// NameBuff[]. Must not be called with a hidden option!
static void
option_value2string(
vimoption_T *opp,
@@ -6637,21 +6561,18 @@ static int wc_use_keyname(char_u *varp, long *wcp)
return false;
}
-/*
- * Any character has an equivalent 'langmap' character. This is used for
- * keyboards that have a special language mode that sends characters above
- * 128 (although other characters can be translated too). The "to" field is a
- * Vim command character. This avoids having to switch the keyboard back to
- * ASCII mode when leaving Insert mode.
- *
- * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
- * commands.
- * langmap_mapga.ga_data is a sorted table of langmap_entry_T.
- * This does the same as langmap_mapchar[] for characters >= 256.
- */
-/*
- * With multi-byte support use growarray for 'langmap' chars >= 256
- */
+/// Any character has an equivalent 'langmap' character. This is used for
+/// keyboards that have a special language mode that sends characters above
+/// 128 (although other characters can be translated too). The "to" field is a
+/// Vim command character. This avoids having to switch the keyboard back to
+/// ASCII mode when leaving Insert mode.
+///
+/// langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim
+/// commands.
+/// langmap_mapga.ga_data is a sorted table of langmap_entry_T.
+/// This does the same as langmap_mapchar[] for characters >= 256.
+///
+/// With multi-byte support use growarray for 'langmap' chars >= 256
typedef struct {
int from;
int to;
@@ -6659,10 +6580,8 @@ typedef struct {
static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE;
-/*
- * Search for an entry in "langmap_mapga" for "from". If found set the "to"
- * field. If not found insert a new entry at the appropriate location.
- */
+/// Search for an entry in "langmap_mapga" for "from". If found set the "to"
+/// field. If not found insert a new entry at the appropriate location.
static void langmap_set_entry(int from, int to)
{
langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
@@ -6697,9 +6616,7 @@ static void langmap_set_entry(int from, int to)
entries[0].to = to;
}
-/*
- * Apply 'langmap' to multi-byte character "c" and return the result.
- */
+/// Apply 'langmap' to multi-byte character "c" and return the result.
int langmap_adjust_mb(int c)
{
langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data);
@@ -6730,10 +6647,8 @@ static void langmap_init(void)
ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8);
}
-/*
- * Called when langmap option is set; the language map can be
- * changed at any time!
- */
+/// Called when langmap option is set; the language map can be
+/// changed at any time!
static void langmap_set(void)
{
char_u *p;
@@ -6836,9 +6751,7 @@ bool shortmess(int x)
&& vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL)));
}
-/*
- * paste_option_changed() - Called after p_paste was set or reset.
- */
+/// paste_option_changed() - Called after p_paste was set or reset.
static void paste_option_changed(void)
{
static int old_p_paste = false;
@@ -6985,9 +6898,7 @@ void reset_option_was_set(const char *name)
}
}
-/*
- * fill_breakat_flags() -- called when 'breakat' changes value.
- */
+/// fill_breakat_flags() -- called when 'breakat' changes value.
static void fill_breakat_flags(void)
{
char_u *p;
@@ -7004,12 +6915,10 @@ static void fill_breakat_flags(void)
}
}
-/*
- * Check an option that can be a range of string values.
- *
- * Return OK for correct value, FAIL otherwise.
- * Empty is always OK.
- */
+/// Check an option that can be a range of string values.
+///
+/// Return OK for correct value, FAIL otherwise.
+/// Empty is always OK.
static int check_opt_strings(
char_u *val,
char **values,
@@ -7019,13 +6928,11 @@ static int check_opt_strings(
return opt_strings_flags(val, values, NULL, list);
}
-/*
- * Handle an option that can be a range of string values.
- * Set a flag in "*flagp" for each string present.
- *
- * Return OK for correct value, FAIL otherwise.
- * Empty is always OK.
- */
+/// Handle an option that can be a range of string values.
+/// Set a flag in "*flagp" for each string present.
+///
+/// Return OK for correct value, FAIL otherwise.
+/// Empty is always OK.
static int opt_strings_flags(
char_u *val, // new value
char **values, // array of valid string values
@@ -7058,9 +6965,7 @@ static int opt_strings_flags(
return OK;
}
-/*
- * Read the 'wildmode' option, fill wim_flags[].
- */
+/// Read the 'wildmode' option, fill wim_flags[].
static int check_opt_wim(void)
{
char_u new_wim_flags[4];
@@ -7113,11 +7018,9 @@ static int check_opt_wim(void)
return OK;
}
-/*
- * Check if backspacing over something is allowed.
- * The parameter what is one of the following: whatBS_INDENT, BS_EOL
- * or BS_START
- */
+/// Check if backspacing over something is allowed.
+/// The parameter what is one of the following: whatBS_INDENT, BS_EOL
+/// or BS_START
bool can_bs(int what)
{
if (what == BS_START && bt_prompt(curbuf)) {
@@ -7131,10 +7034,8 @@ bool can_bs(int what)
return vim_strchr(p_bs, what) != NULL;
}
-/*
- * Save the current values of 'fileformat' and 'fileencoding', so that we know
- * the file must be considered changed when the value is different.
- */
+/// Save the current values of 'fileformat' and 'fileencoding', so that we know
+/// the file must be considered changed when the value is different.
void save_file_ff(buf_T *buf)
{
buf->b_start_ffc = *buf->b_p_ff;
@@ -7184,18 +7085,14 @@ bool file_ff_differs(buf_T *buf, bool ignore_empty)
return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0;
}
-/*
- * return OK if "p" is a valid fileformat name, FAIL otherwise.
- */
+/// return OK if "p" is a valid fileformat name, FAIL otherwise.
int check_ff_value(char_u *p)
{
return check_opt_strings(p, p_ff_values, false);
}
-/*
- * Return the effective shiftwidth value for current buffer, using the
- * 'tabstop' value when 'shiftwidth' is zero.
- */
+/// Return the effective shiftwidth value for current buffer, using the
+/// 'tabstop' value when 'shiftwidth' is zero.
int get_sw_value(buf_T *buf)
{
long result = buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts;
@@ -7203,8 +7100,8 @@ int get_sw_value(buf_T *buf)
return (int)result;
}
-// Return the effective softtabstop value for the current buffer,
-// using the effective shiftwidth value when 'softtabstop' is negative.
+/// Return the effective softtabstop value for the current buffer,
+/// using the effective shiftwidth value when 'softtabstop' is negative.
int get_sts_value(void)
{
long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
@@ -7212,12 +7109,10 @@ int get_sts_value(void)
return (int)result;
}
-/*
- * Check matchpairs option for "*initc".
- * If there is a match set "*initc" to the matching character and "*findc" to
- * the opposite character. Set "*backwards" to the direction.
- * When "switchit" is true swap the direction.
- */
+/// Check matchpairs option for "*initc".
+/// If there is a match set "*initc" to the matching character and "*findc" to
+/// the opposite character. Set "*backwards" to the direction.
+/// When "switchit" is true swap the direction.
void find_mps_values(int *initc, int *findc, int *backwards, int switchit)
{
char_u *ptr = curbuf->b_p_mps;
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index ba6226ef9d..112de9fed8 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -50,22 +50,13 @@ void signal_init(void)
signal_watcher_init(&main_loop, &shup, NULL);
signal_watcher_init(&main_loop, &squit, NULL);
signal_watcher_init(&main_loop, &sterm, NULL);
-#ifdef SIGPIPE
- signal_watcher_start(&spipe, on_signal, SIGPIPE);
-#endif
- signal_watcher_start(&shup, on_signal, SIGHUP);
-#ifdef SIGQUIT
- signal_watcher_start(&squit, on_signal, SIGQUIT);
-#endif
- signal_watcher_start(&sterm, on_signal, SIGTERM);
#ifdef SIGPWR
signal_watcher_init(&main_loop, &spwr, NULL);
- signal_watcher_start(&spwr, on_signal, SIGPWR);
#endif
#ifdef SIGUSR1
signal_watcher_init(&main_loop, &susr1, NULL);
- signal_watcher_start(&susr1, on_signal, SIGUSR1);
#endif
+ signal_start();
}
void signal_teardown(void)
@@ -83,11 +74,33 @@ void signal_teardown(void)
#endif
}
+void signal_start(void)
+{
+#ifdef SIGPIPE
+ signal_watcher_start(&spipe, on_signal, SIGPIPE);
+#endif
+ signal_watcher_start(&shup, on_signal, SIGHUP);
+#ifdef SIGQUIT
+ signal_watcher_start(&squit, on_signal, SIGQUIT);
+#endif
+ signal_watcher_start(&sterm, on_signal, SIGTERM);
+#ifdef SIGPWR
+ signal_watcher_start(&spwr, on_signal, SIGPWR);
+#endif
+#ifdef SIGUSR1
+ signal_watcher_start(&susr1, on_signal, SIGUSR1);
+#endif
+}
+
void signal_stop(void)
{
+#ifdef SIGPIPE
signal_watcher_stop(&spipe);
+#endif
signal_watcher_stop(&shup);
+#ifdef SIGQUIT
signal_watcher_stop(&squit);
+#endif
signal_watcher_stop(&sterm);
#ifdef SIGPWR
signal_watcher_stop(&spwr);
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index ddb9188371..ef4dfb3caa 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -6400,7 +6400,7 @@ static int color_numbers_88[28] = { 0, 4, 2, 6,
75, 11, 78, 15, -1 };
// for xterm with 256 colors...
static int color_numbers_256[28] = { 0, 4, 2, 6,
- 1, 5, 130, 130,
+ 1, 5, 130, 3,
248, 248, 7, 7,
242, 242,
12, 81, 10, 121,
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 6c164b27d2..560a345333 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -997,8 +997,9 @@ static void mouse_action(Terminal *term, int button, int row, int col,
static bool send_mouse_event(Terminal *term, int c)
{
int row = mouse_row, col = mouse_col, grid = mouse_grid;
+ int offset;
win_T *mouse_win = mouse_find_win(&grid, &row, &col);
- if (mouse_win == NULL) {
+ if (mouse_win == NULL || (offset = win_col_off(mouse_win)) > col) {
goto end;
}
@@ -1020,7 +1021,7 @@ static bool send_mouse_event(Terminal *term, int c)
default: return false;
}
- mouse_action(term, button, row, col, drag, 0);
+ mouse_action(term, button, row, col - offset, drag, 0);
size_t len = vterm_output_read(term->vt, term->textbuf,
sizeof(term->textbuf));
terminal_send(term, term->textbuf, (size_t)len);
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index aad21c002f..7fbf04311d 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -6,6 +6,9 @@ function Test_messages()
set nomore
" Avoid the "message maintainer" line.
let $LANG = ''
+ let $LC_ALL = ''
+ let $LC_MESSAGES = ''
+ let $LC_COLLATE = ''
let arr = map(range(10), '"hello" . v:val')
for s in arr
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 0c330149d0..228545a844 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -31,6 +31,7 @@
#include "nvim/event/signal.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
+#include "nvim/os/signal.h"
#include "nvim/os/tty.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
@@ -48,10 +49,15 @@
#define OUTBUF_SIZE 0xffff
#define TOO_MANY_EVENTS 1000000
-#define STARTS_WITH(str, prefix) (strlen(str) >= (sizeof(prefix) - 1) \
- && 0 == memcmp((str), (prefix), sizeof(prefix) - 1))
-#define TMUX_WRAP(is_tmux, seq) ((is_tmux) \
- ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
+#define STARTS_WITH(str, prefix) \
+ (strlen(str) >= (sizeof(prefix) - 1) && 0 == memcmp((str), (prefix), \
+ sizeof(prefix) - 1))
+#define SCREEN_WRAP(is_screen, seq) ((is_screen) \
+ ? DCS_STR seq STERM_STR : seq)
+#define SCREEN_TMUX_WRAP(is_screen, is_tmux, seq) \
+ ((is_screen) \
+ ? DCS_STR seq STERM_STR : (is_tmux) \
+ ? DCS_STR "tmux;\x1b" seq STERM_STR : seq)
#define LINUXSET0C "\x1b[?0c"
#define LINUXSET1C "\x1b[?1c"
@@ -1239,7 +1245,9 @@ static void suspend_event(void **argv)
tui_terminal_stop(ui);
data->cont_received = false;
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
+ signal_stop();
kill(0, SIGTSTP);
+ signal_start();
while (!data->cont_received) {
// poll the event loop until SIGCONT is received
loop_poll_events(data->loop, -1);
@@ -1535,7 +1543,10 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool rxvt = terminfo_is_term_family(term, "rxvt");
bool teraterm = terminfo_is_term_family(term, "teraterm");
bool putty = terminfo_is_term_family(term, "putty");
- bool screen = terminfo_is_term_family(term, "screen");
+ bool screen = terminfo_is_term_family(term, "screen") && !os_getenv("TMUX");
+ bool screen_host_linuxvt =
+ terminfo_is_term_family(screen && term[6] == '.'
+ ? term + 7 : NULL, "linux");
bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX");
bool st = terminfo_is_term_family(term, "st");
bool gnome = terminfo_is_term_family(term, "gnome")
@@ -1694,8 +1705,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
#define XTERM_SETAB_16 \
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m"
- data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg",
- "\x1b]11;?\x07");
+ data->unibi_ext.get_bg =
+ (int)unibi_add_ext_str(ut, "ext.get_bg",
+ SCREEN_TMUX_WRAP(screen, tmux, "\x1b]11;?\x07"));
// Terminals with 256-colour SGR support despite what terminfo says.
if (unibi_get_num(ut, unibi_max_colors) < 256) {
@@ -1730,6 +1742,32 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss");
}
+ // GNU Screen does not have Ss/Se. When terminfo has Ss/Se, it is wrapped with
+ // DCS because it is inherited from the host terminal.
+ if (screen) {
+ size_t len;
+ size_t dcs_st_len = strlen(DCS_STR) + strlen(STERM_STR);
+ if (-1 != data->unibi_ext.set_cursor_style) {
+ const char *orig_ss =
+ unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style);
+ len = STRLEN(orig_ss) + dcs_st_len + 1;
+ char *ss = xmalloc(len);
+ snprintf(ss, len, "%s%s%s", DCS_STR, orig_ss, STERM_STR);
+ unibi_set_ext_str(data->ut, (size_t)data->unibi_ext.set_cursor_style, ss);
+ xfree(ss);
+ }
+ if (-1 != data->unibi_ext.reset_cursor_style) {
+ const char *orig_se =
+ unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style);
+ len = strlen(orig_se) + dcs_st_len + 1;
+ char *se = xmalloc(len);
+ snprintf(se, len, "%s%s%s", DCS_STR, orig_se, STERM_STR);
+ unibi_set_ext_str(data->ut,
+ (size_t)data->unibi_ext.reset_cursor_style, se);
+ xfree(se);
+ }
+ }
+
// Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So
// adding them to terminal types, that have such control sequences but lack
// the correct terminfo entries, is a fixup, not an augmentation.
@@ -1745,7 +1783,12 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|| (konsolev >= 180770) // #9364
|| tmux // per tmux manual page
// https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html
- || screen
+ || (screen
+ && (!screen_host_linuxvt
+ || (screen_host_linuxvt
+ && (xterm_version || (vte_version > 0) || colorterm))))
+ // Since GNU Screen does not support DECSCUSR, DECSCUSR is wrapped
+ // in DCS and output to the host terminal.
|| st // #7641
|| rxvt // per command.C
// per analysis of VT100Terminal.m
@@ -1758,34 +1801,43 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
|| (linuxvt
&& (xterm_version || (vte_version > 0) || colorterm)))) {
data->unibi_ext.set_cursor_style =
- (int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
+ (int)unibi_add_ext_str(ut, "Ss", SCREEN_WRAP(screen, "\x1b[%p1%d q"));
if (-1 == data->unibi_ext.reset_cursor_style) {
data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
"");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- "\x1b[ q");
- } else if (linuxvt) {
+ SCREEN_WRAP(screen, "\x1b[ q"));
+ } else if (linuxvt || screen_host_linuxvt) {
// Linux uses an idiosyncratic escape code to set the cursor shape and
// does not support DECSCUSR.
// See http://linuxgazette.net/137/anonymous.html for more info
- data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
- "\x1b[?"
- "%?"
- // The parameter passed to Ss is the DECSCUSR parameter, so the
- // terminal capability has to translate into the Linux idiosyncratic
- // parameter.
- //
- // linuxvt only supports block and underline. It is also only
- // possible to have a steady block (no steady underline)
- "%p1%{2}%<" "%t%{8}" // blink block
- "%e%p1%{2}%=" "%t%{112}" // steady block
- "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block)
- "%e%p1%{4}%=" "%t%{4}" // steady underline
- "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
- "%e%p1%{6}%=" "%t%{2}" // steady bar
- "%e%{0}" // anything else
- "%;" "%dc");
+ //
+ // Since gnu Screen does not have Ss/Se, if the host terminal is a linux
+ // console that does not support xterm extensions, it will wraps the
+ // linux-specific sequence in DCS and outputs it.
+ data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(
+ ut, "Ss",
+ SCREEN_WRAP(screen,
+ "\x1b[?"
+ "%?"
+ // The parameter passed to Ss is the DECSCUSR parameter,
+ // so the
+ // terminal capability has to translate into the Linux
+ // idiosyncratic parameter.
+ //
+ // linuxvt only supports block and underline. It is also
+ // only possible to have a steady block (no steady
+ // underline)
+ "%p1%{2}%<" "%t%{8}" // blink block
+ "%e%p1%{2}%=" "%t%{112}" // steady block
+ "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half
+ // block)
+ "%e%p1%{4}%=" "%t%{4}" // steady underline
+ "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
+ "%e%p1%{6}%=" "%t%{2}" // steady bar
+ "%e%{0}" // anything else
+ "%;" "%dc"));
if (-1 == data->unibi_ext.reset_cursor_style) {
data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
"");
@@ -1795,21 +1847,25 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
} else if (konsolev > 0 && konsolev < 180770) {
// Konsole before version 18.07.70: set up a nonce profile. This has
// side-effects on temporary font resizing. #6798
- data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
- TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?"
- "%p1%{3}%<" "%t%{0}" // block
- "%e%p1%{5}%<" "%t%{2}" // underline
- "%e%{1}" // everything else is bar
- "%;%d;BlinkingCursorEnabled=%?"
- "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special,
- "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag.
- "%;%d\x07"));
+ data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(
+ ut, "Ss",
+ SCREEN_TMUX_WRAP(screen, tmux,
+ "\x1b]50;CursorShape=%?"
+ "%p1%{3}%<" "%t%{0}" // block
+ "%e%p1%{5}%<" "%t%{2}" // underline
+ "%e%{1}" // everything else is bar
+ "%;%d;BlinkingCursorEnabled=%?"
+ "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude
+ // zero as special,
+ "%e%p1%{1}%&" // in all other c2ses we can treat bit
+ // #0 as a flag.
+ "%;%d\x07"));
if (-1 == data->unibi_ext.reset_cursor_style) {
data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
"");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- "\x1b]50;\x07");
+ SCREEN_TMUX_WRAP(screen, tmux, "\x1b]50;\x07"));
}
}
}
@@ -1838,6 +1894,8 @@ static void augment_terminfo(TUIData *data, const char *term,
bool alacritty = terminfo_is_term_family(term, "alacritty");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
+ bool screen_host_rxvt =
+ terminfo_is_term_family(screen && term[6] == '.' ? term + 7 : NULL, "rxvt");
const char *xterm_version = os_getenv("XTERM_VERSION");
bool true_xterm = xterm && !!xterm_version && !bsdvt;
@@ -1907,7 +1965,7 @@ static void augment_terminfo(TUIData *data, const char *term,
// all panes, which is not particularly desirable. A better approach
// would use a tmux control sequence and an extra if(screen) test.
data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
- ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
+ ut, NULL, SCREEN_TMUX_WRAP(screen, tmux, "\033]Pl%p1%06x\033\\"));
} else if ((xterm || rxvt || tmux || alacritty)
&& (vte_version == 0 || vte_version >= 3900)) {
// Supported in urxvt, newer VTE.
@@ -1927,21 +1985,27 @@ static void augment_terminfo(TUIData *data, const char *term,
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
+ /// If the DECSET is not supported by GNU Screen, it is wrapped with DCS and
+ /// sent to the host terminal.
data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(
ut, "ext.enable_lr_margin", "\x1b[?69h");
data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(
ut, "ext.disable_lr_margin", "\x1b[?69l");
data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.enable_bpaste", "\x1b[?2004h");
+ ut, "ext.enable_bpaste", SCREEN_WRAP(screen, "\x1b[?2004h"));
data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.disable_bpaste", "\x1b[?2004l");
+ ut, "ext.disable_bpaste", SCREEN_WRAP(screen, "\x1b[?2004l"));
// For urxvt send BOTH xterm and old urxvt sequences. #8695
data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(
ut, "ext.enable_focus",
- rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
+ (rxvt || screen_host_rxvt)
+ ? SCREEN_WRAP(screen, "\x1b[?1004h\x1b]777;focus;on\x7")
+ : SCREEN_WRAP(screen, "\x1b[?1004h"));
data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(
ut, "ext.disable_focus",
- rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l");
+ (rxvt || screen_host_rxvt)
+ ? SCREEN_WRAP(screen, "\x1b[?1004l\x1b]777;focus;off\x7")
+ : SCREEN_WRAP(screen, "\x1b[?1004l"));
data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(
ut, "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h");
data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(
@@ -1973,7 +2037,23 @@ static void flush_buf(UI *ui)
uv_buf_t *bufp = &bufs[0];
TUIData *data = ui->data;
- if (data->bufpos <= 0 && data->busy == data->is_invisible) {
+ // The content of the output for each condition is shown in the following
+ // table. Therefore, if data->bufpos == 0 and N/A or invis + norm, there is
+ // no need to output it.
+ //
+ // | is_invisible | !is_invisible
+ // ------+-----------------+--------------+---------------
+ // busy | want_invisible | N/A | invis
+ // | !want_invisible | N/A | invis
+ // ------+-----------------+--------------+---------------
+ // !busy | want_invisible | N/A | invis
+ // | !want_invisible | norm | invis + norm
+ // ------+-----------------+--------------+---------------
+ //
+ if (data->bufpos <= 0
+ && ((data->is_invisible && data->busy)
+ || (data->is_invisible && !data->busy && data->want_invisible)
+ || (!data->is_invisible && !data->busy && !data->want_invisible))) {
return;
}
@@ -2000,8 +2080,8 @@ static void flush_buf(UI *ui)
bufp->base = data->norm;
bufp->len = UV_BUF_LEN(data->normlen);
bufp++;
+ data->is_invisible = false;
}
- data->is_invisible = false;
}
uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 9c14ced2ad..15a9713c7c 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -398,7 +398,7 @@ static const int included_patches[] = {
1523,
1522,
1521,
- // 1520,
+ 1520,
1519,
1518,
1517,
@@ -530,7 +530,7 @@ static const int included_patches[] = {
1391,
1390,
1389,
- // 1388,
+ 1388,
1387,
1386,
1385,
@@ -789,7 +789,7 @@ static const int included_patches[] = {
1132,
1131,
1130,
- // 1129,
+ 1129,
1128,
1127,
1126,
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 369b826adf..e53fb5b9e2 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -812,4 +812,78 @@ describe('LSP', function()
}, buf_lines(1))
end)
end)
+
+ describe('completion_list_to_complete_items', function()
+ -- Completion option precedence:
+ -- textEdit.newText > insertText > label
+ -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+ it('should choose right completion option', function ()
+ local prefix = 'foo'
+ local completion_list = {
+ -- resolves into label
+ { label='foobar' },
+ { label='foobar', textEdit={} },
+ -- resolves into insertText
+ { label='foocar', insertText='foobar' },
+ { label='foocar', insertText='foobar', textEdit={} },
+ -- resolves into textEdit.newText
+ { label='foocar', insertText='foodar', textEdit={newText='foobar'} },
+ { label='foocar', textEdit={newText='foobar'} }
+ }
+ local completion_list_items = {items=completion_list}
+ local expected = {
+ { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foobar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = '', menu = '', word = 'foobar'},
+ }
+
+ eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix))
+ eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list_items, prefix))
+ eq({}, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], {}, prefix))
+ end)
+ end)
+ describe('buf_diagnostics_save_positions', function()
+ it('stores the diagnostics in diagnostics_by_buf', function ()
+ local diagnostics = {
+ { range = {}; message = "diag1" },
+ { range = {}; message = "diag2" },
+ }
+ exec_lua([[
+ vim.lsp.util.buf_diagnostics_save_positions(...)]], 0, diagnostics)
+ eq(1, exec_lua [[ return #vim.lsp.util.diagnostics_by_buf ]])
+ eq(diagnostics, exec_lua [[
+ for _, diagnostics in pairs(vim.lsp.util.diagnostics_by_buf) do
+ return diagnostics
+ end
+ ]])
+ end)
+ end)
+ describe('lsp.util.show_line_diagnostics', function()
+ it('creates floating window and returns popup bufnr and winnr if current line contains diagnostics', function()
+ eq(3, exec_lua [[
+ local buffer = vim.api.nvim_create_buf(false, true)
+ vim.api.nvim_buf_set_lines(buffer, 0, -1, false, {
+ "testing";
+ "123";
+ })
+ local diagnostics = {
+ {
+ range = {
+ start = { line = 0; character = 1; };
+ ["end"] = { line = 0; character = 3; };
+ };
+ severity = vim.lsp.protocol.DiagnosticSeverity.Error;
+ message = "Syntax error";
+ },
+ }
+ vim.api.nvim_win_set_buf(0, buffer)
+ vim.lsp.util.buf_diagnostics_save_positions(vim.fn.bufnr(buffer), diagnostics)
+ local popup_bufnr, winnr = vim.lsp.util.show_line_diagnostics()
+ return popup_bufnr
+ ]])
+ end)
+ end)
end)
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index ee3db7ae97..0eb5901b3b 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -87,6 +87,36 @@ describe(':terminal mouse', function()
{3:-- TERMINAL --} |
]])
end)
+
+ it('will forward mouse clicks to the program with the correct even if set nu', function()
+ if helpers.pending_win32(pending) then return end
+ nvim('command', 'set number')
+ -- When the display area such as a number is clicked, it returns to the
+ -- normal mode.
+ feed('<LeftMouse><3,0>')
+ eq('n', eval('mode()'))
+ screen:expect([[
+ {7: 11 }^line28 |
+ {7: 12 }line29 |
+ {7: 13 }line30 |
+ {7: 14 }mouse enabled |
+ {7: 15 }rows: 6, cols: 46 |
+ {7: 16 }{2: } |
+ |
+ ]])
+ -- If click on the coordinate (0,1) of the region of the terminal
+ -- (i.e. the coordinate (4,1) of vim), 'CSI !"' is sent to the terminal.
+ feed('i<LeftMouse><4,1>')
+ screen:expect([[
+ {7: 11 }line28 |
+ {7: 12 }line29 |
+ {7: 13 }line30 |
+ {7: 14 }mouse enabled |
+ {7: 15 }rows: 6, cols: 46 |
+ {7: 16 } !"{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
end)
describe('with a split window and other buffer', function()
@@ -148,7 +178,7 @@ describe(':terminal mouse', function()
end)
it('wont lose focus if another window is scrolled', function()
- feed('<ScrollWheelUp><0,0><ScrollWheelUp><0,0>')
+ feed('<ScrollWheelUp><4,0><ScrollWheelUp><4,0>')
screen:expect([[
{7: 21 }line │line30 |
{7: 22 }line │rows: 5, cols: 25 |
@@ -158,7 +188,7 @@ describe(':terminal mouse', function()
========== ========== |
{3:-- TERMINAL --} |
]])
- feed('<S-ScrollWheelDown><0,0>')
+ feed('<S-ScrollWheelDown><4,0>')
screen:expect([[
{7: 26 }line │line30 |
{7: 27 }line │rows: 5, cols: 25 |