From 9c26939f75be8057d8880689292a729e8d8c9306 Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Wed, 5 Jan 2022 19:23:00 +0100 Subject: perf(treesitter): cache query parsing --- runtime/lua/vim/treesitter/query.lua | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index ebed502c92..b3036ea679 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -138,6 +138,13 @@ function M.get_query(lang, query_name) end end +local query_cache = setmetatable({}, { + __index = function(tbl, key) + rawset(tbl, key, {}) + return rawget(tbl, key) + end +}) + --- Parse {query} as a string. (If the query is in a file, the caller --- should read the contents into a string before calling). --- @@ -151,17 +158,23 @@ end --- -` info.captures` also points to `captures`. --- - `info.patterns` contains information about predicates. --- ----@param lang The language ----@param query A string containing the query (s-expr syntax) +---@param lang string The language +---@param query string A string containing the query (s-expr syntax) --- ---@returns The query function M.parse_query(lang, query) language.require_language(lang) - local self = setmetatable({}, Query) - self.query = vim._ts_parse_query(lang, query) - self.info = self.query:inspect() - self.captures = self.info.captures - return self + local cached = query_cache[lang][query] + if cached then + return cached + else + local self = setmetatable({}, Query) + self.query = vim._ts_parse_query(lang, query) + self.info = self.query:inspect() + self.captures = self.info.captures + query_cache[lang][query] = self + return self + end end --- Gets the text corresponding to a given node -- cgit From fc8af96888f746aeae84660502d2f529a5c2cfc1 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jan 2022 16:39:15 -0700 Subject: fix(diagnostic): resolve nil opts tables In functions which allow opts to be optional, ensure that the value actually resolves to a non-nil value. --- runtime/lua/vim/diagnostic.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 417b661155..76e19b2de2 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -823,6 +823,7 @@ M.handlers.signs = { } bufnr = get_bufnr(bufnr) + opts = opts or {} if opts.signs and opts.signs.severity then diagnostics = filter_by_severity(opts.signs.severity, diagnostics) @@ -890,6 +891,7 @@ M.handlers.underline = { } bufnr = get_bufnr(bufnr) + opts = opts or {} if opts.underline and opts.underline.severity then diagnostics = filter_by_severity(opts.underline.severity, diagnostics) @@ -942,6 +944,7 @@ M.handlers.virtual_text = { } bufnr = get_bufnr(bufnr) + opts = opts or {} local severity if opts.virtual_text then -- cgit From 984270c09f628415f99e576c64e93041731a8ba6 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jan 2022 16:43:47 -0700 Subject: fix(diagnostic): allow setting arbitrary config values --- runtime/lua/vim/diagnostic.lua | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 76e19b2de2..1425de854a 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -611,10 +611,8 @@ function M.config(opts, namespace) t = global_diagnostic_options end - for opt in pairs(global_diagnostic_options) do - if opts[opt] ~= nil then - t[opt] = opts[opt] - end + for k, v in pairs(opts) do + t[k] = v end if namespace then -- cgit From 8a27205d09405b9b040f0122e2adbd22fc29d498 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jan 2022 16:44:07 -0700 Subject: fix(diagnostic): only set default handler config if unset --- runtime/lua/vim/diagnostic.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 1425de854a..4bf69a2d39 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -30,7 +30,7 @@ M.handlers = setmetatable({}, { __newindex = function(t, name, handler) vim.validate { handler = {handler, "t" } } rawset(t, name, handler) - if not global_diagnostic_options[name] then + if global_diagnostic_options[name] == nil then global_diagnostic_options[name] = true end end, -- cgit From c915571b99d7e1ea99e29b103ca2ad37b5974027 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jan 2022 16:44:31 -0700 Subject: feat(diagnostic): allow retrieving current diagnostic config --- runtime/lua/vim/diagnostic.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 4bf69a2d39..b4537c2882 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -552,7 +552,8 @@ end --- - `table`: Enable this feature with overrides. Use an empty table to use default values. --- - `function`: Function with signature (namespace, bufnr) that returns any of the above. --- ----@param opts table Configuration table with the following keys: +---@param opts table|nil When omitted or "nil", retrieve the current configuration. Otherwise, a +--- configuration table with the following keys: --- - underline: (default true) Use underline for diagnostics. Options: --- * severity: Only underline diagnostics matching the given severity --- |diagnostic-severity| @@ -599,7 +600,7 @@ end --- global diagnostic options. function M.config(opts, namespace) vim.validate { - opts = { opts, 't' }, + opts = { opts, 't', true }, namespace = { namespace, 'n', true }, } @@ -611,6 +612,11 @@ function M.config(opts, namespace) t = global_diagnostic_options end + if not opts then + -- Return current config + return vim.deepcopy(t) + end + for k, v in pairs(opts) do t[k] = v end -- cgit From 43ef7df22d58a72e8b155265620f6c030900812e Mon Sep 17 00:00:00 2001 From: hrsh7th Date: Thu, 13 Jan 2022 18:28:13 +0900 Subject: fix(lsp): fix applying multiple out-of-range TextEdits (#17037) --- runtime/lua/vim/lsp/util.lua | 53 +++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 25 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 89c5ebe8f7..4f893425ef 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -286,7 +286,7 @@ local function get_line_byte_from_position(bufnr, position, offset_encoding) -- When on the first character, we can ignore the difference between byte and -- character if col > 0 then - local line = get_line(bufnr, position.line) + local line = get_line(bufnr, position.line) or '' local ok, result ok, result = pcall(_str_byteindex_enc, line, col, offset_encoding) if ok then @@ -402,25 +402,6 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) end end) - -- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here. - local has_eol_text_edit = false - local max = vim.api.nvim_buf_line_count(bufnr) - local len = _str_utfindex_enc(vim.api.nvim_buf_get_lines(bufnr, -2, -1, false)[1] or '', nil, offset_encoding) - text_edits = vim.tbl_map(function(text_edit) - if max <= text_edit.range.start.line then - text_edit.range.start.line = max - 1 - text_edit.range.start.character = len - text_edit.newText = '\n' .. text_edit.newText - has_eol_text_edit = true - end - if max <= text_edit.range['end'].line then - text_edit.range['end'].line = max - 1 - text_edit.range['end'].character = len - has_eol_text_edit = true - end - return text_edit - end, text_edits) - -- Some LSP servers are depending on the VSCode behavior. -- The VSCode will re-locate the cursor position after applying TextEdit so we also do it. local is_current_buf = vim.api.nvim_get_current_buf() == bufnr @@ -440,16 +421,35 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Apply text edits. local is_cursor_fixed = false + local has_eol_text_edit = false for _, text_edit in ipairs(text_edits) do + -- Convert from LSP style ranges to Neovim style ranges. local e = { start_row = text_edit.range.start.line, - start_col = get_line_byte_from_position(bufnr, text_edit.range.start), + start_col = get_line_byte_from_position(bufnr, text_edit.range.start, offset_encoding), end_row = text_edit.range['end'].line, - end_col = get_line_byte_from_position(bufnr, text_edit.range['end']), + end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding), text = vim.split(text_edit.newText, '\n', true), } + + -- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here. + local max = vim.api.nvim_buf_line_count(bufnr) + if max <= e.start_row or max <= e.end_row then + local len = #(get_line(bufnr, max - 1) or '') + if max <= e.start_row then + e.start_row = max - 1 + e.start_col = len + table.insert(e.text, 1, '') + end + if max <= e.end_row then + e.end_row = max - 1 + e.end_col = len + end + has_eol_text_edit = true + end vim.api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text) + -- Fix cursor position. local row_count = (e.end_row - e.start_row) + 1 if e.end_row < cursor.row then cursor.row = cursor.row + (#e.text - row_count) @@ -464,10 +464,13 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) end end + local max = vim.api.nvim_buf_line_count(bufnr) + + -- Apply fixed cursor position. if is_cursor_fixed then local is_valid_cursor = true - is_valid_cursor = is_valid_cursor and cursor.row < vim.api.nvim_buf_line_count(bufnr) - is_valid_cursor = is_valid_cursor and cursor.col <= #(vim.api.nvim_buf_get_lines(bufnr, cursor.row, cursor.row + 1, false)[1] or '') + is_valid_cursor = is_valid_cursor and cursor.row < max + is_valid_cursor = is_valid_cursor and cursor.col <= #(get_line(bufnr, max - 1) or '') if is_valid_cursor then vim.api.nvim_win_set_cursor(0, { cursor.row + 1, cursor.col }) end @@ -476,7 +479,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Remove final line if needed local fix_eol = has_eol_text_edit fix_eol = fix_eol and api.nvim_buf_get_option(bufnr, 'fixeol') - fix_eol = fix_eol and (vim.api.nvim_buf_get_lines(bufnr, -2, -1, false)[1] or '') == '' + fix_eol = fix_eol and get_line(bufnr, max - 1) == '' if fix_eol then vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {}) end -- cgit From e7cd81156755c2f588752d469bceee9e48377b4e Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 13 Jan 2022 10:47:36 +0100 Subject: fix(lsp): handle negative activeSignature in signatureHelp (#17064) omnisharp-roslyn can send negative values: { activeParameter = 0, activeSignature = -1, signatures = { { documentation = "", label = "TestEntity.TestEntity()", parameters = {} } } } In 3.16 of the specification `activeSignature` is defined as `uinteger` and therefore negative values shouldn't be allowed, but within 3.15 it was defined as `number` which makes me think we can be a bit lenient in this case and handle them. The expected behavior is quite clear: The active signature. If omitted or the value lies outside the range of `signatures` the value defaults to zero or is ignored if the `SignatureHelp` has no signatures. Fixes an error: util.lua:1685: attempt to get length of local 'lines' (a nil value) util.lua:1685: in function 'trim_empty_lines' handlers.lua:334: in function 'textDocument/signatureHelp' --- runtime/lua/vim/lsp/util.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 4f893425ef..a00f7f3673 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -842,7 +842,8 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers local active_hl 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 + -- In 3.15 of the protocol, activeSignature was allowed to be negative + if active_signature >= #signature_help.signatures or active_signature < 0 then active_signature = 0 end local signature = signature_help.signatures[active_signature + 1] -- cgit From bc722c8a74766e14aff3a8e2fc46db72ed864053 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Thu, 13 Jan 2022 02:34:04 -0800 Subject: fix(lsp): strictly enforce passing offset encoding (#17049) This removes the "fallback" to utf-16 in many of our helper functions. We should always explicitly pass these around when possible except in two locations: * generating params with help utilities called by buf.lua functions * the buf.lua functions themselves Anything that is called by the handler should be passed the offset encoding. --- runtime/lua/vim/lsp/buf.lua | 2 +- runtime/lua/vim/lsp/handlers.lua | 41 ++++++++++++++++++++------ runtime/lua/vim/lsp/util.lua | 62 ++++++++++++++++++++++++++++------------ 3 files changed, 77 insertions(+), 28 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index c1d777ae6c..e8633f5924 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -503,7 +503,7 @@ local function on_code_action_results(results, ctx) ---@private local function apply_action(action, client) if action.edit then - util.apply_workspace_edit(action.edit) + util.apply_workspace_edit(action.edit, client.offset_encoding) end if action.command then local command = type(action.command) == 'table' and action.command or action diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index a48302cc4b..6378ed0749 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -111,13 +111,15 @@ M['client/registerCapability'] = function(_, _, ctx) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit -M['workspace/applyEdit'] = function(_, workspace_edit) +M['workspace/applyEdit'] = function(_, workspace_edit, ctx) if not workspace_edit then return end -- TODO(ashkan) Do something more with label? + local client_id = ctx.client_id + local client = vim.lsp.get_client_by_id(client_id) if workspace_edit.label then print("Workspace edit", workspace_edit.label) end - local status, result = pcall(util.apply_workspace_edit, workspace_edit.edit) + local status, result = pcall(util.apply_workspace_edit, workspace_edit.edit, client.offset_encoding) return { applied = status; failureReason = result; @@ -159,6 +161,28 @@ M['textDocument/codeLens'] = function(...) end +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references +M['textDocument/references'] =function(_, result, ctx, config) + if not result or vim.tbl_isempty(result) then + vim.notify('No references found') + else + config = config or {} + if config.loclist then + vim.fn.setloclist(0, {}, ' ', { + title = 'Language Server'; + items = util.locations_to_items(result, ctx.offset_encoding); + }) + api.nvim_command("lopen") + else + vim.fn.setqflist({}, ' ', { + title = 'Language Server'; + items = util.locations_to_items(result, ctx.offset_encoding); + }) + api.nvim_command("botright copen") + end + end +end + ---@private --- Return a function that converts LSP responses to list items and opens the list @@ -194,9 +218,6 @@ local function response_to_list(map_result, entity) end ---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references -M['textDocument/references'] = response_to_list(util.locations_to_items, 'references') - --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols') @@ -277,19 +298,23 @@ local function location_handler(_, result, ctx, _) local _ = log.info() and log.info(ctx.method, 'No location found') return nil end + local client = vim.lsp.get_client_by_id(ctx.client_id) -- 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]) + util.jump_to_location(result[1], client.offset_encoding) if #result > 1 then - vim.fn.setqflist({}, ' ', {title = 'LSP locations', items = util.locations_to_items(result)}) + vim.fn.setqflist({}, ' ', { + title = 'LSP locations', + items = util.locations_to_items(result, client.offset_encoding) + }) api.nvim_command("copen") end else - util.jump_to_location(result) + util.jump_to_location(result, client.offset_encoding) end end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index a00f7f3673..d09865be89 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -277,7 +277,7 @@ end ---@private --- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position --- Returns a zero-indexed column, since set_lines() does the conversion to ----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to utf-16 +---@param offset_encoding string utf-8|utf-16|utf-32 --- 1-indexed local function get_line_byte_from_position(bufnr, position, offset_encoding) -- LSP's line and characters are 0-indexed @@ -360,15 +360,14 @@ end --- Applies a list of text edits to a buffer. ---@param text_edits table list of `TextEdit` objects ---@param bufnr number Buffer id ----@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to encoding of first client of `bufnr` +---@param offset_encoding string utf-8|utf-16|utf-32 defaults to encoding of first client of `bufnr` ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit function M.apply_text_edits(text_edits, bufnr, offset_encoding) validate { text_edits = { text_edits, 't', false }; bufnr = { bufnr, 'number', false }; - offset_encoding = { offset_encoding, 'string', true }; + offset_encoding = { offset_encoding, 'string', false }; } - offset_encoding = offset_encoding or M._get_offset_encoding(bufnr) if not next(text_edits) then return end if not api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) @@ -517,9 +516,12 @@ end ---@param text_document_edit table: a `TextDocumentEdit` object ---@param index number: Optional index of the edit, if from a list of edits (or nil, if not from a list) ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit -function M.apply_text_document_edit(text_document_edit, index) +function M.apply_text_document_edit(text_document_edit, index, offset_encoding) local text_document = text_document_edit.textDocument local bufnr = vim.uri_to_bufnr(text_document.uri) + if offset_encoding == nil then + vim.notify_once("apply_text_document_edit must be called with valid offset encoding", vim.log.levels.WARN) + end -- For lists of text document edits, -- do not check the version after the first edit. @@ -538,7 +540,7 @@ function M.apply_text_document_edit(text_document_edit, index) return end - M.apply_text_edits(text_document_edit.edits, bufnr) + M.apply_text_edits(text_document_edit.edits, bufnr, offset_encoding) end --- Parses snippets in a completion entry. @@ -737,7 +739,10 @@ end --- ---@param workspace_edit (table) `WorkspaceEdit` --see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit -function M.apply_workspace_edit(workspace_edit) +function M.apply_workspace_edit(workspace_edit, offset_encoding) + if offset_encoding == nil then + vim.notify_once("apply_workspace_edit must be called with valid offset encoding", vim.log.levels.WARN) + end if workspace_edit.documentChanges then for idx, change in ipairs(workspace_edit.documentChanges) do if change.kind == "rename" then @@ -753,7 +758,7 @@ function M.apply_workspace_edit(workspace_edit) elseif change.kind then error(string.format("Unsupported change: %q", vim.inspect(change))) else - M.apply_text_document_edit(change, idx) + M.apply_text_document_edit(change, idx, offset_encoding) end end return @@ -984,12 +989,16 @@ end --- Jumps to a location. --- ----@param location (`Location`|`LocationLink`) +---@param location table (`Location`|`LocationLink`) +---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---@returns `true` if the jump succeeded -function M.jump_to_location(location) +function M.jump_to_location(location, offset_encoding) -- location may be Location or LocationLink local uri = location.uri or location.targetUri if uri == nil then return end + if offset_encoding == nil then + vim.notify_once("jump_to_location must be called with valid offset encoding", vim.log.levels.WARN) + end local bufnr = vim.uri_to_bufnr(uri) -- Save position in jumplist vim.cmd "normal! m'" @@ -1004,7 +1013,7 @@ function M.jump_to_location(location) api.nvim_buf_set_option(bufnr, 'buflisted', true) local range = location.range or location.targetSelectionRange local row = range.start.line - local col = get_line_byte_from_position(bufnr, range.start) + local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) api.nvim_win_set_cursor(0, {row + 1, col}) -- Open folds under the cursor vim.cmd("normal! zv") @@ -1513,11 +1522,13 @@ do --[[ References ]] --- ---@param bufnr number Buffer id ---@param references table List of `DocumentHighlight` objects to highlight - ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32", or nil. Defaults to `offset_encoding` of first client of `bufnr` + ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32". ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight function M.buf_highlight_references(bufnr, references, offset_encoding) - validate { bufnr = {bufnr, 'n', true} } - offset_encoding = offset_encoding or M._get_offset_encoding(bufnr) + validate { + bufnr = {bufnr, 'n', true}, + offset_encoding = { offset_encoding, 'string', false }; + } for _, reference in ipairs(references) do local start_line, start_char = reference["range"]["start"]["line"], reference["range"]["start"]["character"] local end_line, end_char = reference["range"]["end"]["line"], reference["range"]["end"]["character"] @@ -1550,9 +1561,14 @@ end) --- The result can be passed to the {list} argument of |setqflist()| or --- |setloclist()|. --- ----@param locations (table) list of `Location`s or `LocationLink`s +---@param locations table list of `Location`s or `LocationLink`s +---@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32 ---@returns (table) list of items -function M.locations_to_items(locations) +function M.locations_to_items(locations, offset_encoding) + if offset_encoding == nil then + vim.notify_once("locations_to_items must be called with valid offset encoding", vim.log.levels.WARN) + end + local items = {} local grouped = setmetatable({}, { __index = function(t, k) @@ -1592,7 +1608,7 @@ function M.locations_to_items(locations) local pos = temp.start local row = pos.line local line = lines[row] or "" - local col = pos.character + local col = M._str_byteindex_enc(line, pos.character, offset_encoding) table.insert(items, { filename = filename, lnum = row + 1, @@ -1776,7 +1792,13 @@ function M._get_offset_encoding(bufnr) local offset_encoding for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do - local this_offset_encoding = client.offset_encoding or "utf-16" + if client.offset_encoding == nil then + vim.notify_once( + string.format("Client (id: %s) offset_encoding is nil. Do not unset offset_encoding.", client.id), + vim.log.levels.ERROR + ) + end + local this_offset_encoding = client.offset_encoding if not offset_encoding then offset_encoding = this_offset_encoding elseif offset_encoding ~= this_offset_encoding then @@ -1905,7 +1927,9 @@ end ---@returns (number, number) `offset_encoding` index of the character in line {row} column {col} in buffer {buf} function M.character_offset(buf, row, col, offset_encoding) local line = get_line(buf, row) - offset_encoding = offset_encoding or M._get_offset_encoding(buf) + if offset_encoding == nil then + vim.notify_once("character_offset must be called with valid offset encoding", vim.log.levels.WARN) + end -- If the col is past the EOL, use the line length. if col > #line then return _str_utfindex_enc(line, nil, offset_encoding) -- cgit From 9304ee3874fc1e0608a9902cf5b1b0ac6645ef0a Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Thu, 13 Jan 2022 06:47:35 -0800 Subject: fix(lsp): forward offset_encoding to apply_text_edits (#17075) --- runtime/lua/vim/lsp/buf.lua | 4 ++-- runtime/lua/vim/lsp/handlers.lua | 6 ++++-- runtime/lua/vim/lsp/util.lua | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index e8633f5924..c9b73e4b70 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -184,7 +184,7 @@ function M.formatting_sync(options, timeout_ms) local result, err = client.request_sync('textDocument/formatting', params, timeout_ms, bufnr) if result and result.result then - util.apply_text_edits(result.result, bufnr) + util.apply_text_edits(result.result, bufnr, client.offset_encoding) elseif err then vim.notify('vim.lsp.buf.formatting_sync: ' .. err, vim.log.levels.WARN) end @@ -228,7 +228,7 @@ function M.formatting_seq_sync(options, timeout_ms, order) local params = util.make_formatting_params(options) local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) if result and result.result then - util.apply_text_edits(result.result, bufnr) + util.apply_text_edits(result.result, bufnr, client.offset_encoding) elseif err then vim.notify(string.format("vim.lsp.buf.formatting_seq_sync: (%s) %s", client.name, err), vim.log.levels.WARN) end diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 6378ed0749..4c0ca28bb9 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -233,13 +233,15 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting M['textDocument/rangeFormatting'] = function(_, result, ctx, _) if not result then return end - util.apply_text_edits(result, ctx.bufnr) + local client = vim.lsp.get_client_by_id(ctx.client_id) + util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting M['textDocument/formatting'] = function(_, result, ctx, _) if not result then return end - util.apply_text_edits(result, ctx.bufnr) + local client = vim.lsp.get_client_by_id(ctx.client_id) + util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d09865be89..edb9f50d20 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -771,7 +771,7 @@ function M.apply_workspace_edit(workspace_edit, offset_encoding) for uri, changes in pairs(all_changes) do local bufnr = vim.uri_to_bufnr(uri) - M.apply_text_edits(changes, bufnr) + M.apply_text_edits(changes, bufnr, offset_encoding) end end -- cgit From 8066abcd65a672010e7159bcb9601f6eb5481e81 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Thu, 13 Jan 2022 09:28:27 -0800 Subject: fix(lsp): forward offset_encoding in rename handler (#17079) --- runtime/lua/vim/lsp/handlers.lua | 5 +++-- runtime/lua/vim/lsp/util.lua | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 4c0ca28bb9..ddfcbf5f75 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -225,9 +225,10 @@ M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'docu M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols') --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename -M['textDocument/rename'] = function(_, result, _) +M['textDocument/rename'] = function(_, result, ctx, _) if not result then return end - util.apply_workspace_edit(result) + local client = vim.lsp.get_client_by_id(ctx.client_id) + util.apply_workspace_edit(result, client.offset_encoding) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index edb9f50d20..4cbd8c9554 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -737,7 +737,8 @@ end --- Applies a `WorkspaceEdit`. --- ----@param workspace_edit (table) `WorkspaceEdit` +---@param workspace_edit table `WorkspaceEdit` +---@param offset_encoding string utf-8|utf-16|utf-32 (required) --see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) if offset_encoding == nil then -- cgit From 596c55756a6a25e8a6d587610292f3e2ca0940b7 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 13 Jan 2022 18:31:15 +0100 Subject: vim-patch:8.2.4077: not all Libsensors files are recognized (#17080) Problem: Not all Libsensors files are recognized. Solution: Add "sensors.d/*" pattern. (Doug Kearns) https://github.com/vim/vim/commit/8d9e470aa91a93da7d6bda62521aef69a79e956d --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 3d91abc406..6ba6b3981d 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1346,6 +1346,7 @@ local pattern = { [".*/constant/g"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*/0/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*/0%.orig/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, + [".*/etc/sensors%.d/[^.].*"] = starsetf('sensors'), -- END PATTERN } -- luacheck: pop -- cgit From 19864bd99529334909922e8d2a61a600fea7b29a Mon Sep 17 00:00:00 2001 From: Gary Sentosa Date: Thu, 6 Jan 2022 21:43:36 +0900 Subject: feat(filetype.lua): fix .env file not detected --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 6ba6b3981d..bf3e060ca6 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1075,6 +1075,7 @@ local filename = { [".alias"] = function() vim.fn["dist#ft#CSH"]() end, [".bashrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, [".cshrc"] = function() vim.fn["dist#ft#CSH"]() end, + [".env"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, [".kshrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end, [".login"] = function() vim.fn["dist#ft#CSH"]() end, [".profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, -- cgit From 94d53589221567444bac2cf6a3692906259fe4c6 Mon Sep 17 00:00:00 2001 From: Gary Sentosa Date: Thu, 6 Jan 2022 16:27:16 +0900 Subject: feat(filetype.lua): add support for tmux.conf files --- runtime/lua/vim/filetype.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index bf3e060ca6..87846f5eed 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1038,6 +1038,7 @@ local filename = { ["tidy.conf"] = "tidy", tidyrc = "tidy", [".tidyrc"] = "tidy", + [".tmux.conf"] = "tmux", ["/.cargo/config"] = "toml", Pipfile = "toml", ["Gopkg.lock"] = "toml", @@ -1233,6 +1234,8 @@ local pattern = { [".*/%.config/systemd/user/.*%.d/.*%.conf"] = "systemd", [".*/etc/systemd/system/.*%.d/.*%.conf"] = "systemd", [".*%.t%.html"] = "tilde", + ["%.?tmux.*%.conf"] = "tmux", + ["%.?tmux.*%.conf.*"] = { "tmux", { priority = -1 } }, [".*/%.cargo/config"] = "toml", [".*/%.cargo/credentials"] = "toml", [".*/etc/udev/udev%.conf"] = "udevconf", -- cgit From 27b664a2de08301ca847c3b06a34df2be71e0caf Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Thu, 6 Jan 2022 21:28:24 +0530 Subject: feat(filetype.lua): add support for patch files --- runtime/lua/vim/filetype.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 87846f5eed..ea7e57c408 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -770,6 +770,14 @@ local extension = { mm = function() vim.fn["dist#ft#FTmm"]() end, mms = function() vim.fn["dist#ft#FTmms"]() end, p = function() vim.fn["dist#ft#FTprogress_pascal"]() end, + patch = function(path, bufnr) + local firstline = getline(bufnr, 1) + if string.find(firstline, "^From " .. string.rep("%x", 40) .. "+ Mon Sep 17 00:00:00 2001$") then + return "gitsendemail" + else + return "diff" + end + end, pl = function() vim.fn["dist#ft#FTpl"]() end, pp = function() vim.fn["dist#ft#FTpp"]() end, pro = function() vim.fn["dist#ft#ProtoCheck"]('idlang') end, -- cgit From 7a574e54f2309eb9d267282619f9383413b85d08 Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Fri, 7 Jan 2022 15:19:49 +0530 Subject: feat(filetype.lua): add support for files under .git --- runtime/lua/vim/filetype.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index ea7e57c408..83e4a20ef7 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1359,6 +1359,12 @@ local pattern = { [".*/0/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*/0%.orig/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*/etc/sensors%.d/[^.].*"] = starsetf('sensors'), + [".*%.git/.*"] = function(path, bufnr) + local firstline = getline(bufnr, 1) + if firstline:find("^" .. string.rep("%x", 40) .. "+ ") or firstline:sub(1, 5) == "ref: " then + return "git" + end + end, -- END PATTERN } -- luacheck: pop -- cgit From c38d602b888a95a4b3b7a3b4241ce5b3e434eb35 Mon Sep 17 00:00:00 2001 From: rhcher <2032877541@qq.com> Date: Sun, 9 Jan 2022 16:49:37 +0800 Subject: feat(filetype.lua): fix .cc file not detected --- runtime/lua/vim/filetype.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 83e4a20ef7..3423be40f9 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -119,7 +119,13 @@ local extension = { tcc = "cpp", hxx = "cpp", hpp = "cpp", - cpp = function() + cpp = function(path, bufnr) + if vim.g.cynlib_syntax_for_cc then + return "cynlib" + end + return "cpp" + end, + cc = function(path, bufnr) if vim.g.cynlib_syntax_for_cc then return "cynlib" end -- cgit From 6e04c8653cf3a5d8d4e9d81645fb65834877349c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 11 Jan 2022 13:50:47 -0700 Subject: fix(filetype): fix foam pattern detection --- runtime/lua/vim/filetype.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 3423be40f9..13da5286c8 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1356,10 +1356,10 @@ local pattern = { ["zlog.*"] = starsetf('zsh'), ["zsh.*"] = starsetf('zsh'), ["ae%d+%.txt"] = 'mail', - ["[a-zA-Z0-9]*Dict"] = function() vim.fn["dist#ft#FTfoam"]() end, - ["[a-zA-Z0-9]*Dict%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, - ["[a-zA-Z]*Properties"] = function() vim.fn["dist#ft#FTfoam"]() end, - ["[a-zA-Z]*Properties%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, + ["[a-zA-Z0-9].*Dict"] = function() vim.fn["dist#ft#FTfoam"]() end, + ["[a-zA-Z0-9].*Dict%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, + ["[a-zA-Z].*Properties"] = function() vim.fn["dist#ft#FTfoam"]() end, + ["[a-zA-Z].*Properties%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*Transport%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*/constant/g"] = function() vim.fn["dist#ft#FTfoam"]() end, [".*/0/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, -- cgit From b72aae85fd980b55a695543c1c34e8f0bf584cc4 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Fri, 14 Jan 2022 08:02:44 -0800 Subject: fix(lsp): always split text edits on \r, \r\n, and \n (#17087) Closes: https://github.com/neovim/neovim/issues/17053 Servers can return a mix of line endings per the language server protocol. See: https://microsoft.github.io/language-server-protocol/specification.html#textDocuments All should be equally treated as line endings. --- runtime/lua/vim/lsp/util.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 4cbd8c9554..8be1683d86 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -422,6 +422,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) local is_cursor_fixed = false local has_eol_text_edit = false for _, text_edit in ipairs(text_edits) do + -- Normalize line ending + text_edit.newText, _ = string.gsub(text_edit.newText, '\r\n?', '\n') + -- Convert from LSP style ranges to Neovim style ranges. local e = { start_row = text_edit.range.start.line, -- cgit From 59ea8fa322c946183631233ae546e3e8b0c37e30 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 14 Jan 2022 14:20:17 -0700 Subject: fix(filetype): expand tildes in filetype patterns (#17091) This allows patterns like ["~/.config/foo"] = "fooscript" to work. --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 13da5286c8..819587bb3e 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1398,7 +1398,7 @@ local pattern_sorted = sort_by_priority(pattern) ---@private local function normalize_path(path) - return (path:gsub("\\", "/")) + return (path:gsub("\\", "/"):gsub("^~", vim.env.HOME)) end --- Add new filetype mappings. -- cgit From 574a5822023939d534d922eaa345bb7e0633d2b8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 14 Jan 2022 14:20:50 -0700 Subject: feat(lsp): dynamically generate list title in response_to_list (#17081) This gives quickfix/location lists created by handlers which use 'response_to_list' (textDocument/documentSymbols and workspace/symbol by default) the ability to set a more useful list title. This commit gives lists created for documentSymbols a title of the form: Symbols in and lists for workspace/symbol a title of the form: Symbols matching '' These are more informative than a standard "Language Server" list title and can help disambiguate results when users have multiple quickfix lists that they cycle through with `:colder` and `:cnewer`. --- runtime/lua/vim/lsp/handlers.lua | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index ddfcbf5f75..c0843e1577 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -162,21 +162,23 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references -M['textDocument/references'] =function(_, result, ctx, config) +M['textDocument/references'] = function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then vim.notify('No references found') else config = config or {} if config.loclist then vim.fn.setloclist(0, {}, ' ', { - title = 'Language Server'; + title = 'References'; items = util.locations_to_items(result, ctx.offset_encoding); + context = ctx; }) api.nvim_command("lopen") else vim.fn.setqflist({}, ' ', { - title = 'Language Server'; + title = 'References'; items = util.locations_to_items(result, ctx.offset_encoding); + context = ctx; }) api.nvim_command("botright copen") end @@ -193,23 +195,26 @@ end --- loclist: (boolean) use the location list (default is to use the quickfix list) --- ---@param map_result function `((resp, bufnr) -> list)` to convert the response ----@param entity name of the resource used in a `not found` error message -local function response_to_list(map_result, entity) - return function(_,result, ctx, config) +---@param entity string name of the resource used in a `not found` error message +---@param title_fn function Function to call to generate list title +local function response_to_list(map_result, entity, title_fn) + return function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then vim.notify('No ' .. entity .. ' found') else config = config or {} if config.loclist then vim.fn.setloclist(0, {}, ' ', { - title = 'Language Server'; + title = title_fn(ctx); items = map_result(result, ctx.bufnr); + context = ctx; }) api.nvim_command("lopen") else vim.fn.setqflist({}, ' ', { - title = 'Language Server'; + title = title_fn(ctx); items = map_result(result, ctx.bufnr); + context = ctx; }) api.nvim_command("botright copen") end @@ -219,10 +224,15 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol -M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols') +M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols', function(ctx) + local fname = vim.fn.fnamemodify(vim.uri_to_fname(ctx.params.textDocument.uri), ":.") + return string.format('Symbols in %s', fname) +end) --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol -M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols') +M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols', function(ctx) + return string.format("Symbols matching '%s'", ctx.params.query) +end) --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M['textDocument/rename'] = function(_, result, ctx, _) -- cgit From b455e0179b4288c69e6231bfcf8d1c132b78f2fc Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sat, 15 Jan 2022 14:19:20 -0800 Subject: feat: use nvim_buf_set_extmark for vim.highlight (#16963) Closes https://github.com/neovim/neovim/issues/13647 This allows customizing the priority of the highlights. * Add default priority of 50 * Use priority of 200 for highlight on yank * use priority of 40 for highlight references (LSP) --- runtime/lua/vim/highlight.lua | 19 ++++++++++++++++--- runtime/lua/vim/lsp/util.lua | 5 ++++- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 236f3165f2..12faa0a6e1 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -25,16 +25,29 @@ end ---@param higroup highlight group to use for highlighting ---@param rtype type of range (:help setreg, default charwise) ---@param inclusive boolean indicating whether the range is end-inclusive (default false) -function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive) +---@param priority number indicating priority of highlight (default 50) +function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive, priority) rtype = rtype or 'v' inclusive = inclusive or false + priority = priority or 50 -- sanity check if start[2] < 0 or finish[1] < start[1] then return end local region = vim.region(bufnr, start, finish, rtype, inclusive) for linenr, cols in pairs(region) do - api.nvim_buf_add_highlight(bufnr, ns, higroup, linenr, cols[1], cols[2]) + local end_row + if cols[2] == -1 then + end_row = linenr + 1 + cols[2] = 0 + end + api.nvim_buf_set_extmark(bufnr, ns, linenr, cols[1], { + hl_group = higroup, + end_row = end_row, + end_col = cols[2], + priority = priority, + strict = false + }) end end @@ -82,7 +95,7 @@ function highlight.on_yank(opts) pos1 = {pos1[2] - 1, pos1[3] - 1 + pos1[4]} pos2 = {pos2[2] - 1, pos2[3] - 1 + pos2[4]} - highlight.range(bufnr, yank_ns, higroup, pos1, pos2, event.regtype, event.inclusive) + highlight.range(bufnr, yank_ns, higroup, pos1, pos2, event.regtype, event.inclusive, 200) vim.defer_fn( function() diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 8be1683d86..d22c00ae76 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1550,7 +1550,10 @@ do --[[ References ]] reference_ns, document_highlight_kind[kind], { start_line, start_idx }, - { end_line, end_idx }) + { end_line, end_idx }, + nil, + false, + 40) end end end -- cgit From a0201b6ed37bae594bd0db2804c8ecff09a29e0e Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sat, 15 Jan 2022 15:49:29 -0800 Subject: fix(lsp): fetch offset_encoding from client in references (#17104) --- runtime/lua/vim/lsp/handlers.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index c0843e1577..36ab6d59dd 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -166,18 +166,19 @@ M['textDocument/references'] = function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then vim.notify('No references found') else + local client = vim.lsp.get_client_by_id(ctx.client_id) config = config or {} if config.loclist then vim.fn.setloclist(0, {}, ' ', { title = 'References'; - items = util.locations_to_items(result, ctx.offset_encoding); + items = util.locations_to_items(result, client.offset_encoding); context = ctx; }) api.nvim_command("lopen") else vim.fn.setqflist({}, ' ', { title = 'References'; - items = util.locations_to_items(result, ctx.offset_encoding); + items = util.locations_to_items(result, client.offset_encoding); context = ctx; }) api.nvim_command("botright copen") -- cgit From 7085e5b0c8588618e643c87802afc515f67812d9 Mon Sep 17 00:00:00 2001 From: Daniel Steinberg Date: Sun, 16 Jan 2022 02:08:35 -0500 Subject: fix(lsp): avoid nil workspace/symbol query (#17107) --- runtime/lua/vim/lsp/buf.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index c9b73e4b70..eb7ec579f1 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -447,6 +447,9 @@ end ---@param query (string, optional) function M.workspace_symbol(query) query = query or npcall(vfn.input, "Query: ") + if query == nil then + return + end local params = {query = query} request('workspace/symbol', params) end -- cgit From 9055ec5792d29eb8ad5e5c20708ffcb980ad8609 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Mon, 17 Jan 2022 08:19:33 -0800 Subject: perf(lsp): request only changed portions of the buffer in changetracking (#17118) This commits introduces two performance improvements in incremental sync: * avoiding expensive lua string reallocations on each on_lines call by requesting only the changed chunk of the buffer as reported by firstline and new_lastline parameters of on_lines * re-using already allocated tables for storing the resulting lines to reduce the load on the garbage collector The majority of the performance improvement is from requesting only changed chunks of the buffer. Benchmark: The following code measures the time required to perform a buffer edit to that operates individually on each line, common to plugins such as vim-commentary. set rtp+=~/.config/nvim/plugged/nvim-lspconfig set rtp+=~/.config/nvim/plugged/vim-commentary lua require('lspconfig')['ccls'].setup({}) function! Benchmark(tries) abort let results_comment = [] let results_undo = [] for i in range(a:tries) echo printf('run %d', i+1) let begin = reltime() normal gggcG call add(results_comment, reltimefloat(reltime(begin))) let begin = reltime() silent! undo call add(results_undo, reltimefloat(reltime(begin))) redraw endfor let avg_comment = 0.0 let avg_undo = 0.0 for i in range(a:tries) echomsg printf('run %3d: comment=%fs undo=%fs', i+1, results_comment[i], results_undo[i]) let avg_comment += results_comment[i] let avg_undo += results_undo[i] endfor echomsg printf('average: comment=%fs undo=%fs', avg_comment / a:tries, avg_undo / a:tries) endfunction command! -bar Benchmark call Benchmark(10) All text changes will be recorded within a single undo operation. Both the comment operation itself and the undo operation will generate an on_lines event for each changed line. Formatter plugins using setline() have also been found to exhibit the same problem (neoformat, :RustFmt in rust.vim), as this function too generates an on_lines event for every line it changes. Using the neovim codebase as an example (commit 2ecf0a4) with neovim itself built at 2ecf0a4 with CMAKE_BUILD_TYPE=Release shows the following performance improvement: src/nvim/lua/executor.c, 1432 lines: - baseline, no optimizations: comment=0.540587s undo=0.440249s - without double-buffering optimization: comment=0.183314s undo=0.060663s - all optimizations in this commit: comment=0.174850s undo=0.052789s src/nvim/search.c, 5467 lines: - baseline, no optimizations: comment=7.420446s undo=7.656624s - without double-buffering optimization: comment=0.889048s undo=0.486026s - all optimizations in this commit: comment=0.662899s undo=0.243628s src/nvim/eval.c, 11355 lines: - baseline, no optimizations: comment=41.775695s undo=44.583374s - without double-buffering optimization: comment=3.643933s undo=2.817158s - all optimizations in this commit: comment=1.510886s undo=0.707928s Co-authored-by: Dmytro Meleshko --- runtime/lua/vim/lsp.lua | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 8b7eb4ac90..37e222a5ce 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -344,6 +344,7 @@ do state.buffers[bufnr] = buf_state if use_incremental_sync then buf_state.lines = nvim_buf_get_lines(bufnr, 0, -1, true) + buf_state.lines_tmp = {} buf_state.pending_changes = {} end end @@ -403,11 +404,40 @@ do ---@private function changetracking.prepare(bufnr, firstline, lastline, new_lastline) local incremental_changes = function(client, buf_state) - local curr_lines = nvim_buf_get_lines(bufnr, 0, -1, true) + + local prev_lines = buf_state.lines + local curr_lines = buf_state.lines_tmp + + local changed_lines = nvim_buf_get_lines(bufnr, firstline, new_lastline, true) + for i = 1, firstline do + curr_lines[i] = prev_lines[i] + end + for i = firstline + 1, new_lastline do + curr_lines[i] = changed_lines[i - firstline] + end + for i = lastline + 1, #prev_lines do + curr_lines[i - lastline + new_lastline] = prev_lines[i] + end + if tbl_isempty(curr_lines) then + -- Can happen when deleting the entire contents of a buffer, see https://github.com/neovim/neovim/issues/16259. + curr_lines[1] = '' + end + local line_ending = buf_get_line_ending(bufnr) local incremental_change = sync.compute_diff( buf_state.lines, curr_lines, firstline, lastline, new_lastline, client.offset_encoding or 'utf-16', line_ending) + + -- Double-buffering of lines tables is used to reduce the load on the garbage collector. + -- At this point the prev_lines table is useless, but its internal storage has already been allocated, + -- so let's keep it around for the next didChange event, in which it will become the next + -- curr_lines table. Note that setting elements to nil doesn't actually deallocate slots in the + -- internal storage - it merely marks them as free, for the GC to deallocate them. + for i in ipairs(prev_lines) do + prev_lines[i] = nil + end buf_state.lines = curr_lines + buf_state.lines_tmp = prev_lines + return incremental_change end local full_changes = once(function() -- cgit From 8e702c14ac5fc481bc4a3c709e75e3c165326128 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Thu, 20 Jan 2022 22:51:34 -0800 Subject: feat(lsp): add handler for workspace/workspaceFolders (#17149) --- runtime/lua/vim/lsp/handlers.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 36ab6d59dd..a997b887d9 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -152,6 +152,17 @@ M['workspace/configuration'] = function(_, result, ctx) return response end +--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_workspaceFolders +M['workspace/workspaceFolders'] = function(_, _, ctx) + local client_id = ctx.client_id + local client = vim.lsp.get_client_by_id(client_id) + if not client then + err_message("LSP[id=", client_id, "] client has shut down after sending the message") + return + end + return client.workspace_folders or vim.NIL +end + M['textDocument/publishDiagnostics'] = function(...) return require('vim.lsp.diagnostic').on_publish_diagnostics(...) end -- cgit From c977d8b43cd6ecf7ad756f9b064eadea79fbd604 Mon Sep 17 00:00:00 2001 From: xnmet <72987524+xnmet@users.noreply.github.com> Date: Fri, 21 Jan 2022 04:40:48 -0300 Subject: docs(lsp): fix on_publish_diagnostics example (#17146) --- runtime/lua/vim/lsp/diagnostic.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index f38b469f3c..68942ae11a 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -168,8 +168,8 @@ end --- }, --- -- Use a function to dynamically turn signs off --- -- and on, using buffer local variables ---- signs = function(bufnr, client_id) ---- return vim.bo[bufnr].show_signs == false +--- signs = function(namespace, bufnr) +--- return vim.b[bufnr].show_signs == true --- end, --- -- Disable a feature --- update_in_insert = false, -- cgit From 9d02fc4c00f61724610224f91950c51bd2700c97 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 21 Jan 2022 16:45:32 +0100 Subject: vim-patch:8.2.4172: filetype detection for BASIC is not optimal (#17161) Problem: Filetype detection for BASIC is not optimal. Solution: Improve BASIC filetype detection. (Doug Kearns) https://github.com/vim/vim/commit/6517f14165cdebf83a07ab9d4aeeb102b4e16e92 --- runtime/lua/vim/filetype.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 819587bb3e..c7e18bf186 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -220,7 +220,6 @@ local extension = { ["f08"] = "fortran", fpc = "fpcmake", fsl = "framescript", - bi = "freebasic", fb = "freebasic", fsi = "fsharp", fsx = "fsharp", @@ -738,7 +737,9 @@ local extension = { PL = function() vim.fn["dist#ft#FTpl"]() end, R = function() vim.fn["dist#ft#FTr"]() end, asm = function() vim.fn["dist#ft#FTasm"]() end, - bas = function() vim.fn["dist#ft#FTVB"]("basic") end, + bas = function() vim.fn["dist#ft#FTbas"]() end, + bi = function() vim.fn["dist#ft#FTbas"]() end, + bm = function() vim.fn["dist#ft#FTbas"]() end, bash = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, btm = function() vim.fn["dist#ft#FTbtm"]() end, c = function() vim.fn["dist#ft#FTlpc"]() end, -- cgit From 3d62dd207733bbdc46fd5b6807e5d7dcf95681e2 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 23 Jan 2022 13:52:37 +0100 Subject: vim-patch:8.2.4187: gnuplot file not recognized (#17177) Problem: Gnuplot file not recognized. Solution: Recognize ".gnuplot". (closes vim/vim#9588) https://github.com/vim/vim/commit/ff5cbe8133c6eb5dd86b9e042f32f589627e9bf9 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c7e18bf186..e5168403b2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -230,6 +230,7 @@ local extension = { gemini = "gemtext", gift = "gift", gpi = "gnuplot", + gnuplot = "gnuplot", go = "go", gp = "gp", gs = "grads", -- cgit From ffd9551aa210ecd652044ad3c43eb480858f191a Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 23 Jan 2022 16:19:48 +0100 Subject: vim-patch:8.2.4191: json5 files are not recognized (#17180) Problem: json5 files are not recognized. Solution: Add a pattern for json5 files. (closes vim/vim#9601) https://github.com/vim/vim/commit/e15ebeffb35da4bb7d9054358671735ce6988c28 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index e5168403b2..060022bce1 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -293,6 +293,7 @@ local extension = { webmanifest = "json", ipynb = "json", ["json-patch"] = "json", + json5 = "json5", jsonc = "jsonc", jsp = "jsp", jl = "julia", -- cgit From 28352dc6e50b9559f32f054c56dc950a79ae45bc Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 23 Jan 2022 17:50:45 +0100 Subject: vim-patch:8.2.4188: not all gitconfig files are recognized (#17178) Problem: Not all gitconfig files are recognized. Solution: Add a few more patterns. (Tim Pope, closes vim/vim#9597) https://github.com/vim/vim/commit/bcfa11b7dfdfbb4d412dd843a6da3fce68ba2e39 --- runtime/lua/vim/filetype.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 060022bce1..736ecc1ff7 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -893,8 +893,6 @@ local filename = { ["EDIT_DESCRIPTION"] = "gitcommit", [".gitconfig"] = "gitconfig", [".gitmodules"] = "gitconfig", - ["/.config/git/config"] = "gitconfig", - ["/etc/gitconfig"] = "gitconfig", ["gitolite.conf"] = "gitolite", ["git-rebase-todo"] = "gitrebase", gkrellmrc = "gkrellmrc", @@ -1149,7 +1147,10 @@ local pattern = { [".*Eterm/.*%.cfg"] = "eterm", [".*%.git/modules/.*/config"] = "gitconfig", [".*%.git/config"] = "gitconfig", + [".*/etc/gitconfig"] = "gitconfig", [".*/%.config/git/config"] = "gitconfig", + [".*%.git/config%.worktree"] = "gitconfig", + [".*%.git/worktrees/.*/config%.worktree"] = "gitconfig", ["%.gitsendemail%.msg%......."] = "gitsendemail", ["gkrellmrc_."] = "gkrellmrc", [".*/usr/.*/gnupg/options%.skel"] = "gpg", -- cgit From ecec957125ca95ef5fbc4534d62ed16cfedb0c44 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 25 Jan 2022 08:22:15 +0100 Subject: vim-patch:8.2.4196: various file types not recognized (#17182) Problem: Various file types not recognized. Solution: Add patterns to recognize more file types (closes vim/vim#9607) https://github.com/vim/vim/commit/428058ab3213e81531cbd7989f4267870f35d52e --- runtime/lua/vim/filetype.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 736ecc1ff7..bd3b44e95b 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -223,23 +223,34 @@ local extension = { fb = "freebasic", fsi = "fsharp", fsx = "fsharp", + fusion = "fusion", gdmo = "gdmo", mo = "gdmo", + tres = "gdresource", + tscn = "gdresource", + gd = "gdscript", ged = "gedcom", gmi = "gemtext", gemini = "gemtext", gift = "gift", + glsl = "glsl", gpi = "gnuplot", gnuplot = "gnuplot", go = "go", gp = "gp", gs = "grads", + gql = "graphql", + graphql = "graphql", + graphqls = "graphql", gretl = "gretl", gradle = "groovy", groovy = "groovy", gsp = "gsp", + hack = "hack", + hackpartial = "hack", haml = "haml", hsm = "hamster", + hbs = "handlebars", ["hs-boot"] = "haskell", hsig = "haskell", hsc = "haskell", @@ -251,8 +262,11 @@ local extension = { errsum = "hercules", ev = "hercules", vc = "hercules", + hcl = "hcl", + heex = "heex", hex = "hex", ["h32"] = "hex", + hjson = "hjson", hog = "hog", hws = "hollywood", htt = "httest", @@ -310,6 +324,9 @@ local extension = { lte = "latte", ld = "ld", ldif = "ldif", + journal = "ledger", + ldg = "ledger", + ledger = "ledger", less = "less", lex = "lex", lxx = "lex", @@ -393,6 +410,7 @@ local extension = { ncf = "ncf", nginx = "nginx", ninja = "ninja", + nix = "nix", nqc = "nqc", roff = "nroff", tmac = "nroff", @@ -427,6 +445,7 @@ local extension = { pcmk = "pcmk", pdf = "pdf", plx = "perl", + prisma = "prisma", psgi = "perl", al = "perl", ctp = "php", @@ -470,6 +489,7 @@ local extension = { ["ps1xml"] = "ps1xml", psf = "psf", psl = "psl", + pug = "pug", arr = "pyret", pxd = "pyrex", pyx = "pyrex", @@ -477,6 +497,8 @@ local extension = { py = "python", pyi = "python", ptl = "python", + ql = "ql", + qll = "ql", rad = "radiance", mat = "radiance", ["pod6"] = "raku", @@ -613,6 +635,7 @@ local extension = { mata = "stata", ado = "stata", stp = "stp", + sface = "surface", svelte = "svelte", svg = "svg", swift = "swift", @@ -626,6 +649,7 @@ local extension = { itcl = "tcl", tk = "tcl", jacl = "tcl", + tl = "teal", tmpl = "template", ti = "terminfo", dtx = "tex", @@ -638,6 +662,8 @@ local extension = { texinfo = "texinfo", text = "text", tf = "tf", + tfvars = "terraform", + tla = "tla", tli = "tli", toml = "toml", tpp = "tpp", @@ -725,6 +751,7 @@ local extension = { yxx = "yacc", yml = "yaml", yaml = "yaml", + yang = "yang", ["z8a"] = "z8a", zig = "zig", zu = "zimbu", @@ -900,6 +927,7 @@ local filename = { [".gnashpluginrc"] = "gnash", gnashpluginrc = "gnash", gnashrc = "gnash", + ["go.work"] = "gowork", [".gprc"] = "gp", ["/.gnupg/gpg.conf"] = "gpg", ["/.gnupg/options"] = "gpg", -- cgit From f9080b24c4f60c3772db2b6e713ea5a6a3b52f1e Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 27 Jan 2022 09:42:59 +0000 Subject: fix(ts): escape lang when loading parsers (#16668) When trying to load a language parser, escape the value of the language. With language injection, the language might be picked up from the buffer. If this value is erroneous it can cause `nvim_get_runtime_file` to hard error. E.g., the markdown expression `~~~{` will extract '{' as a language and then try to get the parser using `parser/{*` as the pattern. --- runtime/lua/vim/treesitter/language.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index 6f347ff25f..8b106108df 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -14,7 +14,7 @@ function M.require_language(lang, path, silent) return true end if path == nil then - local fname = 'parser/' .. lang .. '.*' + local fname = 'parser/' .. vim.fn.fnameescape(lang) .. '.*' local paths = a.nvim_get_runtime_file(fname, false) if #paths == 0 then if silent then -- cgit From 8c140be31f0d203b63e7052e698fdfe253e0b5d4 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 27 Jan 2022 12:46:56 +0100 Subject: feat(ts): expose minimum language version to lua (#17186) --- runtime/lua/vim/treesitter.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 07f6418c0c..f9d539f028 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -11,6 +11,7 @@ local parsers = {} local M = vim.tbl_extend("error", query, language) M.language_version = vim._ts_get_language_version() +M.minimum_language_version = vim._ts_get_minimum_language_version() setmetatable(M, { __index = function (t, k) -- cgit From 5b9980f01eb021b0d84f540a6618f94ad2727153 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 28 Jan 2022 16:59:17 +0100 Subject: vim-patch:8.2.4238: *.tf file could be fileytpe "tf" or "terraform" Problem: *.tf file could be fileytpe "tf" or "terraform". Solution: Detect the type from the file contents. (closes vim/vim#9642) https://github.com/vim/vim/commit/bd8168c7705e315827642f2976ec59e26b7fe009 --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index bd3b44e95b..7fa2fbe001 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -661,7 +661,6 @@ local extension = { txi = "texinfo", texinfo = "texinfo", text = "text", - tf = "tf", tfvars = "terraform", tla = "tla", tli = "tli", @@ -827,6 +826,7 @@ local extension = { stm = function() vim.fn["dist#ft#FThtml"]() end, tcsh = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, tex = function() vim.fn["dist#ft#FTtex"]() end, + tf = function() vim.fn["dist#ft#FTtf"]() end, w = function() vim.fn["dist#ft#FTprogress_cweb"]() end, xml = function() vim.fn["dist#ft#FTxml"]() end, y = function() vim.fn["dist#ft#FTy"]() end, -- cgit From b2f77c354a289ac99de4c28425dc39d7d057cf90 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 29 Jan 2022 15:40:29 +0100 Subject: vim-patch:8.2.4251: vala files are not recognized (#17235) Problem: Vala files are not recognized. Solution: Add the *.vala pattern. (closes vim/vim#9654) https://github.com/vim/vim/commit/97c554d5149c2aa4a43d689c59563e77277265d4 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 7fa2fbe001..82ef2f6263 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -756,6 +756,7 @@ local extension = { zu = "zimbu", zut = "zimbutempl", zsh = "zsh", + vala = "vala", E = function() vim.fn["dist#ft#FTe"]() end, EU = function() vim.fn["dist#ft#EuphoriaCheck"]() end, EW = function() vim.fn["dist#ft#EuphoriaCheck"]() end, -- cgit From 4458413bc02a1308bd722611227664033916d6f7 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 29 Jan 2022 13:43:06 -0600 Subject: feat(filetype): convert patterns for mail buffers (#17238) --- runtime/lua/vim/filetype.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 82ef2f6263..adc838578d 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1389,6 +1389,16 @@ local pattern = { ["zlog.*"] = starsetf('zsh'), ["zsh.*"] = starsetf('zsh'), ["ae%d+%.txt"] = 'mail', + ["snd%.%d+"] = "mail", + ["%.letter%.%d+"] = "mail", + ["%.article%.%d+"] = "mail", + ["pico%.%d+"] = "mail", + ["mutt%-.*%-%w+"] = "mail", + ["neomutt%-.*%-%w+"] = "mail", + ["muttng%-.*%-%w+"] = "mail", + ["mutt" .. string.rep("[%w_-]", 6)] = "mail", + ["neomutt" .. string.rep("[%w_-]", 6)] = "mail", + ["/tmp/SLRN[0-9A-Z.]+"] = "mail", ["[a-zA-Z0-9].*Dict"] = function() vim.fn["dist#ft#FTfoam"]() end, ["[a-zA-Z0-9].*Dict%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, ["[a-zA-Z].*Properties"] = function() vim.fn["dist#ft#FTfoam"]() end, -- cgit From abde91ecaf338da4a0b88e383583624b5cab7b30 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 30 Jan 2022 13:32:55 +0100 Subject: docs: add example to vim.ui.select (#17241) Closes https://github.com/neovim/neovim/issues/17137 --- runtime/lua/vim/ui.lua | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 9568b60fd0..0f2de6ce5c 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -18,6 +18,24 @@ local M = {} --- Called once the user made a choice. --- `idx` is the 1-based index of `item` within `item`. --- `nil` if the user aborted the dialog. +--- +--- +--- Example: +---
+--- vim.ui.select({ 'tabs', 'spaces' }, {
+---     prompt = 'Select tabs or spaces:',
+---     format_item = function(item)
+---         return "I'd like to choose " .. item
+---     end,
+--- }, function(choice)
+---     if choice == 'spaces' then
+---         vim.o.expandtab = true
+---     else
+---         vim.o.expandtab = false
+---     end
+--- end)
+--- 
+ function M.select(items, opts, on_choice) vim.validate { items = { items, 'table', false }, @@ -57,6 +75,13 @@ end --- Called once the user confirms or abort the input. --- `input` is what the user typed. --- `nil` if the user aborted the dialog. +--- +--- Example: +---
+--- vim.ui.input({ prompt = 'Select value for shiftwidth: ' }, function(input)
+---     vim.o.shiftwidth = tonumber(input)
+--- end)
+--- 
function M.input(opts, on_confirm) vim.validate { on_confirm = { on_confirm, 'function', false }, -- cgit From bddce4b0ff0eb7ac1f652eea6fce81b3e2cc5044 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 31 Jan 2022 18:09:51 +0100 Subject: vim-patch:c4573eb12dba (#17258) Update runtime files https://github.com/vim/vim/commit/c4573eb12dba6a062af28ee0b8938d1521934ce4 --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index adc838578d..ff44f48195 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -789,7 +789,7 @@ local extension = { ex = function() vim.fn["dist#ft#ExCheck"]() end, exu = function() vim.fn["dist#ft#EuphoriaCheck"]() end, exw = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - frm = function() vim.fn["dist#ft#FTVB"]("form") end, + frm = function() vim.fn["dist#ft#FTbas"]("form") end, fs = function() vim.fn["dist#ft#FTfs"]() end, h = function() vim.fn["dist#ft#FTheader"]() end, htm = function() vim.fn["dist#ft#FThtml"]() end, -- cgit From a562b5771ea91becd0a469378ec852feaf50d2d0 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 1 Feb 2022 08:35:28 +0100 Subject: vim-patch:8.2.4274: Basic and form filetype detection is incomplete (#17259) Problem: Basic and form filetype detection is incomplete. Solution: Add a separate function for .frm files. (Doug Kearns, closes vim/vim#9675) https://github.com/vim/vim/commit/c570e9cf68c0fe30366e82c96be460047dd659b9 --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index ff44f48195..e2cf408f3b 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -789,7 +789,7 @@ local extension = { ex = function() vim.fn["dist#ft#ExCheck"]() end, exu = function() vim.fn["dist#ft#EuphoriaCheck"]() end, exw = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - frm = function() vim.fn["dist#ft#FTbas"]("form") end, + frm = function() vim.fn["dist#ft#FTfrm"]() end, fs = function() vim.fn["dist#ft#FTfs"]() end, h = function() vim.fn["dist#ft#FTheader"]() end, htm = function() vim.fn["dist#ft#FThtml"]() end, -- cgit From 64116d78502e0ca611e13adf9323ef2d3fe708c2 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 8 Feb 2022 01:19:06 +0100 Subject: chore: fix typos (#17250) Co-authored-by: zeertzjq Co-authored-by: Dani Dickstein Co-authored-by: Axel Dahlberg --- runtime/lua/vim/ui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 0f2de6ce5c..9d4b38f08a 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -78,7 +78,7 @@ end --- --- Example: ---
---- vim.ui.input({ prompt = 'Select value for shiftwidth: ' }, function(input)
+--- vim.ui.input({ prompt = 'Enter value for shiftwidth: ' }, function(input)
 ---     vim.o.shiftwidth = tonumber(input)
 --- end)
 --- 
-- cgit From afcf64479c1aa5ea53286853370082507f2721f7 Mon Sep 17 00:00:00 2001 From: kevinhwang91 Date: Fri, 11 Feb 2022 14:42:23 +0800 Subject: fix(query.lua): check empty table for lines The range of node may make `nvim_buf_get_lines` return an empty table. --- runtime/lua/vim/treesitter/query.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index b3036ea679..14940332d6 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -199,11 +199,13 @@ function M.get_node_text(node, source) lines = a.nvim_buf_get_lines(source, start_row, end_row + 1, true) end - if #lines == 1 then - lines[1] = string.sub(lines[1], start_col+1, end_col) - else - lines[1] = string.sub(lines[1], start_col+1) - lines[#lines] = string.sub(lines[#lines], 1, end_col) + if #lines > 0 then + if #lines == 1 then + lines[1] = string.sub(lines[1], start_col+1, end_col) + else + lines[1] = string.sub(lines[1], start_col+1) + lines[#lines] = string.sub(lines[#lines], 1, end_col) + end end return table.concat(lines, "\n") -- cgit From f6329ea137730e571671ee31309ec1b7dc6ec85e Mon Sep 17 00:00:00 2001 From: Lajos Koszti Date: Fri, 11 Feb 2022 14:04:15 +0100 Subject: fix(lsp): correct prefix when filterText is present (#17051) LSP server might return an item which would replace a token to another. For example in typescript for a `jest.Mock` object `getProductsMock.` text I get the following response: ``` { commitCharacters = { ".", ",", "(" }, data = { entryNames = { "Symbol" }, file = "/foo/bar/baz.service.spec.ts", line = 268, offset = 17 }, filterText = ".Symbol", kind = 6, label = "Symbol", sortText = "11", textEdit = { newText = "[Symbol]", range = { end = { character = 16, line = 267 }, start = { character = 15, line = 267 } } } }, ``` In `lsp.omnifunc` to get a `prefix` we call the `adjust_start_col` which then returns the `textEdit.range.start.character`. Th `prefix` then be the `.` character. Then when filter the items with `remove_unmatch_completion_items`, every item will be filtered out, since no completion word starts `.`. To fix we return the `end.character`, which in that particular case will be the position after the `.`. --- runtime/lua/vim/lsp.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 37e222a5ce..8d11b4621c 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1598,7 +1598,7 @@ end local function adjust_start_col(lnum, line, items, encoding) local min_start_char = nil for _, item in pairs(items) do - if item.textEdit and item.textEdit.range.start.line == lnum - 1 then + if item.filterText == nil and item.textEdit and item.textEdit.range.start.line == lnum - 1 then if min_start_char and min_start_char ~= item.textEdit.range.start.character then return nil end -- cgit From 3b13c7fc8b15d2ab90c070131c0268711fcf4f10 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 12 Feb 2022 12:03:02 +0100 Subject: vim-patch:8.2.4352: ReScript files are not recognized Problem: ReScript files are not recognized. Solution: Add the *.res and *.resi patterns. (Ananda Umamil, closes vim/vim#9752) https://github.com/vim/vim/commit/0c3cc2fec31521b0697edc406f85b7a43e979860 --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index e2cf408f3b..2fe4aa3d32 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -514,6 +514,8 @@ local extension = { rego = "rego", rem = "remind", remind = "remind", + res = "rescript", + resi = "rescript", frt = "reva", testUnit = "rexx", rex = "rexx", -- cgit From e4819017480c801c07619bfe740cc934e2f4c85b Mon Sep 17 00:00:00 2001 From: Chinmay Dalal Date: Sun, 13 Feb 2022 19:13:25 +0530 Subject: docs: treesitter.txt - fix overflowing lines, document minimum_language_version (#17286) --- runtime/lua/vim/treesitter/languagetree.lua | 28 +++++++++++++++------------- runtime/lua/vim/treesitter/query.lua | 4 ++-- 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 85fd5cd8e0..b83df65151 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -76,8 +76,8 @@ function LanguageTree:lang() end --- Determines whether this tree is valid. ---- If the tree is invalid, `parse()` must be called ---- to get the updated tree. +--- If the tree is invalid, call `parse()`. +--- This will return the updated tree. function LanguageTree:is_valid() return self._valid end @@ -234,7 +234,9 @@ end --- Destroys this language tree and all its children. --- --- Any cleanup logic should be performed here. ---- Note, this DOES NOT remove this tree from a parent. +--- +--- Note: +--- This DOES NOT remove this tree from a parent. Instead, --- `remove_child` must be called on the parent to remove it. function LanguageTree:destroy() -- Cleanup here @@ -448,14 +450,14 @@ function LanguageTree:_on_detach(...) self:_do_callback('detach', ...) end ---- Registers callbacks for the parser ----@param cbs An `nvim_buf_attach`-like table argument with the following keys : ---- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback. ---- `on_changedtree` : a callback that will be called every time the tree has syntactical changes. ---- it will only be passed one argument, that is a table of the ranges (as node ranges) that ---- changed. ---- `on_child_added` : emitted when a child is added to the tree. ---- `on_child_removed` : emitted when a child is removed from the tree. +--- Registers callbacks for the parser. +---@param cbs table An |nvim_buf_attach()|-like table argument with the following keys : +--- - `on_bytes` : see |nvim_buf_attach()|, but this will be called _after_ the parsers callback. +--- - `on_changedtree` : a callback that will be called every time the tree has syntactical changes. +--- It will only be passed one argument, which is a table of the ranges (as node ranges) that +--- changed. +--- - `on_child_added` : emitted when a child is added to the tree. +--- - `on_child_removed` : emitted when a child is removed from the tree. function LanguageTree:register_cbs(cbs) if not cbs then return end @@ -493,7 +495,7 @@ local function tree_contains(tree, range) return false end ---- Determines whether @param range is contained in this language tree +--- Determines whether {range} is contained in this language tree --- --- This goes down the tree to recursively check children. --- @@ -508,7 +510,7 @@ function LanguageTree:contains(range) return false end ---- Gets the appropriate language that contains @param range +--- Gets the appropriate language that contains {range} --- ---@param range A text range, see |LanguageTree:contains| function LanguageTree:language_for_range(range) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 14940332d6..8383551b5f 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -146,13 +146,13 @@ local query_cache = setmetatable({}, { }) --- Parse {query} as a string. (If the query is in a file, the caller ---- should read the contents into a string before calling). +--- should read the contents into a string before calling). --- --- Returns a `Query` (see |lua-treesitter-query|) object which can be used to --- search nodes in the syntax tree for the patterns defined in {query} --- using `iter_*` methods below. --- ---- Exposes `info` and `captures` with additional information about the {query}. +--- Exposes `info` and `captures` with additional context about {query}. --- - `captures` contains the list of unique capture names defined in --- {query}. --- -` info.captures` also points to `captures`. -- cgit From 8ab5ec4aaaeed27b1d8086d395171a52568378c2 Mon Sep 17 00:00:00 2001 From: Stephan Seitz Date: Wed, 16 Feb 2022 19:38:19 +0100 Subject: feat(tree-sitter): allow Atom-style capture fallbacks (#14196) This allows falling back to `@definition` when we have no mapping `@definition.fancy-specialization`. This behavior is described in tree-sitter's documentation (https://tree-sitter.github.io/tree-sitter/syntax-highlighting#theme). Fixes https://github.com/nvim-treesitter/nvim-treesitter/issues/738 --- runtime/lua/vim/treesitter/highlighter.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 22b528838c..b6f61cfb2e 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -22,7 +22,21 @@ local _link_default_highlight_once = function(from, to) return from end -TSHighlighter.hl_map = { +-- If @definition.special does not exist use @definition instead +local subcapture_fallback = { + __index = function(self, capture) + local rtn + local shortened = capture + while not rtn and shortened do + shortened = shortened:match('(.*)%.') + rtn = shortened and rawget(self, shortened) + end + rawset(self, capture, rtn or "__notfound") + return rtn + end +} + +TSHighlighter.hl_map = setmetatable({ ["error"] = "Error", -- Miscs @@ -66,7 +80,7 @@ TSHighlighter.hl_map = { ["type.builtin"] = "Type", ["structure"] = "Structure", ["include"] = "Include", -} +}, subcapture_fallback) ---@private local function is_highlight_name(capture_name) -- cgit From 1fd106ca88a606241e1e1fb8c73645dcea5ea5c8 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 17 Feb 2022 23:05:48 +0100 Subject: vim-patch:8.2.4411: bicep files are not recognized (#17447) Problem: Bicep files are not recognized. Solution: Match *.bicep files. (Dundar Goc, closes vim/vim#9791) https://github.com/vim/vim/commit/8e5ba693ad9377fbf4b047093624248b81eac854 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2fe4aa3d32..399e1c7f60 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -65,6 +65,7 @@ local extension = { bdf = "bdf", beancount = "beancount", bib = "bib", + bicep = "bicep", bl = "blank", bsdl = "bsdl", bst = "bst", -- cgit From 36362ef0aed92e726d967d30e3c6cd87c65642b3 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 18 Feb 2022 17:08:43 +0100 Subject: vim-patch:8.2.4414: solidity files are not recognized (#17451) Problem: Solidity files are not recognized. Solution: Add the *.sol pattern. (Dundar Goc, closes vim/vim#9792) https://github.com/vim/vim/commit/97b231541d4e82fbc85e51121448d95bd43c50ad --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 399e1c7f60..c6bcdd965c 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -598,6 +598,7 @@ local extension = { sl = "slang", ice = "slice", score = "slrnsc", + sol = "solidity", tpl = "smarty", ihlp = "smcl", smcl = "smcl", -- cgit From 791e400858ae8d32f974b40c4e1c0d54b66f610f Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sat, 19 Feb 2022 08:38:14 -0800 Subject: fix: lsp and diagnostic highlight priority (#17461) Closes https://github.com/neovim/neovim/issues/17456 * treesitter uses the default highlight priority of 50 * diagnostic highlights have a priority of 150 * lsp reference highlights have a priority of 200 This ensures proper ordering. --- runtime/lua/vim/diagnostic.lua | 5 ++++- runtime/lua/vim/lsp/util.lua | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index b4537c2882..fda70b4e95 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -920,7 +920,10 @@ M.handlers.underline = { underline_ns, higroup, { diagnostic.lnum, diagnostic.col }, - { diagnostic.end_lnum, diagnostic.end_col } + { diagnostic.end_lnum, diagnostic.end_col }, + 'v', + false, + 150 ) end save_extmarks(underline_ns, bufnr) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d22c00ae76..d93331c12f 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1551,9 +1551,9 @@ do --[[ References ]] document_highlight_kind[kind], { start_line, start_idx }, { end_line, end_idx }, - nil, + 'v', false, - 40) + 200) end end end -- cgit From 439a843b80339d80e788e8382ae91414c3db6dd5 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 19 Feb 2022 23:41:11 +0100 Subject: vim-patch:8.2.4424: ".gts" and ".gjs" files are not recognized (#17464) Problem: ".gts" and ".gjs" files are not recognized. Solution: Recognize Glimmer flavored typescript and javascript. (closes vim/vim#9799) https://github.com/vim/vim/commit/cdf717283ca70b18f20b8a2cefe7957083280c6f --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c6bcdd965c..0555b87651 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -247,6 +247,8 @@ local extension = { gradle = "groovy", groovy = "groovy", gsp = "gsp", + gjs = "javascript.glimmer", + gts = "typescript.glimmer", hack = "hack", hackpartial = "hack", haml = "haml", -- cgit From 6a3acccd8be1c3796c0d1630383046b54b9f994c Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sun, 20 Feb 2022 11:09:01 -0800 Subject: fix(lsp): use botright copen for all handlers (#17471) --- runtime/lua/vim/lsp/handlers.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index a997b887d9..f5aefd4402 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -336,7 +336,7 @@ local function location_handler(_, result, ctx, _) title = 'LSP locations', items = util.locations_to_items(result, client.offset_encoding) }) - api.nvim_command("copen") + api.nvim_command("botright copen") end else util.jump_to_location(result, client.offset_encoding) @@ -430,7 +430,7 @@ local make_call_hierarchy_handler = function(direction) end end vim.fn.setqflist({}, ' ', {title = 'LSP call hierarchy', items = items}) - api.nvim_command("copen") + api.nvim_command("botright copen") end end -- cgit From d80c9b925973be87d1d5a2e948d65907234b2134 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sun, 20 Feb 2022 13:44:14 -0800 Subject: fix(diagnostic): use botright copen for qflist (#17475) This matches the LSP handlers, and forces the qflist for diagnostics to span across the horizontal space, below all open windows. --- runtime/lua/vim/diagnostic.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index fda70b4e95..8879e2debd 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -447,7 +447,7 @@ local function set_list(loclist, opts) vim.fn.setqflist({}, ' ', { title = title, items = items }) end if open then - vim.api.nvim_command(loclist and "lopen" or "copen") + vim.api.nvim_command(loclist and "lopen" or "botright copen") end end -- cgit From 10a46a20ce78efa80c1d1f7ac43b2a95ef92ea76 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 21 Feb 2022 21:21:42 +0100 Subject: refactor(highlight)!: optional arguments for highlight.range as table (#17462) also update documentation BREAKING CHANGE: signature of highlight.range is now vim.highlight.range(bufnr, ns, hlgroup, start, finish, { regtype = regtype, inclusive = inclusive, priority = priority }) Co-authored-by: Gregory Anders <8965202+gpanders@users.noreply.github.com> --- runtime/lua/vim/diagnostic.lua | 4 +- runtime/lua/vim/highlight.lua | 105 ++++++++++++++++++++++++++--------------- runtime/lua/vim/lsp/util.lua | 4 +- 3 files changed, 69 insertions(+), 44 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 8879e2debd..fcb1e61764 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -921,9 +921,7 @@ M.handlers.underline = { higroup, { diagnostic.lnum, diagnostic.col }, { diagnostic.end_lnum, diagnostic.end_col }, - 'v', - false, - 150 + { priority = vim.highlight.priorities.diagnostics } ) end save_extmarks(underline_ns, bufnr) diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 12faa0a6e1..4105ef0675 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -1,9 +1,16 @@ local api = vim.api -local highlight = {} +local M = {} + +M.priorities = { + syntax = 50, + treesitter = 100, + diagnostics = 150, + user = 200, +} ---@private -function highlight.create(higroup, hi_info, default) +function M.create(higroup, hi_info, default) local options = {} -- TODO: Add validation for k, v in pairs(hi_info) do @@ -13,28 +20,33 @@ function highlight.create(higroup, hi_info, default) end ---@private -function highlight.link(higroup, link_to, force) +function M.link(higroup, link_to, force) vim.cmd(string.format([[highlight%s link %s %s]], force and "!" or " default", higroup, link_to)) end - --- Highlight range between two positions --- ---@param bufnr number of buffer to apply highlighting to ---@param ns namespace to add highlight to ---@param higroup highlight group to use for highlighting ----@param rtype type of range (:help setreg, default charwise) ----@param inclusive boolean indicating whether the range is end-inclusive (default false) ----@param priority number indicating priority of highlight (default 50) -function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive, priority) - rtype = rtype or 'v' - inclusive = inclusive or false - priority = priority or 50 +---@param start first position (tuple {line,col}) +---@param finish second position (tuple {line,col}) +---@param opts table with options: +-- - regtype type of range (:help setreg, default charwise) +-- - inclusive boolean indicating whether the range is end-inclusive (default false) +-- - priority number indicating priority of highlight (default priorities.user) +function M.range(bufnr, ns, higroup, start, finish, opts) + opts = opts or {} + local regtype = opts.regtype or "v" + local inclusive = opts.inclusive or false + local priority = opts.priority or M.priorities.user -- sanity check - if start[2] < 0 or finish[1] < start[1] then return end + if start[2] < 0 or finish[1] < start[1] then + return + end - local region = vim.region(bufnr, start, finish, rtype, inclusive) + local region = vim.region(bufnr, start, finish, regtype, inclusive) for linenr, cols in pairs(region) do local end_row if cols[2] == -1 then @@ -46,13 +58,12 @@ function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive, pr end_row = end_row, end_col = cols[2], priority = priority, - strict = false + strict = false, }) end - end -local yank_ns = api.nvim_create_namespace('hlyank') +local yank_ns = api.nvim_create_namespace("hlyank") --- Highlight the yanked region --- --- use from init.vim via @@ -62,26 +73,40 @@ local yank_ns = api.nvim_create_namespace('hlyank') --- customize conditions (here: do not highlight a visual selection) via --- au TextYankPost * lua vim.highlight.on_yank {on_visual=false} --- --- @param opts dictionary with options controlling the highlight: +-- @param opts table with options controlling the highlight: -- - higroup highlight group for yanked region (default "IncSearch") -- - timeout time in ms before highlight is cleared (default 150) -- - on_macro highlight when executing macro (default false) -- - on_visual highlight when yanking visual selection (default true) -- - event event structure (default vim.v.event) -function highlight.on_yank(opts) - vim.validate { - opts = { opts, - function(t) if t == nil then return true else return type(t) == 'table' end end, - 'a table or nil to configure options (see `:h highlight.on_yank`)', - }} +function M.on_yank(opts) + vim.validate({ + opts = { + opts, + function(t) + if t == nil then + return true + else + return type(t) == "table" + end + end, + "a table or nil to configure options (see `:h highlight.on_yank`)", + }, + }) opts = opts or {} local event = opts.event or vim.v.event local on_macro = opts.on_macro or false local on_visual = (opts.on_visual ~= false) - if (not on_macro) and vim.fn.reg_executing() ~= '' then return end - if event.operator ~= 'y' or event.regtype == '' then return end - if (not on_visual) and event.visual then return end + if not on_macro and vim.fn.reg_executing() ~= "" then + return + end + if event.operator ~= "y" or event.regtype == "" then + return + end + if not on_visual and event.visual then + return + end local higroup = opts.higroup or "IncSearch" local timeout = opts.timeout or 150 @@ -92,19 +117,23 @@ function highlight.on_yank(opts) local pos1 = vim.fn.getpos("'[") local pos2 = vim.fn.getpos("']") - pos1 = {pos1[2] - 1, pos1[3] - 1 + pos1[4]} - pos2 = {pos2[2] - 1, pos2[3] - 1 + pos2[4]} - - highlight.range(bufnr, yank_ns, higroup, pos1, pos2, event.regtype, event.inclusive, 200) + pos1 = { pos1[2] - 1, pos1[3] - 1 + pos1[4] } + pos2 = { pos2[2] - 1, pos2[3] - 1 + pos2[4] } - vim.defer_fn( - function() - if api.nvim_buf_is_valid(bufnr) then - api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) - end - end, - timeout + M.range( + bufnr, + yank_ns, + higroup, + pos1, + pos2, + { regtype = event.regtype, inclusive = event.inclusive, priority = M.priorities.user } ) + + vim.defer_fn(function() + if api.nvim_buf_is_valid(bufnr) then + api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) + end + end, timeout) end -return highlight +return M diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d93331c12f..655c3a4679 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1551,9 +1551,7 @@ do --[[ References ]] document_highlight_kind[kind], { start_line, start_idx }, { end_line, end_idx }, - 'v', - false, - 200) + { priority = vim.highlight.priorities.user }) end end end -- cgit From d0f8f76224f501d919ba6c8a5cd717de76903b34 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 26 Feb 2022 14:01:37 +0100 Subject: vim-patch:8.2.4464: Dtrace files are recognized as filetype D (#17518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Dtrace files are recognized as filetype D. Solution: Add a pattern for Dtrace files. (Teubel György, closes vim/vim#9841) Add some more testing. https://github.com/vim/vim/commit/4d56b971cbae01cc454eb09713326224993e38ed --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 0555b87651..f5e4dabfb6 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1178,6 +1178,7 @@ local pattern = { [".*/etc/yum%.conf"] = "dosini", [".*lvs"] = "dracula", [".*lpe"] = "dracula", + [".*/dtrace/.*%.d"] = "dtrace", [".*esmtprc"] = "esmtprc", [".*Eterm/.*%.cfg"] = "eterm", [".*%.git/modules/.*/config"] = "gitconfig", -- cgit From b87867e69e94d9784468a126f21c721446f080de Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 11 Sep 2021 11:48:58 +0900 Subject: feat(lua): add proper support of luv threads --- runtime/lua/vim/_load_package.lua | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 runtime/lua/vim/_load_package.lua (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_load_package.lua b/runtime/lua/vim/_load_package.lua new file mode 100644 index 0000000000..3e346fb3f6 --- /dev/null +++ b/runtime/lua/vim/_load_package.lua @@ -0,0 +1,48 @@ +-- prevents luacheck from making lints for setting things on vim +local vim = assert(vim) + +local pathtrails = {} +vim._so_trails = {} +for s in (package.cpath..';'):gmatch('[^;]*;') do + s = s:sub(1, -2) -- Strip trailing semicolon + -- Find out path patterns. pathtrail should contain something like + -- /?.so, \?.dll. This allows not to bother determining what correct + -- suffixes are. + local pathtrail = s:match('[/\\][^/\\]*%?.*$') + if pathtrail and not pathtrails[pathtrail] then + pathtrails[pathtrail] = true + table.insert(vim._so_trails, pathtrail) + end +end + +function vim._load_package(name) + local basename = name:gsub('%.', '/') + local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} + local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true}) + if #found > 0 then + local f, err = loadfile(found[1]) + return f or error(err) + end + + local so_paths = {} + for _,trail in ipairs(vim._so_trails) do + local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash + table.insert(so_paths, path) + end + + found = vim.api.nvim__get_runtime(so_paths, false, {is_lua=true}) + if #found > 0 then + -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is + -- a) strip prefix up to and including the first dash, if any + -- b) replace all dots by underscores + -- c) prepend "luaopen_" + -- So "foo-bar.baz" should result in "luaopen_bar_baz" + local dash = name:find("-", 1, true) + local modname = dash and name:sub(dash + 1) or name + local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) + return f or error(err) + end + return nil +end + +table.insert(package.loaders, 1, vim._load_package) -- cgit From 850b3e19c9fc8d84d960e6932a9ad4f0bcad2a8e Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 26 Feb 2022 11:03:39 +0100 Subject: refactor(lua): cleanup and docs for threads --- runtime/lua/vim/_load_package.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_load_package.lua b/runtime/lua/vim/_load_package.lua index 3e346fb3f6..525f603438 100644 --- a/runtime/lua/vim/_load_package.lua +++ b/runtime/lua/vim/_load_package.lua @@ -45,4 +45,5 @@ function vim._load_package(name) return nil end -table.insert(package.loaders, 1, vim._load_package) +-- Insert vim._load_package after the preloader at position 2 +table.insert(package.loaders, 2, vim._load_package) -- cgit From c031e038df8429e14b0aa608aaa77068daa680f0 Mon Sep 17 00:00:00 2001 From: shadmansaleh <13149513+shadmansaleh@users.noreply.github.com> Date: Fri, 7 Jan 2022 18:17:19 +0600 Subject: chore: remove detection from vim.keymap --- runtime/lua/vim/keymap.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index d53b790746..df49eff4b6 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -42,7 +42,7 @@ local keymap = {} --- |nvim_replace_termcodes()| is applied to the result of Lua expr maps. --- - remap: (boolean) Make the mapping recursive. This is the --- inverse of the "noremap" option from |nvim_set_keymap()|. ---- Default `true` if `lhs` is a string starting with `` (case-insensitive), `false` otherwise. +--- Default `false`. ---@see |nvim_set_keymap()| function keymap.set(mode, lhs, rhs, opts) vim.validate { @@ -66,8 +66,8 @@ function keymap.set(mode, lhs, rhs, opts) opts.replace_keycodes = nil if opts.remap == nil then - -- remap by default on mappings and don't otherwise. - opts.noremap = is_rhs_luaref or rhs:lower():match("^") == nil + -- default remap value is false + opts.noremap = true else -- remaps behavior is opposite of noremap option. opts.noremap = not opts.remap -- cgit From d477788cd5bfd36b6be88e4ea736e5053369252b Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Wed, 2 Mar 2022 14:33:02 -0500 Subject: fix(lsp): respect all of 'fixeol', 'eol', and 'binary' applying edits (#17574) --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 655c3a4679..59ab3d7e1f 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -480,7 +480,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Remove final line if needed local fix_eol = has_eol_text_edit - fix_eol = fix_eol and api.nvim_buf_get_option(bufnr, 'fixeol') + fix_eol = fix_eol and (api.nvim_buf_get_option(bufnr, 'eol') or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option('binary'))) fix_eol = fix_eol and get_line(bufnr, max - 1) == '' if fix_eol then vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {}) -- cgit From 5d6006f9bfc2f1f064adbcfa974da6976e867450 Mon Sep 17 00:00:00 2001 From: David Shen <17462095+mxteries@users.noreply.github.com> Date: Wed, 2 Mar 2022 20:42:27 -0500 Subject: feat(diagnostic): add "code" to the diagnostic structure (#17510) --- runtime/lua/vim/lsp/diagnostic.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 68942ae11a..614d83f565 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -104,8 +104,10 @@ local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) severity = severity_lsp_to_vim(diagnostic.severity), message = diagnostic.message, source = diagnostic.source, + code = diagnostic.code, user_data = { lsp = { + -- usage of user_data.lsp.code is deprecated in favor of the top-level code field code = diagnostic.code, codeDescription = diagnostic.codeDescription, tags = diagnostic.tags, @@ -120,7 +122,8 @@ end ---@private local function diagnostic_vim_to_lsp(diagnostics) return vim.tbl_map(function(diagnostic) - return vim.tbl_extend("error", { + return vim.tbl_extend("keep", { + -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp range = { start = { line = diagnostic.lnum, @@ -134,6 +137,7 @@ local function diagnostic_vim_to_lsp(diagnostics) severity = severity_vim_to_lsp(diagnostic.severity), message = diagnostic.message, source = diagnostic.source, + code = diagnostic.code, }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {}) end, diagnostics) end -- cgit From f9faba88fdc46b2dd1a979a37ba61b000830ff3a Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 1 Mar 2022 14:27:19 +0100 Subject: refactor(lua): reorganize builtin modules, phase 1 --- runtime/lua/vim/_load_package.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_load_package.lua b/runtime/lua/vim/_load_package.lua index 525f603438..59bca9b148 100644 --- a/runtime/lua/vim/_load_package.lua +++ b/runtime/lua/vim/_load_package.lua @@ -47,3 +47,6 @@ end -- Insert vim._load_package after the preloader at position 2 table.insert(package.loaders, 2, vim._load_package) + +-- should always be available +vim.inspect = require'vim.inspect' -- cgit From 186a559818f7a709dbdd4590fe7440ebd619a208 Mon Sep 17 00:00:00 2001 From: bfredl Date: Fri, 4 Mar 2022 16:18:58 +0100 Subject: refactor(lua): move only runtime lua file in src/ to runtime/lua reorganize so that initialization is done in lua --- runtime/lua/vim/_editor.lua | 659 +++++++++++++++++++++++++++++++++++++ runtime/lua/vim/_init_packages.lua | 65 ++++ runtime/lua/vim/_load_package.lua | 52 --- 3 files changed, 724 insertions(+), 52 deletions(-) create mode 100644 runtime/lua/vim/_editor.lua create mode 100644 runtime/lua/vim/_init_packages.lua delete mode 100644 runtime/lua/vim/_load_package.lua (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua new file mode 100644 index 0000000000..5f3329ef42 --- /dev/null +++ b/runtime/lua/vim/_editor.lua @@ -0,0 +1,659 @@ +-- Nvim-Lua stdlib: the `vim` module (:help lua-stdlib) +-- +-- Lua code lives in one of three places: +-- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the +-- `inspect` and `lpeg` modules. +-- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests. +-- (This will go away if we migrate to nvim as the test-runner.) +-- 3. src/nvim/lua/: Compiled-into Nvim itself. +-- +-- Guideline: "If in doubt, put it in the runtime". +-- +-- Most functions should live directly in `vim.`, not in submodules. +-- The only "forbidden" names are those claimed by legacy `if_lua`: +-- $ vim +-- :lua for k,v in pairs(vim) do print(k) end +-- buffer +-- open +-- window +-- lastline +-- firstline +-- type +-- line +-- eval +-- dict +-- beep +-- list +-- command +-- +-- Reference (#6580): +-- - https://github.com/luafun/luafun +-- - https://github.com/rxi/lume +-- - http://leafo.net/lapis/reference/utilities.html +-- - https://github.com/torch/paths +-- - https://github.com/bakpakin/Fennel (pretty print, repl) +-- - https://github.com/howl-editor/howl/tree/master/lib/howl/util + +local vim = assert(vim) +assert(vim.inspect) + +-- These are for loading runtime modules lazily since they aren't available in +-- the nvim binary as specified in executor.c +setmetatable(vim, { + __index = function(t, key) + if key == 'treesitter' then + t.treesitter = require('vim.treesitter') + return t.treesitter + elseif key == 'filetype' then + t.filetype = require('vim.filetype') + return t.filetype + elseif key == 'F' then + t.F = require('vim.F') + return t.F + elseif require('vim.uri')[key] ~= nil then + -- Expose all `vim.uri` functions on the `vim` module. + t[key] = require('vim.uri')[key] + return t[key] + elseif key == 'lsp' then + t.lsp = require('vim.lsp') + return t.lsp + elseif key == 'highlight' then + t.highlight = require('vim.highlight') + return t.highlight + elseif key == 'diagnostic' then + t.diagnostic = require('vim.diagnostic') + return t.diagnostic + elseif key == 'keymap' then + t.keymap = require('vim.keymap') + return t.keymap + elseif key == 'ui' then + t.ui = require('vim.ui') + return t.ui + end + end +}) + +vim.log = { + levels = { + TRACE = 0; + DEBUG = 1; + INFO = 2; + WARN = 3; + ERROR = 4; + } +} + +-- Internal-only until comments in #8107 are addressed. +-- Returns: +-- {errcode}, {output} +function vim._system(cmd) + local out = vim.fn.system(cmd) + local err = vim.v.shell_error + return err, out +end + +-- Gets process info from the `ps` command. +-- Used by nvim_get_proc() as a fallback. +function vim._os_proc_info(pid) + if pid == nil or pid <= 0 or type(pid) ~= 'number' then + error('invalid pid') + end + local cmd = { 'ps', '-p', pid, '-o', 'comm=', } + local err, name = vim._system(cmd) + if 1 == err and vim.trim(name) == '' then + return {} -- Process not found. + elseif 0 ~= err then + error('command failed: '..vim.fn.string(cmd)) + end + local _, ppid = vim._system({ 'ps', '-p', pid, '-o', 'ppid=', }) + -- Remove trailing whitespace. + name = vim.trim(name):gsub('^.*/', '') + ppid = tonumber(ppid) or -1 + return { + name = name, + pid = pid, + ppid = ppid, + } +end + +-- Gets process children from the `pgrep` command. +-- Used by nvim_get_proc_children() as a fallback. +function vim._os_proc_children(ppid) + if ppid == nil or ppid <= 0 or type(ppid) ~= 'number' then + error('invalid ppid') + end + local cmd = { 'pgrep', '-P', ppid, } + local err, rv = vim._system(cmd) + if 1 == err and vim.trim(rv) == '' then + return {} -- Process not found. + elseif 0 ~= err then + error('command failed: '..vim.fn.string(cmd)) + end + local children = {} + for s in rv:gmatch('%S+') do + local i = tonumber(s) + if i ~= nil then + table.insert(children, i) + end + end + return children +end + +-- TODO(ZyX-I): Create compatibility layer. + +--- Return a human-readable representation of the given object. +--- +---@see https://github.com/kikito/inspect.lua +---@see https://github.com/mpeterv/vinspect +local function inspect(object, options) -- luacheck: no unused + error(object, options) -- Stub for gen_vimdoc.py +end + +do + local tdots, tick, got_line1 = 0, 0, false + + --- Paste handler, invoked by |nvim_paste()| when a conforming UI + --- (such as the |TUI|) pastes text into the editor. + --- + --- Example: To remove ANSI color codes when pasting: + ---
+  --- vim.paste = (function(overridden)
+  ---   return function(lines, phase)
+  ---     for i,line in ipairs(lines) do
+  ---       -- Scrub ANSI color codes from paste input.
+  ---       lines[i] = line:gsub('\27%[[0-9;mK]+', '')
+  ---     end
+  ---     overridden(lines, phase)
+  ---   end
+  --- end)(vim.paste)
+  --- 
+ --- + ---@see |paste| + --- + ---@param lines |readfile()|-style list of lines to paste. |channel-lines| + ---@param phase -1: "non-streaming" paste: the call contains all lines. + --- If paste is "streamed", `phase` indicates the stream state: + --- - 1: starts the paste (exactly once) + --- - 2: continues the paste (zero or more times) + --- - 3: ends the paste (exactly once) + ---@returns false if client should cancel the paste. + function vim.paste(lines, phase) + local call = vim.api.nvim_call_function + local now = vim.loop.now() + local mode = call('mode', {}):sub(1,1) + if phase < 2 then -- Reset flags. + tdots, tick, got_line1 = now, 0, false + elseif mode ~= 'c' then + vim.api.nvim_command('undojoin') + end + if mode == 'c' and not got_line1 then -- cmdline-mode: paste only 1 line. + got_line1 = (#lines > 1) + vim.api.nvim_set_option('paste', true) -- For nvim_input(). + local line1 = lines[1]:gsub('<', ''):gsub('[\r\n\012\027]', ' ') -- Scrub. + vim.api.nvim_input(line1) + vim.api.nvim_set_option('paste', false) + elseif mode ~= 'c' then + if phase < 2 and mode:find('^[vV\22sS\19]') then + vim.api.nvim_command([[exe "normal! \"]]) + vim.api.nvim_put(lines, 'c', false, true) + elseif phase < 2 and not mode:find('^[iRt]') then + vim.api.nvim_put(lines, 'c', true, true) + -- XXX: Normal-mode: workaround bad cursor-placement after first chunk. + vim.api.nvim_command('normal! a') + elseif phase < 2 and mode == 'R' then + local nchars = 0 + for _, line in ipairs(lines) do + nchars = nchars + line:len() + end + local row, col = unpack(vim.api.nvim_win_get_cursor(0)) + local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1] + local firstline = lines[1] + firstline = bufline:sub(1, col)..firstline + lines[1] = firstline + lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len()) + vim.api.nvim_buf_set_lines(0, row-1, row, false, lines) + else + vim.api.nvim_put(lines, 'c', false, true) + end + end + if phase ~= -1 and (now - tdots >= 100) then + local dots = ('.'):rep(tick % 4) + tdots = now + tick = tick + 1 + -- Use :echo because Lua print('') is a no-op, and we want to clear the + -- message when there are zero dots. + vim.api.nvim_command(('echo "%s"'):format(dots)) + end + if phase == -1 or phase == 3 then + vim.api.nvim_command('redraw'..(tick > 1 and '|echo ""' or '')) + end + return true -- Paste will not continue if not returning `true`. + end +end + +--- Defers callback `cb` until the Nvim API is safe to call. +--- +---@see |lua-loop-callbacks| +---@see |vim.schedule()| +---@see |vim.in_fast_event()| +function vim.schedule_wrap(cb) + return (function (...) + local args = vim.F.pack_len(...) + vim.schedule(function() cb(vim.F.unpack_len(args)) end) + end) +end + +-- vim.fn.{func}(...) +vim.fn = setmetatable({}, { + __index = function(t, key) + local _fn + if vim.api[key] ~= nil then + _fn = function() + error(string.format("Tried to call API function with vim.fn: use vim.api.%s instead", key)) + end + else + _fn = function(...) + return vim.call(key, ...) + end + end + t[key] = _fn + return _fn + end +}) + +vim.funcref = function(viml_func_name) + return vim.fn[viml_func_name] +end + +-- An easier alias for commands. +vim.cmd = function(command) + return vim.api.nvim_exec(command, false) +end + +-- These are the vim.env/v/g/o/bo/wo variable magic accessors. +do + local validate = vim.validate + + --@private + local function make_dict_accessor(scope, handle) + validate { + scope = {scope, 's'}; + } + local mt = {} + function mt:__newindex(k, v) + return vim._setvar(scope, handle or 0, k, v) + end + function mt:__index(k) + if handle == nil and type(k) == 'number' then + return make_dict_accessor(scope, k) + end + return vim._getvar(scope, handle or 0, k) + end + return setmetatable({}, mt) + end + + vim.g = make_dict_accessor('g', false) + vim.v = make_dict_accessor('v', false) + vim.b = make_dict_accessor('b') + vim.w = make_dict_accessor('w') + vim.t = make_dict_accessor('t') +end + +--- Get a table of lines with start, end columns for a region marked by two points +--- +---@param bufnr number of buffer +---@param pos1 (line, column) tuple marking beginning of region +---@param pos2 (line, column) tuple marking end of region +---@param regtype type of selection (:help setreg) +---@param inclusive boolean indicating whether the selection is end-inclusive +---@return region lua table of the form {linenr = {startcol,endcol}} +function vim.region(bufnr, pos1, pos2, regtype, inclusive) + if not vim.api.nvim_buf_is_loaded(bufnr) then + vim.fn.bufload(bufnr) + end + + -- check that region falls within current buffer + local buf_line_count = vim.api.nvim_buf_line_count(bufnr) + pos1[1] = math.min(pos1[1], buf_line_count - 1) + pos2[1] = math.min(pos2[1], buf_line_count - 1) + + -- in case of block selection, columns need to be adjusted for non-ASCII characters + -- TODO: handle double-width characters + local bufline + if regtype:byte() == 22 then + bufline = vim.api.nvim_buf_get_lines(bufnr, pos1[1], pos1[1] + 1, true)[1] + pos1[2] = vim.str_utfindex(bufline, pos1[2]) + end + + local region = {} + for l = pos1[1], pos2[1] do + local c1, c2 + if regtype:byte() == 22 then -- block selection: take width from regtype + c1 = pos1[2] + c2 = c1 + regtype:sub(2) + -- and adjust for non-ASCII characters + bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1] + if c1 < #bufline then + c1 = vim.str_byteindex(bufline, c1) + end + if c2 < #bufline then + c2 = vim.str_byteindex(bufline, c2) + end + else + c1 = (l == pos1[1]) and (pos1[2]) or 0 + c2 = (l == pos2[1]) and (pos2[2] + (inclusive and 1 or 0)) or -1 + end + table.insert(region, l, {c1, c2}) + end + return region +end + +--- Defers calling `fn` until `timeout` ms passes. +--- +--- Use to do a one-shot timer that calls `fn` +--- Note: The {fn} is |schedule_wrap|ped automatically, so API functions are +--- safe to call. +---@param fn Callback to call once `timeout` expires +---@param timeout Number of milliseconds to wait before calling `fn` +---@return timer luv timer object +function vim.defer_fn(fn, timeout) + vim.validate { fn = { fn, 'c', true}; } + local timer = vim.loop.new_timer() + timer:start(timeout, 0, vim.schedule_wrap(function() + timer:stop() + timer:close() + + fn() + end)) + + return timer +end + + +--- Display a notification to the user. +--- +--- This function can be overridden by plugins to display notifications using a +--- custom provider (such as the system notification provider). By default, +--- writes to |:messages|. +--- +---@param msg string Content of the notification to show to the user. +---@param level number|nil One of the values from |vim.log.levels|. +---@param opts table|nil Optional parameters. Unused by default. +function vim.notify(msg, level, opts) -- luacheck: no unused args + if level == vim.log.levels.ERROR then + vim.api.nvim_err_writeln(msg) + elseif level == vim.log.levels.WARN then + vim.api.nvim_echo({{msg, 'WarningMsg'}}, true, {}) + else + vim.api.nvim_echo({{msg}}, true, {}) + end +end + +do + local notified = {} + + --- Display a notification only one time. + --- + --- Like |vim.notify()|, but subsequent calls with the same message will not + --- display a notification. + --- + ---@param msg string Content of the notification to show to the user. + ---@param level number|nil One of the values from |vim.log.levels|. + ---@param opts table|nil Optional parameters. Unused by default. + function vim.notify_once(msg, level, opts) -- luacheck: no unused args + if not notified[msg] then + vim.notify(msg, level, opts) + notified[msg] = true + end + end +end + +---@private +function vim.register_keystroke_callback() + error('vim.register_keystroke_callback is deprecated, instead use: vim.on_key') +end + +local on_key_cbs = {} + +--- Adds Lua function {fn} with namespace id {ns_id} as a listener to every, +--- yes every, input key. +--- +--- The Nvim command-line option |-w| is related but does not support callbacks +--- and cannot be toggled dynamically. +--- +---@param fn function: Callback function. It should take one string argument. +--- On each key press, Nvim passes the key char to fn(). |i_CTRL-V| +--- If {fn} is nil, it removes the callback for the associated {ns_id} +---@param ns_id number? Namespace ID. If nil or 0, generates and returns a new +--- |nvim_create_namespace()| id. +--- +---@return number Namespace id associated with {fn}. Or count of all callbacks +---if on_key() is called without arguments. +--- +---@note {fn} will be removed if an error occurs while calling. +---@note {fn} will not be cleared by |nvim_buf_clear_namespace()| +---@note {fn} will receive the keys after mappings have been evaluated +function vim.on_key(fn, ns_id) + if fn == nil and ns_id == nil then + return #on_key_cbs + end + + vim.validate { + fn = { fn, 'c', true}, + ns_id = { ns_id, 'n', true } + } + + if ns_id == nil or ns_id == 0 then + ns_id = vim.api.nvim_create_namespace('') + end + + on_key_cbs[ns_id] = fn + return ns_id +end + +--- Executes the on_key callbacks. +---@private +function vim._on_key(char) + local failed_ns_ids = {} + local failed_messages = {} + for k, v in pairs(on_key_cbs) do + local ok, err_msg = pcall(v, char) + if not ok then + vim.on_key(nil, k) + table.insert(failed_ns_ids, k) + table.insert(failed_messages, err_msg) + end + end + + if failed_ns_ids[1] then + error(string.format( + "Error executing 'on_key' with ns_ids '%s'\n Messages: %s", + table.concat(failed_ns_ids, ", "), + table.concat(failed_messages, "\n"))) + end +end + +--- Generate a list of possible completions for the string. +--- String starts with ^ and then has the pattern. +--- +--- 1. Can we get it to just return things in the global namespace with that name prefix +--- 2. Can we get it to return things from global namespace even with `print(` in front. +function vim._expand_pat(pat, env) + env = env or _G + + pat = string.sub(pat, 2, #pat) + + if pat == '' then + local result = vim.tbl_keys(env) + table.sort(result) + return result, 0 + end + + -- TODO: We can handle spaces in [] ONLY. + -- We should probably do that at some point, just for cooler completion. + -- TODO: We can suggest the variable names to go in [] + -- This would be difficult as well. + -- Probably just need to do a smarter match than just `:match` + + -- Get the last part of the pattern + local last_part = pat:match("[%w.:_%[%]'\"]+$") + if not last_part then return {}, 0 end + + local parts, search_index = vim._expand_pat_get_parts(last_part) + + local match_part = string.sub(last_part, search_index, #last_part) + local prefix_match_pat = string.sub(pat, 1, #pat - #match_part) or '' + + local final_env = env + + for _, part in ipairs(parts) do + if type(final_env) ~= 'table' then + return {}, 0 + end + local key + + -- Normally, we just have a string + -- Just attempt to get the string directly from the environment + if type(part) == "string" then + key = part + else + -- However, sometimes you want to use a variable, and complete on it + -- With this, you have the power. + + -- MY_VAR = "api" + -- vim[MY_VAR] + -- -> _G[MY_VAR] -> "api" + local result_key = part[1] + if not result_key then + return {}, 0 + end + + local result = rawget(env, result_key) + + if result == nil then + return {}, 0 + end + + key = result + end + local field = rawget(final_env, key) + if field == nil then + local mt = getmetatable(final_env) + if mt and type(mt.__index) == "table" then + field = rawget(mt.__index, key) + end + end + final_env = field + + if not final_env then + return {}, 0 + end + end + + local keys = {} + ---@private + local function insert_keys(obj) + for k,_ in pairs(obj) do + if type(k) == "string" and string.sub(k,1,string.len(match_part)) == match_part then + table.insert(keys,k) + end + end + end + + if type(final_env) == "table" then + insert_keys(final_env) + end + local mt = getmetatable(final_env) + if mt and type(mt.__index) == "table" then + insert_keys(mt.__index) + end + + table.sort(keys) + + return keys, #prefix_match_pat +end + +vim._expand_pat_get_parts = function(lua_string) + local parts = {} + + local accumulator, search_index = '', 1 + local in_brackets, bracket_end = false, -1 + local string_char = nil + for idx = 1, #lua_string do + local s = lua_string:sub(idx, idx) + + if not in_brackets and (s == "." or s == ":") then + table.insert(parts, accumulator) + accumulator = '' + + search_index = idx + 1 + elseif s == "[" then + in_brackets = true + + table.insert(parts, accumulator) + accumulator = '' + + search_index = idx + 1 + elseif in_brackets then + if idx == bracket_end then + in_brackets = false + search_index = idx + 1 + + if string_char == "VAR" then + table.insert(parts, { accumulator }) + accumulator = '' + + string_char = nil + end + elseif not string_char then + bracket_end = string.find(lua_string, ']', idx, true) + + if s == '"' or s == "'" then + string_char = s + elseif s ~= ' ' then + string_char = "VAR" + accumulator = s + end + elseif string_char then + if string_char ~= s then + accumulator = accumulator .. s + else + table.insert(parts, accumulator) + accumulator = '' + + string_char = nil + end + end + else + accumulator = accumulator .. s + end + end + + parts = vim.tbl_filter(function(val) return #val > 0 end, parts) + + return parts, search_index +end + +---Prints given arguments in human-readable format. +---Example: +---
+---  -- Print highlight group Normal and store it's contents in a variable.
+---  local hl_normal = vim.pretty_print(vim.api.nvim_get_hl_by_name("Normal", true))
+---
+---@see |vim.inspect()| +---@return given arguments. +function vim.pretty_print(...) + local objects = {} + for i = 1, select('#', ...) do + local v = select(i, ...) + table.insert(objects, vim.inspect(v)) + end + + print(table.concat(objects, ' ')) + return ... +end + + +require('vim._meta') + +return vim diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua new file mode 100644 index 0000000000..dcb402287c --- /dev/null +++ b/runtime/lua/vim/_init_packages.lua @@ -0,0 +1,65 @@ +-- prevents luacheck from making lints for setting things on vim +local vim = assert(vim) + +local pathtrails = {} +vim._so_trails = {} +for s in (package.cpath..';'):gmatch('[^;]*;') do + s = s:sub(1, -2) -- Strip trailing semicolon + -- Find out path patterns. pathtrail should contain something like + -- /?.so, \?.dll. This allows not to bother determining what correct + -- suffixes are. + local pathtrail = s:match('[/\\][^/\\]*%?.*$') + if pathtrail and not pathtrails[pathtrail] then + pathtrails[pathtrail] = true + table.insert(vim._so_trails, pathtrail) + end +end + +function vim._load_package(name) + local basename = name:gsub('%.', '/') + local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} + local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true}) + if #found > 0 then + local f, err = loadfile(found[1]) + return f or error(err) + end + + local so_paths = {} + for _,trail in ipairs(vim._so_trails) do + local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash + table.insert(so_paths, path) + end + + found = vim.api.nvim__get_runtime(so_paths, false, {is_lua=true}) + if #found > 0 then + -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is + -- a) strip prefix up to and including the first dash, if any + -- b) replace all dots by underscores + -- c) prepend "luaopen_" + -- So "foo-bar.baz" should result in "luaopen_bar_baz" + local dash = name:find("-", 1, true) + local modname = dash and name:sub(dash + 1) or name + local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) + return f or error(err) + end + return nil +end + +-- Insert vim._load_package after the preloader at position 2 +table.insert(package.loaders, 2, vim._load_package) + +-- builtin functions which always should be available +require'vim.shared' +vim.inspect = require'vim.inspect' + +--- +---@private +--- TODO: should be in vim.shared when vim.shared always uses nvim-lua +function vim.empty_dict() + return setmetatable({}, vim._empty_dict_mt) +end + +-- only on main thread: functions for interacting with editor state +if not vim.is_thread() then + require'vim._editor' +end diff --git a/runtime/lua/vim/_load_package.lua b/runtime/lua/vim/_load_package.lua deleted file mode 100644 index 59bca9b148..0000000000 --- a/runtime/lua/vim/_load_package.lua +++ /dev/null @@ -1,52 +0,0 @@ --- prevents luacheck from making lints for setting things on vim -local vim = assert(vim) - -local pathtrails = {} -vim._so_trails = {} -for s in (package.cpath..';'):gmatch('[^;]*;') do - s = s:sub(1, -2) -- Strip trailing semicolon - -- Find out path patterns. pathtrail should contain something like - -- /?.so, \?.dll. This allows not to bother determining what correct - -- suffixes are. - local pathtrail = s:match('[/\\][^/\\]*%?.*$') - if pathtrail and not pathtrails[pathtrail] then - pathtrails[pathtrail] = true - table.insert(vim._so_trails, pathtrail) - end -end - -function vim._load_package(name) - local basename = name:gsub('%.', '/') - local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} - local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true}) - if #found > 0 then - local f, err = loadfile(found[1]) - return f or error(err) - end - - local so_paths = {} - for _,trail in ipairs(vim._so_trails) do - local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash - table.insert(so_paths, path) - end - - found = vim.api.nvim__get_runtime(so_paths, false, {is_lua=true}) - if #found > 0 then - -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is - -- a) strip prefix up to and including the first dash, if any - -- b) replace all dots by underscores - -- c) prepend "luaopen_" - -- So "foo-bar.baz" should result in "luaopen_bar_baz" - local dash = name:find("-", 1, true) - local modname = dash and name:sub(dash + 1) or name - local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) - return f or error(err) - end - return nil -end - --- Insert vim._load_package after the preloader at position 2 -table.insert(package.loaders, 2, vim._load_package) - --- should always be available -vim.inspect = require'vim.inspect' -- cgit From a5e475fcc269b32a8a487f787af20802cbfabe28 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sat, 5 Mar 2022 09:17:56 -0800 Subject: fix(lsp): start incremental sync range at previous newline character (#17610) This change forces the start of an incremental sync range to begin always on an existing line. --- runtime/lua/vim/lsp/sync.lua | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 0f4e5b572b..e500be46c2 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -131,13 +131,22 @@ end ---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) ---@returns table line_idx, byte_idx, and char_idx of first change position local function compute_start_range(prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding) + local char_idx + local byte_idx -- If firstline == lastline, no existing text is changed. All edit operations -- occur on a new line pointed to by lastline. This occurs during insertion of -- new lines(O), the new newline is inserted at the line indicated by -- new_lastline. + if firstline == lastline then + local line = prev_lines[firstline - 1] + byte_idx = #line + 1 + char_idx = compute_line_length(line, offset_encoding) + 1 + return { line_idx = firstline - 1, byte_idx = byte_idx, char_idx = char_idx } + end + -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- In this case, the first byte change is also at the first byte of firstline - if firstline == new_lastline or firstline == lastline then + if firstline == new_lastline then return { line_idx = firstline, byte_idx = 1, char_idx = 1 } end @@ -158,8 +167,6 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline, end -- Convert byte to codepoint if applicable - local char_idx - local byte_idx if start_byte_idx == 1 or (#prev_line == 0 and start_byte_idx == 1)then byte_idx = start_byte_idx char_idx = 1 -- cgit From 80e6f81862d943b2d31639a0e437b6abdff3373c Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 6 Mar 2022 21:16:21 +0800 Subject: docs(lua): reference runtime/lua/vim/_editor.lua --- runtime/lua/vim/_editor.lua | 2 +- runtime/lua/vim/shared.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 5f3329ef42..ddd1147468 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -5,7 +5,7 @@ -- `inspect` and `lpeg` modules. -- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests. -- (This will go away if we migrate to nvim as the test-runner.) --- 3. src/nvim/lua/: Compiled-into Nvim itself. +-- 3. runtime/lua/vim/_editor.lua: Compiled-into Nvim itself. -- -- Guideline: "If in doubt, put it in the runtime". -- diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index e170befa4c..48d0bd3672 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -2,7 +2,7 @@ -- -- The singular purpose of this module is to share code with the Nvim -- test-suite. If, in the future, Nvim itself is used to run the test-suite --- instead of "vanilla Lua", these functions could move to src/nvim/lua/vim.lua +-- instead of "vanilla Lua", these functions could move to runtime/lua/vim/_editor.lua local vim = vim or {} -- cgit From 3800615da9eaf9e8b26d9040c882c74084d688e4 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sun, 6 Mar 2022 07:52:11 -0800 Subject: fix(lsp): handle insertion of previous line (#17618) --- runtime/lua/vim/lsp/sync.lua | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index e500be46c2..9955fff3e2 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -138,10 +138,18 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline, -- new lines(O), the new newline is inserted at the line indicated by -- new_lastline. if firstline == lastline then + local line_idx local line = prev_lines[firstline - 1] - byte_idx = #line + 1 - char_idx = compute_line_length(line, offset_encoding) + 1 - return { line_idx = firstline - 1, byte_idx = byte_idx, char_idx = char_idx } + if line then + line_idx = firstline - 1 + byte_idx = #line + 1 + char_idx = compute_line_length(line, offset_encoding) + 1 + else + line_idx = firstline + byte_idx = 1 + char_idx = 1 + end + return { line_idx = line_idx, byte_idx = byte_idx, char_idx = char_idx } end -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- cgit From f39a12d629500bdbacb389ed593adac34d058fcb Mon Sep 17 00:00:00 2001 From: bfredl Date: Sun, 6 Mar 2022 13:13:10 +0100 Subject: refactor(lua): make vim submodule lazy loading declarative This will allow us to also use the same logic for lua threads and processes, later. --- runtime/lua/vim/_editor.lua | 52 +++++++++++--------------------------- runtime/lua/vim/_init_packages.lua | 20 ++++++++++++++- runtime/lua/vim/shared.lua | 8 +++--- 3 files changed, 39 insertions(+), 41 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index ddd1147468..2251aca004 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -3,9 +3,11 @@ -- Lua code lives in one of three places: -- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the -- `inspect` and `lpeg` modules. --- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests. --- (This will go away if we migrate to nvim as the test-runner.) --- 3. runtime/lua/vim/_editor.lua: Compiled-into Nvim itself. +-- 2. runtime/lua/vim/shared.lua: pure lua functions which always +-- are available. Used in the test runner, as well as worker threads +-- and processes launched from Nvim. +-- 3. runtime/lua/vim/_editor.lua: Code which directly interacts with +-- the Nvim editor state. Only available in the main thread. -- -- Guideline: "If in doubt, put it in the runtime". -- @@ -35,43 +37,19 @@ -- - https://github.com/howl-editor/howl/tree/master/lib/howl/util local vim = assert(vim) -assert(vim.inspect) -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c -setmetatable(vim, { - __index = function(t, key) - if key == 'treesitter' then - t.treesitter = require('vim.treesitter') - return t.treesitter - elseif key == 'filetype' then - t.filetype = require('vim.filetype') - return t.filetype - elseif key == 'F' then - t.F = require('vim.F') - return t.F - elseif require('vim.uri')[key] ~= nil then - -- Expose all `vim.uri` functions on the `vim` module. - t[key] = require('vim.uri')[key] - return t[key] - elseif key == 'lsp' then - t.lsp = require('vim.lsp') - return t.lsp - elseif key == 'highlight' then - t.highlight = require('vim.highlight') - return t.highlight - elseif key == 'diagnostic' then - t.diagnostic = require('vim.diagnostic') - return t.diagnostic - elseif key == 'keymap' then - t.keymap = require('vim.keymap') - return t.keymap - elseif key == 'ui' then - t.ui = require('vim.ui') - return t.ui - end - end -}) +for k,v in pairs { + treesitter=true; + filetype = true; + F=true; + lsp=true; + highlight=true; + diagnostic=true; + keymap=true; + ui=true; +} do vim._submodules[k] = v end vim.log = { levels = { diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua index dcb402287c..7d27741f1b 100644 --- a/runtime/lua/vim/_init_packages.lua +++ b/runtime/lua/vim/_init_packages.lua @@ -50,7 +50,25 @@ table.insert(package.loaders, 2, vim._load_package) -- builtin functions which always should be available require'vim.shared' -vim.inspect = require'vim.inspect' + +vim._submodules = {inspect=true} + +-- These are for loading runtime modules in the vim namespace lazily. +setmetatable(vim, { + __index = function(t, key) + if vim._submodules[key] then + t[key] = require('vim.'..key) + return t[key] + elseif vim.startswith(key, 'uri_') then + local val = require('vim.uri')[key] + if val ~= nil then + -- Expose all `vim.uri` functions on the `vim` module. + t[key] = val + return t[key] + end + end + end +}) --- ---@private diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 48d0bd3672..8124b23eb1 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -1,8 +1,10 @@ -- Functions shared by Nvim and its test-suite. -- --- The singular purpose of this module is to share code with the Nvim --- test-suite. If, in the future, Nvim itself is used to run the test-suite --- instead of "vanilla Lua", these functions could move to runtime/lua/vim/_editor.lua +-- These are "pure" lua functions not depending of the state of the editor. +-- Thus they should always be available whenever nvim-related lua code is run, +-- regardless if it is code in the editor itself, or in worker threads/processes, +-- or the test suite. (Eventually the test suite will be run in a worker process, +-- so this wouldn't be a separate case to consider) local vim = vim or {} -- cgit From 5ed60804fe69e97a699ca64422f4f7f4cc20f3da Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 9 Mar 2022 14:26:01 +0100 Subject: feat(lua): handle lazy submodules in `:lua vim.` wildmenu completion --- runtime/lua/vim/_editor.lua | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 2251aca004..3136e36043 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -519,6 +519,8 @@ function vim._expand_pat(pat, env) local mt = getmetatable(final_env) if mt and type(mt.__index) == "table" then field = rawget(mt.__index, key) + elseif final_env == vim and vim._submodules[key] then + field = vim[key] end end final_env = field @@ -545,6 +547,9 @@ function vim._expand_pat(pat, env) if mt and type(mt.__index) == "table" then insert_keys(mt.__index) end + if final_env == vim then + insert_keys(vim._submodules) + end table.sort(keys) -- cgit From a7b1c8893c602196541e94b8b24c4c70c32c25b0 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Thu, 10 Mar 2022 07:34:55 +0100 Subject: chore: fix typos (#17331) Co-authored-by: Hongyi Lyu Co-authored-by: Gregory Anders Co-authored-by: notomo Co-authored-by: zeertzjq --- runtime/lua/vim/keymap.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index df49eff4b6..7f12372502 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -25,7 +25,7 @@ local keymap = {} --- vim.keymap.set('n', 'asdf', require('jkl').my_fun) --- --- ---- the require('jkl') gets evaluated during this call in order to access the function. If you want to +--- the `require('jkl')` gets evaluated during this call in order to access the function. If you want to --- avoid this cost at startup you can wrap it in a function, for example: ---
 ---    vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end)
-- 
cgit 


From 5862176764c7a86d5fdd2685122810e14a3d5b02 Mon Sep 17 00:00:00 2001
From: Charlie Groves 
Date: Wed, 16 Feb 2022 17:11:50 -0500
Subject: feat(remote): add basic --remote support

This is starting from @geekodour's work at
https://github.com/neovim/neovim/pull/8326
---
 runtime/lua/vim/_editor.lua | 72 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 3136e36043..5f3d66e108 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -636,6 +636,78 @@ function vim.pretty_print(...)
   return ...
 end
 
+local function __rpcrequest(...)
+  return vim.api.nvim_call_function("rpcrequest", {...})
+end
+
+function vim._cs_remote(rcid, args)
+
+  local f_silent = false
+  local f_wait = false
+  local f_tab = false
+  local should_exit = true
+  local command = 'edit '
+
+  local subcmd = string.sub(args[1],10)
+
+  if subcmd == '' then
+    -- no flags to set
+  elseif subcmd == 'tab' then
+    f_tab = true
+  elseif subcmd == 'silent' then
+    f_silent = true
+  elseif subcmd == 'wait' then
+    f_wait = true
+  elseif subcmd == 'wait-silent' then
+    f_wait = true
+    f_silent = true
+  elseif subcmd == 'tab-wait' then
+    f_tab = true
+    f_wait = true
+  elseif subcmd == 'tab-silent' then
+    f_tab = true
+    f_silent = true
+  elseif subcmd == 'tab-wait-silent' then
+    f_tab = true
+    f_wait = true
+    f_silent = true
+  elseif subcmd == 'send' then
+    __rpcrequest(rcid, 'nvim_input', args[2])
+    return { should_exit = should_exit, tabbed = f_tab, files = 0 }
+    -- should we show warning if --server doesn't exist in --send and --expr?
+  elseif subcmd == 'expr' then
+    local res = __rpcrequest(rcid, 'vim_eval', args[2])
+    print(res)
+    return { should_exit = should_exit, tabbed = f_tab, files = 0 }
+  else
+    print('--remote subcommand not found')
+  end
+
+  table.remove(args,1)
+
+  if not f_silent and rcid == 0 then
+    print('Remote server does not exist.')
+  end
+
+  if f_silent and rcid == 0 then
+    print('Remote server does not exist. starting new server')
+    should_exit = false
+  end
+
+  if f_tab then command = 'tabedit ' end
+
+  if rcid ~= 0 then
+    for _, key in ipairs(args) do
+      __rpcrequest(rcid, 'nvim_command', command .. key)
+    end
+  end
+
+  return {
+    should_exit = should_exit,
+    tabbed = f_tab,
+    files = table.getn(args)
+  }
+end
 
 require('vim._meta')
 
-- 
cgit 


From 039e94f491d2f8576cbef1aeacd5ea1f7bc0982a Mon Sep 17 00:00:00 2001
From: Charlie Groves 
Date: Thu, 24 Feb 2022 10:47:41 -0500
Subject: test(remote): add tests for --remote

This also fixes a fair number of issues found in running the tests
---
 runtime/lua/vim/_editor.lua | 57 +++++++++++++++++++++------------------------
 1 file changed, 26 insertions(+), 31 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 5f3d66e108..869a2706ac 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -636,17 +636,10 @@ function vim.pretty_print(...)
   return ...
 end
 
-local function __rpcrequest(...)
-  return vim.api.nvim_call_function("rpcrequest", {...})
-end
-
 function vim._cs_remote(rcid, args)
-
   local f_silent = false
   local f_wait = false
   local f_tab = false
-  local should_exit = true
-  local command = 'edit '
 
   local subcmd = string.sub(args[1],10)
 
@@ -672,40 +665,42 @@ function vim._cs_remote(rcid, args)
     f_wait = true
     f_silent = true
   elseif subcmd == 'send' then
-    __rpcrequest(rcid, 'nvim_input', args[2])
-    return { should_exit = should_exit, tabbed = f_tab, files = 0 }
-    -- should we show warning if --server doesn't exist in --send and --expr?
+    if rcid == 0 then
+      vim.cmd('echoerr "E247: Remote server does not exist. Send failed."')
+      return
+    end
+    vim.fn.rpcrequest(rcid, 'nvim_input', args[2])
+    return { should_exit = true, tabbed = false }
   elseif subcmd == 'expr' then
-    local res = __rpcrequest(rcid, 'vim_eval', args[2])
-    print(res)
-    return { should_exit = should_exit, tabbed = f_tab, files = 0 }
+    if rcid == 0 then
+      vim.cmd('echoerr "E247: Remote server does not exist. Send expression failed."')
+      return
+    end
+    vim.fn.rpcrequest(rcid, 'nvim_eval', args[2])
+    return { should_exit = true, tabbed = false }
   else
-    print('--remote subcommand not found')
+    vim.cmd('echoerr "Unknown option argument: ' .. args[1] .. '"')
+    return
   end
 
-  table.remove(args,1)
-
-  if not f_silent and rcid == 0 then
-    print('Remote server does not exist.')
-  end
-
-  if f_silent and rcid == 0 then
-    print('Remote server does not exist. starting new server')
+  if rcid == 0 then
+    if not f_silent then
+      vim.cmd('echohl WarningMsg | echomsg "E247: Remote server does not exist. Editing locally" | echohl None')
+    end
     should_exit = false
-  end
-
-  if f_tab then command = 'tabedit ' end
-
-  if rcid ~= 0 then
-    for _, key in ipairs(args) do
-      __rpcrequest(rcid, 'nvim_command', command .. key)
+  else
+    local command = {}
+    if f_tab then table.insert(command, 'tab') end
+    table.insert(command, 'drop')
+    for i = 2, #args do
+      table.insert(command, vim.fn.fnameescape(args[i]))
     end
+    vim.fn.rpcrequest(rcid, 'nvim_command', table.concat(command, ' '))
   end
 
   return {
-    should_exit = should_exit,
+    should_exit = rcid ~= 0,
     tabbed = f_tab,
-    files = table.getn(args)
   }
 end
 
-- 
cgit 


From 29c36322857b37263b07eb1301d71ccd8a2ae044 Mon Sep 17 00:00:00 2001
From: Charlie Groves 
Date: Thu, 3 Mar 2022 16:33:27 -0500
Subject: fix(remote): report on missing wait commands, typecheck lua results

Clean up lint errors, too
---
 runtime/lua/vim/_editor.lua | 33 ++++++++-------------------------
 1 file changed, 8 insertions(+), 25 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 869a2706ac..030c3b40e8 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -638,56 +638,39 @@ end
 
 function vim._cs_remote(rcid, args)
   local f_silent = false
-  local f_wait = false
   local f_tab = false
 
   local subcmd = string.sub(args[1],10)
 
-  if subcmd == '' then
-    -- no flags to set
-  elseif subcmd == 'tab' then
+  if subcmd == 'tab' then
     f_tab = true
   elseif subcmd == 'silent' then
     f_silent = true
-  elseif subcmd == 'wait' then
-    f_wait = true
-  elseif subcmd == 'wait-silent' then
-    f_wait = true
-    f_silent = true
-  elseif subcmd == 'tab-wait' then
-    f_tab = true
-    f_wait = true
+  elseif subcmd == 'wait' or subcmd == 'wait-silent' or subcmd == 'tab-wait' or subcmd == 'tab-wait-silent' then
+    return { errmsg = 'E5600: Wait commands not yet implemented in nvim' }
   elseif subcmd == 'tab-silent' then
     f_tab = true
     f_silent = true
-  elseif subcmd == 'tab-wait-silent' then
-    f_tab = true
-    f_wait = true
-    f_silent = true
   elseif subcmd == 'send' then
     if rcid == 0 then
-      vim.cmd('echoerr "E247: Remote server does not exist. Send failed."')
-      return
+      return { errmsg = 'E247: Remote server does not exist. Send failed.' }
     end
     vim.fn.rpcrequest(rcid, 'nvim_input', args[2])
     return { should_exit = true, tabbed = false }
   elseif subcmd == 'expr' then
     if rcid == 0 then
-      vim.cmd('echoerr "E247: Remote server does not exist. Send expression failed."')
-      return
+      return { errmsg = 'E247: Remote server does not exist. Send expression failed.' }
     end
-    vim.fn.rpcrequest(rcid, 'nvim_eval', args[2])
+    print(vim.fn.rpcrequest(rcid, 'nvim_eval', args[2]))
     return { should_exit = true, tabbed = false }
-  else
-    vim.cmd('echoerr "Unknown option argument: ' .. args[1] .. '"')
-    return
+  elseif subcmd ~= '' then
+    return { errmsg='Unknown option argument: ' .. args[1] }
   end
 
   if rcid == 0 then
     if not f_silent then
       vim.cmd('echohl WarningMsg | echomsg "E247: Remote server does not exist. Editing locally" | echohl None')
     end
-    should_exit = false
   else
     local command = {}
     if f_tab then table.insert(command, 'tab') end
-- 
cgit 


From 1dbf8675c71dc500ae7502085161cd56e311ccf6 Mon Sep 17 00:00:00 2001
From: Charlie Groves 
Date: Fri, 11 Mar 2022 11:16:34 -0500
Subject: fix(remote): respect silent in error reporting

---
 runtime/lua/vim/_editor.lua | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 030c3b40e8..a0c60a7dcf 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -636,12 +636,24 @@ function vim.pretty_print(...)
   return ...
 end
 
-function vim._cs_remote(rcid, args)
+function vim._cs_remote(rcid, server_addr, connect_error, args)
+  local function connection_failure_errmsg(consequence)
+    local explanation
+    if server_addr == '' then
+      explanation = "No server specified with --server"
+    else
+      explanation = "Failed to connect to '" .. server_addr .. "'"
+      if connect_error ~= "" then
+        explanation = explanation .. ": " .. connect_error
+      end
+    end
+    return "E247: " .. explanation .. ". " .. consequence
+  end
+
   local f_silent = false
   local f_tab = false
 
   local subcmd = string.sub(args[1],10)
-
   if subcmd == 'tab' then
     f_tab = true
   elseif subcmd == 'silent' then
@@ -653,13 +665,13 @@ function vim._cs_remote(rcid, args)
     f_silent = true
   elseif subcmd == 'send' then
     if rcid == 0 then
-      return { errmsg = 'E247: Remote server does not exist. Send failed.' }
+      return { errmsg = connection_failure_errmsg('Send failed.') }
     end
     vim.fn.rpcrequest(rcid, 'nvim_input', args[2])
     return { should_exit = true, tabbed = false }
   elseif subcmd == 'expr' then
     if rcid == 0 then
-      return { errmsg = 'E247: Remote server does not exist. Send expression failed.' }
+      return { errmsg = connection_failure_errmsg('Send expression failed.') }
     end
     print(vim.fn.rpcrequest(rcid, 'nvim_eval', args[2]))
     return { should_exit = true, tabbed = false }
@@ -669,7 +681,7 @@ function vim._cs_remote(rcid, args)
 
   if rcid == 0 then
     if not f_silent then
-      vim.cmd('echohl WarningMsg | echomsg "E247: Remote server does not exist. Editing locally" | echohl None')
+      vim.notify(connection_failure_errmsg("Editing locally"), vim.log.levels.WARN)
     end
   else
     local command = {}
-- 
cgit 


From 9b1e1fbc9f795921afd25ba38be5c79dec8b04d2 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 6 Mar 2022 06:56:24 +0800
Subject: fix(paste): use getcmdtype() to determine whether in cmdline mode

---
 runtime/lua/vim/_editor.lua | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index a0c60a7dcf..8000730795 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -156,21 +156,21 @@ do
   ---                - 3: ends the paste (exactly once)
   ---@returns false if client should cancel the paste.
   function vim.paste(lines, phase)
-    local call = vim.api.nvim_call_function
     local now = vim.loop.now()
-    local mode = call('mode', {}):sub(1,1)
+    local mode = vim.api.nvim_get_mode().mode
+    local is_cmdline = vim.fn.getcmdtype() ~= ''
     if phase < 2 then  -- Reset flags.
       tdots, tick, got_line1 = now, 0, false
-    elseif mode ~= 'c' then
+    elseif not is_cmdline then
       vim.api.nvim_command('undojoin')
     end
-    if mode == 'c' and not got_line1 then  -- cmdline-mode: paste only 1 line.
+    if is_cmdline and not got_line1 then  -- cmdline-mode: paste only 1 line.
       got_line1 = (#lines > 1)
       vim.api.nvim_set_option('paste', true)  -- For nvim_input().
       local line1 = lines[1]:gsub('<', ''):gsub('[\r\n\012\027]', ' ')  -- Scrub.
       vim.api.nvim_input(line1)
       vim.api.nvim_set_option('paste', false)
-    elseif mode ~= 'c' then
+    elseif not is_cmdline then
       if phase < 2 and mode:find('^[vV\22sS\19]') then
         vim.api.nvim_command([[exe "normal! \"]])
         vim.api.nvim_put(lines, 'c', false, true)
@@ -178,7 +178,7 @@ do
         vim.api.nvim_put(lines, 'c', true, true)
         -- XXX: Normal-mode: workaround bad cursor-placement after first chunk.
         vim.api.nvim_command('normal! a')
-      elseif phase < 2 and mode == 'R' then
+      elseif phase < 2 and mode:find('^R') then
         local nchars = 0
         for _, line in ipairs(lines) do
             nchars = nchars + line:len()
-- 
cgit 


From 2601e0873ff50ed804487dff00bd27e233709beb Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 6 Mar 2022 06:56:24 +0800
Subject: fix(paste): don't move cursor past the end of pasted text in Normal
 mode

---
 runtime/lua/vim/_editor.lua | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 8000730795..8e49b51cec 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -171,27 +171,34 @@ do
       vim.api.nvim_input(line1)
       vim.api.nvim_set_option('paste', false)
     elseif not is_cmdline then
-      if phase < 2 and mode:find('^[vV\22sS\19]') then
-        vim.api.nvim_command([[exe "normal! \"]])
+      if mode:find('^i') or mode:find('^n?t') then  -- Insert mode or Terminal buffer
         vim.api.nvim_put(lines, 'c', false, true)
-      elseif phase < 2 and not mode:find('^[iRt]') then
-        vim.api.nvim_put(lines, 'c', true, true)
-        -- XXX: Normal-mode: workaround bad cursor-placement after first chunk.
-        vim.api.nvim_command('normal! a')
-      elseif phase < 2 and mode:find('^R') then
+      elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then  -- Replace mode
+        -- TODO: implement Replace mode streamed pasting
+        -- TODO: support Virtual Replace mode
         local nchars = 0
         for _, line in ipairs(lines) do
-            nchars = nchars + line:len()
+          nchars = nchars + line:len()
         end
         local row, col = unpack(vim.api.nvim_win_get_cursor(0))
         local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1]
         local firstline = lines[1]
         firstline = bufline:sub(1, col)..firstline
         lines[1] = firstline
+        -- FIXME: #lines can be 0
         lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len())
         vim.api.nvim_buf_set_lines(0, row-1, row, false, lines)
-      else
-        vim.api.nvim_put(lines, 'c', false, true)
+      elseif mode:find('^[nvV\22sS\19]') then  -- Normal or Visual or Select mode
+        if mode:find('^n') then  -- Normal mode
+          vim.api.nvim_put(lines, 'c', true, false)
+        else  -- Visual or Select mode
+          vim.api.nvim_command([[exe "normal! \"]])
+          vim.api.nvim_put(lines, 'c', false, false)
+        end
+        -- put cursor at the end of the text instead of one character after it
+        vim.fn.setpos('.', vim.fn.getpos("']"))
+      else  -- Don't know what to do in other modes
+        return false
       end
     end
     if phase ~= -1 and (now - tdots >= 100) then
-- 
cgit 


From bfb77544425b7cca372cb87f00ef6b6e87c5f6d5 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 6 Mar 2022 06:56:24 +0800
Subject: fix(paste): deal with eol and eof in Visual mode

---
 runtime/lua/vim/_editor.lua | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 8e49b51cec..6b1725c9ff 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -192,8 +192,19 @@ do
         if mode:find('^n') then  -- Normal mode
           vim.api.nvim_put(lines, 'c', true, false)
         else  -- Visual or Select mode
-          vim.api.nvim_command([[exe "normal! \"]])
-          vim.api.nvim_put(lines, 'c', false, false)
+          vim.api.nvim_command([[exe "silent normal! \"]])
+          local del_start = vim.fn.getpos("'[")
+          local cursor_pos = vim.fn.getpos('.')
+          if mode:find('^[VS]') then  -- linewise
+            if cursor_pos[2] < del_start[2] then  -- replacing lines at eof
+              -- create a new line
+              vim.api.nvim_put({''}, 'l', true, true)
+            end
+            vim.api.nvim_put(lines, 'c', false, false)
+          else
+            -- paste after cursor when replacing text at eol, otherwise paste before cursor
+            vim.api.nvim_put(lines, 'c', cursor_pos[3] < del_start[3], false)
+          end
         end
         -- put cursor at the end of the text instead of one character after it
         vim.fn.setpos('.', vim.fn.getpos("']"))
-- 
cgit 


From 21ba2d81a848e7b85739fc3e9aa2eb0b5e35c879 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 6 Mar 2022 06:56:24 +0800
Subject: refactor(paste): do not print dots in cmdline mode

---
 runtime/lua/vim/_editor.lua | 100 +++++++++++++++++++++++---------------------
 1 file changed, 52 insertions(+), 48 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 6b1725c9ff..a7f8f0e7b6 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -157,60 +157,64 @@ do
   ---@returns false if client should cancel the paste.
   function vim.paste(lines, phase)
     local now = vim.loop.now()
-    local mode = vim.api.nvim_get_mode().mode
-    local is_cmdline = vim.fn.getcmdtype() ~= ''
-    if phase < 2 then  -- Reset flags.
+    local is_first_chunk = phase < 2
+    if is_first_chunk then  -- Reset flags.
       tdots, tick, got_line1 = now, 0, false
-    elseif not is_cmdline then
+    end
+    -- Note: mode doesn't always start with "c" in cmdline mode, so use getcmdtype() instead.
+    if vim.fn.getcmdtype() ~= '' then  -- cmdline-mode: paste only 1 line.
+      if not got_line1 then
+        got_line1 = (#lines > 1)
+        vim.api.nvim_set_option('paste', true)  -- For nvim_input().
+        local line1 = lines[1]:gsub('<', ''):gsub('[\r\n\012\027]', ' ')  -- Scrub.
+        vim.api.nvim_input(line1)
+        vim.api.nvim_set_option('paste', false)
+      end
+      return true
+    end
+    local mode = vim.api.nvim_get_mode().mode
+    if not is_first_chunk then
       vim.api.nvim_command('undojoin')
     end
-    if is_cmdline and not got_line1 then  -- cmdline-mode: paste only 1 line.
-      got_line1 = (#lines > 1)
-      vim.api.nvim_set_option('paste', true)  -- For nvim_input().
-      local line1 = lines[1]:gsub('<', ''):gsub('[\r\n\012\027]', ' ')  -- Scrub.
-      vim.api.nvim_input(line1)
-      vim.api.nvim_set_option('paste', false)
-    elseif not is_cmdline then
-      if mode:find('^i') or mode:find('^n?t') then  -- Insert mode or Terminal buffer
-        vim.api.nvim_put(lines, 'c', false, true)
-      elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then  -- Replace mode
-        -- TODO: implement Replace mode streamed pasting
-        -- TODO: support Virtual Replace mode
-        local nchars = 0
-        for _, line in ipairs(lines) do
-          nchars = nchars + line:len()
-        end
-        local row, col = unpack(vim.api.nvim_win_get_cursor(0))
-        local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1]
-        local firstline = lines[1]
-        firstline = bufline:sub(1, col)..firstline
-        lines[1] = firstline
-        -- FIXME: #lines can be 0
-        lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len())
-        vim.api.nvim_buf_set_lines(0, row-1, row, false, lines)
-      elseif mode:find('^[nvV\22sS\19]') then  -- Normal or Visual or Select mode
-        if mode:find('^n') then  -- Normal mode
-          vim.api.nvim_put(lines, 'c', true, false)
-        else  -- Visual or Select mode
-          vim.api.nvim_command([[exe "silent normal! \"]])
-          local del_start = vim.fn.getpos("'[")
-          local cursor_pos = vim.fn.getpos('.')
-          if mode:find('^[VS]') then  -- linewise
-            if cursor_pos[2] < del_start[2] then  -- replacing lines at eof
-              -- create a new line
-              vim.api.nvim_put({''}, 'l', true, true)
-            end
-            vim.api.nvim_put(lines, 'c', false, false)
-          else
-            -- paste after cursor when replacing text at eol, otherwise paste before cursor
-            vim.api.nvim_put(lines, 'c', cursor_pos[3] < del_start[3], false)
+    if mode:find('^i') or mode:find('^n?t') then  -- Insert mode or Terminal buffer
+      vim.api.nvim_put(lines, 'c', false, true)
+    elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then  -- Replace mode
+      -- TODO: implement Replace mode streamed pasting
+      -- TODO: support Virtual Replace mode
+      local nchars = 0
+      for _, line in ipairs(lines) do
+        nchars = nchars + line:len()
+      end
+      local row, col = unpack(vim.api.nvim_win_get_cursor(0))
+      local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1]
+      local firstline = lines[1]
+      firstline = bufline:sub(1, col)..firstline
+      lines[1] = firstline
+      -- FIXME: #lines can be 0
+      lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len())
+      vim.api.nvim_buf_set_lines(0, row-1, row, false, lines)
+    elseif mode:find('^[nvV\22sS\19]') then  -- Normal or Visual or Select mode
+      if mode:find('^n') then  -- Normal mode
+        vim.api.nvim_put(lines, 'c', true, false)
+      else  -- Visual or Select mode
+        vim.api.nvim_command([[exe "silent normal! \"]])
+        local del_start = vim.fn.getpos("'[")
+        local cursor_pos = vim.fn.getpos('.')
+        if mode:find('^[VS]') then  -- linewise
+          if cursor_pos[2] < del_start[2] then  -- replacing lines at eof
+            -- create a new line
+            vim.api.nvim_put({''}, 'l', true, true)
           end
+          vim.api.nvim_put(lines, 'c', false, false)
+        else
+          -- paste after cursor when replacing text at eol, otherwise paste before cursor
+          vim.api.nvim_put(lines, 'c', cursor_pos[3] < del_start[3], false)
         end
-        -- put cursor at the end of the text instead of one character after it
-        vim.fn.setpos('.', vim.fn.getpos("']"))
-      else  -- Don't know what to do in other modes
-        return false
       end
+      -- put cursor at the end of the text instead of one character after it
+      vim.fn.setpos('.', vim.fn.getpos("']"))
+    else  -- Don't know what to do in other modes
+      return false
     end
     if phase ~= -1 and (now - tdots >= 100) then
       local dots = ('.'):rep(tick % 4)
-- 
cgit 


From fcc6f66cf2a67cf85e72727a08e19d0f800badb9 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 6 Mar 2022 06:56:24 +0800
Subject: fix(paste): avoid edges cases caused by empty chunk

---
 runtime/lua/vim/_editor.lua | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index a7f8f0e7b6..42adda6e7f 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -128,7 +128,7 @@ local function inspect(object, options)  -- luacheck: no unused
 end
 
 do
-  local tdots, tick, got_line1 = 0, 0, false
+  local tdots, tick, got_line1, undo_started = 0, 0, false, false
 
   --- Paste handler, invoked by |nvim_paste()| when a conforming UI
   --- (such as the |TUI|) pastes text into the editor.
@@ -158,8 +158,17 @@ do
   function vim.paste(lines, phase)
     local now = vim.loop.now()
     local is_first_chunk = phase < 2
+    local is_last_chunk = phase == -1 or phase == 3
     if is_first_chunk then  -- Reset flags.
-      tdots, tick, got_line1 = now, 0, false
+      tdots, tick, got_line1, undo_started = now, 0, false, false
+    end
+    if #lines == 0 then
+      lines = {''}
+    end
+    if #lines == 1 and lines[1] == '' and not is_last_chunk then
+      -- An empty chunk can cause some edge cases in streamed pasting,
+      -- so don't do anything unless it is the last chunk.
+      return true
     end
     -- Note: mode doesn't always start with "c" in cmdline mode, so use getcmdtype() instead.
     if vim.fn.getcmdtype() ~= '' then  -- cmdline-mode: paste only 1 line.
@@ -173,7 +182,7 @@ do
       return true
     end
     local mode = vim.api.nvim_get_mode().mode
-    if not is_first_chunk then
+    if undo_started then
       vim.api.nvim_command('undojoin')
     end
     if mode:find('^i') or mode:find('^n?t') then  -- Insert mode or Terminal buffer
@@ -190,7 +199,6 @@ do
       local firstline = lines[1]
       firstline = bufline:sub(1, col)..firstline
       lines[1] = firstline
-      -- FIXME: #lines can be 0
       lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len())
       vim.api.nvim_buf_set_lines(0, row-1, row, false, lines)
     elseif mode:find('^[nvV\22sS\19]') then  -- Normal or Visual or Select mode
@@ -216,6 +224,7 @@ do
     else  -- Don't know what to do in other modes
       return false
     end
+    undo_started = true
     if phase ~= -1 and (now - tdots >= 100) then
       local dots = ('.'):rep(tick % 4)
       tdots = now
@@ -224,7 +233,7 @@ do
       -- message when there are zero dots.
       vim.api.nvim_command(('echo "%s"'):format(dots))
     end
-    if phase == -1 or phase == 3 then
+    if is_last_chunk then
       vim.api.nvim_command('redraw'..(tick > 1 and '|echo ""' or ''))
     end
     return true  -- Paste will not continue if not returning `true`.
-- 
cgit 


From a6eafc77ceaf2d7036aed89361b6556f46131b17 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Sun, 6 Mar 2022 06:56:24 +0800
Subject: fix(paste): deal with trailing new line in chunk

---
 runtime/lua/vim/_editor.lua | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 42adda6e7f..26b9693189 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -128,7 +128,7 @@ local function inspect(object, options)  -- luacheck: no unused
 end
 
 do
-  local tdots, tick, got_line1, undo_started = 0, 0, false, false
+  local tdots, tick, got_line1, undo_started, trailing_nl = 0, 0, false, false, false
 
   --- Paste handler, invoked by |nvim_paste()| when a conforming UI
   --- (such as the |TUI|) pastes text into the editor.
@@ -160,7 +160,7 @@ do
     local is_first_chunk = phase < 2
     local is_last_chunk = phase == -1 or phase == 3
     if is_first_chunk then  -- Reset flags.
-      tdots, tick, got_line1, undo_started = now, 0, false, false
+      tdots, tick, got_line1, undo_started, trailing_nl = now, 0, false, false, false
     end
     if #lines == 0 then
       lines = {''}
@@ -203,7 +203,10 @@ do
       vim.api.nvim_buf_set_lines(0, row-1, row, false, lines)
     elseif mode:find('^[nvV\22sS\19]') then  -- Normal or Visual or Select mode
       if mode:find('^n') then  -- Normal mode
-        vim.api.nvim_put(lines, 'c', true, false)
+        -- When there was a trailing new line in the previous chunk,
+        -- the cursor is on the first character of the next line,
+        -- so paste before the cursor instead of after it.
+        vim.api.nvim_put(lines, 'c', not trailing_nl, false)
       else  -- Visual or Select mode
         vim.api.nvim_command([[exe "silent normal! \"]])
         local del_start = vim.fn.getpos("'[")
@@ -221,6 +224,7 @@ do
       end
       -- put cursor at the end of the text instead of one character after it
       vim.fn.setpos('.', vim.fn.getpos("']"))
+      trailing_nl = lines[#lines] == ''
     else  -- Don't know what to do in other modes
       return false
     end
-- 
cgit 


From e263afc0e972d11d3b9b663c3ac0b5575c4deb88 Mon Sep 17 00:00:00 2001
From: zeertzjq 
Date: Tue, 15 Mar 2022 06:04:50 +0800
Subject: fix(paste): escape control characters in Cmdline mode

---
 runtime/lua/vim/_editor.lua | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 26b9693189..d4db4850bd 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -175,7 +175,8 @@ do
       if not got_line1 then
         got_line1 = (#lines > 1)
         vim.api.nvim_set_option('paste', true)  -- For nvim_input().
-        local line1 = lines[1]:gsub('<', ''):gsub('[\r\n\012\027]', ' ')  -- Scrub.
+        -- Escape "<" and control characters
+        local line1 = lines[1]:gsub('<', ''):gsub('(%c)', '\022%1')
         vim.api.nvim_input(line1)
         vim.api.nvim_set_option('paste', false)
       end
-- 
cgit 


From 5a8bf31d328ecdb79453bf1eb22ff10aabbe0422 Mon Sep 17 00:00:00 2001
From: Jade Lovelace 
Date: Tue, 15 Mar 2022 14:46:32 -0700
Subject: vim-patch:8.2.4571: not all gdb files are recognized (#17727)

Problem:    Not all gdb files are recognized.
Solution:   Add a few more patterns for gdb.
            (closes https://github.com/vim/vim/pull/9956)
https://github.com/vim/vim/commit/8d5e514d77bd4b1956656ad2be2ce7094bd43a72
---
 runtime/lua/vim/filetype.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index f5e4dabfb6..b356f5e3dc 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -225,6 +225,7 @@ local extension = {
   fsi = "fsharp",
   fsx = "fsharp",
   fusion = "fusion",
+  gdb = "gdb",
   gdmo = "gdmo",
   mo = "gdmo",
   tres = "gdresource",
@@ -919,6 +920,8 @@ local filename = {
   mtab = "fstab",
   [".gdbinit"] = "gdb",
   gdbinit = "gdb",
+  [".gdbearlyinit"] = "gdb",
+  gdbearlyinit = "gdb",
   ["lltxxxxx.txt"] = "gedcom",
   ["TAG_EDITMSG"] = "gitcommit",
   ["MERGE_MSG"] = "gitcommit",
-- 
cgit 


From d238b8f6003d34cae7f65ff7585b48a2cd9449fb Mon Sep 17 00:00:00 2001
From: dundargoc <33953936+dundargoc@users.noreply.github.com>
Date: Thu, 17 Mar 2022 06:21:24 +0100
Subject: chore: fix typos (#17670)

Co-authored-by: zeertzjq 
---
 runtime/lua/vim/keymap.lua | 4 ++--
 runtime/lua/vim/lsp.lua    | 2 +-
 runtime/lua/vim/shared.lua | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua
index 7f12372502..1be40b0081 100644
--- a/runtime/lua/vim/keymap.lua
+++ b/runtime/lua/vim/keymap.lua
@@ -25,8 +25,8 @@ local keymap = {}
 ---    vim.keymap.set('n', 'asdf', require('jkl').my_fun)
 --- 
--- ---- the `require('jkl')` gets evaluated during this call in order to access the function. If you want to ---- avoid this cost at startup you can wrap it in a function, for example: +--- the ``require('jkl')`` gets evaluated during this call in order to access the function. +--- If you want to avoid this cost at startup you can wrap it in a function, for example: ---
 ---    vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end)
 --- 
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 8d11b4621c..105e7c4621 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1689,7 +1689,7 @@ end --- --- Currently only supports a single client. This can be set via --- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach` ---- via `vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})')`. +--- via ``vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})')``. --- ---@param opts table options for customizing the formatting expression which takes the --- following optional keys: diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 8124b23eb1..3eb332279a 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -331,7 +331,7 @@ end --- Add the reverse lookup values to an existing table. --- For example: ---- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }` +--- ``tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`` -- --Do note that it *modifies* the input. ---@param o table The table to add the reverse to. -- cgit From 6eca9b69c4a1f40f27a6b41961af787327259de8 Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 19 Mar 2022 13:48:03 +0100 Subject: feat(ui): allow conceal to be defined in decorations Unlike syntax conceal, change highlight of concealed char Can be used in tree-sitter using "conceal" metadata. --- runtime/lua/vim/treesitter/highlighter.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index b6f61cfb2e..e1ffd42a7f 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -274,7 +274,8 @@ local function on_line_impl(self, buf, line) { end_line = end_row, end_col = end_col, hl_group = hl, ephemeral = true, - priority = tonumber(metadata.priority) or 100 -- Low but leaves room below + priority = tonumber(metadata.priority) or 100, -- Low but leaves room below + conceal = metadata.conceal, }) end if start_row > line then -- cgit From af427dedf663b1987fa54c5f885409ad51824a20 Mon Sep 17 00:00:00 2001 From: Tim Pope Date: Sun, 20 Mar 2022 13:41:46 -0400 Subject: fix(lsp): set tabSize from 'shiftwidth', not 'softtabstop' (#17787) The use of 'softtabstop' to set tabSize was introduced in 5d5b068, replacing 'tabstop'. If we look past the name tabSize and at the actual purpose of the field, it's the indentation width used when formatting. This corresponds to the Vim option 'shiftwidth', not 'softtabstop'. The latter has the comparatively mundane purpose of controlling what happens when you hit the tab key (and even this is incomplete, as it fails to account for 'smarttab'). --- runtime/lua/vim/lsp/util.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 59ab3d7e1f..cec3891418 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1894,16 +1894,16 @@ end function M.make_workspace_params(added, removed) return { event = { added = added; removed = removed; } } end ---- Returns visual width of tabstop. +--- Returns indentation size. --- ----@see |softtabstop| +---@see |shiftwidth| ---@param bufnr (optional, number): Buffer handle, defaults to current ----@returns (number) tabstop visual width +---@returns (number) indentation size function M.get_effective_tabstop(bufnr) validate { bufnr = {bufnr, 'n', true} } local bo = bufnr and vim.bo[bufnr] or vim.bo - local sts = bo.softtabstop - return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop + local sw = bo.shiftwidth + return (sw == 0 and bo.tabstop) or sw end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. -- cgit From 58140a94283b1c6e45099c89e66a0c94e9d90931 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 24 Mar 2022 13:22:58 +0000 Subject: feat(keymap): return nil from an expr keymap For Lua callback expr keymaps, returning `nil` or `false` is equivalent to an empty string --- runtime/lua/vim/keymap.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index 1be40b0081..c193a13a7b 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -35,6 +35,8 @@ local keymap = {} --- Can also be list of modes to create mapping on multiple modes. ---@param lhs string Left-hand side |{lhs}| of the mapping. ---@param rhs string|function Right-hand side |{rhs}| of the mapping. Can also be a Lua function. +--- If a Lua function and `opts.expr == true`, returning `nil` or `false` +--- is equivalent to an empty string. -- ---@param opts table A table of |:map-arguments| such as "silent". In addition to the options --- listed in |nvim_set_keymap()|, this table also accepts the following keys: @@ -56,10 +58,18 @@ function keymap.set(mode, lhs, rhs, opts) local is_rhs_luaref = type(rhs) == "function" mode = type(mode) == 'string' and {mode} or mode - if is_rhs_luaref and opts.expr and opts.replace_keycodes ~= false then + if is_rhs_luaref and opts.expr then local user_rhs = rhs rhs = function () - return vim.api.nvim_replace_termcodes(user_rhs(), true, true, true) + local res = user_rhs() + if not res then + -- TODO(lewis6991): Handle this in C? + return '' + elseif opts.replace_keycodes ~= false then + return vim.api.nvim_replace_termcodes(res, true, true, true) + else + return res + end end end -- clear replace_keycodes from opts table -- cgit From 69f1de86dca28d6e339351082df1309ef4fbb6a6 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Thu, 24 Mar 2022 12:01:04 -0700 Subject: feat: add vim.tbl_get (#17831) vim.tbl_get takes a table with subsequent string arguments (variadic) that index into the table. If the value pointed to by the set of keys exists, the function returns the value. If the set of keys does not exist, the function returns nil. --- runtime/lua/vim/shared.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 3eb332279a..f0dc34608c 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -347,6 +347,33 @@ function vim.tbl_add_reverse_lookup(o) return o end +--- Index into a table (first argument) via string keys passed as subsequent arguments. +--- Return `nil` if the key does not exist. +--_ +--- Examples: +---
+---  vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true
+---  vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil
+--- 
+--- +---@param o Table to index +---@param ... Optional strings (0 or more, variadic) via which to index the table +--- +---@returns nested value indexed by key if it exists, else nil +function vim.tbl_get(o, ...) + local keys = {...} + if #keys == 0 then + return + end + for _, k in ipairs(keys) do + o = o[k] + if o == nil then + return + end + end + return o +end + --- Extends a list-like table with the values of another list-like table. --- --- NOTE: This mutates dst! -- cgit From 5e64d65df690000e56fd91577978e1744d6e9e8e Mon Sep 17 00:00:00 2001 From: Jared Weakly Date: Fri, 25 Mar 2022 11:12:00 -0700 Subject: fix(filetype.lua): always return a string in getline helper function (#17852) Uses of `getline` in `filetype.lua` currently assume it always returns a string. However, if the buffer is unloaded when filetype detection runs, `getline` returns `nil`. Fixing this prevents errors when filetype detection is run on unloaded buffers. --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index b356f5e3dc..ab71de54f8 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -21,7 +21,7 @@ end ---@private local function getline(bufnr, lnum) - return api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1] + return api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1] or "" end -- Filetypes based on file extension -- cgit From a8e2c45b9462b740f22305397342b96586b88681 Mon Sep 17 00:00:00 2001 From: Smitesh Patil Date: Sun, 27 Mar 2022 19:40:03 +0530 Subject: fix(diagnostic): make `open_float` respect global diagnostic options (#17879) * make `open_float` respect `scope` option set in `vim.diagnostic.config` * Closes #17878 --- runtime/lua/vim/diagnostic.lua | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index fcb1e61764..1ec66d7c55 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -1224,6 +1224,18 @@ function M.open_float(opts, ...) opts = opts or {} bufnr = get_bufnr(bufnr or opts.bufnr) + + do + -- Resolve options with user settings from vim.diagnostic.config + -- Unlike the other decoration functions (e.g. set_virtual_text, set_signs, etc.) `open_float` + -- does not have a dedicated table for configuration options; instead, the options are mixed in + -- with its `opts` table which also includes "keyword" parameters. So we create a dedicated + -- options table that inherits missing keys from the global configuration before resolving. + local t = global_diagnostic_options.float + local float_opts = vim.tbl_extend("keep", opts, type(t) == "table" and t or {}) + opts = get_resolved_options({ float = float_opts }, nil, bufnr).float + end + local scope = ({l = "line", c = "cursor", b = "buffer"})[opts.scope] or opts.scope or "line" local lnum, col if scope == "line" or scope == "cursor" then @@ -1242,17 +1254,6 @@ function M.open_float(opts, ...) error("Invalid value for option 'scope'") end - do - -- Resolve options with user settings from vim.diagnostic.config - -- Unlike the other decoration functions (e.g. set_virtual_text, set_signs, etc.) `open_float` - -- does not have a dedicated table for configuration options; instead, the options are mixed in - -- with its `opts` table which also includes "keyword" parameters. So we create a dedicated - -- options table that inherits missing keys from the global configuration before resolving. - local t = global_diagnostic_options.float - local float_opts = vim.tbl_extend("keep", opts, type(t) == "table" and t or {}) - opts = get_resolved_options({ float = float_opts }, nil, bufnr).float - end - local diagnostics = get_diagnostics(bufnr, opts, true) if scope == "line" then -- cgit From 4d3acd6bebbdffa3fefc4e102d9ff36845c7a18f Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Tue, 29 Mar 2022 01:16:11 +0900 Subject: fix(lsp): use "text" filetype for plaintext (#17898) --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index cec3891418..991c4be950 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1138,7 +1138,7 @@ function M.stylize_markdown(bufnr, contents, opts) block = {nil, "```+([a-zA-Z0-9_]*)", "```+"}, pre = {"", "
", "
"}, code = {"", "", ""}, - text = {"plaintex", "", ""}, + text = {"text", "", ""}, } local match_begin = function(line) -- cgit From a18c9ba2dab6e122e6fecd2353a0568f52d6c80c Mon Sep 17 00:00:00 2001 From: Andrea Cappuccio Date: Wed, 30 Mar 2022 21:04:17 +0200 Subject: docs(lsp): remove outdated offset_encoding default value for apply_text_edits --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 991c4be950..401dac9acd 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -360,7 +360,7 @@ end --- Applies a list of text edits to a buffer. ---@param text_edits table list of `TextEdit` objects ---@param bufnr number Buffer id ----@param offset_encoding string utf-8|utf-16|utf-32 defaults to encoding of first client of `bufnr` +---@param offset_encoding string utf-8|utf-16|utf-32 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit function M.apply_text_edits(text_edits, bufnr, offset_encoding) validate { -- cgit From 6d648f5594d580766fb28e45d797a4019d8b8149 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:14:20 -0600 Subject: feat(treesitter): add more default groups to highlight map (#17835) This covers some default groups listed in :h group-name. --- runtime/lua/vim/treesitter/highlighter.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index e1ffd42a7f..0ec4ab37ec 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -38,6 +38,9 @@ local subcapture_fallback = { TSHighlighter.hl_map = setmetatable({ ["error"] = "Error", + ["text.underline"] = "Underlined", + ["todo"] = "Todo", + ["debug"] = "Debug", -- Miscs ["comment"] = "Comment", @@ -49,10 +52,13 @@ TSHighlighter.hl_map = setmetatable({ ["constant"] = "Constant", ["constant.builtin"] = "Special", ["constant.macro"] = "Define", + ["define"] = "Define", + ["macro"] = "Macro", ["string"] = "String", ["string.regex"] = "String", ["string.escape"] = "SpecialChar", ["character"] = "Character", + ["character.special"] = "SpecialChar", ["number"] = "Number", ["boolean"] = "Boolean", ["float"] = "Float", @@ -78,8 +84,12 @@ TSHighlighter.hl_map = setmetatable({ ["type"] = "Type", ["type.builtin"] = "Type", + ["type.qualifier"] = "Type", + ["type.definition"] = "Typedef", + ["storageclass"] = "StorageClass", ["structure"] = "Structure", ["include"] = "Include", + ["preproc"] = "PreProc", }, subcapture_fallback) ---@private -- cgit From 2e85af47d2584372f968b760cab3eeee65273424 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 31 Mar 2022 16:46:45 +0200 Subject: feat(runtime): add query filetype (#17905) used for Tree-sitter queries uses Lisp runtime files (in Lua to distinguish from upstream runtime files) --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index ab71de54f8..2194db95a9 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1424,6 +1424,8 @@ local pattern = { return "git" end end, + -- Neovim only + [".*/queries/.*%.scm"] = "query", -- tree-sitter queries -- END PATTERN } -- luacheck: pop -- cgit From 38ba2a75fcbb3a893bf8b22838ed06fec6228509 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 31 Mar 2022 22:16:25 +0200 Subject: vim-patch:8.2.4658: org-mode files are not recognized (#17939) Problem: Org-mode files are not recognized. Solution: Add patterns to recognize "org" files. (closes vim/vim#10046) https://github.com/vim/vim/commit/3a6f952cc87065a4cf1f6502b2054ba99fdf45ed --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2194db95a9..927ef36391 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -438,6 +438,8 @@ local extension = { opam = "opam", ["or"] = "openroad", ora = "ora", + org = "org", + org_archive = "org", pxsl = "papp", papp = "papp", pxml = "papp", -- cgit From 3cc29b7f0d6e1661f39d28716c6a63603a93c11c Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 1 Apr 2022 09:09:30 +0100 Subject: fix(keymap): don't coerce false to '' --- runtime/lua/vim/keymap.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index c193a13a7b..0986d21196 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -35,8 +35,8 @@ local keymap = {} --- Can also be list of modes to create mapping on multiple modes. ---@param lhs string Left-hand side |{lhs}| of the mapping. ---@param rhs string|function Right-hand side |{rhs}| of the mapping. Can also be a Lua function. ---- If a Lua function and `opts.expr == true`, returning `nil` or `false` ---- is equivalent to an empty string. +--- If a Lua function and `opts.expr == true`, returning `nil` is +--- equivalent to an empty string. -- ---@param opts table A table of |:map-arguments| such as "silent". In addition to the options --- listed in |nvim_set_keymap()|, this table also accepts the following keys: @@ -62,7 +62,7 @@ function keymap.set(mode, lhs, rhs, opts) local user_rhs = rhs rhs = function () local res = user_rhs() - if not res then + if res == nil then -- TODO(lewis6991): Handle this in C? return '' elseif opts.replace_keycodes ~= false then -- cgit From e45d141e28a4b31b4c98f7ed1655e9c7141ae74f Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 2 Apr 2022 13:36:19 +0200 Subject: vim-patch:8.2.4664: Elvish files are not recognized (#17963) Problem: Elvish files are not recognized. Solution: Recognize .elv files. (Bruno Roque, closes vim/vim#10058) https://github.com/vim/vim/commit/c1658a196bb05dd96562fd0a92409be2201b62e9 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 927ef36391..65edaed530 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -177,6 +177,7 @@ local extension = { leex = "eelixir", exs = "elixir", elm = "elm", + elv = "elvish", epp = "epuppet", erl = "erlang", hrl = "erlang", -- cgit From f85f4e25d2d5edf46fcb950ced028685fe95a7d7 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 7 Apr 2022 09:09:08 +0200 Subject: vim-patch:8.2.4701: Kuka Robot Language files not recognized (#18012) Problem: Kuka Robot Language files not recognized. Solution: Recognize *.src and *.dat files. (Patrick Meiser-Knosowski, closes vim/vim#10096) https://github.com/vim/vim/commit/3ad2090316edc85e93094bba7af64f9991cc7f85 --- runtime/lua/vim/filetype.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 65edaed530..0466057d72 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1427,6 +1427,9 @@ local pattern = { return "git" end end, + [".*%.[Dd][Aa][Tt]"] = function() vim.fn["dist#ft#FTdat"]() end, + [".*%.[Ss][Rr][Cc]"] = function() vim.fn["dist#ft#FTsrc"]() end, + [".*%.[Ss][Uu][Bb]"] = "krl", -- Neovim only [".*/queries/.*%.scm"] = "query", -- tree-sitter queries -- END PATTERN -- cgit From 8c25dbff468a6360ac8e22ba1e3fec659db16ab8 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 7 Apr 2022 20:24:55 +0200 Subject: vim-patch:8.2.4708: PHP test files are not recognized (#18025) Problem: PHP test files are not recognized. Solution: Add the *.phpt pattern. (Julien Voisin, closes vim/vim#10112) https://github.com/vim/vim/commit/177847e67a495f80a15b6dfd0a3fcd151b44249e --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 0466057d72..6d8f734bed 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -457,6 +457,7 @@ local extension = { al = "perl", ctp = "php", php = "php", + phpt = "php", phtml = "php", pike = "pike", pmod = "pike", -- cgit From 8055f9857b8e384634d457533dfdb08618fc36f0 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 9 Apr 2022 11:19:18 +0200 Subject: vim-patch:8.2.4715: Vagrantfile not recognized (#18052) Problem: Vagrantfile not recognized. Solution: Recognize Vagrantfile as ruby. (Julien Voisin, closes vim/vim#10119) https://github.com/vim/vim/commit/5e1792270a072a96157e5d5e1d6a97414e26d0bf --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 6d8f734bed..7958de97b1 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1061,6 +1061,7 @@ local filename = { Puppetfile = "ruby", [".irbrc"] = "ruby", irbrc = "ruby", + Vagrantfile = "ruby", ["smb.conf"] = "samba", screenrc = "screen", [".screenrc"] = "screen", -- cgit From 3280dc2b60db8d4e36bff6d481e3e873f32040b1 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 9 Apr 2022 17:42:46 +0200 Subject: vim-patch:8.2.4720: ABB Rapid files are not recognized properly (#18057) Problem: ABB Rapid files are not recognized properly. Solution: Add checks for ABB Rapid files. (Patrick Meiser-Knosowski, closes #10104) https://github.com/vim/vim/commit/b09c320039ad49e62d2e2d7f14ba47ee3ca0706a --- runtime/lua/vim/filetype.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 7958de97b1..9397788e9e 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -79,7 +79,6 @@ local extension = { cfc = "cf", cfm = "cf", cfi = "cf", - cfg = "cfg", hgrc = "cfg", chf = "ch", chai = "chaiscript", @@ -158,7 +157,6 @@ local extension = { diff = "diff", rej = "diff", Dockerfile = "dockerfile", - sys = "dosbatch", bat = "dosbatch", wrap = "dosini", ini = "dosini", @@ -395,7 +393,6 @@ local extension = { mmp = "mmp", DEF = "modula2", ["m2"] = "modula2", - MOD = "modula2", mi = "modula2", ssc = "monk", monk = "monk", @@ -1429,9 +1426,13 @@ local pattern = { return "git" end end, + [".*%.[Cc][Ff][Gg]"] = function() vim.fn["dist#ft#FTcfg"]() end, [".*%.[Dd][Aa][Tt]"] = function() vim.fn["dist#ft#FTdat"]() end, + [".*%.[Mm][Oo][Dd]"] = function() vim.fn["dist#ft#FTmod"]() end, [".*%.[Ss][Rr][Cc]"] = function() vim.fn["dist#ft#FTsrc"]() end, [".*%.[Ss][Uu][Bb]"] = "krl", + [".*%.[Pp][Rr][Gg]"] = function() vim.fn["dist#ft#FTprg"]() end, + [".*%.[Ss][Yy][Ss]"] = function() vim.fn["dist#ft#FTsys"]() end, -- Neovim only [".*/queries/.*%.scm"] = "query", -- tree-sitter queries -- END PATTERN -- cgit From 61bd5426f4ef0d8f45d0972f7da870131ae278ba Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 9 Apr 2022 17:43:33 +0200 Subject: vim-patch:8.2.4721: cooklang files are not recognized (#18058) Problem: Cooklang files are not recognized. Solution: recognize *.cook files. (Goc Dundar, closes vim/vim#10120) https://github.com/vim/vim/commit/36951ed1dab2b2e816dc8959c72b5732f36d9e3b --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 9397788e9e..880b99a2fa 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -95,6 +95,7 @@ local extension = { clj = "clojure", cljc = "clojure", cljs = "clojure", + cook = "cook", cmake = "cmake", cmod = "cmod", lib = "cobol", -- cgit From b438bb434305a89457f1c565363f07326d4c5353 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 10 Apr 2022 13:53:33 +0200 Subject: vim-patch:8.2.4729: HEEx and Surface templates do not need a separate filetype (#18065) Problem: HEEx and Surface templates do not need a separate filetype. Solution: Use Eelixir for the similar filetypes. (Aaron Tinio, closes vim/vim#10124) https://github.com/vim/vim/commit/fa76a24109f3c3287e4ee17b6270bfd5310c12f3 --- runtime/lua/vim/filetype.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 880b99a2fa..a4d0264384 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -173,7 +173,9 @@ local extension = { lid = "dylanlid", ecd = "ecd", eex = "eelixir", + heex = "eelixir", leex = "eelixir", + sface = "eelixir", exs = "elixir", elm = "elm", elv = "elvish", @@ -267,7 +269,6 @@ local extension = { ev = "hercules", vc = "hercules", hcl = "hcl", - heex = "heex", hex = "hex", ["h32"] = "hex", hjson = "hjson", @@ -644,7 +645,6 @@ local extension = { mata = "stata", ado = "stata", stp = "stp", - sface = "surface", svelte = "svelte", svg = "svg", swift = "swift", -- cgit From 2dc86ef3b2328e5ee7b2d814cda05da17ec25eaa Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Mon, 11 Apr 2022 18:38:54 +0800 Subject: vim-patch:8.2.4733: HEEx and Surface do need a separate filetype Problem: HEEx and Surface do need a separate filetype. Solution: Revert 8.2.4729. (closes vim/vim#10147) https://github.com/vim/vim/commit/4232dff815db1a727cb1aea26783267d8bd731c3 --- runtime/lua/vim/filetype.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index a4d0264384..880b99a2fa 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -173,9 +173,7 @@ local extension = { lid = "dylanlid", ecd = "ecd", eex = "eelixir", - heex = "eelixir", leex = "eelixir", - sface = "eelixir", exs = "elixir", elm = "elm", elv = "elvish", @@ -269,6 +267,7 @@ local extension = { ev = "hercules", vc = "hercules", hcl = "hcl", + heex = "heex", hex = "hex", ["h32"] = "hex", hjson = "hjson", @@ -645,6 +644,7 @@ local extension = { mata = "stata", ado = "stata", stp = "stp", + sface = "surface", svelte = "svelte", svg = "svg", swift = "swift", -- cgit From 392cb7ac0cf7fd2ede1d3c22c4bbb47f92a55637 Mon Sep 17 00:00:00 2001 From: Tony Fettes Date: Mon, 11 Apr 2022 15:44:31 -0400 Subject: fix(lsp): pass offset_encoding in formatexpr() (#18084) --- runtime/lua/vim/lsp.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 105e7c4621..7bbe3637db 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1719,9 +1719,9 @@ function lsp.formatexpr(opts) local client_results = vim.lsp.buf_request_sync(0, "textDocument/rangeFormatting", params, timeout_ms) -- Apply the text edits from one and only one of the clients. - for _, response in pairs(client_results) do + for client_id, response in pairs(client_results) do if response.result then - vim.lsp.util.apply_text_edits(response.result, 0) + vim.lsp.util.apply_text_edits(response.result, 0, vim.lsp.get_client_by_id(client_id).offset_encoding) return 0 end end -- cgit From 9938740ca6eae26de7c6deff8dd8318136ee5113 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 13 Apr 2022 17:04:38 +0200 Subject: vim-patch:8.2.4746: supercollider filetype not recognized (#18102) Problem: Supercollider filetype not recognized. Solution: Match file extentions and check file contents to detect supercollider. (closes vim/vim#10142) https://github.com/vim/vim/commit/8cac20ed42b7b7fc9c6b54e3055ca1047f50b8ca --- runtime/lua/vim/filetype.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 880b99a2fa..603f9f854a 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -569,8 +569,6 @@ local extension = { sa = "sather", sbt = "sbt", scala = "scala", - sc = "scala", - scd = "scdoc", ss = "scheme", scm = "scheme", sld = "scheme", @@ -644,6 +642,7 @@ local extension = { mata = "stata", ado = "stata", stp = "stp", + quark = "supercollider", sface = "surface", svelte = "svelte", svg = "svg", @@ -830,6 +829,8 @@ local extension = { r = function() vim.fn["dist#ft#FTr"]() end, rdf = function() vim.fn["dist#ft#Redif"]() end, rules = function() vim.fn["dist#ft#FTRules"]() end, + sc = function() vim.fn["dist#ft#FTsc"]() end, + scd = function() vim.fn["dist#ft#FTscd"]() end, sh = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, shtml = function() vim.fn["dist#ft#FThtml"]() end, sql = function() vim.fn["dist#ft#SQL"]() end, -- cgit From 6160973f36b532b6f9ff2cd7c20958fd791f2e2a Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 15 Apr 2022 11:12:41 +0200 Subject: fix(lsp): fix lookup of boolean values in workspace/configuration (#18026) --- runtime/lua/vim/lsp/handlers.lua | 2 +- runtime/lua/vim/lsp/util.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index f5aefd4402..9871f00677 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -141,7 +141,7 @@ M['workspace/configuration'] = function(_, result, ctx) local response = {} for _, item in ipairs(result.items) do if item.section then - local value = util.lookup_section(client.config.settings, item.section) or vim.NIL + local value = util.lookup_section(client.config.settings, item.section) -- For empty sections with no explicit '' key, return settings as is if value == vim.NIL and item.section == '' then value = client.config.settings or vim.NIL diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 401dac9acd..30587afb38 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1950,8 +1950,8 @@ end function M.lookup_section(settings, section) for part in vim.gsplit(section, '.', true) do settings = settings[part] - if not settings then - return + if settings == nil then + return vim.NIL end end return settings -- cgit From e63e5d1dbd3dd4711efa0ecf9e844ff308b370a6 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Fri, 15 Apr 2022 12:35:06 +0200 Subject: docs: typo fixes (#17859) Co-authored-by: Elias Alves Moura Co-authored-by: venkatesh Co-authored-by: zeertzjq Co-authored-by: Vikas Raj <24727447+numToStr@users.noreply.github.com> Co-authored-by: Steve Vermeulen Co-authored-by: Evgeni Chasnovski Co-authored-by: rwxd Co-authored-by: casswedson <58050969+casswedson@users.noreply.github.com> --- runtime/lua/vim/ui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 9d4b38f08a..165dada1b8 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -16,7 +16,7 @@ local M = {} --- `items`, or the context in which select() was called. ---@param on_choice function ((item|nil, idx|nil) -> ()) --- Called once the user made a choice. ---- `idx` is the 1-based index of `item` within `item`. +--- `idx` is the 1-based index of `item` within `items`. --- `nil` if the user aborted the dialog. --- --- -- cgit From 813ecdac795405565aab5cb61cb83b9ca1581b60 Mon Sep 17 00:00:00 2001 From: Eden Zhang <53964412+VelocityDv@users.noreply.github.com> Date: Sun, 17 Apr 2022 12:11:53 +1200 Subject: fix(paste): ignore mappings in Cmdline mode (#18114) --- runtime/lua/vim/_editor.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index d4db4850bd..8e372b806c 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -174,11 +174,11 @@ do if vim.fn.getcmdtype() ~= '' then -- cmdline-mode: paste only 1 line. if not got_line1 then got_line1 = (#lines > 1) - vim.api.nvim_set_option('paste', true) -- For nvim_input(). - -- Escape "<" and control characters - local line1 = lines[1]:gsub('<', ''):gsub('(%c)', '\022%1') - vim.api.nvim_input(line1) - vim.api.nvim_set_option('paste', false) + -- Escape control characters + local line1 = lines[1]:gsub('(%c)', '\022%1') + -- nvim_input() is affected by mappings, + -- so use nvim_feedkeys() with "n" flag to ignore mappings. + vim.api.nvim_feedkeys(line1, 'n', true) end return true end -- cgit From 6e6f5a783333d1bf9d6c719c896e72ac82e1ae54 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 17 Apr 2022 10:15:55 +0200 Subject: vim-patch:8.2.4767: openscad files are not recognized (#18138) Problem: Openscad files are not recognized. Solution: Add a filetype pattern. (Niklas Adam, closes vim/vim#10199) https://github.com/vim/vim/commit/c360b2566ce2390d45d9436a6a85719fe2b387d5 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 603f9f854a..27a3366e0f 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -436,6 +436,7 @@ local extension = { xin = "omnimark", opam = "opam", ["or"] = "openroad", + scad = "openscad", ora = "ora", org = "org", org_archive = "org", -- cgit From 1facad23473eb2d045fe77199b3b0b9fd2586895 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sun, 17 Apr 2022 23:30:13 +0200 Subject: vim-patch:8.2.4778: pacman files use dosini filetype (#18152) Problem: Pacman files use dosini filetype. Solution: Use conf instead. (Chaoren Lin, closes vim/vim#10213) https://github.com/vim/vim/commit/35cff32dd82e5e2b72453b9f27d0655fc5b8a639 --- runtime/lua/vim/filetype.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 27a3366e0f..d8d4afb6c2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -103,6 +103,11 @@ local extension = { cbl = "cobol", atg = "coco", recipe = "conaryrecipe", + hook = function(path, bufnr) + if getline(bufnr, 1) == '[Trigger]' then + return "conf" + end + end, mklx = "context", mkiv = "context", mkii = "context", @@ -903,7 +908,7 @@ local filename = { Dockerfile = "dockerfile", npmrc = "dosini", ["/etc/yum.conf"] = "dosini", - ["/etc/pacman.conf"] = "dosini", + ["/etc/pacman.conf"] = "conf", [".npmrc"] = "dosini", [".editorconfig"] = "dosini", dune = "dune", @@ -1182,7 +1187,7 @@ local pattern = { [".*/etc/DIR_COLORS"] = "dircolors", [".*/etc/dnsmasq%.conf"] = "dnsmasq", ["php%.ini%-.*"] = "dosini", - [".*/etc/pacman%.conf"] = "dosini", + [".*/etc/pacman%.conf"] = "conf", [".*/etc/yum%.conf"] = "dosini", [".*lvs"] = "dracula", [".*lpe"] = "dracula", -- cgit From a391cd517bb4f0d638da3f0aaaf57f98e153447e Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 20 Apr 2022 08:35:22 +0200 Subject: vim-patch:8.2.4790: lilypond filetype not recognized (#18174) Problem: Lilypond filetype not recognized. Solution: Add patterns for lilypond. (Doug Kearns) https://github.com/vim/vim/commit/c448e9c95089b5e7170a0dd36635a226c5eb5b1c --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index d8d4afb6c2..ac36210b23 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -343,6 +343,8 @@ local extension = { l = "lex", lhs = "lhaskell", ll = "lifelines", + ly = "lilypond", + ily = "lilypond", liquid = "liquid", cl = "lisp", L = "lisp", -- cgit From 63eb7e865b3c702d09bfa475587f646722996a56 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 20 Apr 2022 09:50:32 +0200 Subject: vim-patch:8.2.4793: recognizing Maxima filetype even though it might be another Problem: Recognizing Maxima filetype even though it might be another. Solution: Remove *.mc and *.dem patterns from Maxima files https://github.com/vim/vim/commit/928a13135629fa8e73796760077b1b877918a080 --- runtime/lua/vim/filetype.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index ac36210b23..d575869377 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -389,6 +389,12 @@ local extension = { mason = "mason", master = "master", mas = "master", + demo = "maxima", + dm1 = "maxima", + dm2 = "maxima", + dm3 = "maxima", + dmt = "maxima", + wxm = "maxima", mel = "mel", mf = "mf", mgl = "mgl", @@ -1013,6 +1019,7 @@ local filename = { [".mailcap"] = "mailcap", ["/etc/man.conf"] = "manconf", ["man.config"] = "manconf", + ["maxima-init.mac"] = "maxima", ["meson.build"] = "meson", ["meson_options.txt"] = "meson", ["/etc/conf.modules"] = "modconf", -- cgit From 6b0d3ae6a83cb0410c16532a367ed8ad9bd093a8 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 20 Apr 2022 08:16:47 -0600 Subject: fix(diagnostic): use nvim_exec_autocmds to trigger DiagnosticChanged (#18188) Use nvim_exec_autocmds to issue the DiagnosticChanged autocommand, rather than nvim_buf_call, which has some side effects when drawing statuslines. --- runtime/lua/vim/diagnostic.lua | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 1ec66d7c55..80ce1f331d 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -668,14 +668,10 @@ function M.set(namespace, bufnr, diagnostics, opts) M.show(namespace, bufnr, nil, opts) end - vim.api.nvim_buf_call(bufnr, function() - vim.api.nvim_command( - string.format( - "doautocmd DiagnosticChanged %s", - vim.fn.fnameescape(vim.api.nvim_buf_get_name(bufnr)) - ) - ) - end) + vim.api.nvim_exec_autocmds("DiagnosticChanged", { + modeline = false, + buffer = bufnr, + }) end --- Get namespace metadata. @@ -1382,14 +1378,10 @@ function M.reset(namespace, bufnr) M.hide(iter_namespace, iter_bufnr) end - vim.api.nvim_buf_call(iter_bufnr, function() - vim.api.nvim_command( - string.format( - "doautocmd DiagnosticChanged %s", - vim.fn.fnameescape(vim.api.nvim_buf_get_name(iter_bufnr)) - ) - ) - end) + vim.api.nvim_exec_autocmds("DiagnosticChanged", { + modeline = false, + buffer = iter_bufnr, + }) end end -- cgit From 7e7fdca163b10f8141c72936cea82051843c83c6 Mon Sep 17 00:00:00 2001 From: runiq Date: Wed, 20 Apr 2022 18:40:52 +0200 Subject: fix(lsp): unify progress message handling (#18040) The LSP progress handler would put non-progress messages (such as from clangd or pyls; not part of the LSP spec) directly into `client.messages`, while `vim.lsp.util.get_progress_messages()` would try to fetch them from `client.messages.messages` instead (and come up empty everytime). This would result in these messages never being cleaned up by `get_progress_messages()`. This commit fixes that by treating those messages like show-once progress messages (by setting `done=true` immediately). --- runtime/lua/vim/lsp/handlers.lua | 5 +++-- runtime/lua/vim/lsp/util.lua | 24 ------------------------ 2 files changed, 3 insertions(+), 26 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 9871f00677..71b4d33ec0 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -33,7 +33,7 @@ local function progress_handler(_, result, ctx, _) local val = result.value -- unspecified yet local token = result.token -- string or number - + if type(val) ~= 'table' then val = { content=val } end if val.kind then if val.kind == 'begin' then client.messages.progress[token] = { @@ -53,7 +53,8 @@ local function progress_handler(_, result, ctx, _) end end else - table.insert(client.messages, {content = val, show_once = true, shown = 0}) + client.messages.progress[token] = val + client.messages.progress[token].done = true end vim.api.nvim_command("doautocmd User LspProgressUpdate") diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 30587afb38..1f1a34b04a 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -302,7 +302,6 @@ end function M.get_progress_messages() local new_messages = {} - local msg_remove = {} local progress_remove = {} for _, client in ipairs(vim.lsp.get_active_clients()) do @@ -325,29 +324,6 @@ function M.get_progress_messages() end end - for i, msg in ipairs(data.messages) do - if msg.show_once then - msg.shown = msg.shown + 1 - if msg.shown > 1 then - table.insert(msg_remove, {client = client, idx = i}) - end - end - - table.insert(new_messages, {name = data.name, content = msg.content}) - end - - if next(data.status) ~= nil then - table.insert(new_messages, { - name = data.name, - content = data.status.content, - uri = data.status.uri, - status = true - }) - end - for _, item in ipairs(msg_remove) do - table.remove(client.messages, item.idx) - end - end for _, item in ipairs(progress_remove) do -- cgit From 5ecbbba6ee4364dd2ad8ae4bebd0b004ae20deaf Mon Sep 17 00:00:00 2001 From: atusy <30277794+atusy@users.noreply.github.com> Date: Thu, 21 Apr 2022 10:15:19 +0900 Subject: docs: vim.keymap.set can specify buffer as an option --- runtime/lua/vim/keymap.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index 0986d21196..0511584526 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -40,6 +40,8 @@ local keymap = {} -- ---@param opts table A table of |:map-arguments| such as "silent". In addition to the options --- listed in |nvim_set_keymap()|, this table also accepts the following keys: +--- - buffer: (number or boolean) Add a mapping to the given buffer. When "true" +--- or 0, use the current buffer. --- - replace_keycodes: (boolean, default true) When both this and expr is "true", --- |nvim_replace_termcodes()| is applied to the result of Lua expr maps. --- - remap: (boolean) Make the mapping recursive. This is the -- cgit From 64784dccb557340b467d451371d58bf2afeb5ab3 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 21 Apr 2022 16:23:10 +0200 Subject: chore: update inspect.lua to 3.1.3 --- runtime/lua/vim/inspect.lua | 383 ++++++++++++++++++++++---------------------- 1 file changed, 193 insertions(+), 190 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/inspect.lua b/runtime/lua/vim/inspect.lua index 0448ea487f..b19c215dbb 100644 --- a/runtime/lua/vim/inspect.lua +++ b/runtime/lua/vim/inspect.lua @@ -1,7 +1,7 @@ -local inspect ={ - _VERSION = 'inspect.lua 3.1.0', - _URL = 'http://github.com/kikito/inspect.lua', - _DESCRIPTION = 'human-readable representations of tables', +local inspect = { + _VERSION = "inspect.lua 3.1.0", + _URL = "http://github.com/kikito/inspect.lua", + _DESCRIPTION = "human-readable representations of tables", _LICENSE = [[ MIT LICENSE @@ -25,13 +25,26 @@ local inspect ={ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ]] + ]], } -local tostring = tostring +inspect.KEY = setmetatable({}, { + __tostring = function() + return "inspect.KEY" + end, +}) +inspect.METATABLE = setmetatable({}, { + __tostring = function() + return "inspect.METATABLE" + end, +}) -inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) -inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) +local tostring = tostring +local rep = string.rep +local match = string.match +local char = string.char +local gsub = string.gsub +local fmt = string.format local function rawpairs(t) return next, t, nil @@ -40,299 +53,289 @@ end -- Apostrophizes the string if it has quotes, but not aphostrophes -- Otherwise, it returns a regular quoted string local function smartQuote(str) - if str:match('"') and not str:match("'") then + if match(str, '"') and not match(str, "'") then return "'" .. str .. "'" end - return '"' .. str:gsub('"', '\\"') .. '"' + return '"' .. gsub(str, '"', '\\"') .. '"' end -- \a => '\\a', \0 => '\\0', 31 => '\31' local shortControlCharEscapes = { - ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", - ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" + ["\a"] = "\\a", + ["\b"] = "\\b", + ["\f"] = "\\f", + ["\n"] = "\\n", + ["\r"] = "\\r", + ["\t"] = "\\t", + ["\v"] = "\\v", + ["\127"] = "\\127", } -local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 -for i=0, 31 do - local ch = string.char(i) +local longControlCharEscapes = { ["\127"] = "\127" } +for i = 0, 31 do + local ch = char(i) if not shortControlCharEscapes[ch] then - shortControlCharEscapes[ch] = "\\"..i - longControlCharEscapes[ch] = string.format("\\%03d", i) + shortControlCharEscapes[ch] = "\\" .. i + longControlCharEscapes[ch] = fmt("\\%03d", i) end end local function escape(str) - return (str:gsub("\\", "\\\\") - :gsub("(%c)%f[0-9]", longControlCharEscapes) - :gsub("%c", shortControlCharEscapes)) + return (gsub(gsub(gsub(str, "\\", "\\\\"), "(%c)%f[0-9]", longControlCharEscapes), "%c", shortControlCharEscapes)) end local function isIdentifier(str) - return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) + return type(str) == "string" and not not str:match("^[_%a][_%a%d]*$") end +local flr = math.floor local function isSequenceKey(k, sequenceLength) - return type(k) == 'number' - and 1 <= k - and k <= sequenceLength - and math.floor(k) == k + return type(k) == "number" and flr(k) == k and 1 <= k and k <= sequenceLength end local defaultTypeOrders = { - ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, - ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 + ["number"] = 1, + ["boolean"] = 2, + ["string"] = 3, + ["table"] = 4, + ["function"] = 5, + ["userdata"] = 6, + ["thread"] = 7, } local function sortKeys(a, b) local ta, tb = type(a), type(b) -- strings and numbers are sorted numerically/alphabetically - if ta == tb and (ta == 'string' or ta == 'number') then return a < b end + if ta == tb and (ta == "string" or ta == "number") then + return a < b + end - local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] + local dta = defaultTypeOrders[ta] or 100 + local dtb = defaultTypeOrders[tb] or 100 -- Two default types are compared according to the defaultTypeOrders table - if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] - elseif dta then return true -- default types before custom ones - elseif dtb then return false -- custom types after default ones - end -- custom types are sorted out alphabetically - return ta < tb + return dta == dtb and ta < tb or dta < dtb end --- For implementation reasons, the behavior of rawlen & # is "undefined" when --- tables aren't pure sequences. So we implement our own # operator. -local function getSequenceLength(t) - local len = 1 - local v = rawget(t,len) - while v ~= nil do - len = len + 1 - v = rawget(t,len) +local function getKeys(t) + local seqLen = 1 + while rawget(t, seqLen) ~= nil do + seqLen = seqLen + 1 end - return len - 1 -end + seqLen = seqLen - 1 -local function getNonSequentialKeys(t) - local keys, keysLength = {}, 0 - local sequenceLength = getSequenceLength(t) - for k,_ in rawpairs(t) do - if not isSequenceKey(k, sequenceLength) then - keysLength = keysLength + 1 - keys[keysLength] = k + local keys, keysLen = {}, 0 + for k in rawpairs(t) do + if not isSequenceKey(k, seqLen) then + keysLen = keysLen + 1 + keys[keysLen] = k end end table.sort(keys, sortKeys) - return keys, keysLength, sequenceLength + return keys, keysLen, seqLen end -local function countTableAppearances(t, tableAppearances) - tableAppearances = tableAppearances or {} - - if type(t) == 'table' then - if not tableAppearances[t] then - tableAppearances[t] = 1 - for k,v in rawpairs(t) do - countTableAppearances(k, tableAppearances) - countTableAppearances(v, tableAppearances) - end - countTableAppearances(getmetatable(t), tableAppearances) +local function countCycles(x, cycles) + if type(x) == "table" then + if cycles[x] then + cycles[x] = cycles[x] + 1 else - tableAppearances[t] = tableAppearances[t] + 1 + cycles[x] = 1 + for k, v in rawpairs(x) do + countCycles(k, cycles) + countCycles(v, cycles) + end + countCycles(getmetatable(x), cycles) end end - - return tableAppearances -end - -local copySequence = function(s) - local copy, len = {}, #s - for i=1, len do copy[i] = s[i] end - return copy, len end -local function makePath(path, ...) - local keys = {...} - local newPath, len = copySequence(path) - for i=1, #keys do - newPath[len + i] = keys[i] +local function makePath(path, a, b) + local newPath = {} + local len = #path + for i = 1, len do + newPath[i] = path[i] end + + newPath[len + 1] = a + newPath[len + 2] = b + return newPath end local function processRecursive(process, item, path, visited) - if item == nil then return nil end - if visited[item] then return visited[item] end + if item == nil then + return nil + end + if visited[item] then + return visited[item] + end local processed = process(item, path) - if type(processed) == 'table' then + if type(processed) == "table" then local processedCopy = {} visited[item] = processedCopy local processedKey - for k,v in rawpairs(processed) do + for k, v in rawpairs(processed) do processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) if processedKey ~= nil then processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) end end - local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) - if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field + local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) + if type(mt) ~= "table" then + mt = nil + end setmetatable(processedCopy, mt) processed = processedCopy end return processed end - - -------------------------------------------------------------------- - -local Inspector = {} -local Inspector_mt = {__index = Inspector} - -function Inspector:puts(...) - local args = {...} - local buffer = self.buffer - local len = #buffer - for i=1, #args do - len = len + 1 - buffer[len] = args[i] - end +local function puts(buf, str) + buf.n = buf.n + 1 + buf[buf.n] = str end -function Inspector:down(f) - self.level = self.level + 1 - f() - self.level = self.level - 1 -end +local Inspector = {} -function Inspector:tabify() - self:puts(self.newline, string.rep(self.indent, self.level)) -end +local Inspector_mt = { __index = Inspector } -function Inspector:alreadyVisited(v) - return self.ids[v] ~= nil +local function tabify(inspector) + puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level)) end function Inspector:getId(v) local id = self.ids[v] + local ids = self.ids if not id then local tv = type(v) - id = (self.maxIds[tv] or 0) + 1 - self.maxIds[tv] = id - self.ids[v] = id + id = (ids[tv] or 0) + 1 + ids[v], ids[tv] = id, id end return tostring(id) end -function Inspector:putKey(k) - if isIdentifier(k) then return self:puts(k) end - self:puts("[") - self:putValue(k) - self:puts("]") -end +function Inspector:putValue(v) + local buf = self.buf + local tv = type(v) + if tv == "string" then + puts(buf, smartQuote(escape(v))) + elseif + tv == "number" + or tv == "boolean" + or tv == "nil" + or tv == "cdata" + or tv == "ctype" + or (vim and v == vim.NIL) + then + puts(buf, tostring(v)) + elseif tv == "table" and not self.ids[v] then + local t = v + + if t == inspect.KEY or t == inspect.METATABLE then + puts(buf, tostring(t)) + elseif self.level >= self.depth then + puts(buf, "{...}") + else + if self.cycles[t] > 1 then + puts(buf, fmt("<%d>", self:getId(t))) + end -function Inspector:putTable(t) - if t == inspect.KEY or t == inspect.METATABLE then - self:puts(tostring(t)) - elseif self:alreadyVisited(t) then - self:puts('') - elseif self.level >= self.depth then - self:puts('{...}') - else - if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end - - local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t) - local mt = getmetatable(t) - if (vim and sequenceLength == 0 and nonSequentialKeysLength == 0 - and mt == vim._empty_dict_mt) then - self:puts(tostring(t)) - return - end + local keys, keysLen, seqLen = getKeys(t) + local mt = getmetatable(t) - self:puts('{') - self:down(function() - local count = 0 - for i=1, sequenceLength do - if count > 0 then self:puts(',') end - self:puts(' ') - self:putValue(t[i]) - count = count + 1 + if vim and seqLen == 0 and keysLen == 0 and mt == vim._empty_dict_mt then + puts(buf, tostring(t)) + return end - for i=1, nonSequentialKeysLength do - local k = nonSequentialKeys[i] - if count > 0 then self:puts(',') end - self:tabify() - self:putKey(k) - self:puts(' = ') - self:putValue(t[k]) - count = count + 1 + puts(buf, "{") + self.level = self.level + 1 + + for i = 1, seqLen + keysLen do + if i > 1 then + puts(buf, ",") + end + if i <= seqLen then + puts(buf, " ") + self:putValue(t[i]) + else + local k = keys[i - seqLen] + tabify(self) + if isIdentifier(k) then + puts(buf, k) + else + puts(buf, "[") + self:putValue(k) + puts(buf, "]") + end + puts(buf, " = ") + self:putValue(t[k]) + end end - if type(mt) == 'table' then - if count > 0 then self:puts(',') end - self:tabify() - self:puts(' = ') + if type(mt) == "table" then + if seqLen + keysLen > 0 then + puts(buf, ",") + end + tabify(self) + puts(buf, " = ") self:putValue(mt) end - end) - if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing } - self:tabify() - elseif sequenceLength > 0 then -- array tables have one extra space before closing } - self:puts(' ') - end + self.level = self.level - 1 - self:puts('}') - end -end - -function Inspector:putValue(v) - local tv = type(v) + if keysLen > 0 or type(mt) == "table" then + tabify(self) + elseif seqLen > 0 then + puts(buf, " ") + end - if tv == 'string' then - self:puts(smartQuote(escape(v))) - elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or - tv == 'cdata' or tv == 'ctype' or (vim and v == vim.NIL) then - self:puts(tostring(v)) - elseif tv == 'table' then - self:putTable(v) + puts(buf, "}") + end else - self:puts('<', tv, ' ', self:getId(v), '>') + puts(buf, fmt("<%s %d>", tv, self:getId(v))) end end -------------------------------------------------------------------- - function inspect.inspect(root, options) - options = options or {} + options = options or {} - local depth = options.depth or math.huge - local newline = options.newline or '\n' - local indent = options.indent or ' ' + local depth = options.depth or math.huge + local newline = options.newline or "\n" + local indent = options.indent or " " local process = options.process if process then root = processRecursive(process, root, {}, {}) end + local cycles = {} + countCycles(root, cycles) + local inspector = setmetatable({ - depth = depth, - level = 0, - buffer = {}, - ids = {}, - maxIds = {}, - newline = newline, - indent = indent, - tableAppearances = countTableAppearances(root) + buf = { n = 0 }, + ids = {}, + cycles = cycles, + depth = depth, + level = 0, + newline = newline, + indent = indent, }, Inspector_mt) inspector:putValue(root) - return table.concat(inspector.buffer) + return table.concat(inspector.buf) end -setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end }) +setmetatable(inspect, { + __call = function(_, root, options) + return inspect.inspect(root, options) + end, +}) return inspect -- cgit From 6c8a3013ac8cbcbfc8b3e1d51f6491bfa0c4a7aa Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 21 Apr 2022 21:46:07 +0200 Subject: docs(lua): explain and link to lua patterns (#18206) also correct explanation of when it's allowed to omit parens in Lua function calls --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index d575869377..420d343a8a 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1487,7 +1487,7 @@ end --- Filetype mappings can be added either by extension or by filename (either --- the "tail" or the full file path). The full file path is checked first, --- followed by the file name. If a match is not found using the filename, then ---- the filename is matched against the list of patterns (sorted by priority) +--- the filename is matched against the list of |lua-patterns| (sorted by priority) --- until a match is found. Lastly, if pattern matching does not find a --- filetype, then the file extension is used. --- -- cgit From 116a3f4683de501228b422f67cf1030bee78759c Mon Sep 17 00:00:00 2001 From: Chinmay Dalal Date: Fri, 22 Apr 2022 19:45:28 +0530 Subject: fix(treesitter): create new parser if language is not the same as cached parser (#18149) --- runtime/lua/vim/treesitter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index f9d539f028..55398d8180 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -90,7 +90,7 @@ function M.get_parser(bufnr, lang, opts) lang = a.nvim_buf_get_option(bufnr, "filetype") end - if parsers[bufnr] == nil then + if parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then parsers[bufnr] = M._create_parser(bufnr, lang, opts) end -- cgit From 4e4914ab2e523f100c06fc5fb253f8625cc67232 Mon Sep 17 00:00:00 2001 From: Andrey Mishchenko Date: Fri, 22 Apr 2022 20:01:08 -0400 Subject: fix(lua): don't mutate opts parameter of vim.keymap.del (#18227) `vim.keymap.del` takes an `opts` parameter that lets caller refer to and delete buffer-local mappings. For some reason the implementation of `vim.keymap.del` mutates the table that is passed in, setting `opts.buffer` to `nil`. This is wrong and also undocumented. --- runtime/lua/vim/keymap.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index 0511584526..d07232f52f 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -130,7 +130,6 @@ function keymap.del(modes, lhs, opts) local buffer = false if opts.buffer ~= nil then buffer = opts.buffer == true and 0 or opts.buffer - opts.buffer = nil end if buffer == false then -- cgit From af82eab946cf9f36e544b0591b8c8c02e8ddf316 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 25 Apr 2022 20:02:36 +0200 Subject: vim-patch:8.2.4826: .cshtml files are not recognized (#18259) Problem: .cshtml files are not recognized. Solution: Use html filetype for .cshtml files. (Julien Voisin, closes vim/vim#10212) https://github.com/vim/vim/commit/1f435dafff2452e0b55d1ca457ce7402e526e92a --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 420d343a8a..1297ef6241 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -142,6 +142,7 @@ local extension = { cs = "cs", csc = "csc", csdl = "csdl", + cshtml = "html", fdr = "csp", csp = "csp", css = "css", -- cgit From 55135cea619cd1b8b8d7563c14436c092fa749ab Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Tue, 26 Apr 2022 19:00:28 +0200 Subject: fix(lsp): fix unnecessary buffers being added on empty diagnostics (#18275) Some language servers send empty `textDocument/publishDiagnostics` messages after indexing the project with URIs corresponding to unopened buffers. This commit guards against opening buffers corresponding to empty diagnostics. --- runtime/lua/vim/lsp/diagnostic.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 614d83f565..6a8d6dcad7 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -185,7 +185,12 @@ end function M.on_publish_diagnostics(_, result, ctx, config) local client_id = ctx.client_id local uri = result.uri - local bufnr = vim.uri_to_bufnr(uri) + local fname = vim.uri_to_fname(uri) + local diagnostics = result.diagnostics + if #diagnostics == 0 and vim.fn.bufexists(fname) == 0 then + return + end + local bufnr = vim.fn.bufadd(fname) if not bufnr then return @@ -193,7 +198,6 @@ function M.on_publish_diagnostics(_, result, ctx, config) client_id = get_client_id(client_id) local namespace = M.get_namespace(client_id) - local diagnostics = result.diagnostics if config then for _, opt in pairs(config) do -- cgit From 9a1920e2238f8dcde3e923cf67dae2a46a4d40df Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 29 Apr 2022 23:04:00 +0200 Subject: feat(lsp): show feedback on empty hover response (#18308) Without any feedback it gives the impression that the language server is not working properly, which isn't the case. --- runtime/lua/vim/lsp/handlers.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 71b4d33ec0..978e44b6f8 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -298,13 +298,13 @@ function M.hover(_, result, ctx, config) config = config or {} config.focus_id = ctx.method if not (result and result.contents) then - -- return { 'No information available' } + vim.notify('No information available') return end local markdown_lines = util.convert_input_to_markdown_lines(result.contents) markdown_lines = util.trim_empty_lines(markdown_lines) if vim.tbl_isempty(markdown_lines) then - -- return { 'No information available' } + vim.notify('No information available') return end return util.open_floating_preview(markdown_lines, "markdown", config) -- cgit From df09e03cf74337675751c3240069a26aec75fa3b Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Sat, 30 Apr 2022 10:14:31 +0200 Subject: feat(lsp): options to filter and auto-apply code actions (#18221) Implement two new options to vim.lsp.buf.code_action(): - filter (function): predicate taking an Action as input, and returning a boolean. - apply (boolean): when set to true, and there is just one remaining action (after filtering), the action is applied without user query. These options can, for example, be used to filter out, and automatically apply, the action indicated by the server to be preferred: vim.lsp.buf.code_action({ filter = function(action) return action.isPreferred end, apply = true, }) Fix #17514. --- runtime/lua/vim/lsp/buf.lua | 56 ++++++++++++++++++++++++++++------------ runtime/lua/vim/lsp/protocol.lua | 1 + 2 files changed, 41 insertions(+), 16 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index eb7ec579f1..00919c6b04 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -491,11 +491,14 @@ end --- from multiple clients to have 1 single UI prompt for the user, yet we still --- need to be able to link a `CodeAction|Command` to the right client for --- `codeAction/resolve` -local function on_code_action_results(results, ctx) +local function on_code_action_results(results, ctx, options) local action_tuples = {} + local filter = options and options.filter for client_id, result in pairs(results) do for _, action in pairs(result.result or {}) do - table.insert(action_tuples, { client_id, action }) + if not filter or filter(action) then + table.insert(action_tuples, { client_id, action }) + end end end if #action_tuples == 0 then @@ -557,6 +560,13 @@ local function on_code_action_results(results, ctx) end end + -- If options.apply is given, and there are just one remaining code action, + -- apply it directly without querying the user. + if options and options.apply and #action_tuples == 1 then + on_user_choice(action_tuples[1]) + return + end + vim.ui.select(action_tuples, { prompt = 'Code actions:', kind = 'codeaction', @@ -571,35 +581,49 @@ end --- Requests code actions from all clients and calls the handler exactly once --- with all aggregated results ---@private -local function code_action_request(params) +local function code_action_request(params, options) local bufnr = vim.api.nvim_get_current_buf() local method = 'textDocument/codeAction' vim.lsp.buf_request_all(bufnr, method, params, function(results) - on_code_action_results(results, { bufnr = bufnr, method = method, params = params }) + local ctx = { bufnr = bufnr, method = method, params = params} + on_code_action_results(results, ctx, options) end) end --- Selects a code action available at the current --- cursor position. --- ----@param context table|nil `CodeActionContext` of the LSP specification: ---- - diagnostics: (table|nil) ---- LSP `Diagnostic[]`. Inferred from the current ---- position if not provided. ---- - only: (string|nil) ---- LSP `CodeActionKind` used to filter the code actions. ---- Most language servers support values like `refactor` ---- or `quickfix`. +---@param options table|nil Optional table which holds the following optional fields: +--- - context (table|nil): +--- Corresponds to `CodeActionContext` of the LSP specification: +--- - diagnostics (table|nil): +--- LSP `Diagnostic[]`. Inferred from the current +--- position if not provided. +--- - only (string|nil): +--- LSP `CodeActionKind` used to filter the code actions. +--- Most language servers support values like `refactor` +--- or `quickfix`. +--- - filter (function|nil): +--- Predicate function taking an `CodeAction` and returning a boolean. +--- - apply (boolean|nil): +--- When set to `true`, and there is just one remaining action +--- (after filtering), the action is applied without user query. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction -function M.code_action(context) - validate { context = { context, 't', true } } - context = context or {} +function M.code_action(options) + validate { options = { options, 't', true } } + options = options or {} + -- Detect old API call code_action(context) which should now be + -- code_action({ context = context} ) + if options.diagnostics or options.only then + options = { options = options } + end + local context = options.context or {} if not context.diagnostics then context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics() end local params = util.make_range_params() params.context = context - code_action_request(params) + code_action_request(params, options) end --- Performs |vim.lsp.buf.code_action()| for a given range. diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 86c9e2fd58..2cd728ea36 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -645,6 +645,7 @@ function protocol.make_client_capabilities() end)(); }; }; + isPreferredSupport = true; dataSupport = true; resolveSupport = { properties = { 'edit', } -- cgit From c618b314c6a266806edf692122b16ba9ff7a8e10 Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sat, 30 Apr 2022 02:22:30 -0700 Subject: chore(lsp): remove capabilities sanitization (#17814) * feat(lsp)!: remove capabilities sanitization Users must now access client.server_capabilities which matches the same structure as the protocol. https://microsoft.github.io/language-server-protocol/specification client.resolved_capabilities is no longer used to gate capabilities, and will be removed in a future release. BREAKING CHANGE Co-authored-by: Mathias Fussenegger --- runtime/lua/vim/lsp.lua | 96 ++++++++++++++++++++++++---------------- runtime/lua/vim/lsp/buf.lua | 5 +-- runtime/lua/vim/lsp/handlers.lua | 2 +- runtime/lua/vim/lsp/protocol.lua | 46 +++++++++++++++++-- runtime/lua/vim/lsp/rpc.lua | 2 +- 5 files changed, 104 insertions(+), 47 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 7bbe3637db..50fd26957d 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -31,28 +31,28 @@ local lsp = { rpc_response_error = lsp_rpc.rpc_response_error; } --- maps request name to the required resolved_capability in the client. +-- maps request name to the required server_capability in the client. lsp._request_name_to_capability = { - ['textDocument/hover'] = 'hover'; - ['textDocument/signatureHelp'] = 'signature_help'; - ['textDocument/definition'] = 'goto_definition'; - ['textDocument/implementation'] = 'implementation'; - ['textDocument/declaration'] = 'declaration'; - ['textDocument/typeDefinition'] = 'type_definition'; - ['textDocument/documentSymbol'] = 'document_symbol'; - ['textDocument/prepareCallHierarchy'] = 'call_hierarchy'; - ['textDocument/rename'] = 'rename'; - ['textDocument/prepareRename'] = 'rename'; - ['textDocument/codeAction'] = 'code_action'; - ['textDocument/codeLens'] = 'code_lens'; - ['codeLens/resolve'] = 'code_lens_resolve'; - ['workspace/executeCommand'] = 'execute_command'; - ['workspace/symbol'] = 'workspace_symbol'; - ['textDocument/references'] = 'find_references'; - ['textDocument/rangeFormatting'] = 'document_range_formatting'; - ['textDocument/formatting'] = 'document_formatting'; - ['textDocument/completion'] = 'completion'; - ['textDocument/documentHighlight'] = 'document_highlight'; + ['textDocument/hover'] = { 'hoverProvider' }; + ['textDocument/signatureHelp'] = { 'signatureHelpProvider' }; + ['textDocument/definition'] = { 'definitionProvider' }; + ['textDocument/implementation'] = { 'implementationProvider' }; + ['textDocument/declaration'] = { 'declarationProvider' }; + ['textDocument/typeDefinition'] = { 'typeDefinitionProvider' }; + ['textDocument/documentSymbol'] = { 'documentSymbolProvider' }; + ['textDocument/prepareCallHierarchy'] = { 'callHierarchyProvider' }; + ['textDocument/rename'] = { 'renameProvider' }; + ['textDocument/prepareRename'] = { 'renameProvider', 'prepareProvider'} ; + ['textDocument/codeAction'] = { 'codeActionProvider' }; + ['textDocument/codeLens'] = { 'codeLensProvider' }; + ['codeLens/resolve'] = { 'codeLensProvider', 'resolveProvider' }; + ['workspace/executeCommand'] = { 'executeCommandProvider' }; + ['workspace/symbol'] = { 'workspaceSymbolProvider' }; + ['textDocument/references'] = { 'referencesProvider' }; + ['textDocument/rangeFormatting'] = { 'documentRangeFormattingProvider' }; + ['textDocument/formatting'] = { 'documentFormattingProvider' }; + ['textDocument/completion'] = { 'completionProvider' }; + ['textDocument/documentHighlight'] = { 'documentHighlightProvider' }; } -- TODO improve handling of scratch buffers with LSP attached. @@ -328,7 +328,7 @@ do function changetracking.init(client, bufnr) local use_incremental_sync = ( if_nil(client.config.flags.allow_incremental_sync, true) - and client.resolved_capabilities.text_document_did_change == protocol.TextDocumentSyncKind.Incremental + and vim.tbl_get(client.server_capabilities, "textDocumentSync", "change") == protocol.TextDocumentSyncKind.Incremental ) local state = state_by_client[client.id] if not state then @@ -447,7 +447,7 @@ do end) local uri = vim.uri_from_bufnr(bufnr) return function(client) - if client.resolved_capabilities.text_document_did_change == protocol.TextDocumentSyncKind.None then + if vim.tbl_get(client.server_capabilities, "textDocumentSync", "change") == protocol.TextDocumentSyncKind.None then return end local state = state_by_client[client.id] @@ -526,7 +526,7 @@ end ---@param client Client object local function text_document_did_open_handler(bufnr, client) changetracking.init(client, bufnr) - if not client.resolved_capabilities.text_document_open_close then + if not vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then return end if not vim.api.nvim_buf_is_loaded(bufnr) then @@ -632,10 +632,6 @@ end --- --- - {server_capabilities} (table): Response from the server sent on --- `initialize` describing the server's capabilities. ---- ---- - {resolved_capabilities} (table): Normalized table of ---- capabilities that we have detected based on the initialize ---- response from the server in `server_capabilities`. function lsp.client() error() end @@ -884,6 +880,7 @@ function lsp.start_client(config) messages = { name = name, messages = {}, progress = {}, status = {} }; } + -- Store the uninitialized_clients for cleanup in case we exit before initialize finishes. uninitialized_clients[client_id] = client; @@ -960,27 +957,48 @@ function lsp.start_client(config) client.workspace_folders = workspace_folders -- TODO(mjlbach): Backwards compatibility, to be removed in 0.7 client.workspaceFolders = client.workspace_folders - client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities") + -- These are the cleaned up capabilities we use for dynamically deciding -- when to send certain events to clients. - client.resolved_capabilities = protocol.resolve_capabilities(client.server_capabilities) + client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities") + client.server_capabilities = protocol.resolve_capabilities(client.server_capabilities) + + -- Deprecation wrapper: this will be removed in 0.8 + local mt = {} + mt.__index = function(table, key) + if key == 'resolved_capabilities' then + vim.notify_once("[LSP] Accessing client.resolved_capabilities is deprecated, " .. + "update your plugins or configuration to access client.server_capabilities instead." .. + "The new key/value pairs in server_capabilities directly match those " .. + "defined in the language server protocol", vim.log.levels.WARN) + table[key] = protocol._resolve_capabilities_compat(client.server_capabilities) + return table[key] + else + return table[key] + end + end + setmetatable(client, mt) + client.supports_method = function(method) local required_capability = lsp._request_name_to_capability[method] -- if we don't know about the method, assume that the client supports it. if not required_capability then return true end - - return client.resolved_capabilities[required_capability] + if vim.tbl_get(client.server_capabilities, unpack(required_capability)) then + return true + else + return false + end end + if config.on_init then local status, err = pcall(config.on_init, client, result) if not status then pcall(handlers.on_error, lsp.client_errors.ON_INIT_CALLBACK_ERROR, err) end end - local _ = log.debug() and log.debug(log_prefix, "server_capabilities", client.server_capabilities) - local _ = log.info() and log.info(log_prefix, "initialized", { resolved_capabilities = client.resolved_capabilities }) + local _ = log.info() and log.info(log_prefix, "server_capabilities", { server_capabilities = client.server_capabilities }) -- Only assign after initialized. active_clients[client_id] = client @@ -1191,9 +1209,9 @@ function lsp._text_document_did_save_handler(bufnr) local uri = vim.uri_from_bufnr(bufnr) local text = once(buf_get_full_text) for_each_buffer_client(bufnr, function(client, _client_id) - if client.resolved_capabilities.text_document_save then + if vim.tbl_get(client.server_capabilities, "textDocumentSync", "save") then local included_text - if client.resolved_capabilities.text_document_save_include_text then + if vim.tbl_get(client.server_capabilities, "textDocumentSync", "save", "includeText") then included_text = text(bufnr) end client.notify('textDocument/didSave', { @@ -1246,7 +1264,7 @@ function lsp.buf_attach_client(bufnr, client_id) local params = { textDocument = { uri = uri; } } for_each_buffer_client(bufnr, function(client, _) changetracking.reset_buf(client, bufnr) - if client.resolved_capabilities.text_document_open_close then + if vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then client.notify('textDocument/didClose', params) end text_document_did_open_handler(bufnr, client) @@ -1256,7 +1274,7 @@ function lsp.buf_attach_client(bufnr, client_id) local params = { textDocument = { uri = uri; } } for_each_buffer_client(bufnr, function(client, _) changetracking.reset_buf(client, bufnr) - if client.resolved_capabilities.text_document_open_close then + if vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then client.notify('textDocument/didClose', params) end end) @@ -1306,7 +1324,7 @@ function lsp.buf_detach_client(bufnr, client_id) changetracking.reset_buf(client, bufnr) - if client.resolved_capabilities.text_document_open_close then + if vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then local uri = vim.uri_from_bufnr(bufnr) local params = { textDocument = { uri = uri; } } client.notify('textDocument/didClose', params) diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 00919c6b04..62de8d7321 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -224,7 +224,7 @@ function M.formatting_seq_sync(options, timeout_ms, order) -- loop through the clients and make synchronous formatting requests for _, client in pairs(clients) do - if client.resolved_capabilities.document_formatting then + if vim.tbl_get(client.server_capabilities, "documentFormattingProvider") then local params = util.make_formatting_params(options) local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) if result and result.result then @@ -545,8 +545,7 @@ local function on_code_action_results(results, ctx, options) local action = action_tuple[2] if not action.edit and client - and type(client.resolved_capabilities.code_action) == 'table' - and client.resolved_capabilities.code_action.resolveProvider then + and vim.tbl_get(client.server_capabilities, "codeActionProvider", "resolveProvider") then client.request('codeAction/resolve', action, function(err, resolved_action) if err then diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 978e44b6f8..dbe985700e 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -379,7 +379,7 @@ function M.signature_help(_, result, ctx, config) return end local client = vim.lsp.get_client_by_id(ctx.client_id) - local triggers = client.resolved_capabilities.signature_help_trigger_characters + local triggers = vim.tbl_get(client.server_capabilities, "signatureHelpProvider", "triggerCharacters") local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype') local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers) lines = util.trim_empty_lines(lines) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 2cd728ea36..8f50863360 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -1,7 +1,5 @@ -- Protocol for the Microsoft Language Server Protocol (mslsp) -local if_nil = vim.F.if_nil - local protocol = {} --[=[ @@ -777,10 +775,50 @@ function protocol.make_client_capabilities() } end +local if_nil = vim.F.if_nil --- Creates a normalized object describing LSP server capabilities. ---@param server_capabilities table Table of capabilities supported by the server ---@return table Normalized table of capabilities function protocol.resolve_capabilities(server_capabilities) + local TextDocumentSyncKind = protocol.TextDocumentSyncKind + local textDocumentSync = server_capabilities.textDocumentSync + if textDocumentSync == nil then + -- Defaults if omitted. + server_capabilities.textDocumentSync = { + openClose = false, + change = TextDocumentSyncKind.None, + willSave = false, + willSaveWaitUntil = false, + save = { + includeText = false, + } + } + elseif type(textDocumentSync) == 'number' then + -- Backwards compatibility + if not TextDocumentSyncKind[textDocumentSync] then + return nil, "Invalid server TextDocumentSyncKind for textDocumentSync" + end + server_capabilities.textDocumentSync = { + openClose = true, + change = textDocumentSync, + willSave = false, + willSaveWaitUntil = false, + save = { + includeText = false, + } + } + elseif type(textDocumentSync) ~= 'table' then + return nil, string.format("Invalid type for textDocumentSync: %q", type(textDocumentSync)) + end + return server_capabilities +end + +---@private +--- Creates a normalized object describing LSP server capabilities. +-- @deprecated access resolved_capabilities instead +---@param server_capabilities table Table of capabilities supported by the server +---@return table Normalized table of capabilities +function protocol._resolve_capabilities_compat(server_capabilities) local general_properties = {} local text_document_sync_properties do @@ -931,12 +969,14 @@ function protocol.resolve_capabilities(server_capabilities) error("The server sent invalid signatureHelpProvider") end - return vim.tbl_extend("error" + local capabilities = vim.tbl_extend("error" , text_document_sync_properties , signature_help_properties , workspace_properties , general_properties ) + + return capabilities end return protocol diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 1ecac50df4..6d0a78fba8 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -385,7 +385,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) ---@param method (string) The invoked LSP method ---@param params (table) Parameters for the invoked LSP method ---@param callback (function) Callback to invoke - ---@param notify_reply_callback (function) Callback to invoke as soon as a request is no longer pending + ---@param notify_reply_callback (function|nil) Callback to invoke as soon as a request is no longer pending ---@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not local function request(method, params, callback, notify_reply_callback) validate { -- cgit From eecc6535eb5d0a6b9465489e69cbde1cbb8276e6 Mon Sep 17 00:00:00 2001 From: kylo252 <59826753+kylo252@users.noreply.github.com> Date: Sat, 30 Apr 2022 13:55:26 +0200 Subject: fix(handlers): more specific error messages (#16772) Specify which message, or request, was last received in case of an error instead of the same generic message --- runtime/lua/vim/lsp/handlers.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index dbe985700e..5c80ed0d10 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -27,7 +27,7 @@ local function progress_handler(_, result, ctx, _) local client = vim.lsp.get_client_by_id(client_id) local client_name = client and client.name or string.format("id=%d", client_id) if not client then - err_message("LSP[", client_name, "] client has shut down after sending the message") + err_message("LSP[", client_name, "] client has shut down during progress update") return vim.NIL end local val = result.value -- unspecified yet @@ -70,7 +70,7 @@ M['window/workDoneProgress/create'] = function(_, result, ctx) local token = result.token -- string or number local client_name = client and client.name or string.format("id=%d", client_id) if not client then - err_message("LSP[", client_name, "] client has shut down after sending the message") + err_message("LSP[", client_name, "] client has shut down while creating progress report") return vim.NIL end client.messages.progress[token] = {} @@ -132,7 +132,7 @@ M['workspace/configuration'] = function(_, result, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) if not client then - err_message("LSP[id=", client_id, "] client has shut down after sending the message") + err_message("LSP[", client_id, "] client has shut down after sending a workspace/configuration request") return end if not result.items then @@ -449,7 +449,7 @@ M['window/logMessage'] = function(_, result, ctx, _) local client = vim.lsp.get_client_by_id(client_id) local client_name = client and client.name or string.format("id=%d", client_id) if not client then - err_message("LSP[", client_name, "] client has shut down after sending the message") + err_message("LSP[", client_name, "] client has shut down after sending ", message) end if message_type == protocol.MessageType.Error then log.error(message) @@ -471,7 +471,7 @@ M['window/showMessage'] = function(_, result, ctx, _) local client = vim.lsp.get_client_by_id(client_id) local client_name = client and client.name or string.format("id=%d", client_id) if not client then - err_message("LSP[", client_name, "] client has shut down after sending the message") + err_message("LSP[", client_name, "] client has shut down after sending ", message) end if message_type == protocol.MessageType.Error then err_message("LSP[", client_name, "] ", message) -- cgit From 5b04e46d23b65413d934d812d61d8720b815eb1c Mon Sep 17 00:00:00 2001 From: Michael Lingelbach Date: Sat, 30 Apr 2022 06:36:40 -0700 Subject: feat(lsp): add vim.lsp.buf.format (#18193) --- runtime/lua/vim/lsp/buf.lua | 88 +++++++++++++++++++++++++++++++++++++++++--- runtime/lua/vim/lsp/util.lua | 4 +- 2 files changed, 85 insertions(+), 7 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 62de8d7321..59682e8a0a 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -143,9 +143,85 @@ local function select_client(method, on_choice) end end +--- Formats a buffer using the attached (and optionally filtered) language +--- server clients. +--- +--- @param options table|nil Optional table which holds the following optional fields: +--- - formatting_options (table|nil): +--- Can be used to specify FormattingOptions. Some unspecified options will be +--- automatically derived from the current Neovim options. +--- @see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting +--- - timeout_ms (integer|nil, default 1000): +--- Time in milliseconds to block for formatting requests. Formatting requests are current +--- synchronous to prevent editing of the buffer. +--- - bufnr (number|nil): +--- Restrict formatting to the clients attached to the given buffer, defaults to the current +--- buffer (0). +--- - filter (function|nil): +--- Predicate to filter clients used for formatting. Receives the list of clients attached +--- to bufnr as the argument and must return the list of clients on which to request +--- formatting. Example: +--- +---
+---         -- Never request typescript-language-server for formatting
+---         vim.lsp.buf.format {
+---           filter = function(clients)
+---             return vim.tbl_filter(
+---               function(client) return client.name ~= "tsserver" end,
+---               clients
+---             )
+---           end
+---         }
+---         
+--- +--- - id (number|nil): +--- Restrict formatting to the client with ID (client.id) matching this field. +--- - name (string|nil): +--- Restrict formatting to the client with name (client.name) matching this field. + +function M.format(options) + options = options or {} + local bufnr = options.bufnr or vim.api.nvim_get_current_buf() + local clients = vim.lsp.buf_get_clients(bufnr) + + if options.filter then + clients = options.filter(clients) + elseif options.id then + clients = vim.tbl_filter( + function(client) return client.id == options.id end, + clients + ) + elseif options.name then + clients = vim.tbl_filter( + function(client) return client.name == options.name end, + clients + ) + end + + clients = vim.tbl_filter( + function(client) return client.supports_method("textDocument/formatting") end, + clients + ) + + if #clients == 0 then + vim.notify("[LSP] Format request failed, no matching language servers.") + end + + local timeout_ms = options.timeout_ms or 1000 + for _, client in pairs(clients) do + local params = util.make_formatting_params(options.formatting_options) + local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) + if result and result.result then + util.apply_text_edits(result.result, bufnr, client.offset_encoding) + elseif err then + vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + end + end +end + --- Formats the current buffer. --- ----@param options (optional, table) Can be used to specify FormattingOptions. +---@param options (table|nil) Can be used to specify FormattingOptions. --- Some unspecified options will be automatically derived from the current --- Neovim options. -- @@ -171,10 +247,11 @@ end --- autocmd BufWritePre lua vim.lsp.buf.formatting_sync() --- --- ----@param options Table with valid `FormattingOptions` entries +---@param options table|nil with valid `FormattingOptions` entries ---@param timeout_ms (number) Request timeout ---@see |vim.lsp.buf.formatting_seq_sync| function M.formatting_sync(options, timeout_ms) + vim.notify_once('vim.lsp.buf.formatting_sync is deprecated. Use vim.lsp.buf.format instead', vim.log.levels.WARN) local params = util.make_formatting_params(options) local bufnr = vim.api.nvim_get_current_buf() select_client('textDocument/formatting', function(client) @@ -202,12 +279,13 @@ end --- vim.api.nvim_command[[autocmd BufWritePre lua vim.lsp.buf.formatting_seq_sync()]] --- --- ----@param options (optional, table) `FormattingOptions` entries ----@param timeout_ms (optional, number) Request timeout ----@param order (optional, table) List of client names. Formatting is requested from clients +---@param options (table|nil) `FormattingOptions` entries +---@param timeout_ms (number|nil) Request timeout +---@param order (table|nil) List of client names. Formatting is requested from clients ---in the following order: first all clients that are not in the `order` list, then ---the remaining clients in the order as they occur in the `order` list. function M.formatting_seq_sync(options, timeout_ms, order) + vim.notify_once('vim.lsp.buf.formatting_seq_sync is deprecated. Use vim.lsp.buf.format instead', vim.log.levels.WARN) local clients = vim.tbl_values(vim.lsp.buf_get_clients()); local bufnr = vim.api.nvim_get_current_buf() diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 1f1a34b04a..77ab1d4224 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1873,7 +1873,7 @@ end --- Returns indentation size. --- ---@see |shiftwidth| ----@param bufnr (optional, number): Buffer handle, defaults to current +---@param bufnr (number|nil): Buffer handle, defaults to current ---@returns (number) indentation size function M.get_effective_tabstop(bufnr) validate { bufnr = {bufnr, 'n', true} } @@ -1884,7 +1884,7 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ----@param options Table with valid `FormattingOptions` entries +---@param options table|nil with valid `FormattingOptions` entries ---@returns `DocumentFormattingParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) -- cgit From 88411613e23bd829088f48983f0253f1b7e5c3fd Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 30 Apr 2022 17:23:50 +0200 Subject: feat(lsp): add async option to vim.lsp.buf.format (#18322) Deprecates the existing `vim.lsp.buf.formatting` function. With this, `vim.lsp.buf.format` will replace all three: - vim.lsp.buf.formatting - vim.lsp.buf.formatting_sync - vim.lsp.buf.formatting_seq_sync --- runtime/lua/vim/lsp/buf.lua | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 59682e8a0a..aabafc422f 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -152,8 +152,7 @@ end --- automatically derived from the current Neovim options. --- @see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting --- - timeout_ms (integer|nil, default 1000): ---- Time in milliseconds to block for formatting requests. Formatting requests are current ---- synchronous to prevent editing of the buffer. +--- Time in milliseconds to block for formatting requests. No effect if async=true --- - bufnr (number|nil): --- Restrict formatting to the clients attached to the given buffer, defaults to the current --- buffer (0). @@ -174,6 +173,11 @@ end --- } --- --- +--- - async boolean|nil +--- If true the method won't block. Defaults to false. +--- Editing the buffer while formatting asynchronous can lead to unexpected +--- changes. +--- --- - id (number|nil): --- Restrict formatting to the client with ID (client.id) matching this field. --- - name (string|nil): @@ -207,14 +211,30 @@ function M.format(options) vim.notify("[LSP] Format request failed, no matching language servers.") end - local timeout_ms = options.timeout_ms or 1000 - for _, client in pairs(clients) do - local params = util.make_formatting_params(options.formatting_options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) - if result and result.result then - util.apply_text_edits(result.result, bufnr, client.offset_encoding) - elseif err then - vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + if options.async then + local do_format + do_format = function(idx, client) + if not client then + return + end + local params = util.make_formatting_params(options.formatting_options) + client.request("textDocument/formatting", params, function(...) + local handler = client.handlers['textDocument/formatting'] or vim.lsp.handlers['textDocument/formatting'] + handler(...) + do_format(next(clients, idx)) + end, bufnr) + end + do_format(next(clients)) + else + local timeout_ms = options.timeout_ms or 1000 + for _, client in pairs(clients) do + local params = util.make_formatting_params(options.formatting_options) + local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) + if result and result.result then + util.apply_text_edits(result.result, bufnr, client.offset_encoding) + elseif err then + vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + end end end end @@ -227,6 +247,10 @@ end -- ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting function M.formatting(options) + vim.notify_once( + 'vim.lsp.buf.formatting is deprecated. Use vim.lsp.buf.format { async = true } instead', + vim.log.levels.WARN + ) local params = util.make_formatting_params(options) local bufnr = vim.api.nvim_get_current_buf() select_client('textDocument/formatting', function(client) -- cgit From 872622bcdbe3e971973c374392221589815d497a Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 30 Apr 2022 17:31:53 +0200 Subject: vim-patch:8.2.4849: Gleam filetype not detected (#18326) Problem: Gleam filetype not detected. Solution: Add a pattern for Gleam files. (Mathias Jean Johansen, closes vim/vim#10326) https://github.com/vim/vim/commit/917c32c4f75351061a773cd5bc5b6f42c7d10e62 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 1297ef6241..2a34fec7f2 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -241,6 +241,7 @@ local extension = { gmi = "gemtext", gemini = "gemtext", gift = "gift", + gleam = "gleam", glsl = "glsl", gpi = "gnuplot", gnuplot = "gnuplot", -- cgit From 0344736aa698dc205f8f9f80609b7033308d39ca Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sat, 30 Apr 2022 22:13:26 +0200 Subject: fix(lsp): handle textDocumentSync.save bool capability (#18332) Follow up to https://github.com/neovim/neovim/pull/17814 --- runtime/lua/vim/lsp.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 50fd26957d..5c35d3916f 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1208,10 +1208,11 @@ function lsp._text_document_did_save_handler(bufnr) bufnr = resolve_bufnr(bufnr) local uri = vim.uri_from_bufnr(bufnr) local text = once(buf_get_full_text) - for_each_buffer_client(bufnr, function(client, _client_id) - if vim.tbl_get(client.server_capabilities, "textDocumentSync", "save") then + for_each_buffer_client(bufnr, function(client) + local save_capability = vim.tbl_get(client.server_capabilities, "textDocumentSync", "save") + if save_capability then local included_text - if vim.tbl_get(client.server_capabilities, "textDocumentSync", "save", "includeText") then + if type(save_capability) == "table" and save_capability.includeText then included_text = text(bufnr) end client.notify('textDocument/didSave', { -- cgit From 039d60bd9c4468bb53958943196390673569bd7b Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Sat, 30 Apr 2022 23:22:47 +0200 Subject: fix(lsp): fix infinite loop in resolved_capabilities deprecation message (#18333) Co-authored-by: ii14 --- runtime/lua/vim/lsp.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 5c35d3916f..19ee75a1b6 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -971,10 +971,10 @@ function lsp.start_client(config) "update your plugins or configuration to access client.server_capabilities instead." .. "The new key/value pairs in server_capabilities directly match those " .. "defined in the language server protocol", vim.log.levels.WARN) - table[key] = protocol._resolve_capabilities_compat(client.server_capabilities) - return table[key] + rawset(table, key, protocol._resolve_capabilities_compat(client.server_capabilities)) + return rawget(table, key) else - return table[key] + return rawget(table, key) end end setmetatable(client, mt) -- cgit From 069da468d5d2af01279a121473aef09c87b163aa Mon Sep 17 00:00:00 2001 From: William Boman Date: Sun, 1 May 2022 21:08:05 +0200 Subject: fix(shared): avoid indexing unindexable values in vim.tbl_get() (#18337) --- runtime/lua/vim/shared.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index f0dc34608c..172fac3a88 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -365,7 +365,10 @@ function vim.tbl_get(o, ...) if #keys == 0 then return end - for _, k in ipairs(keys) do + for i, k in ipairs(keys) do + if type(o[k]) ~= 'table' and next(keys, i) then + return nil + end o = o[k] if o == nil then return -- cgit From d23ce6ef76db28f50f2107d0b60860992c2842f9 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 2 May 2022 13:54:07 +0200 Subject: vim-patch:8.2.4855: robot files are not recognized (#18364) Problem: Robot files are not recognized. Solution: Add patterns for robot files. (Zoe Roux, closes vim/vim#10339) https://github.com/vim/vim/commit/2096a5f128029b1156a035a27c988995db240cea --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2a34fec7f2..f401de38f4 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -561,6 +561,8 @@ local extension = { snw = "rnoweb", Rnw = "rnoweb", Snw = "rnoweb", + robot = "robot", + resource = "robot", rsc = "routeros", x = "rpcgen", rpl = "rpl", -- cgit From 88595fbb212c0b770ed6aa08b09561af608c73e0 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Mon, 2 May 2022 00:15:16 -0400 Subject: fix(filetype.lua): escape expansion of ~ when used as a pattern --- runtime/lua/vim/filetype.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2a34fec7f2..279fcf92a4 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1480,8 +1480,18 @@ end local pattern_sorted = sort_by_priority(pattern) ---@private -local function normalize_path(path) - return (path:gsub("\\", "/"):gsub("^~", vim.env.HOME)) +local function normalize_path(path, as_pattern) + local normal = path:gsub("\\", '/') + if normal:find('^~') then + if as_pattern then + -- Escape Lua's metacharacters when $HOME is used in a pattern. + -- The rest of path should already be properly escaped. + normal = vim.env.HOME:gsub('[-^$()%%.%[%]+?]', '%%%0') .. normal:sub(2) + else + normal = vim.env.HOME .. normal:sub(2) + end + end + return normal end --- Add new filetype mappings. @@ -1550,7 +1560,7 @@ function M.add(filetypes) end for k, v in pairs(filetypes.pattern or {}) do - pattern[normalize_path(k)] = v + pattern[normalize_path(k, true)] = v end if filetypes.pattern then -- cgit From 46734cf7c1e5abe8e452354db6914364bfe89f0d Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 3 May 2022 10:23:11 +0200 Subject: vim-patch:8.2.4859: wget2 files are not recognized (#18385) Problem: wget2 files are not recognized. Solution: Add patterns to recognize wget2. (Doug Kearns) https://github.com/vim/vim/commit/3a974a89331182139e12386275f052a50c247ecb --- runtime/lua/vim/filetype.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 7679ed555f..911950171f 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1130,7 +1130,9 @@ local filename = { ["_viminfo"] = "viminfo", [".viminfo"] = "viminfo", [".wgetrc"] = "wget", + [".wget2rc"] = "wget2", wgetrc = "wget", + wget2rc = "wget2", [".wvdialrc"] = "wvdial", ["wvdial.conf"] = "wvdial", [".Xresources"] = "xdefaults", -- cgit From b5c15ba7e5266bdd742a835d82525d4625980d4d Mon Sep 17 00:00:00 2001 From: Jose Alvarez Date: Tue, 3 May 2022 08:54:49 -0400 Subject: fix(lsp): add missing bufnr argument (#18382) --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 77ab1d4224..72dfb3cd76 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -456,7 +456,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Remove final line if needed local fix_eol = has_eol_text_edit - fix_eol = fix_eol and (api.nvim_buf_get_option(bufnr, 'eol') or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option('binary'))) + fix_eol = fix_eol and (api.nvim_buf_get_option(bufnr, 'eol') or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option(bufnr, 'binary'))) fix_eol = fix_eol and get_line(bufnr, max - 1) == '' if fix_eol then vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {}) -- cgit From 73741e94867a8dedabcbd356e1e929f198c51905 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Tue, 3 May 2022 15:42:41 +0200 Subject: feat(lua): vim.deprecate() #18320 This is primarily intended to act as documentation for the developer so they know exactly when and what to remove. This will help prevent the situation of deprecated code lingering for far too long as developers don't have to worry if a function is safe to remove. --- runtime/lua/vim/_editor.lua | 16 +++++++++++++++ runtime/lua/vim/lsp/diagnostic.lua | 42 +++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 21 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 8e372b806c..62a7b3df13 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -735,6 +735,22 @@ function vim._cs_remote(rcid, server_addr, connect_error, args) } end +--- Display a deprecation notification to the user. +--- +---@param name string Deprecated function. +---@param alternative string|nil Preferred alternative function. +---@param version string Version in which the deprecated function will +--- be removed. +---@param plugin string|nil Plugin name that the function will be removed +--- from. Defaults to "Nvim". +function vim.deprecate(name, alternative, version, plugin) + local message = name .. ' is deprecated' + plugin = plugin or "Nvim" + message = alternative and (message .. ', use ' .. alternative .. ' instead.') or message + message = message .. ' See :h deprecated\nThis function will be removed in ' .. plugin .. ' version ' .. version + vim.notify_once(message, vim.log.levels.WARN) +end + require('vim._meta') return vim diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 6a8d6dcad7..28a236cc7e 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -251,7 +251,7 @@ end ---@param client_id number ---@private function M.save(diagnostics, bufnr, client_id) - vim.notify_once('vim.lsp.diagnostic.save is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.save', 'vim.diagnostic.set', '0.8' ) local namespace = M.get_namespace(client_id) vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) end @@ -265,7 +265,7 @@ end --- If nil, diagnostics of all clients are included. ---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[]) function M.get_all(client_id) - vim.notify_once('vim.lsp.diagnostic.get_all is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_all', 'vim.diagnostic.get', '0.8' ) local result = {} local namespace if client_id then @@ -287,7 +287,7 @@ end --- Else, return just the diagnostics associated with the client_id. ---@param predicate function|nil Optional function for filtering diagnostics function M.get(bufnr, client_id, predicate) - vim.notify_once('vim.lsp.diagnostic.get is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get', 'vim.diagnostic.get', '0.8' ) predicate = predicate or function() return true end if client_id == nil then local all_diagnostics = {} @@ -349,7 +349,7 @@ end ---@param severity DiagnosticSeverity ---@param client_id number the client id function M.get_count(bufnr, severity, client_id) - vim.notify_once('vim.lsp.diagnostic.get_count is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_count', 'vim.diagnostic.get', '0.8' ) severity = severity_lsp_to_vim(severity) local opts = { severity = severity } if client_id ~= nil then @@ -366,7 +366,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic function M.get_prev(opts) - vim.notify_once('vim.lsp.diagnostic.get_prev is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_prev', 'vim.diagnostic.get_prev', '0.8' ) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -384,7 +384,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic position function M.get_prev_pos(opts) - vim.notify_once('vim.lsp.diagnostic.get_prev_pos is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_prev_pos', 'vim.diagnostic.get_prev_pos', '0.8' ) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -401,7 +401,7 @@ end --- ---@param opts table See |vim.lsp.diagnostic.goto_next()| function M.goto_prev(opts) - vim.notify_once('vim.lsp.diagnostic.goto_prev is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.goto_prev', 'vim.diagnostic.goto_prev', '0.8' ) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -419,7 +419,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic function M.get_next(opts) - vim.notify_once('vim.lsp.diagnostic.get_next is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_next', 'vim.diagnostic.get_next', '0.8' ) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -437,7 +437,7 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic position function M.get_next_pos(opts) - vim.notify_once('vim.lsp.diagnostic.get_next_pos is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_next_pos', 'vim.diagnostic.get_next_pos', '0.8' ) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -452,7 +452,7 @@ end --- ---@deprecated Prefer |vim.diagnostic.goto_next()| function M.goto_next(opts) - vim.notify_once('vim.lsp.diagnostic.goto_next is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.goto_next', 'vim.diagnostic.goto_next', '0.8' ) if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -476,7 +476,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_signs(diagnostics, bufnr, client_id, _, opts) - vim.notify_once('vim.lsp.diagnostic.set_signs is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.set_signs', nil , '0.8' ) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -497,7 +497,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_underline(diagnostics, bufnr, client_id, _, opts) - vim.notify_once('vim.lsp.diagnostic.set_underline is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.set_underline', nil , '0.8' ) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -519,7 +519,7 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts) - vim.notify_once('vim.lsp.diagnostic.set_virtual_text is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.set_virtual_text', nil , '0.8' ) local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} @@ -538,7 +538,7 @@ end ---@return an array of [text, hl_group] arrays. This can be passed directly to --- the {virt_text} option of |nvim_buf_set_extmark()|. function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts) - vim.notify_once('vim.lsp.diagnostic.get_virtual_text_chunks_for_line is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.get_virtual_text_chunks_for_line', nil, '0.8' ) return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts) end @@ -556,7 +556,7 @@ end ---@param position table|nil The (0,0)-indexed position ---@return table {popup_bufnr, win_id} function M.show_position_diagnostics(opts, buf_nr, position) - vim.notify_once('vim.lsp.diagnostic.show_position_diagnostics is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.show_position_diagnostics', 'vim.diagnostic.open_float', '0.8' ) opts = opts or {} opts.scope = "cursor" opts.pos = position @@ -580,7 +580,7 @@ end ---@param client_id number|nil the client id ---@return table {popup_bufnr, win_id} function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id) - vim.notify_once('vim.lsp.diagnostic.show_line_diagnostics is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.show_line_diagnostics', 'vim.diagnostic.open_float', '0.8' ) opts = opts or {} opts.scope = "line" opts.pos = line_nr @@ -604,7 +604,7 @@ end --- client. The default is to redraw diagnostics for all attached --- clients. function M.redraw(bufnr, client_id) - vim.notify_once('vim.lsp.diagnostic.redraw is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.redraw', 'vim.diagnostic.show', '0.8' ) bufnr = get_bufnr(bufnr) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) @@ -632,7 +632,7 @@ end --- - {workspace}: (boolean, default true) --- - Set the list with workspace diagnostics function M.set_qflist(opts) - vim.notify_once('vim.lsp.diagnostic.set_qflist is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.set_qflist', 'vim.diagnostic.setqflist', '0.8' ) opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -664,7 +664,7 @@ end --- - {workspace}: (boolean, default false) --- - Set the list with workspace diagnostics function M.set_loclist(opts) - vim.notify_once('vim.lsp.diagnostic.set_loclist is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.set_loclist', 'vim.diagnostic.setloclist', '0.8' ) opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) @@ -692,7 +692,7 @@ end -- send diagnostic information and the client will still process it. The -- diagnostics are simply not displayed to the user. function M.disable(bufnr, client_id) - vim.notify_once('vim.lsp.diagnostic.disable is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.disable', 'vim.diagnostic.disable', '0.8' ) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.disable(bufnr, client.id) @@ -713,7 +713,7 @@ end --- client. The default is to enable diagnostics for all attached --- clients. function M.enable(bufnr, client_id) - vim.notify_once('vim.lsp.diagnostic.enable is deprecated. See :h deprecated', vim.log.levels.WARN) + vim.deprecate('vim.lsp.diagnostic.enable', 'vim.diagnostic.enable', '0.8' ) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.enable(bufnr, client.id) -- cgit From 70e2c5d10d2574b77c56d0bebeb61527876ff0b1 Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Tue, 3 May 2022 16:49:23 +0200 Subject: feat(lsp): add logging level "OFF" (#18379) --- runtime/lua/vim/_editor.lua | 1 + runtime/lua/vim/lsp.lua | 5 +-- runtime/lua/vim/lsp/log.lua | 81 +++++++++++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 31 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 62a7b3df13..119467de16 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -58,6 +58,7 @@ vim.log = { INFO = 2; WARN = 3; ERROR = 4; + OFF = 5; } } diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 19ee75a1b6..00f1c26692 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1790,13 +1790,14 @@ end -- -- Can be used to lookup the number from the name or the -- name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" -- Level numbers begin with "TRACE" at 0 lsp.log_levels = log.levels --- Sets the global log level for LSP logging. --- ---- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +--- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" +--- --- Level numbers begin with "TRACE" at 0 --- --- Use `lsp.log_levels` for reverse lookup. diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index e0b5653587..fff42fd011 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -8,7 +8,7 @@ local log = {} -- Log level dictionary with reverse lookup as well. -- -- Can be used to lookup the number from the name or the name from the number. --- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR" +-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "OFF" -- Level numbers begin with "TRACE" at 0 log.levels = vim.deepcopy(vim.log.levels) @@ -25,27 +25,47 @@ do end local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') + -- TODO: Ideally the directory should be created in open_logfile(), right + -- before opening the log file, but open_logfile() can be called from libuv + -- callbacks, where using fn.mkdir() is not allowed. + vim.fn.mkdir(vim.fn.stdpath('cache'), "p") + --- Returns the log filename. ---@returns (string) log filename function log.get_filename() return logfilename end - vim.fn.mkdir(vim.fn.stdpath('cache'), "p") - local logfile = assert(io.open(logfilename, "a+")) - - local log_info = vim.loop.fs_stat(logfilename) - if log_info and log_info.size > 1e9 then - local warn_msg = string.format( - "LSP client log is large (%d MB): %s", - log_info.size / (1000 * 1000), - logfilename - ) - vim.notify(warn_msg) + local logfile, openerr + ---@private + --- Opens log file. Returns true if file is open, false on error + local function open_logfile() + -- Try to open file only once + if logfile then return true end + if openerr then return false end + + logfile, openerr = io.open(logfilename, "a+") + if not logfile then + local err_msg = string.format("Failed to open LSP client log file: %s", openerr) + vim.notify(err_msg, vim.log.levels.ERROR) + return false + end + + local log_info = vim.loop.fs_stat(logfilename) + if log_info and log_info.size > 1e9 then + local warn_msg = string.format( + "LSP client log is large (%d MB): %s", + log_info.size / (1000 * 1000), + logfilename + ) + vim.notify(warn_msg) + end + + -- Start message for logging + logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format))) + return true end - -- Start message for logging - logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format))) for level, levelnr in pairs(log.levels) do -- Also export the log level on the root object. log[level] = levelnr @@ -63,23 +83,26 @@ do -- ``` -- -- This way you can avoid string allocations if the log level isn't high enough. - log[level:lower()] = function(...) - local argc = select("#", ...) - if levelnr < current_log_level then return false end - if argc == 0 then return true end - local info = debug.getinfo(2, "Sl") - local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) - local parts = { header } - for i = 1, argc do - local arg = select(i, ...) - if arg == nil then - table.insert(parts, "nil") - else - table.insert(parts, format_func(arg)) + if level ~= "OFF" then + log[level:lower()] = function(...) + local argc = select("#", ...) + if levelnr < current_log_level then return false end + if argc == 0 then return true end + if not open_logfile() then return false end + local info = debug.getinfo(2, "Sl") + local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) + local parts = { header } + for i = 1, argc do + local arg = select(i, ...) + if arg == nil then + table.insert(parts, "nil") + else + table.insert(parts, format_func(arg)) + end end + logfile:write(table.concat(parts, '\t'), "\n") + logfile:flush() end - logfile:write(table.concat(parts, '\t'), "\n") - logfile:flush() end end end -- cgit From 8ef03188e68cc81bcb6a630a20451090c9557a98 Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Tue, 3 May 2022 20:29:04 +0200 Subject: refactor(runtime): convert dist#ft functions to lua (#18247) Co-authored-by: Christian Clason --- runtime/lua/vim/filetype.lua | 84 ++++---- runtime/lua/vim/filetype/detect.lua | 413 ++++++++++++++++++++++++++++++++++++ 2 files changed, 455 insertions(+), 42 deletions(-) create mode 100644 runtime/lua/vim/filetype/detect.lua (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 911950171f..77ebb64b1d 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -784,19 +784,19 @@ local extension = { zsh = "zsh", vala = "vala", E = function() vim.fn["dist#ft#FTe"]() end, - EU = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - EW = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - EX = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - EXU = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - EXW = function() vim.fn["dist#ft#EuphoriaCheck"]() end, + EU = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + EW = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + EX = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + EXU = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + EXW = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, PL = function() vim.fn["dist#ft#FTpl"]() end, - R = function() vim.fn["dist#ft#FTr"]() end, + R = function(path, bufnr) require("vim.filetype.detect").r(bufnr) end, asm = function() vim.fn["dist#ft#FTasm"]() end, bas = function() vim.fn["dist#ft#FTbas"]() end, bi = function() vim.fn["dist#ft#FTbas"]() end, bm = function() vim.fn["dist#ft#FTbas"]() end, bash = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - btm = function() vim.fn["dist#ft#FTbtm"]() end, + btm = function(path, bufnr) return require("vim.filetype.detect").btm(bufnr) end, c = function() vim.fn["dist#ft#FTlpc"]() end, ch = function() vim.fn["dist#ft#FTchange"]() end, com = function() vim.fn["dist#ft#BindzoneCheck"]('dcl') end, @@ -808,29 +808,29 @@ local extension = { e = function() vim.fn["dist#ft#FTe"]() end, ebuild = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, eclass = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ent = function() vim.fn["dist#ft#FTent"]() end, + ent = function(path, bufnr) return require("vim.filetype.detect").ent(bufnr) end, env = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - eu = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - ew = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - ex = function() vim.fn["dist#ft#ExCheck"]() end, - exu = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - exw = function() vim.fn["dist#ft#EuphoriaCheck"]() end, - frm = function() vim.fn["dist#ft#FTfrm"]() end, + eu = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + ew = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + ex = function(path, bufnr) return require("vim.filetype.detect").ex(bufnr) end, + exu = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + exw = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, + frm = function(path, bufnr) require("vim.filetype.detect").frm(bufnr) end, fs = function() vim.fn["dist#ft#FTfs"]() end, - h = function() vim.fn["dist#ft#FTheader"]() end, + h = function(path, bufnr) require("vim.filetype.detect").header(bufnr) end, htm = function() vim.fn["dist#ft#FThtml"]() end, html = function() vim.fn["dist#ft#FThtml"]() end, i = function() vim.fn["dist#ft#FTprogress_asm"]() end, - idl = function() vim.fn["dist#ft#FTidl"]() end, + idl = function(path, bufnr) require("vim.filetype.detect").idl(bufnr) end, inc = function() vim.fn["dist#ft#FTinc"]() end, - inp = function() vim.fn["dist#ft#Check_inp"]() end, + inp = function(path, bufnr) require("vim.filetype.detect").inp(bufnr) end, ksh = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end, lst = function() vim.fn["dist#ft#FTasm"]() end, m = function() vim.fn["dist#ft#FTm"]() end, mac = function() vim.fn["dist#ft#FTasm"]() end, - mc = function() vim.fn["dist#ft#McSetf"]() end, + mc = function(path, bufnr) require("vim.filetype.detect").mc(bufnr) end, mm = function() vim.fn["dist#ft#FTmm"]() end, - mms = function() vim.fn["dist#ft#FTmms"]() end, + mms = function(path, bufnr) require("vim.filetype.detect").mms(bufnr) end, p = function() vim.fn["dist#ft#FTprogress_pascal"]() end, patch = function(path, bufnr) local firstline = getline(bufnr, 1) @@ -844,22 +844,22 @@ local extension = { pp = function() vim.fn["dist#ft#FTpp"]() end, pro = function() vim.fn["dist#ft#ProtoCheck"]('idlang') end, pt = function() vim.fn["dist#ft#FThtml"]() end, - r = function() vim.fn["dist#ft#FTr"]() end, - rdf = function() vim.fn["dist#ft#Redif"]() end, + r = function(path, bufnr) require("vim.filetype.detect").r(bufnr) end, + rdf = function(path, bufnr) require("vim.filetype.detect").redif(bufnr) end, rules = function() vim.fn["dist#ft#FTRules"]() end, - sc = function() vim.fn["dist#ft#FTsc"]() end, - scd = function() vim.fn["dist#ft#FTscd"]() end, + sc = function(path, bufnr) require("vim.filetype.detect").sc(bufnr) end, + scd = function(path, bufnr) require("vim.filetype.detect").scd(bufnr) end, sh = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, shtml = function() vim.fn["dist#ft#FThtml"]() end, - sql = function() vim.fn["dist#ft#SQL"]() end, + sql = function(path, bufnr) require("vim.filetype.detect").sql(bufnr) end, stm = function() vim.fn["dist#ft#FThtml"]() end, tcsh = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, tex = function() vim.fn["dist#ft#FTtex"]() end, - tf = function() vim.fn["dist#ft#FTtf"]() end, - w = function() vim.fn["dist#ft#FTprogress_cweb"]() end, - xml = function() vim.fn["dist#ft#FTxml"]() end, - y = function() vim.fn["dist#ft#FTy"]() end, - zsql = function() vim.fn["dist#ft#SQL"]() end, + tf = function(path, bufnr) require("vim.filetype.detect").tf(bufnr) end, + w = function(path, bufnr) require("vim.filetype.detect").progress_cweb(bufnr) end, + xml = function(path, bufnr) require("vim.filetype.detect").xml(bufnr) end, + y = function(path, bufnr) require("vim.filetype.detect").y(bufnr) end, + zsql = function(path, bufnr) require("vim.filetype.detect").sql(bufnr) end, txt = function(path, bufnr) --helpfiles match *.txt, but should have a modeline as last line if not getline(bufnr, -1):match("vim:.*ft=help") then @@ -933,10 +933,10 @@ local filename = { ["exim.conf"] = "exim", exports = "exports", [".fetchmailrc"] = "fetchmail", - fvSchemes = function() vim.fn["dist#ft#FTfoam"]() end, - fvSolution = function() vim.fn["dist#ft#FTfoam"]() end, - fvConstraints = function() vim.fn["dist#ft#FTfoam"]() end, - fvModels = function() vim.fn["dist#ft#FTfoam"]() end, + fvSchemes = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + fvSolution = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + fvConstraints = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + fvModels = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, fstab = "fstab", mtab = "fstab", [".gdbinit"] = "gdb", @@ -1355,7 +1355,7 @@ local pattern = { ["%.zcompdump.*"] = starsetf('zsh'), ["%.zlog.*"] = starsetf('zsh'), ["%.zsh.*"] = starsetf('zsh'), - [".*%.[1-9]"] = function() vim.fn["dist#ft#FTnroff"]() end, + [".*%.[1-9]"] = function(path, bufnr) return require("vim.filetype.detect").nroff(bufnr) end, [".*%.[aA]"] = function() vim.fn["dist#ft#FTasm"]() end, [".*%.[sS]"] = function() vim.fn["dist#ft#FTasm"]() end, [".*%.properties_.._.._.*"] = starsetf('jproperties'), @@ -1434,14 +1434,14 @@ local pattern = { ["mutt" .. string.rep("[%w_-]", 6)] = "mail", ["neomutt" .. string.rep("[%w_-]", 6)] = "mail", ["/tmp/SLRN[0-9A-Z.]+"] = "mail", - ["[a-zA-Z0-9].*Dict"] = function() vim.fn["dist#ft#FTfoam"]() end, - ["[a-zA-Z0-9].*Dict%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, - ["[a-zA-Z].*Properties"] = function() vim.fn["dist#ft#FTfoam"]() end, - ["[a-zA-Z].*Properties%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, - [".*Transport%..*"] = function() vim.fn["dist#ft#FTfoam"]() end, - [".*/constant/g"] = function() vim.fn["dist#ft#FTfoam"]() end, - [".*/0/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, - [".*/0%.orig/.*"] = function() vim.fn["dist#ft#FTfoam"]() end, + ["[a-zA-Z0-9].*Dict"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + ["[a-zA-Z0-9].*Dict%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + ["[a-zA-Z].*Properties"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + ["[a-zA-Z].*Properties%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + [".*Transport%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + [".*/constant/g"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + [".*/0/.*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, + [".*/0%.orig/.*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, [".*/etc/sensors%.d/[^.].*"] = starsetf('sensors'), [".*%.git/.*"] = function(path, bufnr) local firstline = getline(bufnr, 1) diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua new file mode 100644 index 0000000000..bb41f0956f --- /dev/null +++ b/runtime/lua/vim/filetype/detect.lua @@ -0,0 +1,413 @@ +local M = {} + +---@private +local function getlines(bufnr, start_lnum, end_lnum, opts) + if not end_lnum then + -- Return a single line as a string + return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] + end + + local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) + opts = opts or {} + return opts.concat and (table.concat(lines) or "") or lines +end + +---@private +local function findany(s, patterns) + for _, v in ipairs(patterns) do + if s:find(v) then + return true + end + end + return false +end + +-- luacheck: push no unused args +-- luacheck: push ignore 122 + +function M.asm(path, bufnr) end + +function M.asm_syntax(path, bufnr) end + +function M.bas(path, bufnr) end + +function M.bindzone(path, bufnr) end + +function M.btm(bufnr) + if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then + vim.bo[bufnr].filetype = "dosbatch" + else + vim.bo[bufnr].filetype = "btm" + end +end + +-- Returns true if file content looks like RAPID +local function is_rapid(bufnr, extension) + if extension == "cfg" then + local line = getlines(bufnr, 1):lower() + return findany(line, { "eio:cfg", "mmc:cfg", "moc:cfg", "proc:cfg", "sio:cfg", "sys:cfg" }) + end + local first = "^%s*module%s+%S+%s*" + -- Called from mod, prg or sys functions + for _, line in ipairs(getlines(bufnr, 1, -1)) do + if not line:find("^%s*$") then + return findany(line:lower(), { "^%s*%%%%%%", first .. "(", first .. "$" }) + end + end + -- Only found blank lines + return false +end + +function M.cfg(bufnr) + if vim.g.filetype_cfg then + vim.bo[bufnr].filetype = vim.g.filetype_cfg + elseif is_rapid(bufnr, "cfg") then + vim.bo[bufnr].filetype = "rapid" + else + vim.bo[bufnr].filetype = "cfg" + end +end + +function M.change(path, bufnr) end + +function M.csh(path, bufnr) end + +function M.dat(path, bufnr) end + +function M.dep3patch(path, bufnr) end + +function M.dtrace(path, bufnr) end + +function M.e(path, bufnr) end + +-- This function checks for valid cl syntax in the first five lines. +-- Look for either an opening comment, '#', or a block start, '{'. +-- If not found, assume SGML. +function M.ent(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 5)) do + if line:find("^%s*[#{]") then + vim.bo[bufnr].filetype = "cl" + return + elseif not line:find("^%s*$") then + -- Not a blank line, not a comment, and not a block start, + -- so doesn't look like valid cl code. + break + end + end + vim.bo[bufnr].filetype = "dtd" +end + +function M.euphoria(bufnr) + if vim.g.filetype_euphoria then + vim.bo[bufnr].filetype = vim.g.filetype_euphoria + else + vim.bo[bufnr].filetype = "euphoria3" + end +end + +function M.ex(bufnr) + if vim.g.filetype_euphoria then + vim.bo[bufnr].filetype = vim.g.filetype_euphoria + else + for _, line in ipairs(getlines(bufnr, 1, 100)) do + -- TODO: in the Vim regex, \> is used to match the end of the word, can this be omitted? + if findany(line, { "^%-%-", "^ifdef", "^include" }) then + vim.bo[bufnr].filetype = "euphoria3" + return + end + end + vim.bo[bufnr].filetype = "elixir" + end +end + +-- This function checks the first 15 lines for appearance of 'FoamFile' +-- and then 'object' in a following line. +-- In that case, it's probably an OpenFOAM file +function M.foam(bufnr) + local foam_file = false + for _, line in ipairs(getlines(bufnr, 1, 15)) do + if line:find("^FoamFile") then + foam_file = true + elseif foam_file and line:find("^%s*object") then + vim.bo[bufnr].filetype = "foam" + return + end + end +end + +function M.frm(bufnr) + if vim.g.filetype_frm then + vim.bo[bufnr].filetype = vim.g.filetype_frm + else + -- Always ignore case + local lines = getlines(bufnr, 1, 5, { concat = true }):lower() + if findany(lines, { "vb_name", "begin vb%.form", "begin vb%.mdiform" }) then + vim.bo[bufnr].filetype = "vb" + else + vim.bo[bufnr].filetype = "form" + end + end +end + +function M.fs(path, bufnr) end + +function M.header(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 200)) do + if findany(line, { "^@interface", "^@end", "^@class" }) then + if vim.g.c_syntax_for_h then + vim.bo[bufnr].filetype = "objc" + else + vim.bo[bufnr].filetype = "objcpp" + end + return + end + end + if vim.g.c_syntax_for_h then + vim.bo[bufnr].filetype = "c" + elseif vim.g.ch_syntax_for_h then + vim.bo[bufnr].filetype = "ch" + else + vim.bo[bufnr].filetype = "cpp" + end +end + +function M.idl(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 50)) do + -- Always ignore case + line = line:lower() + if findany(line, { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then + vim.bo[bufnr].filetype = "msidl" + return + end + end + vim.bo[bufnr].filetype = "idl" +end + +function M.inc(path, bufnr) end + +function M.inp(bufnr) + if getlines(bufnr, 1):find("^%*") then + vim.bo[bufnr].filetype = "abaqus" + else + for _, line in ipairs(getlines(bufnr, 1, 500)) do + if line:lower():find("^header surface data") then + vim.bo[bufnr].filetype = "trasys" + return + end + end + end +end + +function M.lpc(path, bufnr) end + +function M.lprolog(path, bufnr) end + +function M.m(path, bufnr) end + +-- Rely on the file to start with a comment. +-- MS message text files use ';', Sendmail files use '#' or 'dnl' +function M.mc(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 20)) do + if findany(line:lower(), { "^%s*#", "^%s*dnl" }) then + -- Sendmail .mc file + vim.bo[bufnr].filetype = "m4" + return + elseif line:find("^%s*;") then + vim.bo[bufnr].filetype = "msmessages" + return + end + end + -- Default: Sendmail .mc file + vim.bo[bufnr].filetype = "m4" +end + +function M.mm(path, bufnr) end + +function M.mms(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 20)) do + if findany(line, { "^%s*%%", "^%s*//", "^%*" }) then + vim.bo[bufnr].filetype = "mmix" + return + elseif line:find("^%s*#") then + vim.bo[bufnr].filetype = "make" + return + end + end + vim.bo[bufnr].filetype = "mmix" +end + +function M.mod(path, bufnr) end + +-- This function checks if one of the first five lines start with a dot. In +-- that case it is probably an nroff file: 'filetype' is set and 1 is returned. +function M.nroff(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 5)) do + if line:find("^%.") then + vim.bo[bufnr].filetype = "nroff" + return 1 + end + end + return 0 +end + +function M.perl(path, bufnr) end + +function M.pl(path, bufnr) end + +function M.pp(path, bufnr) end + +function M.prg(path, bufnr) end + +function M.progress_asm(path, bufnr) end + +function M.progress_cweb(bufnr) + if vim.g.filetype_w then + vim.bo[bufnr].filetype = vim.g.filetype_w + else + if getlines(bufnr, 1):find("^&ANALYZE") or getlines(bufnr, 3):find("^&GLOBAL%-DEFINE") then + vim.bo[bufnr].filetype = "progress" + else + vim.bo[bufnr].filetype = "cweb" + end + end +end + +function M.progress_pascal(path, bufnr) end + +function M.proto(path, bufnr) end + +function M.r(bufnr) + local lines = getlines(bufnr, 1, 50) + -- TODO: \< / \> which match the beginning / end of a word + -- Rebol is easy to recognize, check for that first + if table.concat(lines):lower():find("rebol") then + vim.bo[bufnr].filetype = "rebol" + return + end + + for _, line in ipairs(lines) do + -- R has # comments + if line:find("^%s*#") then + vim.bo[bufnr].filetype = "r" + return + end + -- Rexx has /* comments */ + if line:find("^%s*/%*") then + vim.bo[bufnr].filetype = "rexx" + return + end + end + + -- Nothing recognized, use user default or assume R + if vim.g.filetype_r then + vim.bo[bufnr].filetype = vim.g.filetype_r + else + -- Rexx used to be the default, but R appears to be much more popular. + vim.bo[bufnr].filetype = "r" + end +end + +function M.redif(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 5)) do + if line:lower():find("^template%-type:") then + vim.bo[bufnr].filetype = "redif" + end + end +end + +function M.rules(path, bufnr) end + +-- This function checks the first 25 lines of file extension "sc" to resolve +-- detection between scala and SuperCollider +function M.sc(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 25)) do + if findany(line, { "[A-Za-z0-9]*%s:%s[A-Za-z0-9]", "var%s<", "classvar%s<", "%^this.*", "|%w*|", "%+%s%w*%s{", "%*ar%s" }) then + vim.bo[bufnr].filetype = "supercollider" + return + end + end + vim.bo[bufnr].filetype = "scala" +end + +-- This function checks the first line of file extension "scd" to resolve +-- detection between scdoc and SuperCollider +function M.scd(bufnr) + local first = "^%S+%(%d[0-9A-Za-z]*%)" + local opt = [[%s+"[^"]*"]] + local line = getlines(bufnr, 1) + if findany(line, { "$", first .. opt .. "$", first .. opt .. opt .. "$" }) then + vim.bo[bufnr].filetype = "scdoc" + else + vim.bo[bufnr].filetype = "supercollider" + end +end + +function M.sh(path, bufnr) end + +function M.shell(path, bufnr) end + +function M.sql(bufnr) + if vim.g.filetype_sql then + vim.bo[bufnr].filetype = vim.g.filetype_sql + else + vim.bo[bufnr].filetype = "sql" + end +end + +function M.src(path, bufnr) end + +function M.sys(path, bufnr) end + +function M.tex(path, bufnr) end + +-- Determine if a *.tf file is TF mud client or terraform +function M.tf(bufnr) + for _, line in ipairs(getlines(bufnr, 1, -1)) do + -- Assume terraform file on a non-empty line (not whitespace-only) + -- and when the first non-whitespace character is not a ; or / + if not line:find("^%s*$") and not line:find("^%s*[;/]") then + vim.bo[bufnr].filetype = "terraform" + return + end + end + vim.bo[bufnr].filetype = "tf" +end + +function M.xml(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 100)) do + line = line:lower() + local is_docbook4 = line:find(" is used to match the end of the word after "class", + -- can this be omitted? + if findany(line, { "^%s*#", "^%class", "^%s*#%s*include" }) then + vim.bo[bufnr].filetype = "racc" + end + end + vim.bo[bufnr].filetype = "yacc" +end + +-- luacheck: pop +-- luacheck: pop + +return M -- cgit From 815b65d77713c69bbcb5c80892f6dd49aac8edd9 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Tue, 3 May 2022 15:03:42 -0600 Subject: fix(filetype): fixup scd filetype detection (#18403) --- runtime/lua/vim/filetype/detect.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index bb41f0956f..787b335251 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -335,7 +335,7 @@ function M.scd(bufnr) local first = "^%S+%(%d[0-9A-Za-z]*%)" local opt = [[%s+"[^"]*"]] local line = getlines(bufnr, 1) - if findany(line, { "$", first .. opt .. "$", first .. opt .. opt .. "$" }) then + if findany(line, { first .. "$", first .. opt .. "$", first .. opt .. opt .. "$" }) then vim.bo[bufnr].filetype = "scdoc" else vim.bo[bufnr].filetype = "supercollider" -- cgit From c051ea83dd059920714adb39459b3b703ce6f15a Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 4 May 2022 02:13:01 -0400 Subject: refactor(lua): replace hard-coded gsub with vim.pesc() (#18407) --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 77ebb64b1d..32f4f825c1 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1490,7 +1490,7 @@ local function normalize_path(path, as_pattern) if as_pattern then -- Escape Lua's metacharacters when $HOME is used in a pattern. -- The rest of path should already be properly escaped. - normal = vim.env.HOME:gsub('[-^$()%%.%[%]+?]', '%%%0') .. normal:sub(2) + normal = vim.pesc(vim.env.HOME) .. normal:sub(2) else normal = vim.env.HOME .. normal:sub(2) end -- cgit From 94eb72cc44fee4cae7a41cb1ff5fb21f81976658 Mon Sep 17 00:00:00 2001 From: William Boman Date: Thu, 5 May 2022 18:50:12 +0200 Subject: fix(lsp): make sure to always reset active codelens refreshes (#18331) This fixes issues where subsequent calls to vim.lsp.codelens.refresh() would have no effect due to the buffer not getting cleared from the active_refresh table. Examples of how such scenarios would occur are: - A textDocument/codeLens result yielded an error. - The 'textDocument/codeLens' handler was overriden in such a way that it no longer called vim.lsp.codelens.on_codelens(). --- runtime/lua/vim/lsp/codelens.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 9eb64c9a2e..99695d2ed1 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -1,4 +1,5 @@ local util = require('vim.lsp.util') +local log = require('vim.lsp.log') local api = vim.api local M = {} @@ -214,7 +215,11 @@ end --- |lsp-handler| for the method `textDocument/codeLens` --- function M.on_codelens(err, result, ctx, _) - assert(not err, vim.inspect(err)) + if err then + active_refreshes[ctx.bufnr] = nil + local _ = log.error() and log.error("codelens", err) + return + end M.save(result, ctx.bufnr, ctx.client_id) @@ -222,8 +227,8 @@ function M.on_codelens(err, result, ctx, _) -- once resolved. M.display(result, ctx.bufnr, ctx.client_id) resolve_lenses(result, ctx.bufnr, ctx.client_id, function() - M.display(result, ctx.bufnr, ctx.client_id) active_refreshes[ctx.bufnr] = nil + M.display(result, ctx.bufnr, ctx.client_id) end) end @@ -245,7 +250,7 @@ function M.refresh() return end active_refreshes[bufnr] = true - vim.lsp.buf_request(0, 'textDocument/codeLens', params) + vim.lsp.buf_request(0, 'textDocument/codeLens', params, M.on_codelens) end -- cgit From 55187de1157e05ea71c7c0404345dee0e27e963e Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 5 May 2022 23:56:00 +0200 Subject: fix(lsp): fix rename capability checks and multi client support (#18441) Adds filter and id options to filter the client to use for rename. Similar to the recently added `format` function. rename will use all matching clients one after another and can handle a mix of prepareRename/rename support. Also ensures the right `offset_encoding` is used for the `make_position_params` calls --- runtime/lua/vim/lsp/buf.lua | 148 +++++++++++++++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 35 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index aabafc422f..8db215829f 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -359,50 +359,128 @@ end --- Renames all references to the symbol under the cursor. --- ----@param new_name (string) If not provided, the user will be prompted for a new ----name using |vim.ui.input()|. -function M.rename(new_name) - local opts = { - prompt = "New Name: " - } +---@param new_name string|nil If not provided, the user will be prompted for a new +--- name using |vim.ui.input()|. +---@param options table|nil additional options +--- - filter (function|nil): +--- Predicate to filter clients used for rename. +--- Receives the attached clients as argument and must return a list of +--- clients. +--- - name (string|nil): +--- Restrict clients used for rename to ones where client.name matches +--- this field. +function M.rename(new_name, options) + options = options or {} + local bufnr = options.bufnr or vim.api.nvim_get_current_buf() + local clients = vim.lsp.buf_get_clients(bufnr) - ---@private - local function on_confirm(input) - if not (input and #input > 0) then return end - local params = util.make_position_params() - params.newName = input - request('textDocument/rename', params) + if options.filter then + clients = options.filter(clients) + elseif options.name then + clients = vim.tbl_filter( + function(client) return client.name == options.name end, + clients + ) + end + + if #clients == 0 then + vim.notify("[LSP] Rename request failed, no matching language servers.") end + local win = vim.api.nvim_get_current_win() + + -- Compute early to account for cursor movements after going async + local cword = vfn.expand('') + ---@private - local function prepare_rename(err, result) - if err == nil and result == nil then - vim.notify('nothing to rename', vim.log.levels.INFO) + local function get_text_at_range(range) + return vim.api.nvim_buf_get_text( + bufnr, + range.start.line, + range.start.character, + range['end'].line, + range['end'].character, + {} + )[1] + end + + local try_use_client + try_use_client = function(idx, client) + if not client then return end - if result and result.placeholder then - opts.default = result.placeholder - if not new_name then npcall(vim.ui.input, opts, on_confirm) end - elseif result and result.start and result['end'] and - result.start.line == result['end'].line then - local line = vfn.getline(result.start.line+1) - local start_char = result.start.character+1 - local end_char = result['end'].character - opts.default = string.sub(line, start_char, end_char) - if not new_name then npcall(vim.ui.input, opts, on_confirm) end + + ---@private + local function rename(name) + local params = util.make_position_params(win, client.offset_encoding) + params.newName = name + local handler = client.handlers['textDocument/rename'] or vim.lsp.handlers['textDocument/rename'] + client.request('textDocument/rename', params, function(...) + handler(...) + try_use_client(next(clients, idx)) + end, bufnr) + end + + if client.supports_method("textDocument/prepareRename") then + local params = util.make_position_params(win, client.offset_encoding) + client.request('textDocument/prepareRename', params, function(err, result) + if err or result == nil then + if next(clients, idx) then + try_use_client(next(clients, idx)) + else + local msg = err and ('Error on prepareRename: ' .. (err.message or '')) or 'Nothing to rename' + vim.notify(msg, vim.log.levels.INFO) + end + return + end + + if new_name then + rename(new_name) + return + end + + local prompt_opts = { + prompt = "New Name: " + } + -- result: Range | { range: Range, placeholder: string } + if result.placeholder then + prompt_opts.default = result.placeholder + elseif result.start then + prompt_opts.default = get_text_at_range(result) + elseif result.range then + prompt_opts.default = get_text_at_range(result.range) + else + prompt_opts.default = cword + end + vim.ui.input(prompt_opts, function(input) + if not input or #input == 0 then + return + end + rename(input) + end) + end, bufnr) + elseif client.supports_method("textDocument/rename") then + if new_name then + rename(new_name) + return + end + + local prompt_opts = { + prompt = "New Name: ", + default = cword + } + vim.ui.input(prompt_opts, function(input) + if not input or #input == 0 then + return + end + rename(input) + end) else - -- fallback to guessing symbol using - -- - -- this can happen if the language server does not support prepareRename, - -- returns an unexpected response, or requests for "default behavior" - -- - -- see https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename - opts.default = vfn.expand('') - if not new_name then npcall(vim.ui.input, opts, on_confirm) end + vim.notify('Client ' .. client.id .. '/' .. client.name .. ' has no rename capability') end - if new_name then on_confirm(new_name) end end - request('textDocument/prepareRename', util.make_position_params(), prepare_rename) + + try_use_client(next(clients)) end --- Lists all the references to the symbol under the cursor in the quickfix window. -- cgit From 44a4af0ed02db7f4f1cce8c64935238b4efbee12 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 6 May 2022 18:57:08 +0200 Subject: fix(lsp): skip clients without rename capability (#18449) Follow up to https://github.com/neovim/neovim/pull/18441 This way rename should "just work" in most cases without having to manually filter the client --- runtime/lua/vim/lsp/buf.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 8db215829f..6666b3c044 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -383,8 +383,14 @@ function M.rename(new_name, options) ) end + -- Clients must at least support rename, prepareRename is optional + clients = vim.tbl_filter( + function(client) return client.supports_method("textDocument/rename") end, + clients + ) + if #clients == 0 then - vim.notify("[LSP] Rename request failed, no matching language servers.") + vim.notify("[LSP] Rename, no matching language servers with rename capability.") end local win = vim.api.nvim_get_current_win() @@ -459,7 +465,8 @@ function M.rename(new_name, options) rename(input) end) end, bufnr) - elseif client.supports_method("textDocument/rename") then + else + assert(client.supports_method("textDocument/rename"), 'Client must support textDocument/rename') if new_name then rename(new_name) return @@ -475,8 +482,6 @@ function M.rename(new_name, options) end rename(input) end) - else - vim.notify('Client ' .. client.id .. '/' .. client.name .. ' has no rename capability') end end -- cgit From d30621064105d1f5e4e695fb09607269694f02d0 Mon Sep 17 00:00:00 2001 From: Noval Maulana Date: Sat, 7 May 2022 15:35:08 +0700 Subject: docs: change wrap_at type to number (#18456) --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 72dfb3cd76..bb87e8372b 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1384,7 +1384,7 @@ end --- - height: (number) height of floating window --- - width: (number) width of floating window --- - wrap: (boolean, default true) wrap long lines ---- - wrap_at: (string) character to wrap at for computing height when wrap is enabled +--- - wrap_at: (number) character to wrap at for computing height when wrap is enabled --- - max_width: (number) maximal width of floating window --- - max_height: (number) maximal height of floating window --- - pad_top: (number) number of lines to pad contents at top -- cgit From 6cfb1d4c280a90bcce4e793f56d791b68c66c264 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 8 May 2022 13:00:30 -0600 Subject: fix(lsp): detach spawned LSP server processes (#18477) LSP servers should be daemonized (detached) so that they run in a separate process group from Neovim's. Among other things, this ensures the process does not inherit Neovim's TTY (#18475). Make this configurable so that clients can explicitly opt-out of detaching from Nvim. --- runtime/lua/vim/lsp.lua | 6 ++++++ runtime/lua/vim/lsp/rpc.lua | 4 ++++ 2 files changed, 10 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 00f1c26692..a541b63ee9 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -241,6 +241,7 @@ local function validate_client_config(config) capabilities = { config.capabilities, "t", true }; cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), "directory" }; cmd_env = { config.cmd_env, "t", true }; + detached = { config.detached, "b", true }; name = { config.name, 's', true }; on_error = { config.on_error, "f", true }; on_exit = { config.on_exit, "f", true }; @@ -663,6 +664,10 @@ end --- { "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; } --- --- +---@param detached: (boolean, default true) Daemonize the server process so that it runs in a +--- separate process group from Nvim. Nvim will shutdown the process on exit, but if Nvim fails to +--- exit cleanly this could leave behind orphaned server processes. +--- ---@param workspace_folders (table) List of workspace folders passed to the --- language server. For backwards compatibility rootUri and rootPath will be --- derived from the first workspace folder in this list. See `workspaceFolders` in @@ -859,6 +864,7 @@ function lsp.start_client(config) local rpc = lsp_rpc.start(cmd, cmd_args, dispatch, { cwd = config.cmd_cwd; env = config.cmd_env; + detached = config.detached; }) -- Return nil if client fails to start diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 6d0a78fba8..be2cc58f07 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -319,10 +319,14 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) local spawn_params = { args = cmd_args; stdio = {stdin, stdout, stderr}; + detached = true; } if extra_spawn_params then spawn_params.cwd = extra_spawn_params.cwd spawn_params.env = env_merge(extra_spawn_params.env) + if extra_spawn_params.detached ~= nil then + spawn_params.detached = extra_spawn_params.detached + end end handle, pid = uv.spawn(cmd, spawn_params, onexit) if handle == nil then -- cgit From aefdc6783cb77f09786542c90901a9e7120bea42 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 9 May 2022 11:23:51 +0200 Subject: chore: format runtime with stylua --- runtime/lua/vim/F.lua | 10 +- runtime/lua/vim/_editor.lua | 214 +- runtime/lua/vim/_init_packages.lua | 28 +- runtime/lua/vim/_meta.lua | 233 +- runtime/lua/vim/compat.lua | 4 +- runtime/lua/vim/diagnostic.lua | 446 ++-- runtime/lua/vim/filetype.lua | 3075 +++++++++++++++------------ runtime/lua/vim/filetype/detect.lua | 169 +- runtime/lua/vim/highlight.lua | 20 +- runtime/lua/vim/inspect.lua | 108 +- runtime/lua/vim/keymap.lua | 30 +- runtime/lua/vim/lsp.lua | 535 ++--- runtime/lua/vim/lsp/_snippet.lua | 167 +- runtime/lua/vim/lsp/buf.lua | 169 +- runtime/lua/vim/lsp/codelens.lua | 54 +- runtime/lua/vim/lsp/diagnostic.lua | 107 +- runtime/lua/vim/lsp/handlers.lua | 182 +- runtime/lua/vim/lsp/health.lua | 9 +- runtime/lua/vim/lsp/log.lua | 70 +- runtime/lua/vim/lsp/protocol.lua | 542 ++--- runtime/lua/vim/lsp/rpc.lua | 240 ++- runtime/lua/vim/lsp/sync.lua | 43 +- runtime/lua/vim/lsp/util.lua | 604 +++--- runtime/lua/vim/shared.lua | 144 +- runtime/lua/vim/treesitter.lua | 48 +- runtime/lua/vim/treesitter/health.lua | 12 +- runtime/lua/vim/treesitter/highlighter.lua | 189 +- runtime/lua/vim/treesitter/language.lua | 6 +- runtime/lua/vim/treesitter/languagetree.lua | 97 +- runtime/lua/vim/treesitter/query.lua | 118 +- runtime/lua/vim/ui.lua | 10 +- runtime/lua/vim/uri.lua | 36 +- 32 files changed, 4174 insertions(+), 3545 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/F.lua b/runtime/lua/vim/F.lua index 9327c652db..bca5ddf68b 100644 --- a/runtime/lua/vim/F.lua +++ b/runtime/lua/vim/F.lua @@ -5,13 +5,17 @@ local F = {} ---@param a ---@param b function F.if_nil(a, b) - if a == nil then return b end + if a == nil then + return b + end return a end -- Use in combination with pcall function F.ok_or_nil(status, ...) - if not status then return end + if not status then + return + end return ... end @@ -29,7 +33,7 @@ end --- like {...} except preserve the length explicitly function F.pack_len(...) - return {n=select('#', ...), ...} + return { n = select('#', ...), ... } end --- like unpack() but use the length set by F.pack_len if present diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 119467de16..9bdbf6d1c7 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -40,26 +40,28 @@ local vim = assert(vim) -- These are for loading runtime modules lazily since they aren't available in -- the nvim binary as specified in executor.c -for k,v in pairs { - treesitter=true; - filetype = true; - F=true; - lsp=true; - highlight=true; - diagnostic=true; - keymap=true; - ui=true; -} do vim._submodules[k] = v end +for k, v in pairs({ + treesitter = true, + filetype = true, + F = true, + lsp = true, + highlight = true, + diagnostic = true, + keymap = true, + ui = true, +}) do + vim._submodules[k] = v +end vim.log = { levels = { - TRACE = 0; - DEBUG = 1; - INFO = 2; - WARN = 3; - ERROR = 4; - OFF = 5; - } + TRACE = 0, + DEBUG = 1, + INFO = 2, + WARN = 3, + ERROR = 4, + OFF = 5, + }, } -- Internal-only until comments in #8107 are addressed. @@ -77,14 +79,14 @@ function vim._os_proc_info(pid) if pid == nil or pid <= 0 or type(pid) ~= 'number' then error('invalid pid') end - local cmd = { 'ps', '-p', pid, '-o', 'comm=', } + local cmd = { 'ps', '-p', pid, '-o', 'comm=' } local err, name = vim._system(cmd) if 1 == err and vim.trim(name) == '' then - return {} -- Process not found. + return {} -- Process not found. elseif 0 ~= err then - error('command failed: '..vim.fn.string(cmd)) + error('command failed: ' .. vim.fn.string(cmd)) end - local _, ppid = vim._system({ 'ps', '-p', pid, '-o', 'ppid=', }) + local _, ppid = vim._system({ 'ps', '-p', pid, '-o', 'ppid=' }) -- Remove trailing whitespace. name = vim.trim(name):gsub('^.*/', '') ppid = tonumber(ppid) or -1 @@ -101,12 +103,12 @@ function vim._os_proc_children(ppid) if ppid == nil or ppid <= 0 or type(ppid) ~= 'number' then error('invalid ppid') end - local cmd = { 'pgrep', '-P', ppid, } + local cmd = { 'pgrep', '-P', ppid } local err, rv = vim._system(cmd) if 1 == err and vim.trim(rv) == '' then - return {} -- Process not found. + return {} -- Process not found. elseif 0 ~= err then - error('command failed: '..vim.fn.string(cmd)) + error('command failed: ' .. vim.fn.string(cmd)) end local children = {} for s in rv:gmatch('%S+') do @@ -124,8 +126,8 @@ end --- ---@see https://github.com/kikito/inspect.lua ---@see https://github.com/mpeterv/vinspect -local function inspect(object, options) -- luacheck: no unused - error(object, options) -- Stub for gen_vimdoc.py +local function inspect(object, options) -- luacheck: no unused + error(object, options) -- Stub for gen_vimdoc.py end do @@ -160,11 +162,11 @@ do local now = vim.loop.now() local is_first_chunk = phase < 2 local is_last_chunk = phase == -1 or phase == 3 - if is_first_chunk then -- Reset flags. + if is_first_chunk then -- Reset flags. tdots, tick, got_line1, undo_started, trailing_nl = now, 0, false, false, false end if #lines == 0 then - lines = {''} + lines = { '' } end if #lines == 1 and lines[1] == '' and not is_last_chunk then -- An empty chunk can cause some edge cases in streamed pasting, @@ -172,7 +174,7 @@ do return true end -- Note: mode doesn't always start with "c" in cmdline mode, so use getcmdtype() instead. - if vim.fn.getcmdtype() ~= '' then -- cmdline-mode: paste only 1 line. + if vim.fn.getcmdtype() ~= '' then -- cmdline-mode: paste only 1 line. if not got_line1 then got_line1 = (#lines > 1) -- Escape control characters @@ -187,9 +189,9 @@ do if undo_started then vim.api.nvim_command('undojoin') end - if mode:find('^i') or mode:find('^n?t') then -- Insert mode or Terminal buffer + if mode:find('^i') or mode:find('^n?t') then -- Insert mode or Terminal buffer vim.api.nvim_put(lines, 'c', false, true) - elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then -- Replace mode + elseif phase < 2 and mode:find('^R') and not mode:find('^Rv') then -- Replace mode -- TODO: implement Replace mode streamed pasting -- TODO: support Virtual Replace mode local nchars = 0 @@ -197,26 +199,26 @@ do nchars = nchars + line:len() end local row, col = unpack(vim.api.nvim_win_get_cursor(0)) - local bufline = vim.api.nvim_buf_get_lines(0, row-1, row, true)[1] + local bufline = vim.api.nvim_buf_get_lines(0, row - 1, row, true)[1] local firstline = lines[1] - firstline = bufline:sub(1, col)..firstline + firstline = bufline:sub(1, col) .. firstline lines[1] = firstline - lines[#lines] = lines[#lines]..bufline:sub(col + nchars + 1, bufline:len()) - vim.api.nvim_buf_set_lines(0, row-1, row, false, lines) - elseif mode:find('^[nvV\22sS\19]') then -- Normal or Visual or Select mode - if mode:find('^n') then -- Normal mode + lines[#lines] = lines[#lines] .. bufline:sub(col + nchars + 1, bufline:len()) + vim.api.nvim_buf_set_lines(0, row - 1, row, false, lines) + elseif mode:find('^[nvV\22sS\19]') then -- Normal or Visual or Select mode + if mode:find('^n') then -- Normal mode -- When there was a trailing new line in the previous chunk, -- the cursor is on the first character of the next line, -- so paste before the cursor instead of after it. vim.api.nvim_put(lines, 'c', not trailing_nl, false) - else -- Visual or Select mode + else -- Visual or Select mode vim.api.nvim_command([[exe "silent normal! \"]]) local del_start = vim.fn.getpos("'[") local cursor_pos = vim.fn.getpos('.') - if mode:find('^[VS]') then -- linewise - if cursor_pos[2] < del_start[2] then -- replacing lines at eof + if mode:find('^[VS]') then -- linewise + if cursor_pos[2] < del_start[2] then -- replacing lines at eof -- create a new line - vim.api.nvim_put({''}, 'l', true, true) + vim.api.nvim_put({ '' }, 'l', true, true) end vim.api.nvim_put(lines, 'c', false, false) else @@ -227,7 +229,7 @@ do -- put cursor at the end of the text instead of one character after it vim.fn.setpos('.', vim.fn.getpos("']")) trailing_nl = lines[#lines] == '' - else -- Don't know what to do in other modes + else -- Don't know what to do in other modes return false end undo_started = true @@ -240,9 +242,9 @@ do vim.api.nvim_command(('echo "%s"'):format(dots)) end if is_last_chunk then - vim.api.nvim_command('redraw'..(tick > 1 and '|echo ""' or '')) + vim.api.nvim_command('redraw' .. (tick > 1 and '|echo ""' or '')) end - return true -- Paste will not continue if not returning `true`. + return true -- Paste will not continue if not returning `true`. end end @@ -252,10 +254,12 @@ end ---@see |vim.schedule()| ---@see |vim.in_fast_event()| function vim.schedule_wrap(cb) - return (function (...) + return function(...) local args = vim.F.pack_len(...) - vim.schedule(function() cb(vim.F.unpack_len(args)) end) - end) + vim.schedule(function() + cb(vim.F.unpack_len(args)) + end) + end end -- vim.fn.{func}(...) @@ -264,7 +268,7 @@ vim.fn = setmetatable({}, { local _fn if vim.api[key] ~= nil then _fn = function() - error(string.format("Tried to call API function with vim.fn: use vim.api.%s instead", key)) + error(string.format('Tried to call API function with vim.fn: use vim.api.%s instead', key)) end else _fn = function(...) @@ -273,7 +277,7 @@ vim.fn = setmetatable({}, { end t[key] = _fn return _fn - end + end, }) vim.funcref = function(viml_func_name) @@ -291,9 +295,9 @@ do --@private local function make_dict_accessor(scope, handle) - validate { - scope = {scope, 's'}; - } + validate({ + scope = { scope, 's' }, + }) local mt = {} function mt:__newindex(k, v) return vim._setvar(scope, handle or 0, k, v) @@ -343,7 +347,7 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive) local region = {} for l = pos1[1], pos2[1] do local c1, c2 - if regtype:byte() == 22 then -- block selection: take width from regtype + if regtype:byte() == 22 then -- block selection: take width from regtype c1 = pos1[2] c2 = c1 + regtype:sub(2) -- and adjust for non-ASCII characters @@ -355,10 +359,10 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive) c2 = vim.str_byteindex(bufline, c2) end else - c1 = (l == pos1[1]) and (pos1[2]) or 0 + c1 = (l == pos1[1]) and pos1[2] or 0 c2 = (l == pos2[1]) and (pos2[2] + (inclusive and 1 or 0)) or -1 end - table.insert(region, l, {c1, c2}) + table.insert(region, l, { c1, c2 }) end return region end @@ -372,19 +376,22 @@ end ---@param timeout Number of milliseconds to wait before calling `fn` ---@return timer luv timer object function vim.defer_fn(fn, timeout) - vim.validate { fn = { fn, 'c', true}; } + vim.validate({ fn = { fn, 'c', true } }) local timer = vim.loop.new_timer() - timer:start(timeout, 0, vim.schedule_wrap(function() - timer:stop() - timer:close() + timer:start( + timeout, + 0, + vim.schedule_wrap(function() + timer:stop() + timer:close() - fn() - end)) + fn() + end) + ) return timer end - --- Display a notification to the user. --- --- This function can be overridden by plugins to display notifications using a @@ -398,9 +405,9 @@ function vim.notify(msg, level, opts) -- luacheck: no unused args if level == vim.log.levels.ERROR then vim.api.nvim_err_writeln(msg) elseif level == vim.log.levels.WARN then - vim.api.nvim_echo({{msg, 'WarningMsg'}}, true, {}) + vim.api.nvim_echo({ { msg, 'WarningMsg' } }, true, {}) else - vim.api.nvim_echo({{msg}}, true, {}) + vim.api.nvim_echo({ { msg } }, true, {}) end end @@ -453,10 +460,10 @@ function vim.on_key(fn, ns_id) return #on_key_cbs end - vim.validate { - fn = { fn, 'c', true}, - ns_id = { ns_id, 'n', true } - } + vim.validate({ + fn = { fn, 'c', true }, + ns_id = { ns_id, 'n', true }, + }) if ns_id == nil or ns_id == 0 then ns_id = vim.api.nvim_create_namespace('') @@ -481,10 +488,13 @@ function vim._on_key(char) end if failed_ns_ids[1] then - error(string.format( - "Error executing 'on_key' with ns_ids '%s'\n Messages: %s", - table.concat(failed_ns_ids, ", "), - table.concat(failed_messages, "\n"))) + error( + string.format( + "Error executing 'on_key' with ns_ids '%s'\n Messages: %s", + table.concat(failed_ns_ids, ', '), + table.concat(failed_messages, '\n') + ) + ) end end @@ -511,8 +521,10 @@ function vim._expand_pat(pat, env) -- Probably just need to do a smarter match than just `:match` -- Get the last part of the pattern - local last_part = pat:match("[%w.:_%[%]'\"]+$") - if not last_part then return {}, 0 end + local last_part = pat:match('[%w.:_%[%]\'"]+$') + if not last_part then + return {}, 0 + end local parts, search_index = vim._expand_pat_get_parts(last_part) @@ -529,7 +541,7 @@ function vim._expand_pat(pat, env) -- Normally, we just have a string -- Just attempt to get the string directly from the environment - if type(part) == "string" then + if type(part) == 'string' then key = part else -- However, sometimes you want to use a variable, and complete on it @@ -554,7 +566,7 @@ function vim._expand_pat(pat, env) local field = rawget(final_env, key) if field == nil then local mt = getmetatable(final_env) - if mt and type(mt.__index) == "table" then + if mt and type(mt.__index) == 'table' then field = rawget(mt.__index, key) elseif final_env == vim and vim._submodules[key] then field = vim[key] @@ -570,18 +582,18 @@ function vim._expand_pat(pat, env) local keys = {} ---@private local function insert_keys(obj) - for k,_ in pairs(obj) do - if type(k) == "string" and string.sub(k,1,string.len(match_part)) == match_part then - table.insert(keys,k) + for k, _ in pairs(obj) do + if type(k) == 'string' and string.sub(k, 1, string.len(match_part)) == match_part then + table.insert(keys, k) end end end - if type(final_env) == "table" then + if type(final_env) == 'table' then insert_keys(final_env) end local mt = getmetatable(final_env) - if mt and type(mt.__index) == "table" then + if mt and type(mt.__index) == 'table' then insert_keys(mt.__index) end if final_env == vim then @@ -602,12 +614,12 @@ vim._expand_pat_get_parts = function(lua_string) for idx = 1, #lua_string do local s = lua_string:sub(idx, idx) - if not in_brackets and (s == "." or s == ":") then + if not in_brackets and (s == '.' or s == ':') then table.insert(parts, accumulator) accumulator = '' search_index = idx + 1 - elseif s == "[" then + elseif s == '[' then in_brackets = true table.insert(parts, accumulator) @@ -619,7 +631,7 @@ vim._expand_pat_get_parts = function(lua_string) in_brackets = false search_index = idx + 1 - if string_char == "VAR" then + if string_char == 'VAR' then table.insert(parts, { accumulator }) accumulator = '' @@ -631,7 +643,7 @@ vim._expand_pat_get_parts = function(lua_string) if s == '"' or s == "'" then string_char = s elseif s ~= ' ' then - string_char = "VAR" + string_char = 'VAR' accumulator = s end elseif string_char then @@ -649,7 +661,9 @@ vim._expand_pat_get_parts = function(lua_string) end end - parts = vim.tbl_filter(function(val) return #val > 0 end, parts) + parts = vim.tbl_filter(function(val) + return #val > 0 + end, parts) return parts, search_index end @@ -677,20 +691,20 @@ function vim._cs_remote(rcid, server_addr, connect_error, args) local function connection_failure_errmsg(consequence) local explanation if server_addr == '' then - explanation = "No server specified with --server" + explanation = 'No server specified with --server' else explanation = "Failed to connect to '" .. server_addr .. "'" - if connect_error ~= "" then - explanation = explanation .. ": " .. connect_error + if connect_error ~= '' then + explanation = explanation .. ': ' .. connect_error end end - return "E247: " .. explanation .. ". " .. consequence + return 'E247: ' .. explanation .. '. ' .. consequence end local f_silent = false local f_tab = false - local subcmd = string.sub(args[1],10) + local subcmd = string.sub(args[1], 10) if subcmd == 'tab' then f_tab = true elseif subcmd == 'silent' then @@ -713,16 +727,18 @@ function vim._cs_remote(rcid, server_addr, connect_error, args) print(vim.fn.rpcrequest(rcid, 'nvim_eval', args[2])) return { should_exit = true, tabbed = false } elseif subcmd ~= '' then - return { errmsg='Unknown option argument: ' .. args[1] } + return { errmsg = 'Unknown option argument: ' .. args[1] } end if rcid == 0 then if not f_silent then - vim.notify(connection_failure_errmsg("Editing locally"), vim.log.levels.WARN) + vim.notify(connection_failure_errmsg('Editing locally'), vim.log.levels.WARN) end else local command = {} - if f_tab then table.insert(command, 'tab') end + if f_tab then + table.insert(command, 'tab') + end table.insert(command, 'drop') for i = 2, #args do table.insert(command, vim.fn.fnameescape(args[i])) @@ -745,11 +761,11 @@ end ---@param plugin string|nil Plugin name that the function will be removed --- from. Defaults to "Nvim". function vim.deprecate(name, alternative, version, plugin) - local message = name .. ' is deprecated' - plugin = plugin or "Nvim" - message = alternative and (message .. ', use ' .. alternative .. ' instead.') or message - message = message .. ' See :h deprecated\nThis function will be removed in ' .. plugin .. ' version ' .. version - vim.notify_once(message, vim.log.levels.WARN) + local message = name .. ' is deprecated' + plugin = plugin or 'Nvim' + message = alternative and (message .. ', use ' .. alternative .. ' instead.') or message + message = message .. ' See :h deprecated\nThis function will be removed in ' .. plugin .. ' version ' .. version + vim.notify_once(message, vim.log.levels.WARN) end require('vim._meta') diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua index 7d27741f1b..7e3c73667e 100644 --- a/runtime/lua/vim/_init_packages.lua +++ b/runtime/lua/vim/_init_packages.lua @@ -3,8 +3,8 @@ local vim = assert(vim) local pathtrails = {} vim._so_trails = {} -for s in (package.cpath..';'):gmatch('[^;]*;') do - s = s:sub(1, -2) -- Strip trailing semicolon +for s in (package.cpath .. ';'):gmatch('[^;]*;') do + s = s:sub(1, -2) -- Strip trailing semicolon -- Find out path patterns. pathtrail should contain something like -- /?.so, \?.dll. This allows not to bother determining what correct -- suffixes are. @@ -17,29 +17,29 @@ end function vim._load_package(name) local basename = name:gsub('%.', '/') - local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} - local found = vim.api.nvim__get_runtime(paths, false, {is_lua=true}) + local paths = { 'lua/' .. basename .. '.lua', 'lua/' .. basename .. '/init.lua' } + local found = vim.api.nvim__get_runtime(paths, false, { is_lua = true }) if #found > 0 then local f, err = loadfile(found[1]) return f or error(err) end local so_paths = {} - for _,trail in ipairs(vim._so_trails) do - local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash + for _, trail in ipairs(vim._so_trails) do + local path = 'lua' .. trail:gsub('?', basename) -- so_trails contains a leading slash table.insert(so_paths, path) end - found = vim.api.nvim__get_runtime(so_paths, false, {is_lua=true}) + found = vim.api.nvim__get_runtime(so_paths, false, { is_lua = true }) if #found > 0 then -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is -- a) strip prefix up to and including the first dash, if any -- b) replace all dots by underscores -- c) prepend "luaopen_" -- So "foo-bar.baz" should result in "luaopen_bar_baz" - local dash = name:find("-", 1, true) + local dash = name:find('-', 1, true) local modname = dash and name:sub(dash + 1) or name - local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) + local f, err = package.loadlib(found[1], 'luaopen_' .. modname:gsub('%.', '_')) return f or error(err) end return nil @@ -49,15 +49,15 @@ end table.insert(package.loaders, 2, vim._load_package) -- builtin functions which always should be available -require'vim.shared' +require('vim.shared') -vim._submodules = {inspect=true} +vim._submodules = { inspect = true } -- These are for loading runtime modules in the vim namespace lazily. setmetatable(vim, { __index = function(t, key) if vim._submodules[key] then - t[key] = require('vim.'..key) + t[key] = require('vim.' .. key) return t[key] elseif vim.startswith(key, 'uri_') then local val = require('vim.uri')[key] @@ -67,7 +67,7 @@ setmetatable(vim, { return t[key] end end - end + end, }) --- @@ -79,5 +79,5 @@ end -- only on main thread: functions for interacting with editor state if not vim.is_thread() then - require'vim._editor' + require('vim._editor') end diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 522e26caa7..1706956bca 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -5,15 +5,17 @@ local a = vim.api local validate = vim.validate local SET_TYPES = setmetatable({ - SET = 0, - LOCAL = 1, + SET = 0, + LOCAL = 1, GLOBAL = 2, }, { __index = error }) local options_info = {} for _, v in pairs(a.nvim_get_all_options_info()) do options_info[v.name] = v - if v.shortname ~= "" then options_info[v.shortname] = v end + if v.shortname ~= '' then + options_info[v.shortname] = v + end end local get_scoped_options = function(scope) @@ -27,19 +29,21 @@ local get_scoped_options = function(scope) return result end -local buf_options = get_scoped_options("buf") -local glb_options = get_scoped_options("global") -local win_options = get_scoped_options("win") +local buf_options = get_scoped_options('buf') +local glb_options = get_scoped_options('global') +local win_options = get_scoped_options('win') local function make_meta_accessor(get, set, del, validator) - validator = validator or function() return true end + validator = validator or function() + return true + end - validate { - get = {get, 'f'}; - set = {set, 'f'}; - del = {del, 'f', true}; - validator = {validator, 'f'}; - } + validate({ + get = { get, 'f' }, + set = { set, 'f' }, + del = { del, 'f', true }, + validator = { validator, 'f' }, + }) local mt = {} function mt:__newindex(k, v) @@ -73,7 +77,7 @@ end, vim.fn.setenv) do -- buffer option accessor local function new_buf_opt_accessor(bufnr) local function get(k) - if bufnr == nil and type(k) == "number" then + if bufnr == nil and type(k) == 'number' then return new_buf_opt_accessor(k) end @@ -103,7 +107,7 @@ end do -- window option accessor local function new_win_opt_accessor(winnr) local function get(k) - if winnr == nil and type(k) == "number" then + if winnr == nil and type(k) == 'number' then return new_win_opt_accessor(k) end return a.nvim_win_get_option(winnr or 0, k) @@ -131,17 +135,19 @@ end -- vim global option -- this ONLY sets the global option. like `setglobal` -vim.go = make_meta_accessor( - function(k) return a.nvim_get_option_value(k, {scope = "global"}) end, - function(k, v) return a.nvim_set_option_value(k, v, {scope = "global"}) end -) +vim.go = make_meta_accessor(function(k) + return a.nvim_get_option_value(k, { scope = 'global' }) +end, function(k, v) + return a.nvim_set_option_value(k, v, { scope = 'global' }) +end) -- vim `set` style options. -- it has no additional metamethod magic. -vim.o = make_meta_accessor( - function(k) return a.nvim_get_option_value(k, {}) end, - function(k, v) return a.nvim_set_option_value(k, v, {}) end -) +vim.o = make_meta_accessor(function(k) + return a.nvim_get_option_value(k, {}) +end, function(k, v) + return a.nvim_set_option_value(k, v, {}) +end) ---@brief [[ --- vim.opt, vim.opt_local and vim.opt_global implementation @@ -154,7 +160,9 @@ vim.o = make_meta_accessor( --- Preserves the order and does not mutate the original list local remove_duplicate_values = function(t) local result, seen = {}, {} - if type(t) == "function" then error(debug.traceback("asdf")) end + if type(t) == 'function' then + error(debug.traceback('asdf')) + end for _, v in ipairs(t) do if not seen[v] then table.insert(result, v) @@ -171,37 +179,41 @@ end local key_value_options = { fillchars = true, listchars = true, - winhl = true, + winhl = true, } ---@class OptionTypes --- Option Type Enum local OptionTypes = setmetatable({ BOOLEAN = 0, - NUMBER = 1, - STRING = 2, - ARRAY = 3, - MAP = 4, - SET = 5, + NUMBER = 1, + STRING = 2, + ARRAY = 3, + MAP = 4, + SET = 5, }, { - __index = function(_, k) error("Not a valid OptionType: " .. k) end, - __newindex = function(_, k) error("Cannot set a new OptionType: " .. k) end, + __index = function(_, k) + error('Not a valid OptionType: ' .. k) + end, + __newindex = function(_, k) + error('Cannot set a new OptionType: ' .. k) + end, }) --- Convert a vimoption_T style dictionary to the correct OptionType associated with it. ---@return OptionType local get_option_type = function(name, info) - if info.type == "boolean" then + if info.type == 'boolean' then return OptionTypes.BOOLEAN - elseif info.type == "number" then + elseif info.type == 'number' then return OptionTypes.NUMBER - elseif info.type == "string" then + elseif info.type == 'string' then if not info.commalist and not info.flaglist then return OptionTypes.STRING end if key_value_options[name] then - assert(info.commalist, "Must be a comma list to use key:value style") + assert(info.commalist, 'Must be a comma list to use key:value style') return OptionTypes.MAP end @@ -211,13 +223,12 @@ local get_option_type = function(name, info) return OptionTypes.ARRAY end - error("Fallthrough in OptionTypes") + error('Fallthrough in OptionTypes') else - error("Not a known info.type:" .. info.type) + error('Not a known info.type:' .. info.type) end end - -- Check whether the OptionTypes is allowed for vim.opt -- If it does not match, throw an error which indicates which option causes the error. local function assert_valid_value(name, value, types) @@ -228,16 +239,18 @@ local function assert_valid_value(name, value, types) end end - error(string.format("Invalid option type '%s' for '%s', should be %s", type_of_value, name, table.concat(types, " or "))) + error( + string.format("Invalid option type '%s' for '%s', should be %s", type_of_value, name, table.concat(types, ' or ')) + ) end local valid_types = { - [OptionTypes.BOOLEAN] = { "boolean" }, - [OptionTypes.NUMBER] = { "number" }, - [OptionTypes.STRING] = { "string" }, - [OptionTypes.SET] = { "string", "table" }, - [OptionTypes.ARRAY] = { "string", "table" }, - [OptionTypes.MAP] = { "string", "table" }, + [OptionTypes.BOOLEAN] = { 'boolean' }, + [OptionTypes.NUMBER] = { 'number' }, + [OptionTypes.STRING] = { 'string' }, + [OptionTypes.SET] = { 'string', 'table' }, + [OptionTypes.ARRAY] = { 'string', 'table' }, + [OptionTypes.MAP] = { 'string', 'table' }, } --- Convert a lua value to a vimoption_T value @@ -245,12 +258,20 @@ local convert_value_to_vim = (function() -- Map of functions to take a Lua style value and convert to vimoption_T style value. -- Each function takes (info, lua_value) -> vim_value local to_vim_value = { - [OptionTypes.BOOLEAN] = function(_, value) return value end, - [OptionTypes.NUMBER] = function(_, value) return value end, - [OptionTypes.STRING] = function(_, value) return value end, + [OptionTypes.BOOLEAN] = function(_, value) + return value + end, + [OptionTypes.NUMBER] = function(_, value) + return value + end, + [OptionTypes.STRING] = function(_, value) + return value + end, [OptionTypes.SET] = function(info, value) - if type(value) == "string" then return value end + if type(value) == 'string' then + return value + end if info.flaglist and info.commalist then local keys = {} @@ -261,7 +282,7 @@ local convert_value_to_vim = (function() end table.sort(keys) - return table.concat(keys, ",") + return table.concat(keys, ',') else local result = '' for k, v in pairs(value) do @@ -275,23 +296,27 @@ local convert_value_to_vim = (function() end, [OptionTypes.ARRAY] = function(info, value) - if type(value) == "string" then return value end + if type(value) == 'string' then + return value + end if not info.allows_duplicates then value = remove_duplicate_values(value) end - return table.concat(value, ",") + return table.concat(value, ',') end, [OptionTypes.MAP] = function(_, value) - if type(value) == "string" then return value end + if type(value) == 'string' then + return value + end local result = {} for opt_key, opt_value in pairs(value) do - table.insert(result, string.format("%s:%s", opt_key, opt_value)) + table.insert(result, string.format('%s:%s', opt_key, opt_value)) end table.sort(result) - return table.concat(result, ",") + return table.concat(result, ',') end, } @@ -312,12 +337,18 @@ local convert_value_to_lua = (function() -- Map of OptionType to functions that take vimoption_T values and convert to lua values. -- Each function takes (info, vim_value) -> lua_value local to_lua_value = { - [OptionTypes.BOOLEAN] = function(_, value) return value end, - [OptionTypes.NUMBER] = function(_, value) return value end, - [OptionTypes.STRING] = function(_, value) return value end, + [OptionTypes.BOOLEAN] = function(_, value) + return value + end, + [OptionTypes.NUMBER] = function(_, value) + return value + end, + [OptionTypes.STRING] = function(_, value) + return value + end, [OptionTypes.ARRAY] = function(info, value) - if type(value) == "table" then + if type(value) == 'table' then if not info.allows_duplicates then value = remove_duplicate_values(value) end @@ -332,41 +363,43 @@ local convert_value_to_lua = (function() end -- Handles unescaped commas in a list. - if string.find(value, ",,,") then - local comma_split = vim.split(value, ",,,") + if string.find(value, ',,,') then + local comma_split = vim.split(value, ',,,') local left = comma_split[1] local right = comma_split[2] local result = {} - vim.list_extend(result, vim.split(left, ",")) - table.insert(result, ",") - vim.list_extend(result, vim.split(right, ",")) + vim.list_extend(result, vim.split(left, ',')) + table.insert(result, ',') + vim.list_extend(result, vim.split(right, ',')) table.sort(result) return result end - if string.find(value, ",^,,", 1, true) then - local comma_split = vim.split(value, ",^,,", true) + if string.find(value, ',^,,', 1, true) then + local comma_split = vim.split(value, ',^,,', true) local left = comma_split[1] local right = comma_split[2] local result = {} - vim.list_extend(result, vim.split(left, ",")) - table.insert(result, "^,") - vim.list_extend(result, vim.split(right, ",")) + vim.list_extend(result, vim.split(left, ',')) + table.insert(result, '^,') + vim.list_extend(result, vim.split(right, ',')) table.sort(result) return result end - return vim.split(value, ",") + return vim.split(value, ',') end, [OptionTypes.SET] = function(info, value) - if type(value) == "table" then return value end + if type(value) == 'table' then + return value + end -- Empty strings mean that there is nothing there, -- so empty table should be returned. @@ -374,10 +407,10 @@ local convert_value_to_lua = (function() return {} end - assert(info.flaglist, "That is the only one I know how to handle") + assert(info.flaglist, 'That is the only one I know how to handle') if info.flaglist and info.commalist then - local split_value = vim.split(value, ",") + local split_value = vim.split(value, ',') local result = {} for _, v in ipairs(split_value) do result[v] = true @@ -395,15 +428,17 @@ local convert_value_to_lua = (function() end, [OptionTypes.MAP] = function(info, raw_value) - if type(raw_value) == "table" then return raw_value end + if type(raw_value) == 'table' then + return raw_value + end - assert(info.commalist, "Only commas are supported currently") + assert(info.commalist, 'Only commas are supported currently') local result = {} - local comma_split = vim.split(raw_value, ",") + local comma_split = vim.split(raw_value, ',') for _, key_value_str in ipairs(comma_split) do - local key, value = unpack(vim.split(key_value_str, ":")) + local key, value = unpack(vim.split(key_value_str, ':')) key = vim.trim(key) result[key] = value @@ -443,17 +478,21 @@ local prepend_value = (function() end, [OptionTypes.MAP] = function(left, right) - return vim.tbl_extend("force", left, right) + return vim.tbl_extend('force', left, right) end, [OptionTypes.SET] = function(left, right) - return vim.tbl_extend("force", left, right) + return vim.tbl_extend('force', left, right) end, } return function(name, info, current, new) return value_mutator( - name, info, convert_value_to_lua(name, info, current), convert_value_to_lua(name, info, new), methods + name, + info, + convert_value_to_lua(name, info, current), + convert_value_to_lua(name, info, new), + methods ) end end)() @@ -478,17 +517,21 @@ local add_value = (function() end, [OptionTypes.MAP] = function(left, right) - return vim.tbl_extend("force", left, right) + return vim.tbl_extend('force', left, right) end, [OptionTypes.SET] = function(left, right) - return vim.tbl_extend("force", left, right) + return vim.tbl_extend('force', left, right) end, } return function(name, info, current, new) return value_mutator( - name, info, convert_value_to_lua(name, info, current), convert_value_to_lua(name, info, new), methods + name, + info, + convert_value_to_lua(name, info, current), + convert_value_to_lua(name, info, new), + methods ) end end)() @@ -518,11 +561,11 @@ local remove_value = (function() end, [OptionTypes.STRING] = function() - error("Subtraction not supported for strings.") + error('Subtraction not supported for strings.') end, [OptionTypes.ARRAY] = function(left, right) - if type(right) == "string" then + if type(right) == 'string' then remove_one_item(left, right) else for _, v in ipairs(right) do @@ -534,7 +577,7 @@ local remove_value = (function() end, [OptionTypes.MAP] = function(left, right) - if type(right) == "string" then + if type(right) == 'string' then left[right] = nil else for _, v in ipairs(right) do @@ -546,7 +589,7 @@ local remove_value = (function() end, [OptionTypes.SET] = function(left, right) - if type(right) == "string" then + if type(right) == 'string' then left[right] = nil else for _, v in ipairs(right) do @@ -567,9 +610,9 @@ local create_option_metatable = function(set_type) local set_mt, option_mt local make_option = function(name, value) - local info = assert(options_info[name], "Not a valid option name: " .. name) + local info = assert(options_info[name], 'Not a valid option name: ' .. name) - if type(value) == "table" and getmetatable(value) == option_mt then + if type(value) == 'table' and getmetatable(value) == option_mt then assert(name == value._name, "must be the same value, otherwise that's weird.") value = value._value @@ -584,9 +627,9 @@ local create_option_metatable = function(set_type) local scope if set_type == SET_TYPES.GLOBAL then - scope = "global" + scope = 'global' elseif set_type == SET_TYPES.LOCAL then - scope = "local" + scope = 'local' end option_mt = { @@ -594,7 +637,7 @@ local create_option_metatable = function(set_type) -- opt[my_option] = value _set = function(self) local value = convert_value_to_vim(self._name, self._info, self._value) - a.nvim_set_option_value(self._name, value, {scope = scope}) + a.nvim_set_option_value(self._name, value, { scope = scope }) return self end, @@ -625,13 +668,13 @@ local create_option_metatable = function(set_type) __sub = function(self, right) return make_option(self._name, remove_value(self._name, self._info, self._value, right)) - end + end, } option_mt.__index = option_mt set_mt = { __index = function(_, k) - return make_option(k, a.nvim_get_option_value(k, {scope = scope})) + return make_option(k, a.nvim_get_option_value(k, { scope = scope })) end, __newindex = function(_, k, v) diff --git a/runtime/lua/vim/compat.lua b/runtime/lua/vim/compat.lua index 168979bb95..2c9786d491 100644 --- a/runtime/lua/vim/compat.lua +++ b/runtime/lua/vim/compat.lua @@ -7,6 +7,6 @@ local lua_version = _VERSION:sub(-3) -if lua_version >= "5.2" then - unpack = table.unpack -- luacheck: ignore 121 143 +if lua_version >= '5.2' then + unpack = table.unpack -- luacheck: ignore 121 143 end diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index 80ce1f331d..bb12362234 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -28,7 +28,7 @@ local global_diagnostic_options = { M.handlers = setmetatable({}, { __newindex = function(t, name, handler) - vim.validate { handler = {handler, "t" } } + vim.validate({ handler = { handler, 't' } }) rawset(t, name, handler) if global_diagnostic_options[name] == nil then global_diagnostic_options[name] = true @@ -39,7 +39,7 @@ M.handlers = setmetatable({}, { -- Metatable that automatically creates an empty table when assigning to a missing key local bufnr_and_namespace_cacher_mt = { __index = function(t, bufnr) - assert(bufnr > 0, "Invalid buffer number") + assert(bufnr > 0, 'Invalid buffer number') t[bufnr] = {} return t[bufnr] end, @@ -47,11 +47,11 @@ local bufnr_and_namespace_cacher_mt = { local diagnostic_cache = setmetatable({}, { __index = function(t, bufnr) - assert(bufnr > 0, "Invalid buffer number") + assert(bufnr > 0, 'Invalid buffer number') vim.api.nvim_buf_attach(bufnr, false, { on_detach = function() rawset(t, bufnr, nil) -- clear cache - end + end, }) t[bufnr] = {} return t[bufnr] @@ -68,7 +68,7 @@ local all_namespaces = {} ---@private local function to_severity(severity) if type(severity) == 'string' then - return assert(M.severity[string.upper(severity)], string.format("Invalid severity: %s", severity)) + return assert(M.severity[string.upper(severity)], string.format('Invalid severity: %s', severity)) end return severity end @@ -79,15 +79,19 @@ local function filter_by_severity(severity, diagnostics) return diagnostics end - if type(severity) ~= "table" then + if type(severity) ~= 'table' then severity = to_severity(severity) - return vim.tbl_filter(function(t) return t.severity == severity end, diagnostics) + return vim.tbl_filter(function(t) + return t.severity == severity + end, diagnostics) end local min_severity = to_severity(severity.min) or M.severity.HINT local max_severity = to_severity(severity.max) or M.severity.ERROR - return vim.tbl_filter(function(t) return t.severity <= min_severity and t.severity >= max_severity end, diagnostics) + return vim.tbl_filter(function(t) + return t.severity <= min_severity and t.severity >= max_severity + end, diagnostics) end ---@private @@ -113,17 +117,17 @@ local function prefix_source(diagnostics) end local t = vim.deepcopy(d) - t.message = string.format("%s: %s", d.source, d.message) + t.message = string.format('%s: %s', d.source, d.message) return t end, diagnostics) end ---@private local function reformat_diagnostics(format, diagnostics) - vim.validate { - format = {format, 'f'}, - diagnostics = {diagnostics, 't'}, - } + vim.validate({ + format = { format, 'f' }, + diagnostics = { diagnostics, 't' }, + }) local formatted = vim.deepcopy(diagnostics) for _, diagnostic in ipairs(formatted) do @@ -135,11 +139,11 @@ end ---@private local function enabled_value(option, namespace) local ns = namespace and M.get_namespace(namespace) or {} - if ns.opts and type(ns.opts[option]) == "table" then + if ns.opts and type(ns.opts[option]) == 'table' then return ns.opts[option] end - if type(global_diagnostic_options[option]) == "table" then + if type(global_diagnostic_options[option]) == 'table' then return global_diagnostic_options[option] end @@ -162,7 +166,7 @@ local function resolve_optional_value(option, value, namespace, bufnr) elseif type(value) == 'table' then return value else - error("Unexpected option type: " .. vim.inspect(value)) + error('Unexpected option type: ' .. vim.inspect(value)) end end @@ -181,10 +185,10 @@ end -- Default diagnostic highlights local diagnostic_severities = { - [M.severity.ERROR] = { ctermfg = 1, guifg = "Red" }; - [M.severity.WARN] = { ctermfg = 3, guifg = "Orange" }; - [M.severity.INFO] = { ctermfg = 4, guifg = "LightBlue" }; - [M.severity.HINT] = { ctermfg = 7, guifg = "LightGrey" }; + [M.severity.ERROR] = { ctermfg = 1, guifg = 'Red' }, + [M.severity.WARN] = { ctermfg = 3, guifg = 'Orange' }, + [M.severity.INFO] = { ctermfg = 4, guifg = 'LightBlue' }, + [M.severity.HINT] = { ctermfg = 7, guifg = 'LightGrey' }, } -- Make a map from DiagnosticSeverity -> Highlight Name @@ -194,16 +198,16 @@ local function make_highlight_map(base_name) for k in pairs(diagnostic_severities) do local name = M.severity[k] name = name:sub(1, 1) .. name:sub(2):lower() - result[k] = "Diagnostic" .. base_name .. name + result[k] = 'Diagnostic' .. base_name .. name end return result end -local virtual_text_highlight_map = make_highlight_map("VirtualText") -local underline_highlight_map = make_highlight_map("Underline") -local floating_highlight_map = make_highlight_map("Floating") -local sign_highlight_map = make_highlight_map("Sign") +local virtual_text_highlight_map = make_highlight_map('VirtualText') +local underline_highlight_map = make_highlight_map('Underline') +local floating_highlight_map = make_highlight_map('Floating') +local sign_highlight_map = make_highlight_map('Sign') ---@private local define_default_signs = (function() @@ -244,7 +248,7 @@ local function is_disabled(namespace, bufnr) return true end - if type(diagnostic_disabled[bufnr]) == "table" then + if type(diagnostic_disabled[bufnr]) == 'table' then return diagnostic_disabled[bufnr][namespace] end return diagnostic_disabled[bufnr] @@ -271,8 +275,8 @@ end ---@private local function set_diagnostic_cache(namespace, bufnr, diagnostics) for _, diagnostic in ipairs(diagnostics) do - assert(diagnostic.lnum, "Diagnostic line number is required") - assert(diagnostic.col, "Diagnostic column is required") + assert(diagnostic.lnum, 'Diagnostic line number is required') + assert(diagnostic.col, 'Diagnostic column is required') diagnostic.severity = diagnostic.severity and to_severity(diagnostic.severity) or M.severity.ERROR diagnostic.end_lnum = diagnostic.end_lnum or diagnostic.lnum diagnostic.end_col = diagnostic.end_col or diagnostic.col @@ -285,7 +289,7 @@ end ---@private local function restore_extmarks(bufnr, last) for ns, extmarks in pairs(diagnostic_cache_extmarks[bufnr]) do - local extmarks_current = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {details = true}) + local extmarks_current = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, { details = true }) local found = {} for _, extmark in ipairs(extmarks_current) do -- nvim_buf_set_lines will move any extmark to the line after the last @@ -314,10 +318,17 @@ local function save_extmarks(namespace, bufnr) end, on_detach = function() diagnostic_cache_extmarks[bufnr] = nil - end}) + end, + }) diagnostic_attached_buffers[bufnr] = true end - diagnostic_cache_extmarks[bufnr][namespace] = vim.api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, {details = true}) + diagnostic_cache_extmarks[bufnr][namespace] = vim.api.nvim_buf_get_extmarks( + bufnr, + namespace, + 0, + -1, + { details = true } + ) end local registered_autocmds = {} @@ -325,11 +336,11 @@ local registered_autocmds = {} ---@private local function make_augroup_key(namespace, bufnr) local ns = M.get_namespace(namespace) - return string.format("DiagnosticInsertLeave:%s:%s", bufnr, ns.name) + return string.format('DiagnosticInsertLeave:%s:%s', bufnr, ns.name) end --- Table of autocmd events to fire the update for displaying new diagnostic information -local insert_leave_auto_cmds = { "InsertLeave", "CursorHoldI" } +local insert_leave_auto_cmds = { 'InsertLeave', 'CursorHoldI' } ---@private local function schedule_display(namespace, bufnr, args) @@ -337,15 +348,17 @@ local function schedule_display(namespace, bufnr, args) local key = make_augroup_key(namespace, bufnr) if not registered_autocmds[key] then - vim.cmd(string.format([[augroup %s + vim.cmd(string.format( + [[augroup %s au! autocmd %s lua vim.diagnostic._execute_scheduled_display(%s, %s) augroup END]], key, - table.concat(insert_leave_auto_cmds, ","), + table.concat(insert_leave_auto_cmds, ','), bufnr, namespace, - bufnr)) + bufnr + )) registered_autocmds[key] = true end end @@ -355,9 +368,12 @@ local function clear_scheduled_display(namespace, bufnr) local key = make_augroup_key(namespace, bufnr) if registered_autocmds[key] then - vim.cmd(string.format([[augroup %s + vim.cmd(string.format( + [[augroup %s au! - augroup END]], key)) + augroup END]], + key + )) registered_autocmds[key] = nil end end @@ -382,7 +398,7 @@ local function get_diagnostics(bufnr, opts, clamp) if not opts.lnum or d.lnum == opts.lnum then if clamp and vim.api.nvim_buf_is_loaded(b) then local line_count = buf_line_count[b] - 1 - if (d.lnum > line_count or d.end_lnum > line_count or d.lnum < 0 or d.end_lnum < 0) then + if d.lnum > line_count or d.end_lnum > line_count or d.lnum < 0 or d.end_lnum < 0 then d = vim.deepcopy(d) d.lnum = math.max(math.min(d.lnum, line_count), 0) d.end_lnum = math.max(math.min(d.end_lnum, line_count), 0) @@ -431,7 +447,7 @@ end local function set_list(loclist, opts) opts = opts or {} local open = vim.F.if_nil(opts.open, true) - local title = opts.title or "Diagnostics" + local title = opts.title or 'Diagnostics' local winnr = opts.winnr or 0 local bufnr if loclist then @@ -447,7 +463,7 @@ local function set_list(loclist, opts) vim.fn.setqflist({}, ' ', { title = title, items = items }) end if open then - vim.api.nvim_command(loclist and "lopen" or "botright copen") + vim.api.nvim_command(loclist and 'lopen' or 'botright copen') end end @@ -457,7 +473,7 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) bufnr = get_bufnr(bufnr) local wrap = vim.F.if_nil(opts.wrap, true) local line_count = vim.api.nvim_buf_line_count(bufnr) - local diagnostics = get_diagnostics(bufnr, vim.tbl_extend("keep", opts, {namespace = namespace}), true) + local diagnostics = get_diagnostics(bufnr, vim.tbl_extend('keep', opts, { namespace = namespace }), true) local line_diagnostics = diagnostic_lines(diagnostics) for i = 0, line_count do local offset = i * (search_forward and 1 or -1) @@ -469,14 +485,22 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) lnum = (lnum + line_count) % line_count end if line_diagnostics[lnum] and not vim.tbl_isempty(line_diagnostics[lnum]) then - local line_length = #vim.api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] + local line_length = #vim.api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] local sort_diagnostics, is_next if search_forward then - sort_diagnostics = function(a, b) return a.col < b.col end - is_next = function(d) return math.min(d.col, line_length - 1) > position[2] end + sort_diagnostics = function(a, b) + return a.col < b.col + end + is_next = function(d) + return math.min(d.col, line_length - 1) > position[2] + end else - sort_diagnostics = function(a, b) return a.col > b.col end - is_next = function(d) return math.min(d.col, line_length - 1) < position[2] end + sort_diagnostics = function(a, b) + return a.col > b.col + end + is_next = function(d) + return math.min(d.col, line_length - 1) < position[2] + end end table.sort(line_diagnostics[lnum], sort_diagnostics) if i == 0 then @@ -500,28 +524,26 @@ local function diagnostic_move_pos(opts, pos) local win_id = opts.win_id or vim.api.nvim_get_current_win() if not pos then - vim.api.nvim_echo({{"No more valid diagnostics to move to", "WarningMsg"}}, true, {}) + vim.api.nvim_echo({ { 'No more valid diagnostics to move to', 'WarningMsg' } }, true, {}) return end vim.api.nvim_win_call(win_id, function() -- Save position in the window's jumplist vim.cmd("normal! m'") - vim.api.nvim_win_set_cursor(win_id, {pos[1] + 1, pos[2]}) + vim.api.nvim_win_set_cursor(win_id, { pos[1] + 1, pos[2] }) -- Open folds under the cursor - vim.cmd("normal! zv") + vim.cmd('normal! zv') end) if float then - local float_opts = type(float) == "table" and float or {} + local float_opts = type(float) == 'table' and float or {} vim.schedule(function() - M.open_float( - vim.tbl_extend("keep", float_opts, { - bufnr = vim.api.nvim_win_get_buf(win_id), - scope = "cursor", - focus = false, - }) - ) + M.open_float(vim.tbl_extend('keep', float_opts, { + bufnr = vim.api.nvim_win_get_buf(win_id), + scope = 'cursor', + focus = false, + })) end) end end @@ -599,10 +621,10 @@ end ---@param namespace number|nil Update the options for the given namespace. When omitted, update the --- global diagnostic options. function M.config(opts, namespace) - vim.validate { + vim.validate({ opts = { opts, 't', true }, namespace = { namespace, 'n', true }, - } + }) local t if namespace then @@ -645,16 +667,16 @@ end ---@param diagnostics table A list of diagnostic items |diagnostic-structure| ---@param opts table|nil Display options to pass to |vim.diagnostic.show()| function M.set(namespace, bufnr, diagnostics, opts) - vim.validate { - namespace = {namespace, 'n'}, - bufnr = {bufnr, 'n'}, + vim.validate({ + namespace = { namespace, 'n' }, + bufnr = { bufnr, 'n' }, diagnostics = { diagnostics, vim.tbl_islist, - "a list of diagnostics", + 'a list of diagnostics', }, - opts = {opts, 't', true}, - } + opts = { opts, 't', true }, + }) bufnr = get_bufnr(bufnr) @@ -668,7 +690,7 @@ function M.set(namespace, bufnr, diagnostics, opts) M.show(namespace, bufnr, nil, opts) end - vim.api.nvim_exec_autocmds("DiagnosticChanged", { + vim.api.nvim_exec_autocmds('DiagnosticChanged', { modeline = false, buffer = bufnr, }) @@ -679,7 +701,7 @@ end ---@param namespace number Diagnostic namespace ---@return table Namespace metadata function M.get_namespace(namespace) - vim.validate { namespace = { namespace, 'n' } } + vim.validate({ namespace = { namespace, 'n' } }) if not all_namespaces[namespace] then local name for k, v in pairs(vim.api.nvim_get_namespaces()) do @@ -689,7 +711,7 @@ function M.get_namespace(namespace) end end - assert(name, "namespace does not exist or is anonymous") + assert(name, 'namespace does not exist or is anonymous') all_namespaces[namespace] = { name = name, @@ -717,10 +739,10 @@ end --- - severity: See |diagnostic-severity|. ---@return table A list of diagnostic items |diagnostic-structure|. function M.get(bufnr, opts) - vim.validate { + vim.validate({ bufnr = { bufnr, 'n', true }, opts = { opts, 't', true }, - } + }) return get_diagnostics(bufnr, opts, false) end @@ -749,16 +771,13 @@ function M.get_prev_pos(opts) return false end - return {prev.lnum, prev.col} + return { prev.lnum, prev.col } end --- Move to the previous diagnostic in the current buffer. ---@param opts table See |vim.diagnostic.goto_next()| function M.goto_prev(opts) - return diagnostic_move_pos( - opts, - M.get_prev_pos(opts) - ) + return diagnostic_move_pos(opts, M.get_prev_pos(opts)) end --- Get the next diagnostic closest to the cursor position. @@ -785,7 +804,7 @@ function M.get_next_pos(opts) return false end - return {next.lnum, next.col} + return { next.lnum, next.col } end --- Move to the next diagnostic. @@ -803,24 +822,21 @@ end --- the "scope" option). --- - win_id: (number, default 0) Window ID function M.goto_next(opts) - return diagnostic_move_pos( - opts, - M.get_next_pos(opts) - ) + return diagnostic_move_pos(opts, M.get_next_pos(opts)) end M.handlers.signs = { show = function(namespace, bufnr, diagnostics, opts) - vim.validate { - namespace = {namespace, 'n'}, - bufnr = {bufnr, 'n'}, + vim.validate({ + namespace = { namespace, 'n' }, + bufnr = { bufnr, 'n' }, diagnostics = { diagnostics, vim.tbl_islist, - "a list of diagnostics", + 'a list of diagnostics', }, - opts = {opts, 't', true}, - } + opts = { opts, 't', true }, + }) bufnr = get_bufnr(bufnr) opts = opts or {} @@ -835,7 +851,7 @@ M.handlers.signs = { local priority = opts.signs and opts.signs.priority or 10 local get_priority if opts.severity_sort then - if type(opts.severity_sort) == "table" and opts.severity_sort.reverse then + if type(opts.severity_sort) == 'table' and opts.severity_sort.reverse then get_priority = function(severity) return priority + (severity - vim.diagnostic.severity.ERROR) end @@ -852,43 +868,37 @@ M.handlers.signs = { local ns = M.get_namespace(namespace) if not ns.user_data.sign_group then - ns.user_data.sign_group = string.format("vim.diagnostic.%s", ns.name) + ns.user_data.sign_group = string.format('vim.diagnostic.%s', ns.name) end local sign_group = ns.user_data.sign_group for _, diagnostic in ipairs(diagnostics) do - vim.fn.sign_place( - 0, - sign_group, - sign_highlight_map[diagnostic.severity], - bufnr, - { - priority = get_priority(diagnostic.severity), - lnum = diagnostic.lnum + 1 - } - ) + vim.fn.sign_place(0, sign_group, sign_highlight_map[diagnostic.severity], bufnr, { + priority = get_priority(diagnostic.severity), + lnum = diagnostic.lnum + 1, + }) end end, hide = function(namespace, bufnr) local ns = M.get_namespace(namespace) if ns.user_data.sign_group then - vim.fn.sign_unplace(ns.user_data.sign_group, {buffer=bufnr}) + vim.fn.sign_unplace(ns.user_data.sign_group, { buffer = bufnr }) end end, } M.handlers.underline = { show = function(namespace, bufnr, diagnostics, opts) - vim.validate { - namespace = {namespace, 'n'}, - bufnr = {bufnr, 'n'}, + vim.validate({ + namespace = { namespace, 'n' }, + bufnr = { bufnr, 'n' }, diagnostics = { diagnostics, vim.tbl_islist, - "a list of diagnostics", + 'a list of diagnostics', }, - opts = {opts, 't', true}, - } + opts = { opts, 't', true }, + }) bufnr = get_bufnr(bufnr) opts = opts or {} @@ -899,7 +909,7 @@ M.handlers.underline = { local ns = M.get_namespace(namespace) if not ns.user_data.underline_ns then - ns.user_data.underline_ns = vim.api.nvim_create_namespace("") + ns.user_data.underline_ns = vim.api.nvim_create_namespace('') end local underline_ns = ns.user_data.underline_ns @@ -928,21 +938,21 @@ M.handlers.underline = { diagnostic_cache_extmarks[bufnr][ns.user_data.underline_ns] = {} vim.api.nvim_buf_clear_namespace(bufnr, ns.user_data.underline_ns, 0, -1) end - end + end, } M.handlers.virtual_text = { show = function(namespace, bufnr, diagnostics, opts) - vim.validate { - namespace = {namespace, 'n'}, - bufnr = {bufnr, 'n'}, + vim.validate({ + namespace = { namespace, 'n' }, + bufnr = { bufnr, 'n' }, diagnostics = { diagnostics, vim.tbl_islist, - "a list of diagnostics", + 'a list of diagnostics', }, - opts = {opts, 't', true}, - } + opts = { opts, 't', true }, + }) bufnr = get_bufnr(bufnr) opts = opts or {} @@ -952,10 +962,7 @@ M.handlers.virtual_text = { if opts.virtual_text.format then diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics) end - if - opts.virtual_text.source - and (opts.virtual_text.source ~= "if_many" or count_sources(bufnr) > 1) - then + if opts.virtual_text.source and (opts.virtual_text.source ~= 'if_many' or count_sources(bufnr) > 1) then diagnostics = prefix_source(diagnostics) end if opts.virtual_text.severity then @@ -965,7 +972,7 @@ M.handlers.virtual_text = { local ns = M.get_namespace(namespace) if not ns.user_data.virt_text_ns then - ns.user_data.virt_text_ns = vim.api.nvim_create_namespace("") + ns.user_data.virt_text_ns = vim.api.nvim_create_namespace('') end local virt_text_ns = ns.user_data.virt_text_ns @@ -978,7 +985,7 @@ M.handlers.virtual_text = { if virt_texts then vim.api.nvim_buf_set_extmark(bufnr, virt_text_ns, line, 0, { - hl_mode = "combine", + hl_mode = 'combine', virt_text = virt_texts, }) end @@ -1006,27 +1013,24 @@ function M._get_virt_text_chunks(line_diags, opts) end opts = opts or {} - local prefix = opts.prefix or "■" + local prefix = opts.prefix or '■' local spacing = opts.spacing or 4 -- Create a little more space between virtual text and contents - local virt_texts = {{string.rep(" ", spacing)}} + local virt_texts = { { string.rep(' ', spacing) } } for i = 1, #line_diags - 1 do - table.insert(virt_texts, {prefix, virtual_text_highlight_map[line_diags[i].severity]}) + table.insert(virt_texts, { prefix, virtual_text_highlight_map[line_diags[i].severity] }) end local last = line_diags[#line_diags] -- TODO(tjdevries): Allow different servers to be shown first somehow? -- TODO(tjdevries): Display server name associated with these? if last.message then - table.insert( - virt_texts, - { - string.format("%s %s", prefix, last.message:gsub("\r", ""):gsub("\n", " ")), - virtual_text_highlight_map[last.severity] - } - ) + table.insert(virt_texts, { + string.format('%s %s', prefix, last.message:gsub('\r', ''):gsub('\n', ' ')), + virtual_text_highlight_map[last.severity], + }) return virt_texts end @@ -1066,14 +1070,14 @@ end ---@param bufnr number|nil Buffer number, or 0 for current buffer. When --- omitted, hide diagnostics in all buffers. function M.hide(namespace, bufnr) - vim.validate { + vim.validate({ namespace = { namespace, 'n', true }, bufnr = { bufnr, 'n', true }, - } + }) - local buffers = bufnr and {get_bufnr(bufnr)} or vim.tbl_keys(diagnostic_cache) + local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache) for _, iter_bufnr in ipairs(buffers) do - local namespaces = namespace and {namespace} or vim.tbl_keys(diagnostic_cache[iter_bufnr]) + local namespaces = namespace and { namespace } or vim.tbl_keys(diagnostic_cache[iter_bufnr]) for _, iter_namespace in ipairs(namespaces) do for _, handler in pairs(M.handlers) do if handler.hide then @@ -1098,19 +1102,21 @@ end --- or {bufnr} is nil. ---@param opts table|nil Display options. See |vim.diagnostic.config()|. function M.show(namespace, bufnr, diagnostics, opts) - vim.validate { + vim.validate({ namespace = { namespace, 'n', true }, bufnr = { bufnr, 'n', true }, diagnostics = { diagnostics, - function(v) return v == nil or vim.tbl_islist(v) end, - "a list of diagnostics", + function(v) + return v == nil or vim.tbl_islist(v) + end, + 'a list of diagnostics', }, opts = { opts, 't', true }, - } + }) if not bufnr or not namespace then - assert(not diagnostics, "Cannot show diagnostics without a buffer and namespace") + assert(not diagnostics, 'Cannot show diagnostics without a buffer and namespace') if not bufnr then for iter_bufnr in pairs(diagnostic_cache) do M.show(namespace, iter_bufnr, nil, opts) @@ -1131,7 +1137,7 @@ function M.show(namespace, bufnr, diagnostics, opts) M.hide(namespace, bufnr) - diagnostics = diagnostics or get_diagnostics(bufnr, {namespace=namespace}, true) + diagnostics = diagnostics or get_diagnostics(bufnr, { namespace = namespace }, true) if not diagnostics or vim.tbl_isempty(diagnostics) then return @@ -1150,10 +1156,14 @@ function M.show(namespace, bufnr, diagnostics, opts) end if vim.F.if_nil(opts.severity_sort, false) then - if type(opts.severity_sort) == "table" and opts.severity_sort.reverse then - table.sort(diagnostics, function(a, b) return a.severity < b.severity end) + if type(opts.severity_sort) == 'table' and opts.severity_sort.reverse then + table.sort(diagnostics, function(a, b) + return a.severity < b.severity + end) else - table.sort(diagnostics, function(a, b) return a.severity > b.severity end) + table.sort(diagnostics, function(a, b) + return a.severity > b.severity + end) end end @@ -1209,13 +1219,13 @@ end function M.open_float(opts, ...) -- Support old (bufnr, opts) signature local bufnr - if opts == nil or type(opts) == "number" then + if opts == nil or type(opts) == 'number' then bufnr = opts opts = ... else - vim.validate { + vim.validate({ opts = { opts, 't', true }, - } + }) end opts = opts or {} @@ -1228,41 +1238,39 @@ function M.open_float(opts, ...) -- with its `opts` table which also includes "keyword" parameters. So we create a dedicated -- options table that inherits missing keys from the global configuration before resolving. local t = global_diagnostic_options.float - local float_opts = vim.tbl_extend("keep", opts, type(t) == "table" and t or {}) + local float_opts = vim.tbl_extend('keep', opts, type(t) == 'table' and t or {}) opts = get_resolved_options({ float = float_opts }, nil, bufnr).float end - local scope = ({l = "line", c = "cursor", b = "buffer"})[opts.scope] or opts.scope or "line" + local scope = ({ l = 'line', c = 'cursor', b = 'buffer' })[opts.scope] or opts.scope or 'line' local lnum, col - if scope == "line" or scope == "cursor" then + if scope == 'line' or scope == 'cursor' then if not opts.pos then local pos = vim.api.nvim_win_get_cursor(0) lnum = pos[1] - 1 col = pos[2] - elseif type(opts.pos) == "number" then + elseif type(opts.pos) == 'number' then lnum = opts.pos - elseif type(opts.pos) == "table" then + elseif type(opts.pos) == 'table' then lnum, col = unpack(opts.pos) else error("Invalid value for option 'pos'") end - elseif scope ~= "buffer" then + elseif scope ~= 'buffer' then error("Invalid value for option 'scope'") end local diagnostics = get_diagnostics(bufnr, opts, true) - if scope == "line" then + if scope == 'line' then diagnostics = vim.tbl_filter(function(d) return d.lnum == lnum end, diagnostics) - elseif scope == "cursor" then + elseif scope == 'cursor' then -- LSP servers can send diagnostics with `end_col` past the length of the line local line_length = #vim.api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] diagnostics = vim.tbl_filter(function(d) - return d.lnum == lnum - and math.min(d.col, line_length - 1) <= col - and (d.end_col >= col or d.end_lnum > lnum) + return d.lnum == lnum and math.min(d.col, line_length - 1) <= col and (d.end_col >= col or d.end_lnum > lnum) end, diagnostics) end @@ -1272,29 +1280,39 @@ function M.open_float(opts, ...) local severity_sort = vim.F.if_nil(opts.severity_sort, global_diagnostic_options.severity_sort) if severity_sort then - if type(severity_sort) == "table" and severity_sort.reverse then - table.sort(diagnostics, function(a, b) return a.severity > b.severity end) + if type(severity_sort) == 'table' and severity_sort.reverse then + table.sort(diagnostics, function(a, b) + return a.severity > b.severity + end) else - table.sort(diagnostics, function(a, b) return a.severity < b.severity end) + table.sort(diagnostics, function(a, b) + return a.severity < b.severity + end) end end local lines = {} local highlights = {} - local header = if_nil(opts.header, "Diagnostics:") + local header = if_nil(opts.header, 'Diagnostics:') if header then - vim.validate { header = { header, function(v) - return type(v) == "string" or type(v) == "table" - end, "'string' or 'table'" } } - if type(header) == "table" then + vim.validate({ + header = { + header, + function(v) + return type(v) == 'string' or type(v) == 'table' + end, + "'string' or 'table'", + }, + }) + if type(header) == 'table' then -- Don't insert any lines for an empty string - if string.len(if_nil(header[1], "")) > 0 then + if string.len(if_nil(header[1], '')) > 0 then table.insert(lines, header[1]) - table.insert(highlights, {0, header[2] or "Bold"}) + table.insert(highlights, { 0, header[2] or 'Bold' }) end elseif #header > 0 then table.insert(lines, header) - table.insert(highlights, {0, "Bold"}) + table.insert(highlights, { 0, 'Bold' }) end end @@ -1302,38 +1320,44 @@ function M.open_float(opts, ...) diagnostics = reformat_diagnostics(opts.format, diagnostics) end - if opts.source and (opts.source ~= "if_many" or count_sources(bufnr) > 1) then + if opts.source and (opts.source ~= 'if_many' or count_sources(bufnr) > 1) then diagnostics = prefix_source(diagnostics) end - local prefix_opt = if_nil(opts.prefix, (scope == "cursor" and #diagnostics <= 1) and "" or function(_, i) - return string.format("%d. ", i) + local prefix_opt = if_nil(opts.prefix, (scope == 'cursor' and #diagnostics <= 1) and '' or function(_, i) + return string.format('%d. ', i) end) local prefix, prefix_hl_group if prefix_opt then - vim.validate { prefix = { prefix_opt, function(v) - return type(v) == "string" or type(v) == "table" or type(v) == "function" - end, "'string' or 'table' or 'function'" } } - if type(prefix_opt) == "string" then - prefix, prefix_hl_group = prefix_opt, "NormalFloat" - elseif type(prefix_opt) == "table" then - prefix, prefix_hl_group = prefix_opt[1] or "", prefix_opt[2] or "NormalFloat" + vim.validate({ + prefix = { + prefix_opt, + function(v) + return type(v) == 'string' or type(v) == 'table' or type(v) == 'function' + end, + "'string' or 'table' or 'function'", + }, + }) + if type(prefix_opt) == 'string' then + prefix, prefix_hl_group = prefix_opt, 'NormalFloat' + elseif type(prefix_opt) == 'table' then + prefix, prefix_hl_group = prefix_opt[1] or '', prefix_opt[2] or 'NormalFloat' end end for i, diagnostic in ipairs(diagnostics) do - if prefix_opt and type(prefix_opt) == "function" then + if prefix_opt and type(prefix_opt) == 'function' then prefix, prefix_hl_group = prefix_opt(diagnostic, i, #diagnostics) - prefix, prefix_hl_group = prefix or "", prefix_hl_group or "NormalFloat" + prefix, prefix_hl_group = prefix or '', prefix_hl_group or 'NormalFloat' end local hiname = floating_highlight_map[diagnostic.severity] local message_lines = vim.split(diagnostic.message, '\n') - table.insert(lines, prefix..message_lines[1]) - table.insert(highlights, {#prefix, hiname, prefix_hl_group}) + table.insert(lines, prefix .. message_lines[1]) + table.insert(highlights, { #prefix, hiname, prefix_hl_group }) for j = 2, #message_lines do table.insert(lines, string.rep(' ', #prefix) .. message_lines[j]) - table.insert(highlights, {0, hiname}) + table.insert(highlights, { 0, hiname }) end end @@ -1345,9 +1369,9 @@ function M.open_float(opts, ...) for i, hi in ipairs(highlights) do local prefixlen, hiname, prefix_hiname = unpack(hi) if prefix_hiname then - vim.api.nvim_buf_add_highlight(float_bufnr, -1, prefix_hiname, i-1, 0, prefixlen) + vim.api.nvim_buf_add_highlight(float_bufnr, -1, prefix_hiname, i - 1, 0, prefixlen) end - vim.api.nvim_buf_add_highlight(float_bufnr, -1, hiname, i-1, prefixlen, -1) + vim.api.nvim_buf_add_highlight(float_bufnr, -1, hiname, i - 1, prefixlen, -1) end return float_bufnr, winnr @@ -1365,20 +1389,20 @@ end ---@param bufnr number|nil Remove diagnostics for the given buffer. When omitted, --- diagnostics are removed for all buffers. function M.reset(namespace, bufnr) - vim.validate { - namespace = {namespace, 'n', true}, - bufnr = {bufnr, 'n', true}, - } + vim.validate({ + namespace = { namespace, 'n', true }, + bufnr = { bufnr, 'n', true }, + }) - local buffers = bufnr and {get_bufnr(bufnr)} or vim.tbl_keys(diagnostic_cache) + local buffers = bufnr and { get_bufnr(bufnr) } or vim.tbl_keys(diagnostic_cache) for _, iter_bufnr in ipairs(buffers) do - local namespaces = namespace and {namespace} or vim.tbl_keys(diagnostic_cache[iter_bufnr]) + local namespaces = namespace and { namespace } or vim.tbl_keys(diagnostic_cache[iter_bufnr]) for _, iter_namespace in ipairs(namespaces) do diagnostic_cache[iter_bufnr][iter_namespace] = nil M.hide(iter_namespace, iter_bufnr) end - vim.api.nvim_exec_autocmds("DiagnosticChanged", { + vim.api.nvim_exec_autocmds('DiagnosticChanged', { modeline = false, buffer = iter_bufnr, }) @@ -1414,7 +1438,7 @@ end --- omitted, disable diagnostics in all buffers. ---@param namespace number|nil Only disable diagnostics for the given namespace. function M.disable(bufnr, namespace) - vim.validate { bufnr = {bufnr, 'n', true}, namespace = {namespace, 'n', true} } + vim.validate({ bufnr = { bufnr, 'n', true }, namespace = { namespace, 'n', true } }) if bufnr == nil then if namespace == nil then -- Disable everything (including as yet non-existing buffers and @@ -1422,7 +1446,9 @@ function M.disable(bufnr, namespace) -- its metatable to always return true. This metatable is removed -- in enable() diagnostic_disabled = setmetatable({}, { - __index = function() return true end, + __index = function() + return true + end, }) else local ns = M.get_namespace(namespace) @@ -1433,7 +1459,7 @@ function M.disable(bufnr, namespace) if namespace == nil then diagnostic_disabled[bufnr] = true else - if type(diagnostic_disabled[bufnr]) ~= "table" then + if type(diagnostic_disabled[bufnr]) ~= 'table' then diagnostic_disabled[bufnr] = {} end diagnostic_disabled[bufnr][namespace] = true @@ -1449,7 +1475,7 @@ end --- omitted, enable diagnostics in all buffers. ---@param namespace number|nil Only enable diagnostics for the given namespace. function M.enable(bufnr, namespace) - vim.validate { bufnr = {bufnr, 'n', true}, namespace = {namespace, 'n', true} } + vim.validate({ bufnr = { bufnr, 'n', true }, namespace = { namespace, 'n', true } }) if bufnr == nil then if namespace == nil then -- Enable everything by setting diagnostic_disabled to an empty table @@ -1463,7 +1489,7 @@ function M.enable(bufnr, namespace) if namespace == nil then diagnostic_disabled[bufnr] = nil else - if type(diagnostic_disabled[bufnr]) ~= "table" then + if type(diagnostic_disabled[bufnr]) ~= 'table' then return end diagnostic_disabled[bufnr][namespace] = nil @@ -1500,33 +1526,33 @@ end --- ERROR. ---@return diagnostic |diagnostic-structure| or `nil` if {pat} fails to match {str}. function M.match(str, pat, groups, severity_map, defaults) - vim.validate { + vim.validate({ str = { str, 's' }, pat = { pat, 's' }, groups = { groups, 't' }, severity_map = { severity_map, 't', true }, defaults = { defaults, 't', true }, - } + }) severity_map = severity_map or M.severity local diagnostic = {} - local matches = {string.match(str, pat)} + local matches = { string.match(str, pat) } if vim.tbl_isempty(matches) then return end for i, match in ipairs(matches) do local field = groups[i] - if field == "severity" then + if field == 'severity' then match = severity_map[match] - elseif field == "lnum" or field == "end_lnum" or field == "col" or field == "end_col" then + elseif field == 'lnum' or field == 'end_lnum' or field == 'col' or field == 'end_col' then match = assert(tonumber(match)) - 1 end diagnostic[field] = match end - diagnostic = vim.tbl_extend("keep", diagnostic, defaults or {}) + diagnostic = vim.tbl_extend('keep', diagnostic, defaults or {}) diagnostic.severity = diagnostic.severity or M.severity.ERROR diagnostic.col = diagnostic.col or 0 diagnostic.end_lnum = diagnostic.end_lnum or diagnostic.lnum @@ -1547,13 +1573,13 @@ local errlist_type_map = { ---@param diagnostics table List of diagnostics |diagnostic-structure|. ---@return array of quickfix list items |setqflist-what| function M.toqflist(diagnostics) - vim.validate { + vim.validate({ diagnostics = { diagnostics, vim.tbl_islist, - "a list of diagnostics", + 'a list of diagnostics', }, - } + }) local list = {} for _, v in ipairs(diagnostics) do @@ -1584,13 +1610,13 @@ end --- |getloclist()|. ---@return array of diagnostics |diagnostic-structure| function M.fromqflist(list) - vim.validate { + vim.validate({ list = { list, vim.tbl_islist, - "a list of quickfix items", + 'a list of quickfix items', }, - } + }) local diagnostics = {} for _, item in ipairs(list) do @@ -1599,7 +1625,7 @@ function M.fromqflist(list) local col = math.max(0, item.col - 1) local end_lnum = item.end_lnum > 0 and (item.end_lnum - 1) or lnum local end_col = item.end_col > 0 and (item.end_col - 1) or col - local severity = item.type ~= "" and M.severity[item.type] or M.severity.ERROR + local severity = item.type ~= '' and M.severity[item.type] or M.severity.ERROR table.insert(diagnostics, { bufnr = item.bufnr, lnum = lnum, diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 32f4f825c1..fed0231ae9 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -4,866 +4,1007 @@ local M = {} ---@private local function starsetf(ft) - return {function(path) - if not vim.g.fg_ignore_pat then - return ft - end + return { + function(path) + if not vim.g.fg_ignore_pat then + return ft + end - local re = vim.regex(vim.g.fg_ignore_pat) - if re:match_str(path) then - return ft - end - end, { - -- Starset matches should always have lowest priority - priority = -math.huge, - }} + local re = vim.regex(vim.g.fg_ignore_pat) + if re:match_str(path) then + return ft + end + end, + { + -- Starset matches should always have lowest priority + priority = -math.huge, + }, + } end ---@private local function getline(bufnr, lnum) - return api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1] or "" + return api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, false)[1] or '' end -- Filetypes based on file extension -- luacheck: push no unused args local extension = { -- BEGIN EXTENSION - ["8th"] = "8th", - ["a65"] = "a65", - aap = "aap", - abap = "abap", - abc = "abc", - abl = "abel", - wrm = "acedb", - ads = "ada", - ada = "ada", - gpr = "ada", - adb = "ada", - tdf = "ahdl", - aidl = "aidl", - aml = "aml", - run = "ampl", - scpt = "applescript", - ino = "arduino", - pde = "arduino", - art = "art", - asciidoc = "asciidoc", - adoc = "asciidoc", - ["asn1"] = "asn", - asn = "asn", - atl = "atlas", - as = "atlas", - ahk = "autohotkey", - ["au3"] = "autoit", - ave = "ave", - gawk = "awk", - awk = "awk", - ref = "b", - imp = "b", - mch = "b", - bc = "bc", - bdf = "bdf", - beancount = "beancount", - bib = "bib", - bicep = "bicep", - bl = "blank", - bsdl = "bsdl", - bst = "bst", - bzl = "bzl", - bazel = "bzl", - BUILD = "bzl", - qc = "c", - cabal = "cabal", - cdl = "cdl", - toc = "cdrtoc", - cfc = "cf", - cfm = "cf", - cfi = "cf", - hgrc = "cfg", - chf = "ch", - chai = "chaiscript", - chs = "chaskell", - chopro = "chordpro", - crd = "chordpro", - crdpro = "chordpro", - cho = "chordpro", - chordpro = "chordpro", - eni = "cl", - dcl = "clean", - icl = "clean", - cljx = "clojure", - clj = "clojure", - cljc = "clojure", - cljs = "clojure", - cook = "cook", - cmake = "cmake", - cmod = "cmod", - lib = "cobol", - cob = "cobol", - cbl = "cobol", - atg = "coco", - recipe = "conaryrecipe", + ['8th'] = '8th', + ['a65'] = 'a65', + aap = 'aap', + abap = 'abap', + abc = 'abc', + abl = 'abel', + wrm = 'acedb', + ads = 'ada', + ada = 'ada', + gpr = 'ada', + adb = 'ada', + tdf = 'ahdl', + aidl = 'aidl', + aml = 'aml', + run = 'ampl', + scpt = 'applescript', + ino = 'arduino', + pde = 'arduino', + art = 'art', + asciidoc = 'asciidoc', + adoc = 'asciidoc', + ['asn1'] = 'asn', + asn = 'asn', + atl = 'atlas', + as = 'atlas', + ahk = 'autohotkey', + ['au3'] = 'autoit', + ave = 'ave', + gawk = 'awk', + awk = 'awk', + ref = 'b', + imp = 'b', + mch = 'b', + bc = 'bc', + bdf = 'bdf', + beancount = 'beancount', + bib = 'bib', + bicep = 'bicep', + bl = 'blank', + bsdl = 'bsdl', + bst = 'bst', + bzl = 'bzl', + bazel = 'bzl', + BUILD = 'bzl', + qc = 'c', + cabal = 'cabal', + cdl = 'cdl', + toc = 'cdrtoc', + cfc = 'cf', + cfm = 'cf', + cfi = 'cf', + hgrc = 'cfg', + chf = 'ch', + chai = 'chaiscript', + chs = 'chaskell', + chopro = 'chordpro', + crd = 'chordpro', + crdpro = 'chordpro', + cho = 'chordpro', + chordpro = 'chordpro', + eni = 'cl', + dcl = 'clean', + icl = 'clean', + cljx = 'clojure', + clj = 'clojure', + cljc = 'clojure', + cljs = 'clojure', + cook = 'cook', + cmake = 'cmake', + cmod = 'cmod', + lib = 'cobol', + cob = 'cobol', + cbl = 'cobol', + atg = 'coco', + recipe = 'conaryrecipe', hook = function(path, bufnr) if getline(bufnr, 1) == '[Trigger]' then - return "conf" + return 'conf' end end, - mklx = "context", - mkiv = "context", - mkii = "context", - mkxl = "context", - mkvi = "context", - moc = "cpp", - hh = "cpp", - tlh = "cpp", - inl = "cpp", - ipp = "cpp", - ["c++"] = "cpp", - C = "cpp", - cxx = "cpp", - H = "cpp", - tcc = "cpp", - hxx = "cpp", - hpp = "cpp", + mklx = 'context', + mkiv = 'context', + mkii = 'context', + mkxl = 'context', + mkvi = 'context', + moc = 'cpp', + hh = 'cpp', + tlh = 'cpp', + inl = 'cpp', + ipp = 'cpp', + ['c++'] = 'cpp', + C = 'cpp', + cxx = 'cpp', + H = 'cpp', + tcc = 'cpp', + hxx = 'cpp', + hpp = 'cpp', cpp = function(path, bufnr) if vim.g.cynlib_syntax_for_cc then - return "cynlib" + return 'cynlib' end - return "cpp" + return 'cpp' end, cc = function(path, bufnr) if vim.g.cynlib_syntax_for_cc then - return "cynlib" + return 'cynlib' end - return "cpp" - end, - crm = "crm", - csx = "cs", - cs = "cs", - csc = "csc", - csdl = "csdl", - cshtml = "html", - fdr = "csp", - csp = "csp", - css = "css", - con = "cterm", - feature = "cucumber", - cuh = "cuda", - cu = "cuda", - pld = "cupl", - si = "cuplsim", - cyn = "cynpp", - dart = "dart", - drt = "dart", - ds = "datascript", - dcd = "dcd", - def = "def", - desc = "desc", - directory = "desktop", - desktop = "desktop", - diff = "diff", - rej = "diff", - Dockerfile = "dockerfile", - bat = "dosbatch", - wrap = "dosini", - ini = "dosini", - dot = "dot", - gv = "dot", - drac = "dracula", - drc = "dracula", - dtd = "dtd", - dts = "dts", - dtsi = "dts", - dylan = "dylan", - intr = "dylanintr", - lid = "dylanlid", - ecd = "ecd", - eex = "eelixir", - leex = "eelixir", - exs = "elixir", - elm = "elm", - elv = "elvish", - epp = "epuppet", - erl = "erlang", - hrl = "erlang", - yaws = "erlang", - erb = "eruby", - rhtml = "eruby", - ec = "esqlc", - EC = "esqlc", - strl = "esterel", - exp = "expect", - factor = "factor", - fal = "falcon", - fan = "fan", - fwt = "fan", - fnl = "fennel", - ["m4gl"] = "fgl", - ["4gl"] = "fgl", - ["4gh"] = "fgl", - fish = "fish", - focexec = "focexec", - fex = "focexec", - fth = "forth", - ft = "forth", - FOR = "fortran", - ["f77"] = "fortran", - ["f03"] = "fortran", - fortran = "fortran", - ["F95"] = "fortran", - ["f90"] = "fortran", - ["F03"] = "fortran", - fpp = "fortran", - FTN = "fortran", - ftn = "fortran", - ["for"] = "fortran", - ["F90"] = "fortran", - ["F77"] = "fortran", - ["f95"] = "fortran", - FPP = "fortran", - f = "fortran", - F = "fortran", - ["F08"] = "fortran", - ["f08"] = "fortran", - fpc = "fpcmake", - fsl = "framescript", - fb = "freebasic", - fsi = "fsharp", - fsx = "fsharp", - fusion = "fusion", - gdb = "gdb", - gdmo = "gdmo", - mo = "gdmo", - tres = "gdresource", - tscn = "gdresource", - gd = "gdscript", - ged = "gedcom", - gmi = "gemtext", - gemini = "gemtext", - gift = "gift", - gleam = "gleam", - glsl = "glsl", - gpi = "gnuplot", - gnuplot = "gnuplot", - go = "go", - gp = "gp", - gs = "grads", - gql = "graphql", - graphql = "graphql", - graphqls = "graphql", - gretl = "gretl", - gradle = "groovy", - groovy = "groovy", - gsp = "gsp", - gjs = "javascript.glimmer", - gts = "typescript.glimmer", - hack = "hack", - hackpartial = "hack", - haml = "haml", - hsm = "hamster", - hbs = "handlebars", - ["hs-boot"] = "haskell", - hsig = "haskell", - hsc = "haskell", - hs = "haskell", - ht = "haste", - htpp = "hastepreproc", - hb = "hb", - sum = "hercules", - errsum = "hercules", - ev = "hercules", - vc = "hercules", - hcl = "hcl", - heex = "heex", - hex = "hex", - ["h32"] = "hex", - hjson = "hjson", - hog = "hog", - hws = "hollywood", - htt = "httest", - htb = "httest", - iba = "ibasic", - ibi = "ibasic", - icn = "icon", - inf = "inform", - INF = "inform", - ii = "initng", - iss = "iss", - mst = "ist", - ist = "ist", - ijs = "j", - JAL = "jal", - jal = "jal", - jpr = "jam", - jpl = "jam", - jav = "java", - java = "java", - jj = "javacc", - jjt = "javacc", - es = "javascript", - mjs = "javascript", - javascript = "javascript", - js = "javascript", - cjs = "javascript", - jsx = "javascriptreact", - clp = "jess", - jgr = "jgraph", - ["j73"] = "jovial", - jov = "jovial", - jovial = "jovial", - properties = "jproperties", - slnf = "json", - json = "json", - jsonp = "json", - webmanifest = "json", - ipynb = "json", - ["json-patch"] = "json", - json5 = "json5", - jsonc = "jsonc", - jsp = "jsp", - jl = "julia", - kv = "kivy", - kix = "kix", - kts = "kotlin", - kt = "kotlin", - ktm = "kotlin", - ks = "kscript", - k = "kwt", - ACE = "lace", - ace = "lace", - latte = "latte", - lte = "latte", - ld = "ld", - ldif = "ldif", - journal = "ledger", - ldg = "ledger", - ledger = "ledger", - less = "less", - lex = "lex", - lxx = "lex", - ["l++"] = "lex", - l = "lex", - lhs = "lhaskell", - ll = "lifelines", - ly = "lilypond", - ily = "lilypond", - liquid = "liquid", - cl = "lisp", - L = "lisp", - lisp = "lisp", - el = "lisp", - lsp = "lisp", - asd = "lisp", - lt = "lite", - lite = "lite", - lgt = "logtalk", - lotos = "lotos", - lot = "lotos", - lout = "lout", - lou = "lout", - ulpc = "lpc", - lpc = "lpc", - sig = "lprolog", - lsl = "lsl", - lss = "lss", - nse = "lua", - rockspec = "lua", - lua = "lua", - quake = "m3quake", - at = "m4", - eml = "mail", - mk = "make", - mak = "make", - dsp = "make", - page = "mallard", - map = "map", - mws = "maple", - mpl = "maple", - mv = "maple", - mkdn = "markdown", - md = "markdown", - mdwn = "markdown", - mkd = "markdown", - markdown = "markdown", - mdown = "markdown", - mhtml = "mason", - comp = "mason", - mason = "mason", - master = "master", - mas = "master", - demo = "maxima", - dm1 = "maxima", - dm2 = "maxima", - dm3 = "maxima", - dmt = "maxima", - wxm = "maxima", - mel = "mel", - mf = "mf", - mgl = "mgl", - mgp = "mgp", - my = "mib", - mib = "mib", - mix = "mix", - mixal = "mix", - nb = "mma", - mmp = "mmp", - DEF = "modula2", - ["m2"] = "modula2", - mi = "modula2", - ssc = "monk", - monk = "monk", - tsc = "monk", - isc = "monk", - moo = "moo", - mp = "mp", - mof = "msidl", - odl = "msidl", - msql = "msql", - mu = "mupad", - mush = "mush", - mysql = "mysql", - ["n1ql"] = "n1ql", - nql = "n1ql", - nanorc = "nanorc", - ncf = "ncf", - nginx = "nginx", - ninja = "ninja", - nix = "nix", - nqc = "nqc", - roff = "nroff", - tmac = "nroff", - man = "nroff", - mom = "nroff", - nr = "nroff", - tr = "nroff", - nsi = "nsis", - nsh = "nsis", - obj = "obj", - mlt = "ocaml", - mly = "ocaml", - mll = "ocaml", - mlp = "ocaml", - mlip = "ocaml", - mli = "ocaml", - ml = "ocaml", - occ = "occam", - xom = "omnimark", - xin = "omnimark", - opam = "opam", - ["or"] = "openroad", - scad = "openscad", - ora = "ora", - org = "org", - org_archive = "org", - pxsl = "papp", - papp = "papp", - pxml = "papp", - pas = "pascal", - lpr = "pascal", - dpr = "pascal", - pbtxt = "pbtxt", - g = "pccts", - pcmk = "pcmk", - pdf = "pdf", - plx = "perl", - prisma = "prisma", - psgi = "perl", - al = "perl", - ctp = "php", - php = "php", - phpt = "php", - phtml = "php", - pike = "pike", - pmod = "pike", - rcp = "pilrc", - pli = "pli", - ["pl1"] = "pli", - ["p36"] = "plm", - plm = "plm", - pac = "plm", - plp = "plp", - pls = "plsql", - plsql = "plsql", - po = "po", - pot = "po", - pod = "pod", - pk = "poke", - ps = "postscr", - epsi = "postscr", - afm = "postscr", - epsf = "postscr", - eps = "postscr", - pfa = "postscr", - ai = "postscr", - pov = "pov", - ppd = "ppd", - it = "ppwiz", - ih = "ppwiz", - action = "privoxy", - pc = "proc", - pdb = "prolog", - pml = "promela", - proto = "proto", - ["psd1"] = "ps1", - ["psm1"] = "ps1", - ["ps1"] = "ps1", - pssc = "ps1", - ["ps1xml"] = "ps1xml", - psf = "psf", - psl = "psl", - pug = "pug", - arr = "pyret", - pxd = "pyrex", - pyx = "pyrex", - pyw = "python", - py = "python", - pyi = "python", - ptl = "python", - ql = "ql", - qll = "ql", - rad = "radiance", - mat = "radiance", - ["pod6"] = "raku", - rakudoc = "raku", - rakutest = "raku", - rakumod = "raku", - ["pm6"] = "raku", - raku = "raku", - ["t6"] = "raku", - ["p6"] = "raku", - raml = "raml", - rbs = "rbs", - rego = "rego", - rem = "remind", - remind = "remind", - res = "rescript", - resi = "rescript", - frt = "reva", - testUnit = "rexx", - rex = "rexx", - orx = "rexx", - rexx = "rexx", - jrexx = "rexx", - rxj = "rexx", - rexxj = "rexx", - testGroup = "rexx", - rxo = "rexx", - Rd = "rhelp", - rd = "rhelp", - rib = "rib", - Rmd = "rmd", - rmd = "rmd", - smd = "rmd", - Smd = "rmd", - rnc = "rnc", - rng = "rng", - rnw = "rnoweb", - snw = "rnoweb", - Rnw = "rnoweb", - Snw = "rnoweb", - robot = "robot", - resource = "robot", - rsc = "routeros", - x = "rpcgen", - rpl = "rpl", - Srst = "rrst", - srst = "rrst", - Rrst = "rrst", - rrst = "rrst", - rst = "rst", - rtf = "rtf", - rjs = "ruby", - rxml = "ruby", - rb = "ruby", - rant = "ruby", - ru = "ruby", - rbw = "ruby", - gemspec = "ruby", - builder = "ruby", - rake = "ruby", - rs = "rust", - sas = "sas", - sass = "sass", - sa = "sather", - sbt = "sbt", - scala = "scala", - ss = "scheme", - scm = "scheme", - sld = "scheme", - rkt = "scheme", - rktd = "scheme", - rktl = "scheme", - sce = "scilab", - sci = "scilab", - scss = "scss", - sd = "sd", - sdc = "sdc", - pr = "sdl", - sdl = "sdl", - sed = "sed", - sexp = "sexplib", - sieve = "sieve", - siv = "sieve", - sil = "sil", - sim = "simula", - ["s85"] = "sinda", - sin = "sinda", - ssm = "sisu", - sst = "sisu", - ssi = "sisu", - ["_sst"] = "sisu", - ["-sst"] = "sisu", - il = "skill", - ils = "skill", - cdf = "skill", - sl = "slang", - ice = "slice", - score = "slrnsc", - sol = "solidity", - tpl = "smarty", - ihlp = "smcl", - smcl = "smcl", - hlp = "smcl", - smith = "smith", - smt = "smith", - sml = "sml", - spt = "snobol4", - sno = "snobol4", - sln = "solution", - sparql = "sparql", - rq = "sparql", - spec = "spec", - spice = "spice", - sp = "spice", - spd = "spup", - spdata = "spup", - speedup = "spup", - spi = "spyce", - spy = "spyce", - tyc = "sql", - typ = "sql", - pkb = "sql", - tyb = "sql", - pks = "sql", - sqlj = "sqlj", - sqi = "sqr", - sqr = "sqr", - nut = "squirrel", - ["s28"] = "srec", - ["s37"] = "srec", - srec = "srec", - mot = "srec", - ["s19"] = "srec", - st = "st", - imata = "stata", - ["do"] = "stata", - mata = "stata", - ado = "stata", - stp = "stp", - quark = "supercollider", - sface = "surface", - svelte = "svelte", - svg = "svg", - swift = "swift", - svh = "systemverilog", - sv = "systemverilog", - tak = "tak", - task = "taskedit", - tm = "tcl", - tcl = "tcl", - itk = "tcl", - itcl = "tcl", - tk = "tcl", - jacl = "tcl", - tl = "teal", - tmpl = "template", - ti = "terminfo", - dtx = "tex", - ltx = "tex", - bbl = "tex", - latex = "tex", - sty = "tex", - texi = "texinfo", - txi = "texinfo", - texinfo = "texinfo", - text = "text", - tfvars = "terraform", - tla = "tla", - tli = "tli", - toml = "toml", - tpp = "tpp", - treetop = "treetop", - slt = "tsalt", - tsscl = "tsscl", - tssgm = "tssgm", - tssop = "tssop", - tutor = "tutor", - twig = "twig", + return 'cpp' + end, + crm = 'crm', + csx = 'cs', + cs = 'cs', + csc = 'csc', + csdl = 'csdl', + cshtml = 'html', + fdr = 'csp', + csp = 'csp', + css = 'css', + con = 'cterm', + feature = 'cucumber', + cuh = 'cuda', + cu = 'cuda', + pld = 'cupl', + si = 'cuplsim', + cyn = 'cynpp', + dart = 'dart', + drt = 'dart', + ds = 'datascript', + dcd = 'dcd', + def = 'def', + desc = 'desc', + directory = 'desktop', + desktop = 'desktop', + diff = 'diff', + rej = 'diff', + Dockerfile = 'dockerfile', + bat = 'dosbatch', + wrap = 'dosini', + ini = 'dosini', + dot = 'dot', + gv = 'dot', + drac = 'dracula', + drc = 'dracula', + dtd = 'dtd', + dts = 'dts', + dtsi = 'dts', + dylan = 'dylan', + intr = 'dylanintr', + lid = 'dylanlid', + ecd = 'ecd', + eex = 'eelixir', + leex = 'eelixir', + exs = 'elixir', + elm = 'elm', + elv = 'elvish', + epp = 'epuppet', + erl = 'erlang', + hrl = 'erlang', + yaws = 'erlang', + erb = 'eruby', + rhtml = 'eruby', + ec = 'esqlc', + EC = 'esqlc', + strl = 'esterel', + exp = 'expect', + factor = 'factor', + fal = 'falcon', + fan = 'fan', + fwt = 'fan', + fnl = 'fennel', + ['m4gl'] = 'fgl', + ['4gl'] = 'fgl', + ['4gh'] = 'fgl', + fish = 'fish', + focexec = 'focexec', + fex = 'focexec', + fth = 'forth', + ft = 'forth', + FOR = 'fortran', + ['f77'] = 'fortran', + ['f03'] = 'fortran', + fortran = 'fortran', + ['F95'] = 'fortran', + ['f90'] = 'fortran', + ['F03'] = 'fortran', + fpp = 'fortran', + FTN = 'fortran', + ftn = 'fortran', + ['for'] = 'fortran', + ['F90'] = 'fortran', + ['F77'] = 'fortran', + ['f95'] = 'fortran', + FPP = 'fortran', + f = 'fortran', + F = 'fortran', + ['F08'] = 'fortran', + ['f08'] = 'fortran', + fpc = 'fpcmake', + fsl = 'framescript', + fb = 'freebasic', + fsi = 'fsharp', + fsx = 'fsharp', + fusion = 'fusion', + gdb = 'gdb', + gdmo = 'gdmo', + mo = 'gdmo', + tres = 'gdresource', + tscn = 'gdresource', + gd = 'gdscript', + ged = 'gedcom', + gmi = 'gemtext', + gemini = 'gemtext', + gift = 'gift', + gleam = 'gleam', + glsl = 'glsl', + gpi = 'gnuplot', + gnuplot = 'gnuplot', + go = 'go', + gp = 'gp', + gs = 'grads', + gql = 'graphql', + graphql = 'graphql', + graphqls = 'graphql', + gretl = 'gretl', + gradle = 'groovy', + groovy = 'groovy', + gsp = 'gsp', + gjs = 'javascript.glimmer', + gts = 'typescript.glimmer', + hack = 'hack', + hackpartial = 'hack', + haml = 'haml', + hsm = 'hamster', + hbs = 'handlebars', + ['hs-boot'] = 'haskell', + hsig = 'haskell', + hsc = 'haskell', + hs = 'haskell', + ht = 'haste', + htpp = 'hastepreproc', + hb = 'hb', + sum = 'hercules', + errsum = 'hercules', + ev = 'hercules', + vc = 'hercules', + hcl = 'hcl', + heex = 'heex', + hex = 'hex', + ['h32'] = 'hex', + hjson = 'hjson', + hog = 'hog', + hws = 'hollywood', + htt = 'httest', + htb = 'httest', + iba = 'ibasic', + ibi = 'ibasic', + icn = 'icon', + inf = 'inform', + INF = 'inform', + ii = 'initng', + iss = 'iss', + mst = 'ist', + ist = 'ist', + ijs = 'j', + JAL = 'jal', + jal = 'jal', + jpr = 'jam', + jpl = 'jam', + jav = 'java', + java = 'java', + jj = 'javacc', + jjt = 'javacc', + es = 'javascript', + mjs = 'javascript', + javascript = 'javascript', + js = 'javascript', + cjs = 'javascript', + jsx = 'javascriptreact', + clp = 'jess', + jgr = 'jgraph', + ['j73'] = 'jovial', + jov = 'jovial', + jovial = 'jovial', + properties = 'jproperties', + slnf = 'json', + json = 'json', + jsonp = 'json', + webmanifest = 'json', + ipynb = 'json', + ['json-patch'] = 'json', + json5 = 'json5', + jsonc = 'jsonc', + jsp = 'jsp', + jl = 'julia', + kv = 'kivy', + kix = 'kix', + kts = 'kotlin', + kt = 'kotlin', + ktm = 'kotlin', + ks = 'kscript', + k = 'kwt', + ACE = 'lace', + ace = 'lace', + latte = 'latte', + lte = 'latte', + ld = 'ld', + ldif = 'ldif', + journal = 'ledger', + ldg = 'ledger', + ledger = 'ledger', + less = 'less', + lex = 'lex', + lxx = 'lex', + ['l++'] = 'lex', + l = 'lex', + lhs = 'lhaskell', + ll = 'lifelines', + ly = 'lilypond', + ily = 'lilypond', + liquid = 'liquid', + cl = 'lisp', + L = 'lisp', + lisp = 'lisp', + el = 'lisp', + lsp = 'lisp', + asd = 'lisp', + lt = 'lite', + lite = 'lite', + lgt = 'logtalk', + lotos = 'lotos', + lot = 'lotos', + lout = 'lout', + lou = 'lout', + ulpc = 'lpc', + lpc = 'lpc', + sig = 'lprolog', + lsl = 'lsl', + lss = 'lss', + nse = 'lua', + rockspec = 'lua', + lua = 'lua', + quake = 'm3quake', + at = 'm4', + eml = 'mail', + mk = 'make', + mak = 'make', + dsp = 'make', + page = 'mallard', + map = 'map', + mws = 'maple', + mpl = 'maple', + mv = 'maple', + mkdn = 'markdown', + md = 'markdown', + mdwn = 'markdown', + mkd = 'markdown', + markdown = 'markdown', + mdown = 'markdown', + mhtml = 'mason', + comp = 'mason', + mason = 'mason', + master = 'master', + mas = 'master', + demo = 'maxima', + dm1 = 'maxima', + dm2 = 'maxima', + dm3 = 'maxima', + dmt = 'maxima', + wxm = 'maxima', + mel = 'mel', + mf = 'mf', + mgl = 'mgl', + mgp = 'mgp', + my = 'mib', + mib = 'mib', + mix = 'mix', + mixal = 'mix', + nb = 'mma', + mmp = 'mmp', + DEF = 'modula2', + ['m2'] = 'modula2', + mi = 'modula2', + ssc = 'monk', + monk = 'monk', + tsc = 'monk', + isc = 'monk', + moo = 'moo', + mp = 'mp', + mof = 'msidl', + odl = 'msidl', + msql = 'msql', + mu = 'mupad', + mush = 'mush', + mysql = 'mysql', + ['n1ql'] = 'n1ql', + nql = 'n1ql', + nanorc = 'nanorc', + ncf = 'ncf', + nginx = 'nginx', + ninja = 'ninja', + nix = 'nix', + nqc = 'nqc', + roff = 'nroff', + tmac = 'nroff', + man = 'nroff', + mom = 'nroff', + nr = 'nroff', + tr = 'nroff', + nsi = 'nsis', + nsh = 'nsis', + obj = 'obj', + mlt = 'ocaml', + mly = 'ocaml', + mll = 'ocaml', + mlp = 'ocaml', + mlip = 'ocaml', + mli = 'ocaml', + ml = 'ocaml', + occ = 'occam', + xom = 'omnimark', + xin = 'omnimark', + opam = 'opam', + ['or'] = 'openroad', + scad = 'openscad', + ora = 'ora', + org = 'org', + org_archive = 'org', + pxsl = 'papp', + papp = 'papp', + pxml = 'papp', + pas = 'pascal', + lpr = 'pascal', + dpr = 'pascal', + pbtxt = 'pbtxt', + g = 'pccts', + pcmk = 'pcmk', + pdf = 'pdf', + plx = 'perl', + prisma = 'prisma', + psgi = 'perl', + al = 'perl', + ctp = 'php', + php = 'php', + phpt = 'php', + phtml = 'php', + pike = 'pike', + pmod = 'pike', + rcp = 'pilrc', + pli = 'pli', + ['pl1'] = 'pli', + ['p36'] = 'plm', + plm = 'plm', + pac = 'plm', + plp = 'plp', + pls = 'plsql', + plsql = 'plsql', + po = 'po', + pot = 'po', + pod = 'pod', + pk = 'poke', + ps = 'postscr', + epsi = 'postscr', + afm = 'postscr', + epsf = 'postscr', + eps = 'postscr', + pfa = 'postscr', + ai = 'postscr', + pov = 'pov', + ppd = 'ppd', + it = 'ppwiz', + ih = 'ppwiz', + action = 'privoxy', + pc = 'proc', + pdb = 'prolog', + pml = 'promela', + proto = 'proto', + ['psd1'] = 'ps1', + ['psm1'] = 'ps1', + ['ps1'] = 'ps1', + pssc = 'ps1', + ['ps1xml'] = 'ps1xml', + psf = 'psf', + psl = 'psl', + pug = 'pug', + arr = 'pyret', + pxd = 'pyrex', + pyx = 'pyrex', + pyw = 'python', + py = 'python', + pyi = 'python', + ptl = 'python', + ql = 'ql', + qll = 'ql', + rad = 'radiance', + mat = 'radiance', + ['pod6'] = 'raku', + rakudoc = 'raku', + rakutest = 'raku', + rakumod = 'raku', + ['pm6'] = 'raku', + raku = 'raku', + ['t6'] = 'raku', + ['p6'] = 'raku', + raml = 'raml', + rbs = 'rbs', + rego = 'rego', + rem = 'remind', + remind = 'remind', + res = 'rescript', + resi = 'rescript', + frt = 'reva', + testUnit = 'rexx', + rex = 'rexx', + orx = 'rexx', + rexx = 'rexx', + jrexx = 'rexx', + rxj = 'rexx', + rexxj = 'rexx', + testGroup = 'rexx', + rxo = 'rexx', + Rd = 'rhelp', + rd = 'rhelp', + rib = 'rib', + Rmd = 'rmd', + rmd = 'rmd', + smd = 'rmd', + Smd = 'rmd', + rnc = 'rnc', + rng = 'rng', + rnw = 'rnoweb', + snw = 'rnoweb', + Rnw = 'rnoweb', + Snw = 'rnoweb', + robot = 'robot', + resource = 'robot', + rsc = 'routeros', + x = 'rpcgen', + rpl = 'rpl', + Srst = 'rrst', + srst = 'rrst', + Rrst = 'rrst', + rrst = 'rrst', + rst = 'rst', + rtf = 'rtf', + rjs = 'ruby', + rxml = 'ruby', + rb = 'ruby', + rant = 'ruby', + ru = 'ruby', + rbw = 'ruby', + gemspec = 'ruby', + builder = 'ruby', + rake = 'ruby', + rs = 'rust', + sas = 'sas', + sass = 'sass', + sa = 'sather', + sbt = 'sbt', + scala = 'scala', + ss = 'scheme', + scm = 'scheme', + sld = 'scheme', + rkt = 'scheme', + rktd = 'scheme', + rktl = 'scheme', + sce = 'scilab', + sci = 'scilab', + scss = 'scss', + sd = 'sd', + sdc = 'sdc', + pr = 'sdl', + sdl = 'sdl', + sed = 'sed', + sexp = 'sexplib', + sieve = 'sieve', + siv = 'sieve', + sil = 'sil', + sim = 'simula', + ['s85'] = 'sinda', + sin = 'sinda', + ssm = 'sisu', + sst = 'sisu', + ssi = 'sisu', + ['_sst'] = 'sisu', + ['-sst'] = 'sisu', + il = 'skill', + ils = 'skill', + cdf = 'skill', + sl = 'slang', + ice = 'slice', + score = 'slrnsc', + sol = 'solidity', + tpl = 'smarty', + ihlp = 'smcl', + smcl = 'smcl', + hlp = 'smcl', + smith = 'smith', + smt = 'smith', + sml = 'sml', + spt = 'snobol4', + sno = 'snobol4', + sln = 'solution', + sparql = 'sparql', + rq = 'sparql', + spec = 'spec', + spice = 'spice', + sp = 'spice', + spd = 'spup', + spdata = 'spup', + speedup = 'spup', + spi = 'spyce', + spy = 'spyce', + tyc = 'sql', + typ = 'sql', + pkb = 'sql', + tyb = 'sql', + pks = 'sql', + sqlj = 'sqlj', + sqi = 'sqr', + sqr = 'sqr', + nut = 'squirrel', + ['s28'] = 'srec', + ['s37'] = 'srec', + srec = 'srec', + mot = 'srec', + ['s19'] = 'srec', + st = 'st', + imata = 'stata', + ['do'] = 'stata', + mata = 'stata', + ado = 'stata', + stp = 'stp', + quark = 'supercollider', + sface = 'surface', + svelte = 'svelte', + svg = 'svg', + swift = 'swift', + svh = 'systemverilog', + sv = 'systemverilog', + tak = 'tak', + task = 'taskedit', + tm = 'tcl', + tcl = 'tcl', + itk = 'tcl', + itcl = 'tcl', + tk = 'tcl', + jacl = 'tcl', + tl = 'teal', + tmpl = 'template', + ti = 'terminfo', + dtx = 'tex', + ltx = 'tex', + bbl = 'tex', + latex = 'tex', + sty = 'tex', + texi = 'texinfo', + txi = 'texinfo', + texinfo = 'texinfo', + text = 'text', + tfvars = 'terraform', + tla = 'tla', + tli = 'tli', + toml = 'toml', + tpp = 'tpp', + treetop = 'treetop', + slt = 'tsalt', + tsscl = 'tsscl', + tssgm = 'tssgm', + tssop = 'tssop', + tutor = 'tutor', + twig = 'twig', ts = function(path, bufnr) - if getline(bufnr, 1):find("<%?xml") then - return "xml" + if getline(bufnr, 1):find('<%?xml') then + return 'xml' else - return "typescript" + return 'typescript' end end, - tsx = "typescriptreact", - uc = "uc", - uit = "uil", - uil = "uil", - sba = "vb", - vb = "vb", - dsm = "vb", - ctl = "vb", - vbs = "vb", - vr = "vera", - vri = "vera", - vrh = "vera", - v = "verilog", - va = "verilogams", - vams = "verilogams", - vhdl = "vhdl", - vst = "vhdl", - vhd = "vhdl", - hdl = "vhdl", - vho = "vhdl", - vbe = "vhdl", - vim = "vim", - vba = "vim", - mar = "vmasm", - cm = "voscm", - wrl = "vrml", - vroom = "vroom", - vue = "vue", - wat = "wast", - wast = "wast", - wm = "webmacro", - wbt = "winbatch", - wml = "wml", - wsml = "wsml", - ad = "xdefaults", - xhtml = "xhtml", - xht = "xhtml", - msc = "xmath", - msf = "xmath", - ["psc1"] = "xml", - tpm = "xml", - xliff = "xml", - atom = "xml", - xul = "xml", - cdxml = "xml", - mpd = "xml", - rss = "xml", - fsproj = "xml", - ui = "xml", - vbproj = "xml", - xlf = "xml", - wsdl = "xml", - csproj = "xml", - wpl = "xml", - xmi = "xml", - ["xpm2"] = "xpm2", - xqy = "xquery", - xqm = "xquery", - xquery = "xquery", - xq = "xquery", - xql = "xquery", - xs = "xs", - xsd = "xsd", - xsl = "xslt", - xslt = "xslt", - yy = "yacc", - ["y++"] = "yacc", - yxx = "yacc", - yml = "yaml", - yaml = "yaml", - yang = "yang", - ["z8a"] = "z8a", - zig = "zig", - zu = "zimbu", - zut = "zimbutempl", - zsh = "zsh", - vala = "vala", - E = function() vim.fn["dist#ft#FTe"]() end, - EU = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - EW = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - EX = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - EXU = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - EXW = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - PL = function() vim.fn["dist#ft#FTpl"]() end, - R = function(path, bufnr) require("vim.filetype.detect").r(bufnr) end, - asm = function() vim.fn["dist#ft#FTasm"]() end, - bas = function() vim.fn["dist#ft#FTbas"]() end, - bi = function() vim.fn["dist#ft#FTbas"]() end, - bm = function() vim.fn["dist#ft#FTbas"]() end, - bash = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - btm = function(path, bufnr) return require("vim.filetype.detect").btm(bufnr) end, - c = function() vim.fn["dist#ft#FTlpc"]() end, - ch = function() vim.fn["dist#ft#FTchange"]() end, - com = function() vim.fn["dist#ft#BindzoneCheck"]('dcl') end, - cpt = function() vim.fn["dist#ft#FThtml"]() end, - csh = function() vim.fn["dist#ft#CSH"]() end, - d = function() vim.fn["dist#ft#DtraceCheck"]() end, - db = function() vim.fn["dist#ft#BindzoneCheck"]('') end, - dtml = function() vim.fn["dist#ft#FThtml"]() end, - e = function() vim.fn["dist#ft#FTe"]() end, - ebuild = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - eclass = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ent = function(path, bufnr) return require("vim.filetype.detect").ent(bufnr) end, - env = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - eu = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - ew = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - ex = function(path, bufnr) return require("vim.filetype.detect").ex(bufnr) end, - exu = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - exw = function(path, bufnr) return require("vim.filetype.detect").euphoria(bufnr) end, - frm = function(path, bufnr) require("vim.filetype.detect").frm(bufnr) end, - fs = function() vim.fn["dist#ft#FTfs"]() end, - h = function(path, bufnr) require("vim.filetype.detect").header(bufnr) end, - htm = function() vim.fn["dist#ft#FThtml"]() end, - html = function() vim.fn["dist#ft#FThtml"]() end, - i = function() vim.fn["dist#ft#FTprogress_asm"]() end, - idl = function(path, bufnr) require("vim.filetype.detect").idl(bufnr) end, - inc = function() vim.fn["dist#ft#FTinc"]() end, - inp = function(path, bufnr) require("vim.filetype.detect").inp(bufnr) end, - ksh = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end, - lst = function() vim.fn["dist#ft#FTasm"]() end, - m = function() vim.fn["dist#ft#FTm"]() end, - mac = function() vim.fn["dist#ft#FTasm"]() end, - mc = function(path, bufnr) require("vim.filetype.detect").mc(bufnr) end, - mm = function() vim.fn["dist#ft#FTmm"]() end, - mms = function(path, bufnr) require("vim.filetype.detect").mms(bufnr) end, - p = function() vim.fn["dist#ft#FTprogress_pascal"]() end, + tsx = 'typescriptreact', + uc = 'uc', + uit = 'uil', + uil = 'uil', + sba = 'vb', + vb = 'vb', + dsm = 'vb', + ctl = 'vb', + vbs = 'vb', + vr = 'vera', + vri = 'vera', + vrh = 'vera', + v = 'verilog', + va = 'verilogams', + vams = 'verilogams', + vhdl = 'vhdl', + vst = 'vhdl', + vhd = 'vhdl', + hdl = 'vhdl', + vho = 'vhdl', + vbe = 'vhdl', + vim = 'vim', + vba = 'vim', + mar = 'vmasm', + cm = 'voscm', + wrl = 'vrml', + vroom = 'vroom', + vue = 'vue', + wat = 'wast', + wast = 'wast', + wm = 'webmacro', + wbt = 'winbatch', + wml = 'wml', + wsml = 'wsml', + ad = 'xdefaults', + xhtml = 'xhtml', + xht = 'xhtml', + msc = 'xmath', + msf = 'xmath', + ['psc1'] = 'xml', + tpm = 'xml', + xliff = 'xml', + atom = 'xml', + xul = 'xml', + cdxml = 'xml', + mpd = 'xml', + rss = 'xml', + fsproj = 'xml', + ui = 'xml', + vbproj = 'xml', + xlf = 'xml', + wsdl = 'xml', + csproj = 'xml', + wpl = 'xml', + xmi = 'xml', + ['xpm2'] = 'xpm2', + xqy = 'xquery', + xqm = 'xquery', + xquery = 'xquery', + xq = 'xquery', + xql = 'xquery', + xs = 'xs', + xsd = 'xsd', + xsl = 'xslt', + xslt = 'xslt', + yy = 'yacc', + ['y++'] = 'yacc', + yxx = 'yacc', + yml = 'yaml', + yaml = 'yaml', + yang = 'yang', + ['z8a'] = 'z8a', + zig = 'zig', + zu = 'zimbu', + zut = 'zimbutempl', + zsh = 'zsh', + vala = 'vala', + E = function() + vim.fn['dist#ft#FTe']() + end, + EU = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + EW = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + EX = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + EXU = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + EXW = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + PL = function() + vim.fn['dist#ft#FTpl']() + end, + R = function(path, bufnr) + require('vim.filetype.detect').r(bufnr) + end, + asm = function() + vim.fn['dist#ft#FTasm']() + end, + bas = function() + vim.fn['dist#ft#FTbas']() + end, + bi = function() + vim.fn['dist#ft#FTbas']() + end, + bm = function() + vim.fn['dist#ft#FTbas']() + end, + bash = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + btm = function(path, bufnr) + return require('vim.filetype.detect').btm(bufnr) + end, + c = function() + vim.fn['dist#ft#FTlpc']() + end, + ch = function() + vim.fn['dist#ft#FTchange']() + end, + com = function() + vim.fn['dist#ft#BindzoneCheck']('dcl') + end, + cpt = function() + vim.fn['dist#ft#FThtml']() + end, + csh = function() + vim.fn['dist#ft#CSH']() + end, + d = function() + vim.fn['dist#ft#DtraceCheck']() + end, + db = function() + vim.fn['dist#ft#BindzoneCheck']('') + end, + dtml = function() + vim.fn['dist#ft#FThtml']() + end, + e = function() + vim.fn['dist#ft#FTe']() + end, + ebuild = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + eclass = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ent = function(path, bufnr) + return require('vim.filetype.detect').ent(bufnr) + end, + env = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + eu = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + ew = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + ex = function(path, bufnr) + return require('vim.filetype.detect').ex(bufnr) + end, + exu = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + exw = function(path, bufnr) + return require('vim.filetype.detect').euphoria(bufnr) + end, + frm = function(path, bufnr) + require('vim.filetype.detect').frm(bufnr) + end, + fs = function() + vim.fn['dist#ft#FTfs']() + end, + h = function(path, bufnr) + require('vim.filetype.detect').header(bufnr) + end, + htm = function() + vim.fn['dist#ft#FThtml']() + end, + html = function() + vim.fn['dist#ft#FThtml']() + end, + i = function() + vim.fn['dist#ft#FTprogress_asm']() + end, + idl = function(path, bufnr) + require('vim.filetype.detect').idl(bufnr) + end, + inc = function() + vim.fn['dist#ft#FTinc']() + end, + inp = function(path, bufnr) + require('vim.filetype.detect').inp(bufnr) + end, + ksh = function() + vim.fn['dist#ft#SetFileTypeSH']('ksh') + end, + lst = function() + vim.fn['dist#ft#FTasm']() + end, + m = function() + vim.fn['dist#ft#FTm']() + end, + mac = function() + vim.fn['dist#ft#FTasm']() + end, + mc = function(path, bufnr) + require('vim.filetype.detect').mc(bufnr) + end, + mm = function() + vim.fn['dist#ft#FTmm']() + end, + mms = function(path, bufnr) + require('vim.filetype.detect').mms(bufnr) + end, + p = function() + vim.fn['dist#ft#FTprogress_pascal']() + end, patch = function(path, bufnr) local firstline = getline(bufnr, 1) - if string.find(firstline, "^From " .. string.rep("%x", 40) .. "+ Mon Sep 17 00:00:00 2001$") then - return "gitsendemail" + if string.find(firstline, '^From ' .. string.rep('%x', 40) .. '+ Mon Sep 17 00:00:00 2001$') then + return 'gitsendemail' else - return "diff" + return 'diff' end end, - pl = function() vim.fn["dist#ft#FTpl"]() end, - pp = function() vim.fn["dist#ft#FTpp"]() end, - pro = function() vim.fn["dist#ft#ProtoCheck"]('idlang') end, - pt = function() vim.fn["dist#ft#FThtml"]() end, - r = function(path, bufnr) require("vim.filetype.detect").r(bufnr) end, - rdf = function(path, bufnr) require("vim.filetype.detect").redif(bufnr) end, - rules = function() vim.fn["dist#ft#FTRules"]() end, - sc = function(path, bufnr) require("vim.filetype.detect").sc(bufnr) end, - scd = function(path, bufnr) require("vim.filetype.detect").scd(bufnr) end, - sh = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - shtml = function() vim.fn["dist#ft#FThtml"]() end, - sql = function(path, bufnr) require("vim.filetype.detect").sql(bufnr) end, - stm = function() vim.fn["dist#ft#FThtml"]() end, - tcsh = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, - tex = function() vim.fn["dist#ft#FTtex"]() end, - tf = function(path, bufnr) require("vim.filetype.detect").tf(bufnr) end, - w = function(path, bufnr) require("vim.filetype.detect").progress_cweb(bufnr) end, - xml = function(path, bufnr) require("vim.filetype.detect").xml(bufnr) end, - y = function(path, bufnr) require("vim.filetype.detect").y(bufnr) end, - zsql = function(path, bufnr) require("vim.filetype.detect").sql(bufnr) end, + pl = function() + vim.fn['dist#ft#FTpl']() + end, + pp = function() + vim.fn['dist#ft#FTpp']() + end, + pro = function() + vim.fn['dist#ft#ProtoCheck']('idlang') + end, + pt = function() + vim.fn['dist#ft#FThtml']() + end, + r = function(path, bufnr) + require('vim.filetype.detect').r(bufnr) + end, + rdf = function(path, bufnr) + require('vim.filetype.detect').redif(bufnr) + end, + rules = function() + vim.fn['dist#ft#FTRules']() + end, + sc = function(path, bufnr) + require('vim.filetype.detect').sc(bufnr) + end, + scd = function(path, bufnr) + require('vim.filetype.detect').scd(bufnr) + end, + sh = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + shtml = function() + vim.fn['dist#ft#FThtml']() + end, + sql = function(path, bufnr) + require('vim.filetype.detect').sql(bufnr) + end, + stm = function() + vim.fn['dist#ft#FThtml']() + end, + tcsh = function() + vim.fn['dist#ft#SetFileTypeShell']('tcsh') + end, + tex = function() + vim.fn['dist#ft#FTtex']() + end, + tf = function(path, bufnr) + require('vim.filetype.detect').tf(bufnr) + end, + w = function(path, bufnr) + require('vim.filetype.detect').progress_cweb(bufnr) + end, + xml = function(path, bufnr) + require('vim.filetype.detect').xml(bufnr) + end, + y = function(path, bufnr) + require('vim.filetype.detect').y(bufnr) + end, + zsql = function(path, bufnr) + require('vim.filetype.detect').sql(bufnr) + end, txt = function(path, bufnr) --helpfiles match *.txt, but should have a modeline as last line - if not getline(bufnr, -1):match("vim:.*ft=help") then - return "text" + if not getline(bufnr, -1):match('vim:.*ft=help') then + return 'text' end end, -- END EXTENSION @@ -871,593 +1012,695 @@ local extension = { local filename = { -- BEGIN FILENAME - ["a2psrc"] = "a2ps", - ["/etc/a2ps.cfg"] = "a2ps", - [".a2psrc"] = "a2ps", - [".asoundrc"] = "alsaconf", - ["/usr/share/alsa/alsa.conf"] = "alsaconf", - ["/etc/asound.conf"] = "alsaconf", - ["build.xml"] = "ant", - [".htaccess"] = "apache", - ["apt.conf"] = "aptconf", - ["/.aptitude/config"] = "aptconf", - ["=tagging-method"] = "arch", - [".arch-inventory"] = "arch", - ["GNUmakefile.am"] = "automake", - ["named.root"] = "bindzone", - WORKSPACE = "bzl", - BUILD = "bzl", - ["cabal.config"] = "cabalconfig", - ["cabal.project"] = "cabalproject", - calendar = "calendar", - catalog = "catalog", - ["/etc/cdrdao.conf"] = "cdrdaoconf", - [".cdrdao"] = "cdrdaoconf", - ["/etc/default/cdrdao"] = "cdrdaoconf", - ["/etc/defaults/cdrdao"] = "cdrdaoconf", - ["cfengine.conf"] = "cfengine", - ["CMakeLists.txt"] = "cmake", - ["auto.master"] = "conf", - ["configure.in"] = "config", - ["configure.ac"] = "config", - [".cvsrc"] = "cvsrc", - ["/debian/changelog"] = "debchangelog", - ["changelog.dch"] = "debchangelog", - ["changelog.Debian"] = "debchangelog", - ["NEWS.dch"] = "debchangelog", - ["NEWS.Debian"] = "debchangelog", - ["/debian/control"] = "debcontrol", - ["/debian/copyright"] = "debcopyright", - ["/etc/apt/sources.list"] = "debsources", - ["denyhosts.conf"] = "denyhosts", - ["dict.conf"] = "dictconf", - [".dictrc"] = "dictconf", - ["/etc/DIR_COLORS"] = "dircolors", - [".dir_colors"] = "dircolors", - [".dircolors"] = "dircolors", - ["/etc/dnsmasq.conf"] = "dnsmasq", - Containerfile = "dockerfile", - Dockerfile = "dockerfile", - npmrc = "dosini", - ["/etc/yum.conf"] = "dosini", - ["/etc/pacman.conf"] = "conf", - [".npmrc"] = "dosini", - [".editorconfig"] = "dosini", - dune = "dune", - jbuild = "dune", - ["dune-workspace"] = "dune", - ["dune-project"] = "dune", - ["elinks.conf"] = "elinks", - ["mix.lock"] = "elixir", - ["filter-rules"] = "elmfilt", - ["exim.conf"] = "exim", - exports = "exports", - [".fetchmailrc"] = "fetchmail", - fvSchemes = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - fvSolution = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - fvConstraints = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - fvModels = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - fstab = "fstab", - mtab = "fstab", - [".gdbinit"] = "gdb", - gdbinit = "gdb", - [".gdbearlyinit"] = "gdb", - gdbearlyinit = "gdb", - ["lltxxxxx.txt"] = "gedcom", - ["TAG_EDITMSG"] = "gitcommit", - ["MERGE_MSG"] = "gitcommit", - ["COMMIT_EDITMSG"] = "gitcommit", - ["NOTES_EDITMSG"] = "gitcommit", - ["EDIT_DESCRIPTION"] = "gitcommit", - [".gitconfig"] = "gitconfig", - [".gitmodules"] = "gitconfig", - ["gitolite.conf"] = "gitolite", - ["git-rebase-todo"] = "gitrebase", - gkrellmrc = "gkrellmrc", - [".gnashrc"] = "gnash", - [".gnashpluginrc"] = "gnash", - gnashpluginrc = "gnash", - gnashrc = "gnash", - ["go.work"] = "gowork", - [".gprc"] = "gp", - ["/.gnupg/gpg.conf"] = "gpg", - ["/.gnupg/options"] = "gpg", - ["/var/backups/gshadow.bak"] = "group", - ["/etc/gshadow"] = "group", - ["/etc/group-"] = "group", - ["/etc/gshadow.edit"] = "group", - ["/etc/gshadow-"] = "group", - ["/etc/group"] = "group", - ["/var/backups/group.bak"] = "group", - ["/etc/group.edit"] = "group", - ["/boot/grub/menu.lst"] = "grub", - ["/etc/grub.conf"] = "grub", - ["/boot/grub/grub.conf"] = "grub", - [".gtkrc"] = "gtkrc", - gtkrc = "gtkrc", - ["snort.conf"] = "hog", - ["vision.conf"] = "hog", - ["/etc/host.conf"] = "hostconf", - ["/etc/hosts.allow"] = "hostsaccess", - ["/etc/hosts.deny"] = "hostsaccess", - ["/i3/config"] = "i3config", - ["/sway/config"] = "i3config", - ["/.sway/config"] = "i3config", - ["/.i3/config"] = "i3config", - ["/.icewm/menu"] = "icemenu", - [".indent.pro"] = "indent", - indentrc = "indent", - inittab = "inittab", - ["ipf.conf"] = "ipfilter", - ["ipf6.conf"] = "ipfilter", - ["ipf.rules"] = "ipfilter", - [".eslintrc"] = "json", - [".babelrc"] = "json", - ["Pipfile.lock"] = "json", - [".firebaserc"] = "json", - [".prettierrc"] = "json", - Kconfig = "kconfig", - ["Kconfig.debug"] = "kconfig", - ["lftp.conf"] = "lftp", - [".lftprc"] = "lftp", - ["/.libao"] = "libao", - ["/etc/libao.conf"] = "libao", - ["lilo.conf"] = "lilo", - ["/etc/limits"] = "limits", - [".emacs"] = "lisp", - sbclrc = "lisp", - [".sbclrc"] = "lisp", - [".sawfishrc"] = "lisp", - ["/etc/login.access"] = "loginaccess", - ["/etc/login.defs"] = "logindefs", - ["lynx.cfg"] = "lynx", - ["m3overrides"] = "m3build", - ["m3makefile"] = "m3build", - ["cm3.cfg"] = "m3quake", - [".followup"] = "mail", - [".article"] = "mail", - [".letter"] = "mail", - ["/etc/aliases"] = "mailaliases", - ["/etc/mail/aliases"] = "mailaliases", - mailcap = "mailcap", - [".mailcap"] = "mailcap", - ["/etc/man.conf"] = "manconf", - ["man.config"] = "manconf", - ["maxima-init.mac"] = "maxima", - ["meson.build"] = "meson", - ["meson_options.txt"] = "meson", - ["/etc/conf.modules"] = "modconf", - ["/etc/modules"] = "modconf", - ["/etc/modules.conf"] = "modconf", - ["/.mplayer/config"] = "mplayerconf", - ["mplayer.conf"] = "mplayerconf", - mrxvtrc = "mrxvtrc", - [".mrxvtrc"] = "mrxvtrc", - ["/etc/nanorc"] = "nanorc", - Neomuttrc = "neomuttrc", - [".netrc"] = "netrc", - [".ocamlinit"] = "ocaml", - [".octaverc"] = "octave", - octaverc = "octave", - ["octave.conf"] = "octave", - opam = "opam", - ["/etc/pam.conf"] = "pamconf", - ["pam_env.conf"] = "pamenv", - [".pam_environment"] = "pamenv", - ["/var/backups/passwd.bak"] = "passwd", - ["/var/backups/shadow.bak"] = "passwd", - ["/etc/passwd"] = "passwd", - ["/etc/passwd-"] = "passwd", - ["/etc/shadow.edit"] = "passwd", - ["/etc/shadow-"] = "passwd", - ["/etc/shadow"] = "passwd", - ["/etc/passwd.edit"] = "passwd", - ["pf.conf"] = "pf", - ["main.cf"] = "pfmain", - pinerc = "pine", - [".pinercex"] = "pine", - [".pinerc"] = "pine", - pinercex = "pine", - ["/etc/pinforc"] = "pinfo", - ["/.pinforc"] = "pinfo", - [".povrayrc"] = "povini", - [".procmailrc"] = "procmail", - [".procmail"] = "procmail", - ["/etc/protocols"] = "protocols", - [".pythonstartup"] = "python", - [".pythonrc"] = "python", - SConstruct = "python", - ratpoisonrc = "ratpoison", - [".ratpoisonrc"] = "ratpoison", - v = "rcs", - inputrc = "readline", - [".inputrc"] = "readline", - [".reminders"] = "remind", - ["resolv.conf"] = "resolv", - ["robots.txt"] = "robots", - Gemfile = "ruby", - Puppetfile = "ruby", - [".irbrc"] = "ruby", - irbrc = "ruby", - Vagrantfile = "ruby", - ["smb.conf"] = "samba", - screenrc = "screen", - [".screenrc"] = "screen", - ["/etc/sensors3.conf"] = "sensors", - ["/etc/sensors.conf"] = "sensors", - ["/etc/services"] = "services", - ["/etc/serial.conf"] = "setserial", - ["/etc/udev/cdsymlinks.conf"] = "sh", - ["/etc/slp.conf"] = "slpconf", - ["/etc/slp.reg"] = "slpreg", - ["/etc/slp.spi"] = "slpspi", - [".slrnrc"] = "slrnrc", - ["sendmail.cf"] = "sm", - ["squid.conf"] = "squid", - ["/.ssh/config"] = "sshconfig", - ["ssh_config"] = "sshconfig", - ["sshd_config"] = "sshdconfig", - ["/etc/sudoers"] = "sudoers", - ["sudoers.tmp"] = "sudoers", - ["/etc/sysctl.conf"] = "sysctl", - tags = "tags", - [".tclshrc"] = "tcl", - [".wishrc"] = "tcl", - ["tclsh.rc"] = "tcl", - ["texmf.cnf"] = "texmf", - COPYING = "text", - README = "text", - LICENSE = "text", - AUTHORS = "text", - tfrc = "tf", - [".tfrc"] = "tf", - ["tidy.conf"] = "tidy", - tidyrc = "tidy", - [".tidyrc"] = "tidy", - [".tmux.conf"] = "tmux", - ["/.cargo/config"] = "toml", - Pipfile = "toml", - ["Gopkg.lock"] = "toml", - ["/.cargo/credentials"] = "toml", - ["Cargo.lock"] = "toml", - ["trustees.conf"] = "trustees", - ["/etc/udev/udev.conf"] = "udevconf", - ["/etc/updatedb.conf"] = "updatedb", - ["fdrupstream.log"] = "upstreamlog", - vgrindefs = "vgrindefs", - [".exrc"] = "vim", - ["_exrc"] = "vim", - ["_viminfo"] = "viminfo", - [".viminfo"] = "viminfo", - [".wgetrc"] = "wget", - [".wget2rc"] = "wget2", - wgetrc = "wget", - wget2rc = "wget2", - [".wvdialrc"] = "wvdial", - ["wvdial.conf"] = "wvdial", - [".Xresources"] = "xdefaults", - [".Xpdefaults"] = "xdefaults", - ["xdm-config"] = "xdefaults", - [".Xdefaults"] = "xdefaults", - ["/etc/xinetd.conf"] = "xinetd", - fglrxrc = "xml", - ["/etc/blkid.tab"] = "xml", - ["/etc/blkid.tab.old"] = "xml", - ["/etc/zprofile"] = "zsh", - [".zlogin"] = "zsh", - [".zlogout"] = "zsh", - [".zshrc"] = "zsh", - [".zprofile"] = "zsh", - [".zcompdump"] = "zsh", - [".zshenv"] = "zsh", - [".zfbfmarks"] = "zsh", - [".alias"] = function() vim.fn["dist#ft#CSH"]() end, - [".bashrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - [".cshrc"] = function() vim.fn["dist#ft#CSH"]() end, - [".env"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - [".kshrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end, - [".login"] = function() vim.fn["dist#ft#CSH"]() end, - [".profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - [".tcshrc"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, - ["/etc/profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - APKBUILD = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - PKGBUILD = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ["bash.bashrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - bashrc = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, + ['a2psrc'] = 'a2ps', + ['/etc/a2ps.cfg'] = 'a2ps', + ['.a2psrc'] = 'a2ps', + ['.asoundrc'] = 'alsaconf', + ['/usr/share/alsa/alsa.conf'] = 'alsaconf', + ['/etc/asound.conf'] = 'alsaconf', + ['build.xml'] = 'ant', + ['.htaccess'] = 'apache', + ['apt.conf'] = 'aptconf', + ['/.aptitude/config'] = 'aptconf', + ['=tagging-method'] = 'arch', + ['.arch-inventory'] = 'arch', + ['GNUmakefile.am'] = 'automake', + ['named.root'] = 'bindzone', + WORKSPACE = 'bzl', + BUILD = 'bzl', + ['cabal.config'] = 'cabalconfig', + ['cabal.project'] = 'cabalproject', + calendar = 'calendar', + catalog = 'catalog', + ['/etc/cdrdao.conf'] = 'cdrdaoconf', + ['.cdrdao'] = 'cdrdaoconf', + ['/etc/default/cdrdao'] = 'cdrdaoconf', + ['/etc/defaults/cdrdao'] = 'cdrdaoconf', + ['cfengine.conf'] = 'cfengine', + ['CMakeLists.txt'] = 'cmake', + ['auto.master'] = 'conf', + ['configure.in'] = 'config', + ['configure.ac'] = 'config', + ['.cvsrc'] = 'cvsrc', + ['/debian/changelog'] = 'debchangelog', + ['changelog.dch'] = 'debchangelog', + ['changelog.Debian'] = 'debchangelog', + ['NEWS.dch'] = 'debchangelog', + ['NEWS.Debian'] = 'debchangelog', + ['/debian/control'] = 'debcontrol', + ['/debian/copyright'] = 'debcopyright', + ['/etc/apt/sources.list'] = 'debsources', + ['denyhosts.conf'] = 'denyhosts', + ['dict.conf'] = 'dictconf', + ['.dictrc'] = 'dictconf', + ['/etc/DIR_COLORS'] = 'dircolors', + ['.dir_colors'] = 'dircolors', + ['.dircolors'] = 'dircolors', + ['/etc/dnsmasq.conf'] = 'dnsmasq', + Containerfile = 'dockerfile', + Dockerfile = 'dockerfile', + npmrc = 'dosini', + ['/etc/yum.conf'] = 'dosini', + ['/etc/pacman.conf'] = 'conf', + ['.npmrc'] = 'dosini', + ['.editorconfig'] = 'dosini', + dune = 'dune', + jbuild = 'dune', + ['dune-workspace'] = 'dune', + ['dune-project'] = 'dune', + ['elinks.conf'] = 'elinks', + ['mix.lock'] = 'elixir', + ['filter-rules'] = 'elmfilt', + ['exim.conf'] = 'exim', + exports = 'exports', + ['.fetchmailrc'] = 'fetchmail', + fvSchemes = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + fvSolution = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + fvConstraints = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + fvModels = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + fstab = 'fstab', + mtab = 'fstab', + ['.gdbinit'] = 'gdb', + gdbinit = 'gdb', + ['.gdbearlyinit'] = 'gdb', + gdbearlyinit = 'gdb', + ['lltxxxxx.txt'] = 'gedcom', + ['TAG_EDITMSG'] = 'gitcommit', + ['MERGE_MSG'] = 'gitcommit', + ['COMMIT_EDITMSG'] = 'gitcommit', + ['NOTES_EDITMSG'] = 'gitcommit', + ['EDIT_DESCRIPTION'] = 'gitcommit', + ['.gitconfig'] = 'gitconfig', + ['.gitmodules'] = 'gitconfig', + ['gitolite.conf'] = 'gitolite', + ['git-rebase-todo'] = 'gitrebase', + gkrellmrc = 'gkrellmrc', + ['.gnashrc'] = 'gnash', + ['.gnashpluginrc'] = 'gnash', + gnashpluginrc = 'gnash', + gnashrc = 'gnash', + ['go.work'] = 'gowork', + ['.gprc'] = 'gp', + ['/.gnupg/gpg.conf'] = 'gpg', + ['/.gnupg/options'] = 'gpg', + ['/var/backups/gshadow.bak'] = 'group', + ['/etc/gshadow'] = 'group', + ['/etc/group-'] = 'group', + ['/etc/gshadow.edit'] = 'group', + ['/etc/gshadow-'] = 'group', + ['/etc/group'] = 'group', + ['/var/backups/group.bak'] = 'group', + ['/etc/group.edit'] = 'group', + ['/boot/grub/menu.lst'] = 'grub', + ['/etc/grub.conf'] = 'grub', + ['/boot/grub/grub.conf'] = 'grub', + ['.gtkrc'] = 'gtkrc', + gtkrc = 'gtkrc', + ['snort.conf'] = 'hog', + ['vision.conf'] = 'hog', + ['/etc/host.conf'] = 'hostconf', + ['/etc/hosts.allow'] = 'hostsaccess', + ['/etc/hosts.deny'] = 'hostsaccess', + ['/i3/config'] = 'i3config', + ['/sway/config'] = 'i3config', + ['/.sway/config'] = 'i3config', + ['/.i3/config'] = 'i3config', + ['/.icewm/menu'] = 'icemenu', + ['.indent.pro'] = 'indent', + indentrc = 'indent', + inittab = 'inittab', + ['ipf.conf'] = 'ipfilter', + ['ipf6.conf'] = 'ipfilter', + ['ipf.rules'] = 'ipfilter', + ['.eslintrc'] = 'json', + ['.babelrc'] = 'json', + ['Pipfile.lock'] = 'json', + ['.firebaserc'] = 'json', + ['.prettierrc'] = 'json', + Kconfig = 'kconfig', + ['Kconfig.debug'] = 'kconfig', + ['lftp.conf'] = 'lftp', + ['.lftprc'] = 'lftp', + ['/.libao'] = 'libao', + ['/etc/libao.conf'] = 'libao', + ['lilo.conf'] = 'lilo', + ['/etc/limits'] = 'limits', + ['.emacs'] = 'lisp', + sbclrc = 'lisp', + ['.sbclrc'] = 'lisp', + ['.sawfishrc'] = 'lisp', + ['/etc/login.access'] = 'loginaccess', + ['/etc/login.defs'] = 'logindefs', + ['lynx.cfg'] = 'lynx', + ['m3overrides'] = 'm3build', + ['m3makefile'] = 'm3build', + ['cm3.cfg'] = 'm3quake', + ['.followup'] = 'mail', + ['.article'] = 'mail', + ['.letter'] = 'mail', + ['/etc/aliases'] = 'mailaliases', + ['/etc/mail/aliases'] = 'mailaliases', + mailcap = 'mailcap', + ['.mailcap'] = 'mailcap', + ['/etc/man.conf'] = 'manconf', + ['man.config'] = 'manconf', + ['maxima-init.mac'] = 'maxima', + ['meson.build'] = 'meson', + ['meson_options.txt'] = 'meson', + ['/etc/conf.modules'] = 'modconf', + ['/etc/modules'] = 'modconf', + ['/etc/modules.conf'] = 'modconf', + ['/.mplayer/config'] = 'mplayerconf', + ['mplayer.conf'] = 'mplayerconf', + mrxvtrc = 'mrxvtrc', + ['.mrxvtrc'] = 'mrxvtrc', + ['/etc/nanorc'] = 'nanorc', + Neomuttrc = 'neomuttrc', + ['.netrc'] = 'netrc', + ['.ocamlinit'] = 'ocaml', + ['.octaverc'] = 'octave', + octaverc = 'octave', + ['octave.conf'] = 'octave', + opam = 'opam', + ['/etc/pam.conf'] = 'pamconf', + ['pam_env.conf'] = 'pamenv', + ['.pam_environment'] = 'pamenv', + ['/var/backups/passwd.bak'] = 'passwd', + ['/var/backups/shadow.bak'] = 'passwd', + ['/etc/passwd'] = 'passwd', + ['/etc/passwd-'] = 'passwd', + ['/etc/shadow.edit'] = 'passwd', + ['/etc/shadow-'] = 'passwd', + ['/etc/shadow'] = 'passwd', + ['/etc/passwd.edit'] = 'passwd', + ['pf.conf'] = 'pf', + ['main.cf'] = 'pfmain', + pinerc = 'pine', + ['.pinercex'] = 'pine', + ['.pinerc'] = 'pine', + pinercex = 'pine', + ['/etc/pinforc'] = 'pinfo', + ['/.pinforc'] = 'pinfo', + ['.povrayrc'] = 'povini', + ['.procmailrc'] = 'procmail', + ['.procmail'] = 'procmail', + ['/etc/protocols'] = 'protocols', + ['.pythonstartup'] = 'python', + ['.pythonrc'] = 'python', + SConstruct = 'python', + ratpoisonrc = 'ratpoison', + ['.ratpoisonrc'] = 'ratpoison', + v = 'rcs', + inputrc = 'readline', + ['.inputrc'] = 'readline', + ['.reminders'] = 'remind', + ['resolv.conf'] = 'resolv', + ['robots.txt'] = 'robots', + Gemfile = 'ruby', + Puppetfile = 'ruby', + ['.irbrc'] = 'ruby', + irbrc = 'ruby', + Vagrantfile = 'ruby', + ['smb.conf'] = 'samba', + screenrc = 'screen', + ['.screenrc'] = 'screen', + ['/etc/sensors3.conf'] = 'sensors', + ['/etc/sensors.conf'] = 'sensors', + ['/etc/services'] = 'services', + ['/etc/serial.conf'] = 'setserial', + ['/etc/udev/cdsymlinks.conf'] = 'sh', + ['/etc/slp.conf'] = 'slpconf', + ['/etc/slp.reg'] = 'slpreg', + ['/etc/slp.spi'] = 'slpspi', + ['.slrnrc'] = 'slrnrc', + ['sendmail.cf'] = 'sm', + ['squid.conf'] = 'squid', + ['/.ssh/config'] = 'sshconfig', + ['ssh_config'] = 'sshconfig', + ['sshd_config'] = 'sshdconfig', + ['/etc/sudoers'] = 'sudoers', + ['sudoers.tmp'] = 'sudoers', + ['/etc/sysctl.conf'] = 'sysctl', + tags = 'tags', + ['.tclshrc'] = 'tcl', + ['.wishrc'] = 'tcl', + ['tclsh.rc'] = 'tcl', + ['texmf.cnf'] = 'texmf', + COPYING = 'text', + README = 'text', + LICENSE = 'text', + AUTHORS = 'text', + tfrc = 'tf', + ['.tfrc'] = 'tf', + ['tidy.conf'] = 'tidy', + tidyrc = 'tidy', + ['.tidyrc'] = 'tidy', + ['.tmux.conf'] = 'tmux', + ['/.cargo/config'] = 'toml', + Pipfile = 'toml', + ['Gopkg.lock'] = 'toml', + ['/.cargo/credentials'] = 'toml', + ['Cargo.lock'] = 'toml', + ['trustees.conf'] = 'trustees', + ['/etc/udev/udev.conf'] = 'udevconf', + ['/etc/updatedb.conf'] = 'updatedb', + ['fdrupstream.log'] = 'upstreamlog', + vgrindefs = 'vgrindefs', + ['.exrc'] = 'vim', + ['_exrc'] = 'vim', + ['_viminfo'] = 'viminfo', + ['.viminfo'] = 'viminfo', + ['.wgetrc'] = 'wget', + ['.wget2rc'] = 'wget2', + wgetrc = 'wget', + wget2rc = 'wget2', + ['.wvdialrc'] = 'wvdial', + ['wvdial.conf'] = 'wvdial', + ['.Xresources'] = 'xdefaults', + ['.Xpdefaults'] = 'xdefaults', + ['xdm-config'] = 'xdefaults', + ['.Xdefaults'] = 'xdefaults', + ['/etc/xinetd.conf'] = 'xinetd', + fglrxrc = 'xml', + ['/etc/blkid.tab'] = 'xml', + ['/etc/blkid.tab.old'] = 'xml', + ['/etc/zprofile'] = 'zsh', + ['.zlogin'] = 'zsh', + ['.zlogout'] = 'zsh', + ['.zshrc'] = 'zsh', + ['.zprofile'] = 'zsh', + ['.zcompdump'] = 'zsh', + ['.zshenv'] = 'zsh', + ['.zfbfmarks'] = 'zsh', + ['.alias'] = function() + vim.fn['dist#ft#CSH']() + end, + ['.bashrc'] = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ['.cshrc'] = function() + vim.fn['dist#ft#CSH']() + end, + ['.env'] = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + ['.kshrc'] = function() + vim.fn['dist#ft#SetFileTypeSH']('ksh') + end, + ['.login'] = function() + vim.fn['dist#ft#CSH']() + end, + ['.profile'] = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + ['.tcshrc'] = function() + vim.fn['dist#ft#SetFileTypeShell']('tcsh') + end, + ['/etc/profile'] = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + APKBUILD = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + PKGBUILD = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ['bash.bashrc'] = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + bashrc = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, crontab = starsetf('crontab'), - ["csh.cshrc"] = function() vim.fn["dist#ft#CSH"]() end, - ["csh.login"] = function() vim.fn["dist#ft#CSH"]() end, - ["csh.logout"] = function() vim.fn["dist#ft#CSH"]() end, - ["indent.pro"] = function() vim.fn["dist#ft#ProtoCheck"]('indent') end, - ["tcsh.login"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, - ["tcsh.tcshrc"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, + ['csh.cshrc'] = function() + vim.fn['dist#ft#CSH']() + end, + ['csh.login'] = function() + vim.fn['dist#ft#CSH']() + end, + ['csh.logout'] = function() + vim.fn['dist#ft#CSH']() + end, + ['indent.pro'] = function() + vim.fn['dist#ft#ProtoCheck']('indent') + end, + ['tcsh.login'] = function() + vim.fn['dist#ft#SetFileTypeShell']('tcsh') + end, + ['tcsh.tcshrc'] = function() + vim.fn['dist#ft#SetFileTypeShell']('tcsh') + end, -- END FILENAME } local pattern = { -- BEGIN PATTERN - [".*/etc/a2ps/.*%.cfg"] = "a2ps", - [".*/etc/a2ps%.cfg"] = "a2ps", - [".*/usr/share/alsa/alsa%.conf"] = "alsaconf", - [".*/etc/asound%.conf"] = "alsaconf", - [".*/etc/apache2/sites%-.*/.*%.com"] = "apache", - [".*/etc/httpd/.*%.conf"] = "apache", - [".*/%.aptitude/config"] = "aptconf", - ["[mM]akefile%.am"] = "automake", - [".*bsd"] = "bsdl", - ["bzr_log%..*"] = "bzr", - [".*enlightenment/.*%.cfg"] = "c", - [".*/etc/defaults/cdrdao"] = "cdrdaoconf", - [".*/etc/cdrdao%.conf"] = "cdrdaoconf", - [".*/etc/default/cdrdao"] = "cdrdaoconf", - [".*hgrc"] = "cfg", - [".*%.%.ch"] = "chill", - [".*%.cmake%.in"] = "cmake", - [".*/debian/changelog"] = "debchangelog", - [".*/debian/control"] = "debcontrol", - [".*/debian/copyright"] = "debcopyright", - [".*/etc/apt/sources%.list%.d/.*%.list"] = "debsources", - [".*/etc/apt/sources%.list"] = "debsources", - ["dictd.*%.conf"] = "dictdconf", - [".*/etc/DIR_COLORS"] = "dircolors", - [".*/etc/dnsmasq%.conf"] = "dnsmasq", - ["php%.ini%-.*"] = "dosini", - [".*/etc/pacman%.conf"] = "conf", - [".*/etc/yum%.conf"] = "dosini", - [".*lvs"] = "dracula", - [".*lpe"] = "dracula", - [".*/dtrace/.*%.d"] = "dtrace", - [".*esmtprc"] = "esmtprc", - [".*Eterm/.*%.cfg"] = "eterm", - [".*%.git/modules/.*/config"] = "gitconfig", - [".*%.git/config"] = "gitconfig", - [".*/etc/gitconfig"] = "gitconfig", - [".*/%.config/git/config"] = "gitconfig", - [".*%.git/config%.worktree"] = "gitconfig", - [".*%.git/worktrees/.*/config%.worktree"] = "gitconfig", - ["%.gitsendemail%.msg%......."] = "gitsendemail", - ["gkrellmrc_."] = "gkrellmrc", - [".*/usr/.*/gnupg/options%.skel"] = "gpg", - [".*/%.gnupg/options"] = "gpg", - [".*/%.gnupg/gpg%.conf"] = "gpg", - [".*/etc/group"] = "group", - [".*/etc/gshadow"] = "group", - [".*/etc/group%.edit"] = "group", - [".*/var/backups/gshadow%.bak"] = "group", - [".*/etc/group-"] = "group", - [".*/etc/gshadow-"] = "group", - [".*/var/backups/group%.bak"] = "group", - [".*/etc/gshadow%.edit"] = "group", - [".*/boot/grub/grub%.conf"] = "grub", - [".*/boot/grub/menu%.lst"] = "grub", - [".*/etc/grub%.conf"] = "grub", - ["hg%-editor%-.*%.txt"] = "hgcommit", - [".*/etc/host%.conf"] = "hostconf", - [".*/etc/hosts%.deny"] = "hostsaccess", - [".*/etc/hosts%.allow"] = "hostsaccess", - [".*%.html%.m4"] = "htmlm4", - [".*/%.i3/config"] = "i3config", - [".*/sway/config"] = "i3config", - [".*/i3/config"] = "i3config", - [".*/%.sway/config"] = "i3config", - [".*/%.icewm/menu"] = "icemenu", - [".*/etc/initng/.*/.*%.i"] = "initng", - [".*%.properties_.."] = "jproperties", - [".*%.properties_.._.."] = "jproperties", - [".*lftp/rc"] = "lftp", - [".*/%.libao"] = "libao", - [".*/etc/libao%.conf"] = "libao", - [".*/etc/.*limits%.conf"] = "limits", - [".*/etc/limits"] = "limits", - [".*/etc/.*limits%.d/.*%.conf"] = "limits", - [".*/LiteStep/.*/.*%.rc"] = "litestep", - [".*/etc/login%.access"] = "loginaccess", - [".*/etc/login%.defs"] = "logindefs", - [".*/etc/mail/aliases"] = "mailaliases", - [".*/etc/aliases"] = "mailaliases", - [".*[mM]akefile"] = "make", - [".*/etc/man%.conf"] = "manconf", - [".*/etc/modules%.conf"] = "modconf", - [".*/etc/conf%.modules"] = "modconf", - [".*/etc/modules"] = "modconf", - [".*%.[mi][3g]"] = "modula3", - [".*/%.mplayer/config"] = "mplayerconf", - ["rndc.*%.conf"] = "named", - ["rndc.*%.key"] = "named", - ["named.*%.conf"] = "named", - [".*/etc/nanorc"] = "nanorc", - [".*%.NS[ACGLMNPS]"] = "natural", - ["nginx.*%.conf"] = "nginx", - [".*/etc/nginx/.*"] = "nginx", - [".*nginx%.conf"] = "nginx", - [".*/nginx/.*%.conf"] = "nginx", - [".*/usr/local/nginx/conf/.*"] = "nginx", - [".*%.ml%.cppo"] = "ocaml", - [".*%.mli%.cppo"] = "ocaml", - [".*%.opam%.template"] = "opam", - [".*%.[Oo][Pp][Ll]"] = "opl", - [".*/etc/pam%.conf"] = "pamconf", - [".*/etc/passwd-"] = "passwd", - [".*/etc/shadow"] = "passwd", - [".*/etc/shadow%.edit"] = "passwd", - [".*/var/backups/shadow%.bak"] = "passwd", - [".*/var/backups/passwd%.bak"] = "passwd", - [".*/etc/passwd"] = "passwd", - [".*/etc/passwd%.edit"] = "passwd", - [".*/etc/shadow-"] = "passwd", - [".*/%.pinforc"] = "pinfo", - [".*/etc/pinforc"] = "pinfo", - [".*/etc/protocols"] = "protocols", - [".*baseq[2-3]/.*%.cfg"] = "quake", - [".*quake[1-3]/.*%.cfg"] = "quake", - [".*id1/.*%.cfg"] = "quake", - ["[rR]antfile"] = "ruby", - ["[rR]akefile"] = "ruby", - [".*/etc/sensors%.conf"] = "sensors", - [".*/etc/sensors3%.conf"] = "sensors", - [".*/etc/services"] = "services", - [".*/etc/serial%.conf"] = "setserial", - [".*/etc/udev/cdsymlinks%.conf"] = "sh", - [".*%._sst%.meta"] = "sisu", - [".*%.%-sst%.meta"] = "sisu", - [".*%.sst%.meta"] = "sisu", - [".*/etc/slp%.conf"] = "slpconf", - [".*/etc/slp%.reg"] = "slpreg", - [".*/etc/slp%.spi"] = "slpspi", - [".*/etc/ssh/ssh_config%.d/.*%.conf"] = "sshconfig", - [".*/%.ssh/config"] = "sshconfig", - [".*/etc/ssh/sshd_config%.d/.*%.conf"] = "sshdconfig", - [".*/etc/sudoers"] = "sudoers", - ["svn%-commit.*%.tmp"] = "svn", - [".*%.swift%.gyb"] = "swiftgyb", - [".*/etc/sysctl%.conf"] = "sysctl", - [".*/etc/sysctl%.d/.*%.conf"] = "sysctl", - [".*/etc/systemd/.*%.conf%.d/.*%.conf"] = "systemd", - [".*/%.config/systemd/user/.*%.d/.*%.conf"] = "systemd", - [".*/etc/systemd/system/.*%.d/.*%.conf"] = "systemd", - [".*%.t%.html"] = "tilde", - ["%.?tmux.*%.conf"] = "tmux", - ["%.?tmux.*%.conf.*"] = { "tmux", { priority = -1 } }, - [".*/%.cargo/config"] = "toml", - [".*/%.cargo/credentials"] = "toml", - [".*/etc/udev/udev%.conf"] = "udevconf", - [".*/etc/udev/permissions%.d/.*%.permissions"] = "udevperm", - [".*/etc/updatedb%.conf"] = "updatedb", - [".*/%.init/.*%.override"] = "upstart", - [".*/usr/share/upstart/.*%.conf"] = "upstart", - [".*/%.config/upstart/.*%.override"] = "upstart", - [".*/etc/init/.*%.conf"] = "upstart", - [".*/etc/init/.*%.override"] = "upstart", - [".*/%.config/upstart/.*%.conf"] = "upstart", - [".*/%.init/.*%.conf"] = "upstart", - [".*/usr/share/upstart/.*%.override"] = "upstart", - [".*%.ws[fc]"] = "wsh", - [".*/etc/xinetd%.conf"] = "xinetd", - [".*/etc/blkid%.tab"] = "xml", - [".*/etc/blkid%.tab%.old"] = "xml", - [".*%.vbproj%.user"] = "xml", - [".*%.fsproj%.user"] = "xml", - [".*%.csproj%.user"] = "xml", - [".*/etc/xdg/menus/.*%.menu"] = "xml", - [".*Xmodmap"] = "xmodmap", - [".*/etc/zprofile"] = "zsh", - ["%.bash[_-]aliases"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ["%.bash[_-]logout"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ["%.bash[_-]profile"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ["%.cshrc.*"] = function() vim.fn["dist#ft#CSH"]() end, - ["%.gtkrc.*"] = starsetf('gtkrc'), - ["%.kshrc.*"] = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end, - ["%.login.*"] = function() vim.fn["dist#ft#CSH"]() end, - ["%.neomuttrc.*"] = starsetf('neomuttrc'), - ["%.profile.*"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - ["%.reminders.*"] = starsetf('remind'), - ["%.tcshrc.*"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end, - ["%.zcompdump.*"] = starsetf('zsh'), - ["%.zlog.*"] = starsetf('zsh'), - ["%.zsh.*"] = starsetf('zsh'), - [".*%.[1-9]"] = function(path, bufnr) return require("vim.filetype.detect").nroff(bufnr) end, - [".*%.[aA]"] = function() vim.fn["dist#ft#FTasm"]() end, - [".*%.[sS]"] = function() vim.fn["dist#ft#FTasm"]() end, - [".*%.properties_.._.._.*"] = starsetf('jproperties'), - [".*%.vhdl_[0-9].*"] = starsetf('vhdl'), - [".*/%.fvwm/.*"] = starsetf('fvwm'), - [".*/%.gitconfig%.d/.*"] = starsetf('gitconfig'), - [".*/%.neomutt/neomuttrc.*"] = starsetf('neomuttrc'), - [".*/Xresources/.*"] = starsetf('xdefaults'), - [".*/app%-defaults/.*"] = starsetf('xdefaults'), - [".*/bind/db%..*"] = starsetf('bindzone'), - [".*/debian/patches/.*"] = function() vim.fn["dist#ft#Dep3patch"]() end, - [".*/etc/Muttrc%.d/.*"] = starsetf('muttrc'), - [".*/etc/apache2/.*%.conf.*"] = starsetf('apache'), - [".*/etc/apache2/conf%..*/.*"] = starsetf('apache'), - [".*/etc/apache2/mods%-.*/.*"] = starsetf('apache'), - [".*/etc/apache2/sites%-.*/.*"] = starsetf('apache'), - [".*/etc/cron%.d/.*"] = starsetf('crontab'), - [".*/etc/dnsmasq%.d/.*"] = starsetf('dnsmasq'), - [".*/etc/httpd/conf%..*/.*"] = starsetf('apache'), - [".*/etc/httpd/conf%.d/.*%.conf.*"] = starsetf('apache'), - [".*/etc/httpd/mods%-.*/.*"] = starsetf('apache'), - [".*/etc/httpd/sites%-.*/.*"] = starsetf('apache'), - [".*/etc/logcheck/.*%.d.*/.*"] = starsetf('logcheck'), - [".*/etc/modprobe%..*"] = starsetf('modconf'), - [".*/etc/pam%.d/.*"] = starsetf('pamconf'), - [".*/etc/profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end, - [".*/etc/proftpd/.*%.conf.*"] = starsetf('apachestyle'), - [".*/etc/proftpd/conf%..*/.*"] = starsetf('apachestyle'), - [".*/etc/sudoers%.d/.*"] = starsetf('sudoers'), - [".*/etc/xinetd%.d/.*"] = starsetf('xinetd'), - [".*/etc/yum%.repos%.d/.*"] = starsetf('dosini'), - [".*/gitolite%-admin/conf/.*"] = starsetf('gitolite'), - [".*/named/db%..*"] = starsetf('bindzone'), - [".*/tmp/lltmp.*"] = starsetf('gedcom'), - [".*asterisk.*/.*voicemail%.conf.*"] = starsetf('asteriskvm'), - [".*asterisk/.*%.conf.*"] = starsetf('asterisk'), - [".*vimrc.*"] = starsetf('vim'), - [".*xmodmap.*"] = starsetf('xmodmap'), - ["/etc/gitconfig%.d/.*"] = starsetf('gitconfig'), - ["/etc/hostname%..*"] = starsetf('config'), - ["Containerfile%..*"] = starsetf('dockerfile'), - ["Dockerfile%..*"] = starsetf('dockerfile'), - ["JAM.*%..*"] = starsetf('jam'), - ["Kconfig%..*"] = starsetf('kconfig'), - ["Neomuttrc.*"] = starsetf('neomuttrc'), - ["Prl.*%..*"] = starsetf('jam'), - ["Xresources.*"] = starsetf('xdefaults'), - ["[mM]akefile.*"] = starsetf('make'), - ["[rR]akefile.*"] = starsetf('ruby'), - ["access%.conf.*"] = starsetf('apache'), - ["apache%.conf.*"] = starsetf('apache'), - ["apache2%.conf.*"] = starsetf('apache'), - ["bash%-fc[-%.]"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end, - ["cabal%.project%..*"] = starsetf('cabalproject'), - ["crontab%..*"] = starsetf('crontab'), - ["drac%..*"] = starsetf('dracula'), - ["gtkrc.*"] = starsetf('gtkrc'), - ["httpd%.conf.*"] = starsetf('apache'), - ["lilo%.conf.*"] = starsetf('lilo'), - ["neomuttrc.*"] = starsetf('neomuttrc'), - ["proftpd%.conf.*"] = starsetf('apachestyle'), - ["reportbug%-.*"] = starsetf('mail'), - ["sgml%.catalog.*"] = starsetf('catalog'), - ["srm%.conf.*"] = starsetf('apache'), - ["tmac%..*"] = starsetf('nroff'), - ["zlog.*"] = starsetf('zsh'), - ["zsh.*"] = starsetf('zsh'), - ["ae%d+%.txt"] = 'mail', - ["snd%.%d+"] = "mail", - ["%.letter%.%d+"] = "mail", - ["%.article%.%d+"] = "mail", - ["pico%.%d+"] = "mail", - ["mutt%-.*%-%w+"] = "mail", - ["neomutt%-.*%-%w+"] = "mail", - ["muttng%-.*%-%w+"] = "mail", - ["mutt" .. string.rep("[%w_-]", 6)] = "mail", - ["neomutt" .. string.rep("[%w_-]", 6)] = "mail", - ["/tmp/SLRN[0-9A-Z.]+"] = "mail", - ["[a-zA-Z0-9].*Dict"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - ["[a-zA-Z0-9].*Dict%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - ["[a-zA-Z].*Properties"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - ["[a-zA-Z].*Properties%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - [".*Transport%..*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - [".*/constant/g"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - [".*/0/.*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - [".*/0%.orig/.*"] = function(path, bufnr) require("vim.filetype.detect").foam(bufnr) end, - [".*/etc/sensors%.d/[^.].*"] = starsetf('sensors'), - [".*%.git/.*"] = function(path, bufnr) + ['.*/etc/a2ps/.*%.cfg'] = 'a2ps', + ['.*/etc/a2ps%.cfg'] = 'a2ps', + ['.*/usr/share/alsa/alsa%.conf'] = 'alsaconf', + ['.*/etc/asound%.conf'] = 'alsaconf', + ['.*/etc/apache2/sites%-.*/.*%.com'] = 'apache', + ['.*/etc/httpd/.*%.conf'] = 'apache', + ['.*/%.aptitude/config'] = 'aptconf', + ['[mM]akefile%.am'] = 'automake', + ['.*bsd'] = 'bsdl', + ['bzr_log%..*'] = 'bzr', + ['.*enlightenment/.*%.cfg'] = 'c', + ['.*/etc/defaults/cdrdao'] = 'cdrdaoconf', + ['.*/etc/cdrdao%.conf'] = 'cdrdaoconf', + ['.*/etc/default/cdrdao'] = 'cdrdaoconf', + ['.*hgrc'] = 'cfg', + ['.*%.%.ch'] = 'chill', + ['.*%.cmake%.in'] = 'cmake', + ['.*/debian/changelog'] = 'debchangelog', + ['.*/debian/control'] = 'debcontrol', + ['.*/debian/copyright'] = 'debcopyright', + ['.*/etc/apt/sources%.list%.d/.*%.list'] = 'debsources', + ['.*/etc/apt/sources%.list'] = 'debsources', + ['dictd.*%.conf'] = 'dictdconf', + ['.*/etc/DIR_COLORS'] = 'dircolors', + ['.*/etc/dnsmasq%.conf'] = 'dnsmasq', + ['php%.ini%-.*'] = 'dosini', + ['.*/etc/pacman%.conf'] = 'conf', + ['.*/etc/yum%.conf'] = 'dosini', + ['.*lvs'] = 'dracula', + ['.*lpe'] = 'dracula', + ['.*/dtrace/.*%.d'] = 'dtrace', + ['.*esmtprc'] = 'esmtprc', + ['.*Eterm/.*%.cfg'] = 'eterm', + ['.*%.git/modules/.*/config'] = 'gitconfig', + ['.*%.git/config'] = 'gitconfig', + ['.*/etc/gitconfig'] = 'gitconfig', + ['.*/%.config/git/config'] = 'gitconfig', + ['.*%.git/config%.worktree'] = 'gitconfig', + ['.*%.git/worktrees/.*/config%.worktree'] = 'gitconfig', + ['%.gitsendemail%.msg%.......'] = 'gitsendemail', + ['gkrellmrc_.'] = 'gkrellmrc', + ['.*/usr/.*/gnupg/options%.skel'] = 'gpg', + ['.*/%.gnupg/options'] = 'gpg', + ['.*/%.gnupg/gpg%.conf'] = 'gpg', + ['.*/etc/group'] = 'group', + ['.*/etc/gshadow'] = 'group', + ['.*/etc/group%.edit'] = 'group', + ['.*/var/backups/gshadow%.bak'] = 'group', + ['.*/etc/group-'] = 'group', + ['.*/etc/gshadow-'] = 'group', + ['.*/var/backups/group%.bak'] = 'group', + ['.*/etc/gshadow%.edit'] = 'group', + ['.*/boot/grub/grub%.conf'] = 'grub', + ['.*/boot/grub/menu%.lst'] = 'grub', + ['.*/etc/grub%.conf'] = 'grub', + ['hg%-editor%-.*%.txt'] = 'hgcommit', + ['.*/etc/host%.conf'] = 'hostconf', + ['.*/etc/hosts%.deny'] = 'hostsaccess', + ['.*/etc/hosts%.allow'] = 'hostsaccess', + ['.*%.html%.m4'] = 'htmlm4', + ['.*/%.i3/config'] = 'i3config', + ['.*/sway/config'] = 'i3config', + ['.*/i3/config'] = 'i3config', + ['.*/%.sway/config'] = 'i3config', + ['.*/%.icewm/menu'] = 'icemenu', + ['.*/etc/initng/.*/.*%.i'] = 'initng', + ['.*%.properties_..'] = 'jproperties', + ['.*%.properties_.._..'] = 'jproperties', + ['.*lftp/rc'] = 'lftp', + ['.*/%.libao'] = 'libao', + ['.*/etc/libao%.conf'] = 'libao', + ['.*/etc/.*limits%.conf'] = 'limits', + ['.*/etc/limits'] = 'limits', + ['.*/etc/.*limits%.d/.*%.conf'] = 'limits', + ['.*/LiteStep/.*/.*%.rc'] = 'litestep', + ['.*/etc/login%.access'] = 'loginaccess', + ['.*/etc/login%.defs'] = 'logindefs', + ['.*/etc/mail/aliases'] = 'mailaliases', + ['.*/etc/aliases'] = 'mailaliases', + ['.*[mM]akefile'] = 'make', + ['.*/etc/man%.conf'] = 'manconf', + ['.*/etc/modules%.conf'] = 'modconf', + ['.*/etc/conf%.modules'] = 'modconf', + ['.*/etc/modules'] = 'modconf', + ['.*%.[mi][3g]'] = 'modula3', + ['.*/%.mplayer/config'] = 'mplayerconf', + ['rndc.*%.conf'] = 'named', + ['rndc.*%.key'] = 'named', + ['named.*%.conf'] = 'named', + ['.*/etc/nanorc'] = 'nanorc', + ['.*%.NS[ACGLMNPS]'] = 'natural', + ['nginx.*%.conf'] = 'nginx', + ['.*/etc/nginx/.*'] = 'nginx', + ['.*nginx%.conf'] = 'nginx', + ['.*/nginx/.*%.conf'] = 'nginx', + ['.*/usr/local/nginx/conf/.*'] = 'nginx', + ['.*%.ml%.cppo'] = 'ocaml', + ['.*%.mli%.cppo'] = 'ocaml', + ['.*%.opam%.template'] = 'opam', + ['.*%.[Oo][Pp][Ll]'] = 'opl', + ['.*/etc/pam%.conf'] = 'pamconf', + ['.*/etc/passwd-'] = 'passwd', + ['.*/etc/shadow'] = 'passwd', + ['.*/etc/shadow%.edit'] = 'passwd', + ['.*/var/backups/shadow%.bak'] = 'passwd', + ['.*/var/backups/passwd%.bak'] = 'passwd', + ['.*/etc/passwd'] = 'passwd', + ['.*/etc/passwd%.edit'] = 'passwd', + ['.*/etc/shadow-'] = 'passwd', + ['.*/%.pinforc'] = 'pinfo', + ['.*/etc/pinforc'] = 'pinfo', + ['.*/etc/protocols'] = 'protocols', + ['.*baseq[2-3]/.*%.cfg'] = 'quake', + ['.*quake[1-3]/.*%.cfg'] = 'quake', + ['.*id1/.*%.cfg'] = 'quake', + ['[rR]antfile'] = 'ruby', + ['[rR]akefile'] = 'ruby', + ['.*/etc/sensors%.conf'] = 'sensors', + ['.*/etc/sensors3%.conf'] = 'sensors', + ['.*/etc/services'] = 'services', + ['.*/etc/serial%.conf'] = 'setserial', + ['.*/etc/udev/cdsymlinks%.conf'] = 'sh', + ['.*%._sst%.meta'] = 'sisu', + ['.*%.%-sst%.meta'] = 'sisu', + ['.*%.sst%.meta'] = 'sisu', + ['.*/etc/slp%.conf'] = 'slpconf', + ['.*/etc/slp%.reg'] = 'slpreg', + ['.*/etc/slp%.spi'] = 'slpspi', + ['.*/etc/ssh/ssh_config%.d/.*%.conf'] = 'sshconfig', + ['.*/%.ssh/config'] = 'sshconfig', + ['.*/etc/ssh/sshd_config%.d/.*%.conf'] = 'sshdconfig', + ['.*/etc/sudoers'] = 'sudoers', + ['svn%-commit.*%.tmp'] = 'svn', + ['.*%.swift%.gyb'] = 'swiftgyb', + ['.*/etc/sysctl%.conf'] = 'sysctl', + ['.*/etc/sysctl%.d/.*%.conf'] = 'sysctl', + ['.*/etc/systemd/.*%.conf%.d/.*%.conf'] = 'systemd', + ['.*/%.config/systemd/user/.*%.d/.*%.conf'] = 'systemd', + ['.*/etc/systemd/system/.*%.d/.*%.conf'] = 'systemd', + ['.*%.t%.html'] = 'tilde', + ['%.?tmux.*%.conf'] = 'tmux', + ['%.?tmux.*%.conf.*'] = { 'tmux', { priority = -1 } }, + ['.*/%.cargo/config'] = 'toml', + ['.*/%.cargo/credentials'] = 'toml', + ['.*/etc/udev/udev%.conf'] = 'udevconf', + ['.*/etc/udev/permissions%.d/.*%.permissions'] = 'udevperm', + ['.*/etc/updatedb%.conf'] = 'updatedb', + ['.*/%.init/.*%.override'] = 'upstart', + ['.*/usr/share/upstart/.*%.conf'] = 'upstart', + ['.*/%.config/upstart/.*%.override'] = 'upstart', + ['.*/etc/init/.*%.conf'] = 'upstart', + ['.*/etc/init/.*%.override'] = 'upstart', + ['.*/%.config/upstart/.*%.conf'] = 'upstart', + ['.*/%.init/.*%.conf'] = 'upstart', + ['.*/usr/share/upstart/.*%.override'] = 'upstart', + ['.*%.ws[fc]'] = 'wsh', + ['.*/etc/xinetd%.conf'] = 'xinetd', + ['.*/etc/blkid%.tab'] = 'xml', + ['.*/etc/blkid%.tab%.old'] = 'xml', + ['.*%.vbproj%.user'] = 'xml', + ['.*%.fsproj%.user'] = 'xml', + ['.*%.csproj%.user'] = 'xml', + ['.*/etc/xdg/menus/.*%.menu'] = 'xml', + ['.*Xmodmap'] = 'xmodmap', + ['.*/etc/zprofile'] = 'zsh', + ['%.bash[_-]aliases'] = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ['%.bash[_-]logout'] = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ['%.bash[_-]profile'] = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ['%.cshrc.*'] = function() + vim.fn['dist#ft#CSH']() + end, + ['%.gtkrc.*'] = starsetf('gtkrc'), + ['%.kshrc.*'] = function() + vim.fn['dist#ft#SetFileTypeSH']('ksh') + end, + ['%.login.*'] = function() + vim.fn['dist#ft#CSH']() + end, + ['%.neomuttrc.*'] = starsetf('neomuttrc'), + ['%.profile.*'] = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + ['%.reminders.*'] = starsetf('remind'), + ['%.tcshrc.*'] = function() + vim.fn['dist#ft#SetFileTypeShell']('tcsh') + end, + ['%.zcompdump.*'] = starsetf('zsh'), + ['%.zlog.*'] = starsetf('zsh'), + ['%.zsh.*'] = starsetf('zsh'), + ['.*%.[1-9]'] = function(path, bufnr) + return require('vim.filetype.detect').nroff(bufnr) + end, + ['.*%.[aA]'] = function() + vim.fn['dist#ft#FTasm']() + end, + ['.*%.[sS]'] = function() + vim.fn['dist#ft#FTasm']() + end, + ['.*%.properties_.._.._.*'] = starsetf('jproperties'), + ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), + ['.*/%.fvwm/.*'] = starsetf('fvwm'), + ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), + ['.*/%.neomutt/neomuttrc.*'] = starsetf('neomuttrc'), + ['.*/Xresources/.*'] = starsetf('xdefaults'), + ['.*/app%-defaults/.*'] = starsetf('xdefaults'), + ['.*/bind/db%..*'] = starsetf('bindzone'), + ['.*/debian/patches/.*'] = function() + vim.fn['dist#ft#Dep3patch']() + end, + ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'), + ['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'), + ['.*/etc/apache2/conf%..*/.*'] = starsetf('apache'), + ['.*/etc/apache2/mods%-.*/.*'] = starsetf('apache'), + ['.*/etc/apache2/sites%-.*/.*'] = starsetf('apache'), + ['.*/etc/cron%.d/.*'] = starsetf('crontab'), + ['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'), + ['.*/etc/httpd/conf%..*/.*'] = starsetf('apache'), + ['.*/etc/httpd/conf%.d/.*%.conf.*'] = starsetf('apache'), + ['.*/etc/httpd/mods%-.*/.*'] = starsetf('apache'), + ['.*/etc/httpd/sites%-.*/.*'] = starsetf('apache'), + ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'), + ['.*/etc/modprobe%..*'] = starsetf('modconf'), + ['.*/etc/pam%.d/.*'] = starsetf('pamconf'), + ['.*/etc/profile'] = function() + vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + end, + ['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'), + ['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'), + ['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'), + ['.*/etc/xinetd%.d/.*'] = starsetf('xinetd'), + ['.*/etc/yum%.repos%.d/.*'] = starsetf('dosini'), + ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'), + ['.*/named/db%..*'] = starsetf('bindzone'), + ['.*/tmp/lltmp.*'] = starsetf('gedcom'), + ['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'), + ['.*asterisk/.*%.conf.*'] = starsetf('asterisk'), + ['.*vimrc.*'] = starsetf('vim'), + ['.*xmodmap.*'] = starsetf('xmodmap'), + ['/etc/gitconfig%.d/.*'] = starsetf('gitconfig'), + ['/etc/hostname%..*'] = starsetf('config'), + ['Containerfile%..*'] = starsetf('dockerfile'), + ['Dockerfile%..*'] = starsetf('dockerfile'), + ['JAM.*%..*'] = starsetf('jam'), + ['Kconfig%..*'] = starsetf('kconfig'), + ['Neomuttrc.*'] = starsetf('neomuttrc'), + ['Prl.*%..*'] = starsetf('jam'), + ['Xresources.*'] = starsetf('xdefaults'), + ['[mM]akefile.*'] = starsetf('make'), + ['[rR]akefile.*'] = starsetf('ruby'), + ['access%.conf.*'] = starsetf('apache'), + ['apache%.conf.*'] = starsetf('apache'), + ['apache2%.conf.*'] = starsetf('apache'), + ['bash%-fc[-%.]'] = function() + vim.fn['dist#ft#SetFileTypeSH']('bash') + end, + ['cabal%.project%..*'] = starsetf('cabalproject'), + ['crontab%..*'] = starsetf('crontab'), + ['drac%..*'] = starsetf('dracula'), + ['gtkrc.*'] = starsetf('gtkrc'), + ['httpd%.conf.*'] = starsetf('apache'), + ['lilo%.conf.*'] = starsetf('lilo'), + ['neomuttrc.*'] = starsetf('neomuttrc'), + ['proftpd%.conf.*'] = starsetf('apachestyle'), + ['reportbug%-.*'] = starsetf('mail'), + ['sgml%.catalog.*'] = starsetf('catalog'), + ['srm%.conf.*'] = starsetf('apache'), + ['tmac%..*'] = starsetf('nroff'), + ['zlog.*'] = starsetf('zsh'), + ['zsh.*'] = starsetf('zsh'), + ['ae%d+%.txt'] = 'mail', + ['snd%.%d+'] = 'mail', + ['%.letter%.%d+'] = 'mail', + ['%.article%.%d+'] = 'mail', + ['pico%.%d+'] = 'mail', + ['mutt%-.*%-%w+'] = 'mail', + ['neomutt%-.*%-%w+'] = 'mail', + ['muttng%-.*%-%w+'] = 'mail', + ['mutt' .. string.rep('[%w_-]', 6)] = 'mail', + ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail', + ['/tmp/SLRN[0-9A-Z.]+'] = 'mail', + ['[a-zA-Z0-9].*Dict'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['[a-zA-Z0-9].*Dict%..*'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['[a-zA-Z].*Properties'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['[a-zA-Z].*Properties%..*'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['.*Transport%..*'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['.*/constant/g'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['.*/0/.*'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['.*/0%.orig/.*'] = function(path, bufnr) + require('vim.filetype.detect').foam(bufnr) + end, + ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), + ['.*%.git/.*'] = function(path, bufnr) local firstline = getline(bufnr, 1) - if firstline:find("^" .. string.rep("%x", 40) .. "+ ") or firstline:sub(1, 5) == "ref: " then - return "git" + if firstline:find('^' .. string.rep('%x', 40) .. '+ ') or firstline:sub(1, 5) == 'ref: ' then + return 'git' end end, - [".*%.[Cc][Ff][Gg]"] = function() vim.fn["dist#ft#FTcfg"]() end, - [".*%.[Dd][Aa][Tt]"] = function() vim.fn["dist#ft#FTdat"]() end, - [".*%.[Mm][Oo][Dd]"] = function() vim.fn["dist#ft#FTmod"]() end, - [".*%.[Ss][Rr][Cc]"] = function() vim.fn["dist#ft#FTsrc"]() end, - [".*%.[Ss][Uu][Bb]"] = "krl", - [".*%.[Pp][Rr][Gg]"] = function() vim.fn["dist#ft#FTprg"]() end, - [".*%.[Ss][Yy][Ss]"] = function() vim.fn["dist#ft#FTsys"]() end, + ['.*%.[Cc][Ff][Gg]'] = function() + vim.fn['dist#ft#FTcfg']() + end, + ['.*%.[Dd][Aa][Tt]'] = function() + vim.fn['dist#ft#FTdat']() + end, + ['.*%.[Mm][Oo][Dd]'] = function() + vim.fn['dist#ft#FTmod']() + end, + ['.*%.[Ss][Rr][Cc]'] = function() + vim.fn['dist#ft#FTsrc']() + end, + ['.*%.[Ss][Uu][Bb]'] = 'krl', + ['.*%.[Pp][Rr][Gg]'] = function() + vim.fn['dist#ft#FTprg']() + end, + ['.*%.[Ss][Yy][Ss]'] = function() + vim.fn['dist#ft#FTsys']() + end, -- Neovim only - [".*/queries/.*%.scm"] = "query", -- tree-sitter queries + ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries -- END PATTERN } -- luacheck: pop @@ -1466,10 +1709,10 @@ local pattern = { local function sort_by_priority(t) local sorted = {} for k, v in pairs(t) do - local ft = type(v) == "table" and v[1] or v - assert(type(ft) == "string" or type(ft) == "function", "Expected string or function for filetype") + local ft = type(v) == 'table' and v[1] or v + assert(type(ft) == 'string' or type(ft) == 'function', 'Expected string or function for filetype') - local opts = (type(v) == "table" and type(v[2]) == "table") and v[2] or {} + local opts = (type(v) == 'table' and type(v[2]) == 'table') and v[2] or {} if not opts.priority then opts.priority = 0 end @@ -1485,7 +1728,7 @@ local pattern_sorted = sort_by_priority(pattern) ---@private local function normalize_path(path, as_pattern) - local normal = path:gsub("\\", '/') + local normal = path:gsub('\\', '/') if normal:find('^~') then if as_pattern then -- Escape Lua's metacharacters when $HOME is used in a pattern. @@ -1574,12 +1817,12 @@ end ---@private local function dispatch(ft, path, bufnr, ...) - if type(ft) == "function" then + if type(ft) == 'function' then ft = ft(path, bufnr, ...) end - if type(ft) == "string" then - api.nvim_buf_set_option(bufnr, "filetype", ft) + if type(ft) == 'string' then + api.nvim_buf_set_option(bufnr, 'filetype', ft) return true end @@ -1592,9 +1835,9 @@ end ---@private local function match_pattern(name, path, tail, pat) -- If the pattern contains a / match against the full path, otherwise just the tail - local fullpat = "^" .. pat .. "$" + local fullpat = '^' .. pat .. '$' local matches - if pat:find("/") then + if pat:find('/') then -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against -- both the short file name (as typed) and the full file name (after expanding to full path -- and resolving symlinks) @@ -1618,13 +1861,13 @@ function M.match(name, bufnr) name = normalize_path(name) -- First check for the simple case where the full path exists as a key - local path = vim.fn.resolve(vim.fn.fnamemodify(name, ":p")) + local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p')) if dispatch(filename[path], path, bufnr) then return end -- Next check against just the file name - local tail = vim.fn.fnamemodify(name, ":t") + local tail = vim.fn.fnamemodify(name, ':t') if dispatch(filename[tail], path, bufnr) then return end @@ -1649,7 +1892,7 @@ function M.match(name, bufnr) end -- Next, check file extension - local ext = vim.fn.fnamemodify(name, ":e") + local ext = vim.fn.fnamemodify(name, ':e') if dispatch(extension[ext], path, bufnr) then return end diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 787b335251..4c363e7403 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -9,7 +9,7 @@ local function getlines(bufnr, start_lnum, end_lnum, opts) local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) opts = opts or {} - return opts.concat and (table.concat(lines) or "") or lines + return opts.concat and (table.concat(lines) or '') or lines end ---@private @@ -35,23 +35,23 @@ function M.bindzone(path, bufnr) end function M.btm(bufnr) if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then - vim.bo[bufnr].filetype = "dosbatch" + vim.bo[bufnr].filetype = 'dosbatch' else - vim.bo[bufnr].filetype = "btm" + vim.bo[bufnr].filetype = 'btm' end end -- Returns true if file content looks like RAPID local function is_rapid(bufnr, extension) - if extension == "cfg" then + if extension == 'cfg' then local line = getlines(bufnr, 1):lower() - return findany(line, { "eio:cfg", "mmc:cfg", "moc:cfg", "proc:cfg", "sio:cfg", "sys:cfg" }) + return findany(line, { 'eio:cfg', 'mmc:cfg', 'moc:cfg', 'proc:cfg', 'sio:cfg', 'sys:cfg' }) end - local first = "^%s*module%s+%S+%s*" + local first = '^%s*module%s+%S+%s*' -- Called from mod, prg or sys functions for _, line in ipairs(getlines(bufnr, 1, -1)) do - if not line:find("^%s*$") then - return findany(line:lower(), { "^%s*%%%%%%", first .. "(", first .. "$" }) + if not line:find('^%s*$') then + return findany(line:lower(), { '^%s*%%%%%%', first .. '(', first .. '$' }) end end -- Only found blank lines @@ -61,10 +61,10 @@ end function M.cfg(bufnr) if vim.g.filetype_cfg then vim.bo[bufnr].filetype = vim.g.filetype_cfg - elseif is_rapid(bufnr, "cfg") then - vim.bo[bufnr].filetype = "rapid" + elseif is_rapid(bufnr, 'cfg') then + vim.bo[bufnr].filetype = 'rapid' else - vim.bo[bufnr].filetype = "cfg" + vim.bo[bufnr].filetype = 'cfg' end end @@ -85,23 +85,23 @@ function M.e(path, bufnr) end -- If not found, assume SGML. function M.ent(bufnr) for _, line in ipairs(getlines(bufnr, 1, 5)) do - if line:find("^%s*[#{]") then - vim.bo[bufnr].filetype = "cl" + if line:find('^%s*[#{]') then + vim.bo[bufnr].filetype = 'cl' return - elseif not line:find("^%s*$") then + elseif not line:find('^%s*$') then -- Not a blank line, not a comment, and not a block start, -- so doesn't look like valid cl code. break end end - vim.bo[bufnr].filetype = "dtd" + vim.bo[bufnr].filetype = 'dtd' end function M.euphoria(bufnr) if vim.g.filetype_euphoria then vim.bo[bufnr].filetype = vim.g.filetype_euphoria else - vim.bo[bufnr].filetype = "euphoria3" + vim.bo[bufnr].filetype = 'euphoria3' end end @@ -111,12 +111,12 @@ function M.ex(bufnr) else for _, line in ipairs(getlines(bufnr, 1, 100)) do -- TODO: in the Vim regex, \> is used to match the end of the word, can this be omitted? - if findany(line, { "^%-%-", "^ifdef", "^include" }) then - vim.bo[bufnr].filetype = "euphoria3" + if findany(line, { '^%-%-', '^ifdef', '^include' }) then + vim.bo[bufnr].filetype = 'euphoria3' return end end - vim.bo[bufnr].filetype = "elixir" + vim.bo[bufnr].filetype = 'elixir' end end @@ -126,10 +126,10 @@ end function M.foam(bufnr) local foam_file = false for _, line in ipairs(getlines(bufnr, 1, 15)) do - if line:find("^FoamFile") then + if line:find('^FoamFile') then foam_file = true - elseif foam_file and line:find("^%s*object") then - vim.bo[bufnr].filetype = "foam" + elseif foam_file and line:find('^%s*object') then + vim.bo[bufnr].filetype = 'foam' return end end @@ -141,10 +141,10 @@ function M.frm(bufnr) else -- Always ignore case local lines = getlines(bufnr, 1, 5, { concat = true }):lower() - if findany(lines, { "vb_name", "begin vb%.form", "begin vb%.mdiform" }) then - vim.bo[bufnr].filetype = "vb" + if findany(lines, { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform' }) then + vim.bo[bufnr].filetype = 'vb' else - vim.bo[bufnr].filetype = "form" + vim.bo[bufnr].filetype = 'form' end end end @@ -153,21 +153,21 @@ function M.fs(path, bufnr) end function M.header(bufnr) for _, line in ipairs(getlines(bufnr, 1, 200)) do - if findany(line, { "^@interface", "^@end", "^@class" }) then + if findany(line, { '^@interface', '^@end', '^@class' }) then if vim.g.c_syntax_for_h then - vim.bo[bufnr].filetype = "objc" + vim.bo[bufnr].filetype = 'objc' else - vim.bo[bufnr].filetype = "objcpp" + vim.bo[bufnr].filetype = 'objcpp' end return end end if vim.g.c_syntax_for_h then - vim.bo[bufnr].filetype = "c" + vim.bo[bufnr].filetype = 'c' elseif vim.g.ch_syntax_for_h then - vim.bo[bufnr].filetype = "ch" + vim.bo[bufnr].filetype = 'ch' else - vim.bo[bufnr].filetype = "cpp" + vim.bo[bufnr].filetype = 'cpp' end end @@ -176,22 +176,22 @@ function M.idl(bufnr) -- Always ignore case line = line:lower() if findany(line, { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then - vim.bo[bufnr].filetype = "msidl" + vim.bo[bufnr].filetype = 'msidl' return end end - vim.bo[bufnr].filetype = "idl" + vim.bo[bufnr].filetype = 'idl' end function M.inc(path, bufnr) end function M.inp(bufnr) - if getlines(bufnr, 1):find("^%*") then - vim.bo[bufnr].filetype = "abaqus" + if getlines(bufnr, 1):find('^%*') then + vim.bo[bufnr].filetype = 'abaqus' else for _, line in ipairs(getlines(bufnr, 1, 500)) do - if line:lower():find("^header surface data") then - vim.bo[bufnr].filetype = "trasys" + if line:lower():find('^header surface data') then + vim.bo[bufnr].filetype = 'trasys' return end end @@ -208,32 +208,32 @@ function M.m(path, bufnr) end -- MS message text files use ';', Sendmail files use '#' or 'dnl' function M.mc(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do - if findany(line:lower(), { "^%s*#", "^%s*dnl" }) then + if findany(line:lower(), { '^%s*#', '^%s*dnl' }) then -- Sendmail .mc file - vim.bo[bufnr].filetype = "m4" + vim.bo[bufnr].filetype = 'm4' return - elseif line:find("^%s*;") then - vim.bo[bufnr].filetype = "msmessages" + elseif line:find('^%s*;') then + vim.bo[bufnr].filetype = 'msmessages' return end end -- Default: Sendmail .mc file - vim.bo[bufnr].filetype = "m4" + vim.bo[bufnr].filetype = 'm4' end function M.mm(path, bufnr) end function M.mms(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do - if findany(line, { "^%s*%%", "^%s*//", "^%*" }) then - vim.bo[bufnr].filetype = "mmix" + if findany(line, { '^%s*%%', '^%s*//', '^%*' }) then + vim.bo[bufnr].filetype = 'mmix' return - elseif line:find("^%s*#") then - vim.bo[bufnr].filetype = "make" + elseif line:find('^%s*#') then + vim.bo[bufnr].filetype = 'make' return end end - vim.bo[bufnr].filetype = "mmix" + vim.bo[bufnr].filetype = 'mmix' end function M.mod(path, bufnr) end @@ -242,8 +242,8 @@ function M.mod(path, bufnr) end -- that case it is probably an nroff file: 'filetype' is set and 1 is returned. function M.nroff(bufnr) for _, line in ipairs(getlines(bufnr, 1, 5)) do - if line:find("^%.") then - vim.bo[bufnr].filetype = "nroff" + if line:find('^%.') then + vim.bo[bufnr].filetype = 'nroff' return 1 end end @@ -264,10 +264,10 @@ function M.progress_cweb(bufnr) if vim.g.filetype_w then vim.bo[bufnr].filetype = vim.g.filetype_w else - if getlines(bufnr, 1):find("^&ANALYZE") or getlines(bufnr, 3):find("^&GLOBAL%-DEFINE") then - vim.bo[bufnr].filetype = "progress" + if getlines(bufnr, 1):find('^&ANALYZE') or getlines(bufnr, 3):find('^&GLOBAL%-DEFINE') then + vim.bo[bufnr].filetype = 'progress' else - vim.bo[bufnr].filetype = "cweb" + vim.bo[bufnr].filetype = 'cweb' end end end @@ -280,20 +280,20 @@ function M.r(bufnr) local lines = getlines(bufnr, 1, 50) -- TODO: \< / \> which match the beginning / end of a word -- Rebol is easy to recognize, check for that first - if table.concat(lines):lower():find("rebol") then - vim.bo[bufnr].filetype = "rebol" + if table.concat(lines):lower():find('rebol') then + vim.bo[bufnr].filetype = 'rebol' return end for _, line in ipairs(lines) do -- R has # comments - if line:find("^%s*#") then - vim.bo[bufnr].filetype = "r" + if line:find('^%s*#') then + vim.bo[bufnr].filetype = 'r' return end -- Rexx has /* comments */ - if line:find("^%s*/%*") then - vim.bo[bufnr].filetype = "rexx" + if line:find('^%s*/%*') then + vim.bo[bufnr].filetype = 'rexx' return end end @@ -303,14 +303,14 @@ function M.r(bufnr) vim.bo[bufnr].filetype = vim.g.filetype_r else -- Rexx used to be the default, but R appears to be much more popular. - vim.bo[bufnr].filetype = "r" + vim.bo[bufnr].filetype = 'r' end end function M.redif(bufnr) for _, line in ipairs(getlines(bufnr, 1, 5)) do - if line:lower():find("^template%-type:") then - vim.bo[bufnr].filetype = "redif" + if line:lower():find('^template%-type:') then + vim.bo[bufnr].filetype = 'redif' end end end @@ -321,24 +321,29 @@ function M.rules(path, bufnr) end -- detection between scala and SuperCollider function M.sc(bufnr) for _, line in ipairs(getlines(bufnr, 1, 25)) do - if findany(line, { "[A-Za-z0-9]*%s:%s[A-Za-z0-9]", "var%s<", "classvar%s<", "%^this.*", "|%w*|", "%+%s%w*%s{", "%*ar%s" }) then - vim.bo[bufnr].filetype = "supercollider" + if + findany( + line, + { '[A-Za-z0-9]*%s:%s[A-Za-z0-9]', 'var%s<', 'classvar%s<', '%^this.*', '|%w*|', '%+%s%w*%s{', '%*ar%s' } + ) + then + vim.bo[bufnr].filetype = 'supercollider' return end end - vim.bo[bufnr].filetype = "scala" + vim.bo[bufnr].filetype = 'scala' end -- This function checks the first line of file extension "scd" to resolve -- detection between scdoc and SuperCollider function M.scd(bufnr) - local first = "^%S+%(%d[0-9A-Za-z]*%)" + local first = '^%S+%(%d[0-9A-Za-z]*%)' local opt = [[%s+"[^"]*"]] local line = getlines(bufnr, 1) - if findany(line, { first .. "$", first .. opt .. "$", first .. opt .. opt .. "$" }) then - vim.bo[bufnr].filetype = "scdoc" + if findany(line, { first .. '$', first .. opt .. '$', first .. opt .. opt .. '$' }) then + vim.bo[bufnr].filetype = 'scdoc' else - vim.bo[bufnr].filetype = "supercollider" + vim.bo[bufnr].filetype = 'supercollider' end end @@ -350,7 +355,7 @@ function M.sql(bufnr) if vim.g.filetype_sql then vim.bo[bufnr].filetype = vim.g.filetype_sql else - vim.bo[bufnr].filetype = "sql" + vim.bo[bufnr].filetype = 'sql' end end @@ -365,46 +370,46 @@ function M.tf(bufnr) for _, line in ipairs(getlines(bufnr, 1, -1)) do -- Assume terraform file on a non-empty line (not whitespace-only) -- and when the first non-whitespace character is not a ; or / - if not line:find("^%s*$") and not line:find("^%s*[;/]") then - vim.bo[bufnr].filetype = "terraform" + if not line:find('^%s*$') and not line:find('^%s*[;/]') then + vim.bo[bufnr].filetype = 'terraform' return end end - vim.bo[bufnr].filetype = "tf" + vim.bo[bufnr].filetype = 'tf' end function M.xml(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do line = line:lower() - local is_docbook4 = line:find(" is used to match the end of the word after "class", -- can this be omitted? - if findany(line, { "^%s*#", "^%class", "^%s*#%s*include" }) then - vim.bo[bufnr].filetype = "racc" + if findany(line, { '^%s*#', '^%class', '^%s*#%s*include' }) then + vim.bo[bufnr].filetype = 'racc' end end - vim.bo[bufnr].filetype = "yacc" + vim.bo[bufnr].filetype = 'yacc' end -- luacheck: pop diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 4105ef0675..22b67aee88 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -14,14 +14,14 @@ function M.create(higroup, hi_info, default) local options = {} -- TODO: Add validation for k, v in pairs(hi_info) do - table.insert(options, string.format("%s=%s", k, v)) + table.insert(options, string.format('%s=%s', k, v)) end - vim.cmd(string.format([[highlight %s %s %s]], default and "default" or "", higroup, table.concat(options, " "))) + vim.cmd(string.format([[highlight %s %s %s]], default and 'default' or '', higroup, table.concat(options, ' '))) end ---@private function M.link(higroup, link_to, force) - vim.cmd(string.format([[highlight%s link %s %s]], force and "!" or " default", higroup, link_to)) + vim.cmd(string.format([[highlight%s link %s %s]], force and '!' or ' default', higroup, link_to)) end --- Highlight range between two positions @@ -37,7 +37,7 @@ end -- - priority number indicating priority of highlight (default priorities.user) function M.range(bufnr, ns, higroup, start, finish, opts) opts = opts or {} - local regtype = opts.regtype or "v" + local regtype = opts.regtype or 'v' local inclusive = opts.inclusive or false local priority = opts.priority or M.priorities.user @@ -63,7 +63,7 @@ function M.range(bufnr, ns, higroup, start, finish, opts) end end -local yank_ns = api.nvim_create_namespace("hlyank") +local yank_ns = api.nvim_create_namespace('hlyank') --- Highlight the yanked region --- --- use from init.vim via @@ -87,10 +87,10 @@ function M.on_yank(opts) if t == nil then return true else - return type(t) == "table" + return type(t) == 'table' end end, - "a table or nil to configure options (see `:h highlight.on_yank`)", + 'a table or nil to configure options (see `:h highlight.on_yank`)', }, }) opts = opts or {} @@ -98,17 +98,17 @@ function M.on_yank(opts) local on_macro = opts.on_macro or false local on_visual = (opts.on_visual ~= false) - if not on_macro and vim.fn.reg_executing() ~= "" then + if not on_macro and vim.fn.reg_executing() ~= '' then return end - if event.operator ~= "y" or event.regtype == "" then + if event.operator ~= 'y' or event.regtype == '' then return end if not on_visual and event.visual then return end - local higroup = opts.higroup or "IncSearch" + local higroup = opts.higroup or 'IncSearch' local timeout = opts.timeout or 150 local bufnr = api.nvim_get_current_buf() diff --git a/runtime/lua/vim/inspect.lua b/runtime/lua/vim/inspect.lua index b19c215dbb..c19e55fb37 100644 --- a/runtime/lua/vim/inspect.lua +++ b/runtime/lua/vim/inspect.lua @@ -1,7 +1,7 @@ local inspect = { - _VERSION = "inspect.lua 3.1.0", - _URL = "http://github.com/kikito/inspect.lua", - _DESCRIPTION = "human-readable representations of tables", + _VERSION = 'inspect.lua 3.1.0', + _URL = 'http://github.com/kikito/inspect.lua', + _DESCRIPTION = 'human-readable representations of tables', _LICENSE = [[ MIT LICENSE @@ -30,12 +30,12 @@ local inspect = { inspect.KEY = setmetatable({}, { __tostring = function() - return "inspect.KEY" + return 'inspect.KEY' end, }) inspect.METATABLE = setmetatable({}, { __tostring = function() - return "inspect.METATABLE" + return 'inspect.METATABLE' end, }) @@ -61,52 +61,52 @@ end -- \a => '\\a', \0 => '\\0', 31 => '\31' local shortControlCharEscapes = { - ["\a"] = "\\a", - ["\b"] = "\\b", - ["\f"] = "\\f", - ["\n"] = "\\n", - ["\r"] = "\\r", - ["\t"] = "\\t", - ["\v"] = "\\v", - ["\127"] = "\\127", + ['\a'] = '\\a', + ['\b'] = '\\b', + ['\f'] = '\\f', + ['\n'] = '\\n', + ['\r'] = '\\r', + ['\t'] = '\\t', + ['\v'] = '\\v', + ['\127'] = '\\127', } -local longControlCharEscapes = { ["\127"] = "\127" } +local longControlCharEscapes = { ['\127'] = '\127' } for i = 0, 31 do local ch = char(i) if not shortControlCharEscapes[ch] then - shortControlCharEscapes[ch] = "\\" .. i - longControlCharEscapes[ch] = fmt("\\%03d", i) + shortControlCharEscapes[ch] = '\\' .. i + longControlCharEscapes[ch] = fmt('\\%03d', i) end end local function escape(str) - return (gsub(gsub(gsub(str, "\\", "\\\\"), "(%c)%f[0-9]", longControlCharEscapes), "%c", shortControlCharEscapes)) + return (gsub(gsub(gsub(str, '\\', '\\\\'), '(%c)%f[0-9]', longControlCharEscapes), '%c', shortControlCharEscapes)) end local function isIdentifier(str) - return type(str) == "string" and not not str:match("^[_%a][_%a%d]*$") + return type(str) == 'string' and not not str:match('^[_%a][_%a%d]*$') end local flr = math.floor local function isSequenceKey(k, sequenceLength) - return type(k) == "number" and flr(k) == k and 1 <= k and k <= sequenceLength + return type(k) == 'number' and flr(k) == k and 1 <= k and k <= sequenceLength end local defaultTypeOrders = { - ["number"] = 1, - ["boolean"] = 2, - ["string"] = 3, - ["table"] = 4, - ["function"] = 5, - ["userdata"] = 6, - ["thread"] = 7, + ['number'] = 1, + ['boolean'] = 2, + ['string'] = 3, + ['table'] = 4, + ['function'] = 5, + ['userdata'] = 6, + ['thread'] = 7, } local function sortKeys(a, b) local ta, tb = type(a), type(b) -- strings and numbers are sorted numerically/alphabetically - if ta == tb and (ta == "string" or ta == "number") then + if ta == tb and (ta == 'string' or ta == 'number') then return a < b end @@ -137,7 +137,7 @@ local function getKeys(t) end local function countCycles(x, cycles) - if type(x) == "table" then + if type(x) == 'table' then if cycles[x] then cycles[x] = cycles[x] + 1 else @@ -173,7 +173,7 @@ local function processRecursive(process, item, path, visited) end local processed = process(item, path) - if type(processed) == "table" then + if type(processed) == 'table' then local processedCopy = {} visited[item] = processedCopy local processedKey @@ -186,7 +186,7 @@ local function processRecursive(process, item, path, visited) end local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) - if type(mt) ~= "table" then + if type(mt) ~= 'table' then mt = nil end setmetatable(processedCopy, mt) @@ -222,27 +222,27 @@ end function Inspector:putValue(v) local buf = self.buf local tv = type(v) - if tv == "string" then + if tv == 'string' then puts(buf, smartQuote(escape(v))) elseif - tv == "number" - or tv == "boolean" - or tv == "nil" - or tv == "cdata" - or tv == "ctype" + tv == 'number' + or tv == 'boolean' + or tv == 'nil' + or tv == 'cdata' + or tv == 'ctype' or (vim and v == vim.NIL) then puts(buf, tostring(v)) - elseif tv == "table" and not self.ids[v] then + elseif tv == 'table' and not self.ids[v] then local t = v if t == inspect.KEY or t == inspect.METATABLE then puts(buf, tostring(t)) elseif self.level >= self.depth then - puts(buf, "{...}") + puts(buf, '{...}') else if self.cycles[t] > 1 then - puts(buf, fmt("<%d>", self:getId(t))) + puts(buf, fmt('<%d>', self:getId(t))) end local keys, keysLen, seqLen = getKeys(t) @@ -253,15 +253,15 @@ function Inspector:putValue(v) return end - puts(buf, "{") + puts(buf, '{') self.level = self.level + 1 for i = 1, seqLen + keysLen do if i > 1 then - puts(buf, ",") + puts(buf, ',') end if i <= seqLen then - puts(buf, " ") + puts(buf, ' ') self:putValue(t[i]) else local k = keys[i - seqLen] @@ -269,36 +269,36 @@ function Inspector:putValue(v) if isIdentifier(k) then puts(buf, k) else - puts(buf, "[") + puts(buf, '[') self:putValue(k) - puts(buf, "]") + puts(buf, ']') end - puts(buf, " = ") + puts(buf, ' = ') self:putValue(t[k]) end end - if type(mt) == "table" then + if type(mt) == 'table' then if seqLen + keysLen > 0 then - puts(buf, ",") + puts(buf, ',') end tabify(self) - puts(buf, " = ") + puts(buf, ' = ') self:putValue(mt) end self.level = self.level - 1 - if keysLen > 0 or type(mt) == "table" then + if keysLen > 0 or type(mt) == 'table' then tabify(self) elseif seqLen > 0 then - puts(buf, " ") + puts(buf, ' ') end - puts(buf, "}") + puts(buf, '}') end else - puts(buf, fmt("<%s %d>", tv, self:getId(v))) + puts(buf, fmt('<%s %d>', tv, self:getId(v))) end end @@ -306,8 +306,8 @@ function inspect.inspect(root, options) options = options or {} local depth = options.depth or math.huge - local newline = options.newline or "\n" - local indent = options.indent or " " + local newline = options.newline or '\n' + local indent = options.indent or ' ' local process = options.process if process then diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua index d07232f52f..f4c2b507a9 100644 --- a/runtime/lua/vim/keymap.lua +++ b/runtime/lua/vim/keymap.lua @@ -49,20 +49,20 @@ local keymap = {} --- Default `false`. ---@see |nvim_set_keymap()| function keymap.set(mode, lhs, rhs, opts) - vim.validate { - mode = {mode, {'s', 't'}}, - lhs = {lhs, 's'}, - rhs = {rhs, {'s', 'f'}}, - opts = {opts, 't', true} - } + vim.validate({ + mode = { mode, { 's', 't' } }, + lhs = { lhs, 's' }, + rhs = { rhs, { 's', 'f' } }, + opts = { opts, 't', true }, + }) opts = vim.deepcopy(opts) or {} - local is_rhs_luaref = type(rhs) == "function" - mode = type(mode) == 'string' and {mode} or mode + local is_rhs_luaref = type(rhs) == 'function' + mode = type(mode) == 'string' and { mode } or mode if is_rhs_luaref and opts.expr then local user_rhs = rhs - rhs = function () + rhs = function() local res = user_rhs() if res == nil then -- TODO(lewis6991): Handle this in C? @@ -118,14 +118,14 @@ end ---@see |vim.keymap.set()| --- function keymap.del(modes, lhs, opts) - vim.validate { - mode = {modes, {'s', 't'}}, - lhs = {lhs, 's'}, - opts = {opts, 't', true} - } + vim.validate({ + mode = { modes, { 's', 't' } }, + lhs = { lhs, 's' }, + opts = { opts, 't', true }, + }) opts = opts or {} - modes = type(modes) == 'string' and {modes} or modes + modes = type(modes) == 'string' and { modes } or modes local buffer = false if opts.buffer ~= nil then diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index a541b63ee9..e99a7c282c 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1,58 +1,58 @@ local if_nil = vim.F.if_nil -local default_handlers = require 'vim.lsp.handlers' -local log = require 'vim.lsp.log' -local lsp_rpc = require 'vim.lsp.rpc' -local protocol = require 'vim.lsp.protocol' -local util = require 'vim.lsp.util' -local sync = require 'vim.lsp.sync' +local default_handlers = require('vim.lsp.handlers') +local log = require('vim.lsp.log') +local lsp_rpc = require('vim.lsp.rpc') +local protocol = require('vim.lsp.protocol') +local util = require('vim.lsp.util') +local sync = require('vim.lsp.sync') local vim = vim -local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option - = vim.api.nvim_err_writeln, vim.api.nvim_buf_get_lines, vim.api.nvim_command, vim.api.nvim_buf_get_option +local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option = + vim.api.nvim_err_writeln, vim.api.nvim_buf_get_lines, vim.api.nvim_command, vim.api.nvim_buf_get_option local uv = vim.loop local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend local validate = vim.validate local lsp = { - protocol = protocol; + protocol = protocol, - handlers = default_handlers; + handlers = default_handlers, - buf = require'vim.lsp.buf'; - diagnostic = require'vim.lsp.diagnostic'; - codelens = require'vim.lsp.codelens'; - util = util; + buf = require('vim.lsp.buf'), + diagnostic = require('vim.lsp.diagnostic'), + codelens = require('vim.lsp.codelens'), + util = util, -- Allow raw RPC access. - rpc = lsp_rpc; + rpc = lsp_rpc, -- Export these directly from rpc. - rpc_response_error = lsp_rpc.rpc_response_error; + rpc_response_error = lsp_rpc.rpc_response_error, } -- maps request name to the required server_capability in the client. lsp._request_name_to_capability = { - ['textDocument/hover'] = { 'hoverProvider' }; - ['textDocument/signatureHelp'] = { 'signatureHelpProvider' }; - ['textDocument/definition'] = { 'definitionProvider' }; - ['textDocument/implementation'] = { 'implementationProvider' }; - ['textDocument/declaration'] = { 'declarationProvider' }; - ['textDocument/typeDefinition'] = { 'typeDefinitionProvider' }; - ['textDocument/documentSymbol'] = { 'documentSymbolProvider' }; - ['textDocument/prepareCallHierarchy'] = { 'callHierarchyProvider' }; - ['textDocument/rename'] = { 'renameProvider' }; - ['textDocument/prepareRename'] = { 'renameProvider', 'prepareProvider'} ; - ['textDocument/codeAction'] = { 'codeActionProvider' }; - ['textDocument/codeLens'] = { 'codeLensProvider' }; - ['codeLens/resolve'] = { 'codeLensProvider', 'resolveProvider' }; - ['workspace/executeCommand'] = { 'executeCommandProvider' }; - ['workspace/symbol'] = { 'workspaceSymbolProvider' }; - ['textDocument/references'] = { 'referencesProvider' }; - ['textDocument/rangeFormatting'] = { 'documentRangeFormattingProvider' }; - ['textDocument/formatting'] = { 'documentFormattingProvider' }; - ['textDocument/completion'] = { 'completionProvider' }; - ['textDocument/documentHighlight'] = { 'documentHighlightProvider' }; + ['textDocument/hover'] = { 'hoverProvider' }, + ['textDocument/signatureHelp'] = { 'signatureHelpProvider' }, + ['textDocument/definition'] = { 'definitionProvider' }, + ['textDocument/implementation'] = { 'implementationProvider' }, + ['textDocument/declaration'] = { 'declarationProvider' }, + ['textDocument/typeDefinition'] = { 'typeDefinitionProvider' }, + ['textDocument/documentSymbol'] = { 'documentSymbolProvider' }, + ['textDocument/prepareCallHierarchy'] = { 'callHierarchyProvider' }, + ['textDocument/rename'] = { 'renameProvider' }, + ['textDocument/prepareRename'] = { 'renameProvider', 'prepareProvider' }, + ['textDocument/codeAction'] = { 'codeActionProvider' }, + ['textDocument/codeLens'] = { 'codeLensProvider' }, + ['codeLens/resolve'] = { 'codeLensProvider', 'resolveProvider' }, + ['workspace/executeCommand'] = { 'executeCommandProvider' }, + ['workspace/symbol'] = { 'workspaceSymbolProvider' }, + ['textDocument/references'] = { 'referencesProvider' }, + ['textDocument/rangeFormatting'] = { 'documentRangeFormattingProvider' }, + ['textDocument/formatting'] = { 'documentFormattingProvider' }, + ['textDocument/completion'] = { 'completionProvider' }, + ['textDocument/documentHighlight'] = { 'documentHighlightProvider' }, } -- TODO improve handling of scratch buffers with LSP attached. @@ -62,8 +62,8 @@ lsp._request_name_to_capability = { --- ---@param {...} (List of strings) List to write to the buffer local function err_message(...) - nvim_err_writeln(table.concat(vim.tbl_flatten{...})) - nvim_command("redraw") + nvim_err_writeln(table.concat(vim.tbl_flatten({ ... }))) + nvim_command('redraw') end ---@private @@ -73,7 +73,7 @@ end ---buffer if not given. ---@returns bufnr (number) Number of requested buffer local function resolve_bufnr(bufnr) - validate { bufnr = { bufnr, 'n', true } } + validate({ bufnr = { bufnr, 'n', true } }) if bufnr == nil or bufnr == 0 then return vim.api.nvim_get_current_buf() end @@ -85,7 +85,10 @@ end --- supported in any of the servers registered for the current buffer. ---@param method (string) name of the method function lsp._unsupported_method(method) - local msg = string.format("method %s is not supported by any of the servers registered for the current buffer", method) + local msg = string.format( + 'method %s is not supported by any of the servers registered for the current buffer', + method + ) log.warn(msg) return msg end @@ -96,23 +99,29 @@ end ---@param filename (string) path to check ---@returns true if {filename} exists and is a directory, false otherwise local function is_dir(filename) - validate{filename={filename,'s'}} + validate({ filename = { filename, 's' } }) local stat = uv.fs_stat(filename) return stat and stat.type == 'directory' or false end -local wait_result_reason = { [-1] = "timeout"; [-2] = "interrupted"; [-3] = "error" } +local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'error' } local valid_encodings = { - ["utf-8"] = 'utf-8'; ["utf-16"] = 'utf-16'; ["utf-32"] = 'utf-32'; - ["utf8"] = 'utf-8'; ["utf16"] = 'utf-16'; ["utf32"] = 'utf-32'; - UTF8 = 'utf-8'; UTF16 = 'utf-16'; UTF32 = 'utf-32'; + ['utf-8'] = 'utf-8', + ['utf-16'] = 'utf-16', + ['utf-32'] = 'utf-32', + ['utf8'] = 'utf-8', + ['utf16'] = 'utf-16', + ['utf32'] = 'utf-32', + UTF8 = 'utf-8', + UTF16 = 'utf-16', + UTF32 = 'utf-32', } local format_line_ending = { - ["unix"] = '\n', - ["dos"] = '\r\n', - ["mac"] = '\r', + ['unix'] = '\n', + ['dos'] = '\r\n', + ['mac'] = '\r', } ---@private @@ -138,10 +147,10 @@ local uninitialized_clients = {} ---@private local function for_each_buffer_client(bufnr, fn, restrict_client_ids) - validate { - fn = { fn, 'f' }; - restrict_client_ids = { restrict_client_ids, 't' , true}; - } + validate({ + fn = { fn, 'f' }, + restrict_client_ids = { restrict_client_ids, 't', true }, + }) bufnr = resolve_bufnr(bufnr) local client_ids = all_buffer_active_clients[bufnr] if not client_ids or tbl_isempty(client_ids) then @@ -169,9 +178,13 @@ end -- Error codes to be used with `on_error` from |vim.lsp.start_client|. -- Can be used to look up the string from a the number or the number -- from the string. -lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_reverse_lookup { - ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1; -}) +lsp.client_errors = tbl_extend( + 'error', + lsp_rpc.client_errors, + vim.tbl_add_reverse_lookup({ + ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1, + }) +) ---@private --- Normalizes {encoding} to valid LSP encoding names. @@ -179,11 +192,11 @@ lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_rever ---@param encoding (string) Encoding to normalize ---@returns (string) normalized encoding name local function validate_encoding(encoding) - validate { - encoding = { encoding, 's' }; - } + validate({ + encoding = { encoding, 's' }, + }) return valid_encodings[encoding:lower()] - or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding)) + or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding)) end ---@internal @@ -194,16 +207,19 @@ end ---@returns (string) the command ---@returns (list of strings) its arguments function lsp._cmd_parts(input) - vim.validate{cmd={ + vim.validate({ cmd = { input, - function() return vim.tbl_islist(input) end, - "list"}} + function() + return vim.tbl_islist(input) + end, + 'list', + } }) local cmd = input[1] local cmd_args = {} -- Don't mutate our input. for i, v in ipairs(input) do - vim.validate{["cmd argument"]={v, "s"}} + vim.validate({ ['cmd argument'] = { v, 's' } }) if i > 1 then table.insert(cmd_args, v) end @@ -233,31 +249,29 @@ end --- ---@see |vim.lsp.start_client()| local function validate_client_config(config) - validate { - config = { config, 't' }; - } - validate { - handlers = { config.handlers, "t", true }; - capabilities = { config.capabilities, "t", true }; - cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), "directory" }; - cmd_env = { config.cmd_env, "t", true }; - detached = { config.detached, "b", true }; - name = { config.name, 's', true }; - on_error = { config.on_error, "f", true }; - on_exit = { config.on_exit, "f", true }; - on_init = { config.on_init, "f", true }; - settings = { config.settings, "t", true }; - commands = { config.commands, 't', true }; - before_init = { config.before_init, "f", true }; - offset_encoding = { config.offset_encoding, "s", true }; - flags = { config.flags, "t", true }; - get_language_id = { config.get_language_id, "f", true }; - } + validate({ + config = { config, 't' }, + }) + validate({ + handlers = { config.handlers, 't', true }, + capabilities = { config.capabilities, 't', true }, + cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), 'directory' }, + cmd_env = { config.cmd_env, 't', true }, + detached = { config.detached, 'b', true }, + name = { config.name, 's', true }, + on_error = { config.on_error, 'f', true }, + on_exit = { config.on_exit, 'f', true }, + on_init = { config.on_init, 'f', true }, + settings = { config.settings, 't', true }, + commands = { config.commands, 't', true }, + before_init = { config.before_init, 'f', true }, + offset_encoding = { config.offset_encoding, 's', true }, + flags = { config.flags, 't', true }, + get_language_id = { config.get_language_id, 'f', true }, + }) assert( - (not config.flags - or not config.flags.debounce_text_changes - or type(config.flags.debounce_text_changes) == 'number'), - "flags.debounce_text_changes must be a number with the debounce time in milliseconds" + (not config.flags or not config.flags.debounce_text_changes or type(config.flags.debounce_text_changes) == 'number'), + 'flags.debounce_text_changes must be a number with the debounce time in milliseconds' ) local cmd, cmd_args = lsp._cmd_parts(config.cmd) @@ -267,9 +281,9 @@ local function validate_client_config(config) end return { - cmd = cmd; - cmd_args = cmd_args; - offset_encoding = offset_encoding; + cmd = cmd, + cmd_args = cmd_args, + offset_encoding = offset_encoding, } end @@ -329,14 +343,15 @@ do function changetracking.init(client, bufnr) local use_incremental_sync = ( if_nil(client.config.flags.allow_incremental_sync, true) - and vim.tbl_get(client.server_capabilities, "textDocumentSync", "change") == protocol.TextDocumentSyncKind.Incremental + and vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') + == protocol.TextDocumentSyncKind.Incremental ) local state = state_by_client[client.id] if not state then state = { - buffers = {}; + buffers = {}, debounce = client.config.flags.debounce_text_changes or 150, - use_incremental_sync = use_incremental_sync; + use_incremental_sync = use_incremental_sync, } state_by_client[client.id] = state end @@ -405,7 +420,6 @@ do ---@private function changetracking.prepare(bufnr, firstline, lastline, new_lastline) local incremental_changes = function(client, buf_state) - local prev_lines = buf_state.lines local curr_lines = buf_state.lines_tmp @@ -426,7 +440,14 @@ do local line_ending = buf_get_line_ending(bufnr) local incremental_change = sync.compute_diff( - buf_state.lines, curr_lines, firstline, lastline, new_lastline, client.offset_encoding or 'utf-16', line_ending) + buf_state.lines, + curr_lines, + firstline, + lastline, + new_lastline, + client.offset_encoding or 'utf-16', + line_ending + ) -- Double-buffering of lines tables is used to reduce the load on the garbage collector. -- At this point the prev_lines table is useless, but its internal storage has already been allocated, @@ -443,12 +464,14 @@ do end local full_changes = once(function() return { - text = buf_get_full_text(bufnr); - }; + text = buf_get_full_text(bufnr), + } end) local uri = vim.uri_from_bufnr(bufnr) return function(client) - if vim.tbl_get(client.server_capabilities, "textDocumentSync", "change") == protocol.TextDocumentSyncKind.None then + if + vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') == protocol.TextDocumentSyncKind.None + then return end local state = state_by_client[client.id] @@ -467,7 +490,7 @@ do return end local changes = state.use_incremental_sync and buf_state.pending_changes or { full_changes() } - client.notify("textDocument/didChange", { + client.notify('textDocument/didChange', { textDocument = { uri = uri, version = util.buf_versions[bufnr], @@ -519,7 +542,6 @@ do end end - ---@private --- Default handler for the 'textDocument/didOpen' LSP notification. --- @@ -527,7 +549,7 @@ end ---@param client Client object local function text_document_did_open_handler(bufnr, client) changetracking.init(client, bufnr) - if not vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then + if not vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then return end if not vim.api.nvim_buf_is_loaded(bufnr) then @@ -537,11 +559,11 @@ local function text_document_did_open_handler(bufnr, client) local params = { textDocument = { - version = 0; - uri = vim.uri_from_bufnr(bufnr); - languageId = client.config.get_language_id(bufnr, filetype); - text = buf_get_full_text(bufnr); - } + version = 0, + uri = vim.uri_from_bufnr(bufnr), + languageId = client.config.get_language_id(bufnr, filetype), + text = buf_get_full_text(bufnr), + }, } client.notify('textDocument/didOpen', params) util.buf_versions[bufnr] = params.textDocument.version @@ -763,13 +785,15 @@ function lsp.start_client(config) -- By default, get_language_id just returns the exact filetype it is passed. -- It is possible to pass in something that will calculate a different filetype, -- to be sent by the client. - config.get_language_id = config.get_language_id or function(_, filetype) return filetype end + config.get_language_id = config.get_language_id or function(_, filetype) + return filetype + end local client_id = next_client_id() local handlers = config.handlers or {} local name = config.name or tostring(client_id) - local log_prefix = string.format("LSP[%s]", name) + local log_prefix = string.format('LSP[%s]', name) local dispatch = {} @@ -794,7 +818,7 @@ function lsp.start_client(config) local handler = resolve_handler(method) if handler then -- Method name is provided here for convenience. - handler(nil, params, {method=method, client_id=client_id}) + handler(nil, params, { method = method, client_id = client_id }) end end @@ -807,10 +831,10 @@ function lsp.start_client(config) local _ = log.trace() and log.trace('server_request', method, params) local handler = resolve_handler(method) if handler then - local _ = log.trace() and log.trace("server_request: found handler for", method) - return handler(nil, params, {method=method, client_id=client_id}) + local _ = log.trace() and log.trace('server_request: found handler for', method) + return handler(nil, params, { method = method, client_id = client_id }) end - local _ = log.warn() and log.warn("server_request: no handler found for", method) + local _ = log.warn() and log.warn('server_request: no handler found for', method) return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound) end @@ -822,12 +846,12 @@ function lsp.start_client(config) ---@see |vim.lsp.rpc.client_errors| for possible errors. Use ---`vim.lsp.rpc.client_errors[code]` to get a human-friendly name. function dispatch.on_error(code, err) - local _ = log.error() and log.error(log_prefix, "on_error", { code = lsp.client_errors[code], err = err }) + local _ = log.error() and log.error(log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) err_message(log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err)) if config.on_error then local status, usererr = pcall(config.on_error, code, err) if not status then - local _ = log.error() and log.error(log_prefix, "user on_error failed", { err = usererr }) + local _ = log.error() and log.error(log_prefix, 'user on_error failed', { err = usererr }) err_message(log_prefix, ' user on_error failed: ', tostring(usererr)) end end @@ -853,7 +877,7 @@ function lsp.start_client(config) end if code ~= 0 or (signal ~= 0 and signal ~= 15) then - local msg = string.format("Client %s quit with exit code %s and signal %s", client_id, code, signal) + local msg = string.format('Client %s quit with exit code %s and signal %s', client_id, code, signal) vim.schedule(function() vim.notify(msg, vim.log.levels.WARN) end) @@ -862,38 +886,41 @@ function lsp.start_client(config) -- Start the RPC client. local rpc = lsp_rpc.start(cmd, cmd_args, dispatch, { - cwd = config.cmd_cwd; - env = config.cmd_env; - detached = config.detached; + cwd = config.cmd_cwd, + env = config.cmd_env, + detached = config.detached, }) -- Return nil if client fails to start - if not rpc then return end + if not rpc then + return + end local client = { - id = client_id; - name = name; - rpc = rpc; - offset_encoding = offset_encoding; - config = config; - attached_buffers = {}; + id = client_id, + name = name, + rpc = rpc, + offset_encoding = offset_encoding, + config = config, + attached_buffers = {}, - handlers = handlers; - commands = config.commands or {}; + handlers = handlers, + commands = config.commands or {}, - requests = {}; + requests = {}, -- for $/progress report - messages = { name = name, messages = {}, progress = {}, status = {} }; + messages = { name = name, messages = {}, progress = {}, status = {} }, } - -- Store the uninitialized_clients for cleanup in case we exit before initialize finishes. - uninitialized_clients[client_id] = client; + uninitialized_clients[client_id] = client ---@private local function initialize() local valid_traces = { - off = 'off'; messages = 'messages'; verbose = 'verbose'; + off = 'off', + messages = 'messages', + verbose = 'verbose', } local version = vim.version() @@ -902,10 +929,12 @@ function lsp.start_client(config) local root_path if config.workspace_folders or config.root_dir then if config.root_dir and not config.workspace_folders then - workspace_folders = {{ - uri = vim.uri_from_fname(config.root_dir); - name = string.format("%s", config.root_dir); - }}; + workspace_folders = { + { + uri = vim.uri_from_fname(config.root_dir), + name = string.format('%s', config.root_dir), + }, + } else workspace_folders = config.workspace_folders end @@ -922,41 +951,41 @@ function lsp.start_client(config) -- the process has not been started by another process. If the parent -- process is not alive then the server should exit (see exit notification) -- its process. - processId = uv.getpid(); + processId = uv.getpid(), -- Information about the client -- since 3.15.0 clientInfo = { - name = "Neovim", - version = string.format("%s.%s.%s", version.major, version.minor, version.patch) - }; + name = 'Neovim', + version = string.format('%s.%s.%s', version.major, version.minor, version.patch), + }, -- The rootPath of the workspace. Is null if no folder is open. -- -- @deprecated in favour of rootUri. - rootPath = root_path or vim.NIL; + rootPath = root_path or vim.NIL, -- The rootUri of the workspace. Is null if no folder is open. If both -- `rootPath` and `rootUri` are set `rootUri` wins. - rootUri = root_uri or vim.NIL; + rootUri = root_uri or vim.NIL, -- The workspace folders configured in the client when the server starts. -- This property is only available if the client supports workspace folders. -- It can be `null` if the client supports workspace folders but none are -- configured. - workspaceFolders = workspace_folders or vim.NIL; + workspaceFolders = workspace_folders or vim.NIL, -- User provided initialization options. - initializationOptions = config.init_options; + initializationOptions = config.init_options, -- The capabilities provided by the client (editor or tool) - capabilities = config.capabilities or protocol.make_client_capabilities(); + capabilities = config.capabilities or protocol.make_client_capabilities(), -- The initial trace setting. If omitted trace is disabled ("off"). -- trace = "off" | "messages" | "verbose"; - trace = valid_traces[config.trace] or 'off'; + trace = valid_traces[config.trace] or 'off', } if config.before_init then -- TODO(ashkan) handle errors here. pcall(config.before_init, initialize_params, config) end - local _ = log.trace() and log.trace(log_prefix, "initialize_params", initialize_params) + local _ = log.trace() and log.trace(log_prefix, 'initialize_params', initialize_params) rpc.request('initialize', initialize_params, function(init_err, result) assert(not init_err, tostring(init_err)) - assert(result, "server sent empty result") + assert(result, 'server sent empty result') rpc.notify('initialized', vim.empty_dict()) client.initialized = true uninitialized_clients[client_id] = nil @@ -973,10 +1002,13 @@ function lsp.start_client(config) local mt = {} mt.__index = function(table, key) if key == 'resolved_capabilities' then - vim.notify_once("[LSP] Accessing client.resolved_capabilities is deprecated, " .. - "update your plugins or configuration to access client.server_capabilities instead." .. - "The new key/value pairs in server_capabilities directly match those " .. - "defined in the language server protocol", vim.log.levels.WARN) + vim.notify_once( + '[LSP] Accessing client.resolved_capabilities is deprecated, ' + .. 'update your plugins or configuration to access client.server_capabilities instead.' + .. 'The new key/value pairs in server_capabilities directly match those ' + .. 'defined in the language server protocol', + vim.log.levels.WARN + ) rawset(table, key, protocol._resolve_capabilities_compat(client.server_capabilities)) return rawget(table, key) else @@ -1004,7 +1036,8 @@ function lsp.start_client(config) pcall(handlers.on_error, lsp.client_errors.ON_INIT_CALLBACK_ERROR, err) end end - local _ = log.info() and log.info(log_prefix, "server_capabilities", { server_capabilities = client.server_capabilities }) + local _ = log.info() + and log.info(log_prefix, 'server_capabilities', { server_capabilities = client.server_capabilities }) -- Only assign after initialized. active_clients[client_id] = client @@ -1039,22 +1072,22 @@ function lsp.start_client(config) function client.request(method, params, handler, bufnr) if not handler then handler = resolve_handler(method) - or error(string.format("not found: %q request handler for client %q.", method, client.name)) + or error(string.format('not found: %q request handler for client %q.', method, client.name)) end -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state changetracking.flush(client, bufnr) bufnr = resolve_bufnr(bufnr) - local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, handler, bufnr) + local _ = log.debug() and log.debug(log_prefix, 'client.request', client_id, method, params, handler, bufnr) local success, request_id = rpc.request(method, params, function(err, result) - handler(err, result, {method=method, client_id=client_id, bufnr=bufnr, params=params}) + handler(err, result, { method = method, client_id = client_id, bufnr = bufnr, params = params }) end, function(request_id) client.requests[request_id] = nil - nvim_command("doautocmd User LspRequest") + nvim_command('doautocmd User LspRequest') end) if success then - client.requests[request_id] = { type='pending', bufnr=bufnr, method=method } - nvim_command("doautocmd User LspRequest") + client.requests[request_id] = { type = 'pending', bufnr = bufnr, method = method } + nvim_command('doautocmd User LspRequest') end return success, request_id @@ -1081,9 +1114,10 @@ function lsp.start_client(config) request_result = { err = err, result = result } end - local success, request_id = client.request(method, params, _sync_handler, - bufnr) - if not success then return nil end + local success, request_id = client.request(method, params, _sync_handler, bufnr) + if not success then + return nil + end local wait_result, reason = vim.wait(timeout_ms or 1000, function() return request_result ~= nil @@ -1118,13 +1152,13 @@ function lsp.start_client(config) ---@returns true if any client returns true; false otherwise ---@see |vim.lsp.client.notify()| function client.cancel_request(id) - validate{id = {id, 'n'}} + validate({ id = { id, 'n' } }) local request = client.requests[id] if request and request.type == 'pending' then request.type = 'cancel' - nvim_command("doautocmd User LspRequest") + nvim_command('doautocmd User LspRequest') end - return rpc.notify("$/cancelRequest", { id = id }) + return rpc.notify('$/cancelRequest', { id = id }) end -- Track this so that we can escalate automatically if we've already tried a @@ -1139,7 +1173,6 @@ function lsp.start_client(config) --- ---@param force (bool, optional) function client.stop(force) - lsp.diagnostic.reset(client_id, all_buffer_active_clients) changetracking.reset(client_id) for _, client_ids in pairs(all_buffer_active_clients) do @@ -1150,7 +1183,7 @@ function lsp.start_client(config) if handle:is_closing() then return end - if force or (not client.initialized) or graceful_shutdown_failed then + if force or not client.initialized or graceful_shutdown_failed then handle:kill(15) return end @@ -1198,7 +1231,6 @@ end local text_document_did_change_handler do text_document_did_change_handler = function(_, bufnr, changedtick, firstline, lastline, new_lastline) - -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then return true @@ -1215,17 +1247,17 @@ function lsp._text_document_did_save_handler(bufnr) local uri = vim.uri_from_bufnr(bufnr) local text = once(buf_get_full_text) for_each_buffer_client(bufnr, function(client) - local save_capability = vim.tbl_get(client.server_capabilities, "textDocumentSync", "save") + local save_capability = vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'save') if save_capability then local included_text - if type(save_capability) == "table" and save_capability.includeText then + if type(save_capability) == 'table' and save_capability.includeText then included_text = text(bufnr) end client.notify('textDocument/didSave', { textDocument = { - uri = uri; - }; - text = included_text; + uri = uri, + }, + text = included_text, }) end end) @@ -1239,15 +1271,13 @@ end ---@param bufnr (number) Buffer handle, or 0 for current ---@param client_id (number) Client id function lsp.buf_attach_client(bufnr, client_id) - validate { - bufnr = {bufnr, 'n', true}; - client_id = {client_id, 'n'}; - } + validate({ + bufnr = { bufnr, 'n', true }, + client_id = { client_id, 'n' }, + }) bufnr = resolve_bufnr(bufnr) if not vim.api.nvim_buf_is_loaded(bufnr) then - local _ = log.warn() and log.warn( - string.format("buf_attach_client called on unloaded buffer (id: %d): ", bufnr) - ) + local _ = log.warn() and log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr)) return false end local buffer_client_ids = all_buffer_active_clients[bufnr] @@ -1266,36 +1296,38 @@ function lsp.buf_attach_client(bufnr, client_id) vim.api.nvim_exec(string.format(buf_did_save_autocommand, client_id, bufnr, bufnr), false) -- First time, so attach and set up stuff. vim.api.nvim_buf_attach(bufnr, false, { - on_lines = text_document_did_change_handler; + on_lines = text_document_did_change_handler, on_reload = function() - local params = { textDocument = { uri = uri; } } + local params = { textDocument = { uri = uri } } for_each_buffer_client(bufnr, function(client, _) changetracking.reset_buf(client, bufnr) - if vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then + if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then client.notify('textDocument/didClose', params) end text_document_did_open_handler(bufnr, client) end) - end; + end, on_detach = function() - local params = { textDocument = { uri = uri; } } + local params = { textDocument = { uri = uri } } for_each_buffer_client(bufnr, function(client, _) changetracking.reset_buf(client, bufnr) - if vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then + if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then client.notify('textDocument/didClose', params) end end) util.buf_versions[bufnr] = nil all_buffer_active_clients[bufnr] = nil - end; + end, -- TODO if we know all of the potential clients ahead of time, then we -- could conditionally set this. -- utf_sizes = size_index > 1; - utf_sizes = true; + utf_sizes = true, }) end - if buffer_client_ids[client_id] then return end + if buffer_client_ids[client_id] then + return + end -- This is our first time attaching this client to this buffer. buffer_client_ids[client_id] = true @@ -1315,25 +1347,23 @@ end ---@param bufnr number Buffer handle, or 0 for current ---@param client_id number Client id function lsp.buf_detach_client(bufnr, client_id) - validate { - bufnr = {bufnr, 'n', true}; - client_id = {client_id, 'n'}; - } + validate({ + bufnr = { bufnr, 'n', true }, + client_id = { client_id, 'n' }, + }) bufnr = resolve_bufnr(bufnr) local client = lsp.get_client_by_id(client_id) if not client or not client.attached_buffers[bufnr] then - vim.notify( - string.format('Buffer (id: %d) is not attached to client (id: %d). Cannot detach.', client_id, bufnr) - ) + vim.notify(string.format('Buffer (id: %d) is not attached to client (id: %d). Cannot detach.', client_id, bufnr)) return end changetracking.reset_buf(client, bufnr) - if vim.tbl_get(client.server_capabilities, "textDocumentSync", "openClose") then + if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then local uri = vim.uri_from_bufnr(bufnr) - local params = { textDocument = { uri = uri; } } + local params = { textDocument = { uri = uri } } client.notify('textDocument/didClose', params) end @@ -1349,7 +1379,6 @@ function lsp.buf_detach_client(bufnr, client_id) vim.diagnostic.reset(namespace, bufnr) vim.notify(string.format('Detached buffer (id: %d) from client (id: %d)', bufnr, client_id)) - end --- Checks if a buffer is attached for a particular client. @@ -1394,7 +1423,7 @@ end ---@param client_id client id or |vim.lsp.client| object, or list thereof ---@param force boolean (optional) shutdown forcefully function lsp.stop_client(client_id, force) - local ids = type(client_id) == 'table' and client_id or {client_id} + local ids = type(client_id) == 'table' and client_id or { client_id } for _, id in ipairs(ids) do if type(id) == 'table' and id.stop ~= nil then id.stop(force) @@ -1414,7 +1443,7 @@ function lsp.get_active_clients() end function lsp._vim_exit_handler() - log.info("exit_handler", active_clients) + log.info('exit_handler', active_clients) for _, client in pairs(uninitialized_clients) do client.stop(true) end @@ -1466,8 +1495,7 @@ function lsp._vim_exit_handler() end end -nvim_command("autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()") - +nvim_command('autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()') --- Sends an async request for all active clients attached to the --- buffer. @@ -1483,11 +1511,11 @@ nvim_command("autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()") --- - Function which can be used to cancel all the requests. You could instead --- iterate all clients and call their `cancel_request()` methods. function lsp.buf_request(bufnr, method, params, handler) - validate { - bufnr = { bufnr, 'n', true }; - method = { method, 's' }; - handler = { handler, 'f', true }; - } + validate({ + bufnr = { bufnr, 'n', true }, + method = { method, 's' }, + handler = { handler, 'f', true }, + }) local supported_clients = {} local method_supported = false @@ -1501,18 +1529,18 @@ function lsp.buf_request(bufnr, method, params, handler) -- if has client but no clients support the given method, notify the user if not tbl_isempty(all_buffer_active_clients[resolve_bufnr(bufnr)] or {}) and not method_supported then vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR) - vim.api.nvim_command("redraw") + vim.api.nvim_command('redraw') return {}, function() end end local client_request_ids = {} for_each_buffer_client(bufnr, function(client, client_id, resolved_bufnr) - local request_success, request_id = client.request(method, params, handler, resolved_bufnr) - -- This could only fail if the client shut down in the time since we looked - -- it up and we did the request, which should be rare. - if request_success then - client_request_ids[client_id] = request_id - end + local request_success, request_id = client.request(method, params, handler, resolved_bufnr) + -- This could only fail if the client shut down in the time since we looked + -- it up and we did the request, which should be rare. + if request_success then + client_request_ids[client_id] = request_id + end end, supported_clients) local function _cancel_all_requests() @@ -1543,7 +1571,7 @@ function lsp.buf_request_all(bufnr, method, params, callback) local result_count = 0 local expected_result_count = 0 - local set_expected_result_count = once(function () + local set_expected_result_count = once(function() for_each_buffer_client(bufnr, function(client) if client.supports_method(method) then expected_result_count = expected_result_count + 1 @@ -1607,18 +1635,19 @@ end --- ---@returns true if any client returns true; false otherwise function lsp.buf_notify(bufnr, method, params) - validate { - bufnr = { bufnr, 'n', true }; - method = { method, 's' }; - } + validate({ + bufnr = { bufnr, 'n', true }, + method = { method, 's' }, + }) local resp = false for_each_buffer_client(bufnr, function(client, _client_id, _resolved_bufnr) - if client.rpc.notify(method, params) then resp = true end + if client.rpc.notify(method, params) then + resp = true + end end) return resp end - ---@private local function adjust_start_col(lnum, line, items, encoding) local min_start_char = nil @@ -1650,7 +1679,7 @@ end --- - findstart=0: column where the completion starts, or -2 or -3 --- - findstart=1: list of matches (actually just calls |complete()|) function lsp.omnifunc(findstart, base) - local _ = log.debug() and log.debug("omnifunc.findstart", { findstart = findstart, base = base }) + local _ = log.debug() and log.debug('omnifunc.findstart', { findstart = findstart, base = base }) local bufnr = resolve_bufnr() local has_buffer_clients = not tbl_isempty(all_buffer_active_clients[bufnr] or {}) @@ -1663,12 +1692,12 @@ function lsp.omnifunc(findstart, base) end -- Then, perform standard completion request - local _ = log.info() and log.info("base ", base) + local _ = log.info() and log.info('base ', base) local pos = vim.api.nvim_win_get_cursor(0) local line = vim.api.nvim_get_current_line() local line_to_cursor = line:sub(1, pos[2]) - local _ = log.trace() and log.trace("omnifunc.line", pos, line) + local _ = log.trace() and log.trace('omnifunc.line', pos, line) -- Get the start position of the current keyword local textMatch = vim.fn.match(line_to_cursor, '\\k*$') @@ -1677,7 +1706,9 @@ function lsp.omnifunc(findstart, base) local items = {} lsp.buf_request(bufnr, 'textDocument/completion', params, function(err, result, ctx) - if err or not result or vim.fn.mode() ~= "i" then return end + if err or not result or vim.fn.mode() ~= 'i' then + return + end -- Completion response items may be relative to a position different than `textMatch`. -- Concrete example, with sumneko/lua-language-server: @@ -1723,7 +1754,7 @@ function lsp.formatexpr(opts) opts = opts or {} local timeout_ms = opts.timeout_ms or 500 - if vim.tbl_contains({'i', 'R', 'ic', 'ix'}, vim.fn.mode()) then + if vim.tbl_contains({ 'i', 'R', 'ic', 'ix' }, vim.fn.mode()) then -- `formatexpr` is also called when exceeding `textwidth` in insert mode -- fall back to internal formatting return 1 @@ -1734,14 +1765,14 @@ function lsp.formatexpr(opts) if start_line > 0 and end_line > 0 then local params = { - textDocument = util.make_text_document_params(); + textDocument = util.make_text_document_params(), range = { - start = { line = start_line - 1; character = 0; }; - ["end"] = { line = end_line - 1; character = 0; }; - }; - }; + start = { line = start_line - 1, character = 0 }, + ['end'] = { line = end_line - 1, character = 0 }, + }, + } params.options = util.make_formatting_params().options - local client_results = vim.lsp.buf_request_sync(0, "textDocument/rangeFormatting", params, timeout_ms) + local client_results = vim.lsp.buf_request_sync(0, 'textDocument/rangeFormatting', params, timeout_ms) -- Apply the text edits from one and only one of the clients. for client_id, response in pairs(client_results) do @@ -1785,11 +1816,11 @@ end ---@param bufnr (optional, number): Buffer handle, or 0 for current function lsp.buf_get_clients(bufnr) bufnr = resolve_bufnr(bufnr) - local result = {} - for_each_buffer_client(bufnr, function(client, client_id) - result[client_id] = client - end) - return result + local result = {} + for_each_buffer_client(bufnr, function(client, client_id) + result[client_id] = client + end) + return result end -- Log level dictionary with reverse lookup as well. @@ -1815,7 +1846,7 @@ function lsp.set_log_level(level) if type(level) == 'string' or type(level) == 'number' then log.set_level(level) else - error(string.format("Invalid log level: %q", level)) + error(string.format('Invalid log level: %q', level)) end end @@ -1845,7 +1876,7 @@ end ---@param override_config (table) Table containing the keys to override behavior of the {handler} function lsp.with(handler, override_config) return function(err, result, ctx, config) - return handler(err, result, ctx, vim.tbl_deep_extend("force", config or {}, override_config)) + return handler(err, result, ctx, vim.tbl_deep_extend('force', config or {}, override_config)) end end @@ -1860,12 +1891,16 @@ function lsp._with_extend(name, options, user_config) local resulting_config = {} for k, v in pairs(user_config) do if options[k] == nil then - error(debug.traceback(string.format( - "Invalid option for `%s`: %s. Valid options are:\n%s", - name, - k, - vim.inspect(vim.tbl_keys(options)) - ))) + error( + debug.traceback( + string.format( + 'Invalid option for `%s`: %s. Valid options are:\n%s', + name, + k, + vim.inspect(vim.tbl_keys(options)) + ) + ) + ) end resulting_config[k] = v @@ -1880,7 +1915,6 @@ function lsp._with_extend(name, options, user_config) return resulting_config end - --- Registry for client side commands. --- This is an extension point for plugins to handle custom commands which are --- not part of the core language server protocol specification. @@ -1902,12 +1936,11 @@ end --- The second argument is the `ctx` of |lsp-handler| lsp.commands = setmetatable({}, { __newindex = function(tbl, key, value) - assert(type(key) == 'string', "The key for commands in `vim.lsp.commands` must be a string") - assert(type(value) == 'function', "Command added to `vim.lsp.commands` must be a function") + assert(type(key) == 'string', 'The key for commands in `vim.lsp.commands` must be a string') + assert(type(value) == 'function', 'Command added to `vim.lsp.commands` must be a function') rawset(tbl, key, value) - end; + end, }) - return lsp -- vim:sw=2 ts=2 et diff --git a/runtime/lua/vim/lsp/_snippet.lua b/runtime/lua/vim/lsp/_snippet.lua index 0140b0aee3..28064f36e9 100644 --- a/runtime/lua/vim/lsp/_snippet.lua +++ b/runtime/lua/vim/lsp/_snippet.lua @@ -41,7 +41,7 @@ P.take_until = function(targets, specials) parsed = true, value = { raw = table.concat(raw, ''), - esc = table.concat(esc, '') + esc = table.concat(esc, ''), }, pos = new_pos, } @@ -248,49 +248,67 @@ S.format = P.any( capture_index = values[3], }, Node) end), - P.map(P.seq(S.dollar, S.open, S.int, S.colon, S.slash, P.any( - P.token('upcase'), - P.token('downcase'), - P.token('capitalize'), - P.token('camelcase'), - P.token('pascalcase') - ), S.close), function(values) - return setmetatable({ - type = Node.Type.FORMAT, - capture_index = values[3], - modifier = values[6], - }, Node) - end), - P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.any( - P.seq(S.question, P.take_until({ ':' }, { '\\' }), S.colon, P.take_until({ '}' }, { '\\' })), - P.seq(S.plus, P.take_until({ '}' }, { '\\' })), - P.seq(S.minus, P.take_until({ '}' }, { '\\' })) - ), S.close), function(values) + P.map( + P.seq( + S.dollar, + S.open, + S.int, + S.colon, + S.slash, + P.any(P.token('upcase'), P.token('downcase'), P.token('capitalize'), P.token('camelcase'), P.token('pascalcase')), + S.close + ), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + modifier = values[6], + }, Node) + end + ), + P.map( + P.seq( + S.dollar, + S.open, + S.int, + S.colon, + P.any( + P.seq(S.question, P.take_until({ ':' }, { '\\' }), S.colon, P.take_until({ '}' }, { '\\' })), + P.seq(S.plus, P.take_until({ '}' }, { '\\' })), + P.seq(S.minus, P.take_until({ '}' }, { '\\' })) + ), + S.close + ), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = values[5][2].esc, + else_text = (values[5][4] or {}).esc, + }, Node) + end + ) +) + +S.transform = P.map( + P.seq( + S.slash, + P.take_until({ '/' }, { '\\' }), + S.slash, + P.many(P.any(S.format, S.text({ '$', '/' }, { '\\' }))), + S.slash, + P.opt(P.pattern('[ig]+')) + ), + function(values) return setmetatable({ - type = Node.Type.FORMAT, - capture_index = values[3], - if_text = values[5][2].esc, - else_text = (values[5][4] or {}).esc, + type = Node.Type.TRANSFORM, + pattern = values[2].raw, + format = values[4], + option = values[6], }, Node) - end) + end ) -S.transform = P.map(P.seq( - S.slash, - P.take_until({ '/' }, { '\\' }), - S.slash, - P.many(P.any(S.format, S.text({ '$', '/' }, { '\\' }))), - S.slash, - P.opt(P.pattern('[ig]+')) -), function(values) - return setmetatable({ - type = Node.Type.TRANSFORM, - pattern = values[2].raw, - format = values[4], - option = values[6], - }, Node) -end) - S.tabstop = P.any( P.map(P.seq(S.dollar, S.int), function(values) return setmetatable({ @@ -314,34 +332,38 @@ S.tabstop = P.any( ) S.placeholder = P.any( - P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), function(values) - return setmetatable({ - type = Node.Type.PLACEHOLDER, - tabstop = values[3], - children = values[5], - }, Node) - end) + P.map( + P.seq(S.dollar, S.open, S.int, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), + function(values) + return setmetatable({ + type = Node.Type.PLACEHOLDER, + tabstop = values[3], + children = values[5], + }, Node) + end + ) ) -S.choice = P.map(P.seq( - S.dollar, - S.open, - S.int, - S.pipe, - P.many( - P.map(P.seq(S.text({ ',', '|' }), P.opt(S.comma)), function(values) +S.choice = P.map( + P.seq( + S.dollar, + S.open, + S.int, + S.pipe, + P.many(P.map(P.seq(S.text({ ',', '|' }), P.opt(S.comma)), function(values) return values[1].esc - end) + end)), + S.pipe, + S.close ), - S.pipe, - S.close -), function(values) - return setmetatable({ - type = Node.Type.CHOICE, - tabstop = values[3], - items = values[5], - }, Node) -end) + function(values) + return setmetatable({ + type = Node.Type.CHOICE, + tabstop = values[3], + items = values[5], + }, Node) + end +) S.variable = P.any( P.map(P.seq(S.dollar, S.var), function(values) @@ -363,13 +385,16 @@ S.variable = P.any( transform = values[4], }, Node) end), - P.map(P.seq(S.dollar, S.open, S.var, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), function(values) - return setmetatable({ - type = Node.Type.VARIABLE, - name = values[3], - children = values[5], - }, Node) - end) + P.map( + P.seq(S.dollar, S.open, S.var, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), + function(values) + return setmetatable({ + type = Node.Type.VARIABLE, + name = values[3], + children = values[5], + }, Node) + end + ) ) S.snippet = P.map(P.many(P.any(S.toplevel, S.text({ '$' }, { '}', '\\' }))), function(values) diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 6666b3c044..11243dea49 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -1,7 +1,7 @@ local vim = vim local validate = vim.validate local vfn = vim.fn -local util = require 'vim.lsp.util' +local util = require('vim.lsp.util') local M = {} @@ -9,7 +9,9 @@ local M = {} --- Returns nil if {status} is false or nil, otherwise returns the rest of the --- arguments. local function ok_or_nil(status, ...) - if not status then return end + if not status then + return + end return ... end @@ -39,10 +41,10 @@ end --- ---@see |vim.lsp.buf_request()| local function request(method, params, handler) - validate { - method = {method, 's'}; - handler = {handler, 'f', true}; - } + validate({ + method = { method, 's' }, + handler = { handler, 'f', true }, + }) return vim.lsp.buf_request(0, method, params, handler) end @@ -51,7 +53,7 @@ end --- ---@returns `true` if server responds. function M.server_ready() - return not not vim.lsp.buf_notify(0, "window/progress", {}) + return not not vim.lsp.buf_notify(0, 'window/progress', {}) end --- Displays hover information about the symbol under the cursor in a floating @@ -117,9 +119,9 @@ end -- ---@returns The client that the user selected or nil local function select_client(method, on_choice) - validate { + validate({ on_choice = { on_choice, 'function', false }, - } + }) local clients = vim.tbl_values(vim.lsp.buf_get_clients()) clients = vim.tbl_filter(function(client) return client.supports_method(method) @@ -191,24 +193,21 @@ function M.format(options) if options.filter then clients = options.filter(clients) elseif options.id then - clients = vim.tbl_filter( - function(client) return client.id == options.id end, - clients - ) + clients = vim.tbl_filter(function(client) + return client.id == options.id + end, clients) elseif options.name then - clients = vim.tbl_filter( - function(client) return client.name == options.name end, - clients - ) + clients = vim.tbl_filter(function(client) + return client.name == options.name + end, clients) end - clients = vim.tbl_filter( - function(client) return client.supports_method("textDocument/formatting") end, - clients - ) + clients = vim.tbl_filter(function(client) + return client.supports_method('textDocument/formatting') + end, clients) if #clients == 0 then - vim.notify("[LSP] Format request failed, no matching language servers.") + vim.notify('[LSP] Format request failed, no matching language servers.') end if options.async then @@ -218,7 +217,7 @@ function M.format(options) return end local params = util.make_formatting_params(options.formatting_options) - client.request("textDocument/formatting", params, function(...) + client.request('textDocument/formatting', params, function(...) local handler = client.handlers['textDocument/formatting'] or vim.lsp.handlers['textDocument/formatting'] handler(...) do_format(next(clients, idx)) @@ -229,11 +228,11 @@ function M.format(options) local timeout_ms = options.timeout_ms or 1000 for _, client in pairs(clients) do local params = util.make_formatting_params(options.formatting_options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) + local result, err = client.request_sync('textDocument/formatting', params, timeout_ms, bufnr) if result and result.result then util.apply_text_edits(result.result, bufnr, client.offset_encoding) elseif err then - vim.notify(string.format("[LSP][%s] %s", client.name, err), vim.log.levels.WARN) + vim.notify(string.format('[LSP][%s] %s', client.name, err), vim.log.levels.WARN) end end end @@ -310,7 +309,7 @@ end ---the remaining clients in the order as they occur in the `order` list. function M.formatting_seq_sync(options, timeout_ms, order) vim.notify_once('vim.lsp.buf.formatting_seq_sync is deprecated. Use vim.lsp.buf.format instead', vim.log.levels.WARN) - local clients = vim.tbl_values(vim.lsp.buf_get_clients()); + local clients = vim.tbl_values(vim.lsp.buf_get_clients()) local bufnr = vim.api.nvim_get_current_buf() -- sort the clients according to `order` @@ -326,13 +325,18 @@ function M.formatting_seq_sync(options, timeout_ms, order) -- loop through the clients and make synchronous formatting requests for _, client in pairs(clients) do - if vim.tbl_get(client.server_capabilities, "documentFormattingProvider") then + if vim.tbl_get(client.server_capabilities, 'documentFormattingProvider') then local params = util.make_formatting_params(options) - local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf()) + local result, err = client.request_sync( + 'textDocument/formatting', + params, + timeout_ms, + vim.api.nvim_get_current_buf() + ) if result and result.result then util.apply_text_edits(result.result, bufnr, client.offset_encoding) elseif err then - vim.notify(string.format("vim.lsp.buf.formatting_seq_sync: (%s) %s", client.name, err), vim.log.levels.WARN) + vim.notify(string.format('vim.lsp.buf.formatting_seq_sync: (%s) %s', client.name, err), vim.log.levels.WARN) end end end @@ -377,20 +381,18 @@ function M.rename(new_name, options) if options.filter then clients = options.filter(clients) elseif options.name then - clients = vim.tbl_filter( - function(client) return client.name == options.name end, - clients - ) + clients = vim.tbl_filter(function(client) + return client.name == options.name + end, clients) end -- Clients must at least support rename, prepareRename is optional - clients = vim.tbl_filter( - function(client) return client.supports_method("textDocument/rename") end, - clients - ) + clients = vim.tbl_filter(function(client) + return client.supports_method('textDocument/rename') + end, clients) if #clients == 0 then - vim.notify("[LSP] Rename, no matching language servers with rename capability.") + vim.notify('[LSP] Rename, no matching language servers with rename capability.') end local win = vim.api.nvim_get_current_win() @@ -427,7 +429,7 @@ function M.rename(new_name, options) end, bufnr) end - if client.supports_method("textDocument/prepareRename") then + if client.supports_method('textDocument/prepareRename') then local params = util.make_position_params(win, client.offset_encoding) client.request('textDocument/prepareRename', params, function(err, result) if err or result == nil then @@ -446,7 +448,7 @@ function M.rename(new_name, options) end local prompt_opts = { - prompt = "New Name: " + prompt = 'New Name: ', } -- result: Range | { range: Range, placeholder: string } if result.placeholder then @@ -466,15 +468,15 @@ function M.rename(new_name, options) end) end, bufnr) else - assert(client.supports_method("textDocument/rename"), 'Client must support textDocument/rename') + assert(client.supports_method('textDocument/rename'), 'Client must support textDocument/rename') if new_name then rename(new_name) return end local prompt_opts = { - prompt = "New Name: ", - default = cword + prompt = 'New Name: ', + default = cword, } vim.ui.input(prompt_opts, function(input) if not input or #input == 0 then @@ -493,10 +495,10 @@ end ---@param context (table) Context for the request ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references function M.references(context) - validate { context = { context, 't', true } } + validate({ context = { context, 't', true } }) local params = util.make_position_params() params.context = context or { - includeDeclaration = true; + includeDeclaration = true, } request('textDocument/references', params) end @@ -510,14 +512,16 @@ end ---@private local function pick_call_hierarchy_item(call_hierarchy_items) - if not call_hierarchy_items then return end + if not call_hierarchy_items then + return + end if #call_hierarchy_items == 1 then return call_hierarchy_items[1] end local items = {} for i, item in pairs(call_hierarchy_items) do local entry = item.detail or item.name - table.insert(items, string.format("%d. %s", i, entry)) + table.insert(items, string.format('%d. %s', i, entry)) end local choice = vim.fn.inputlist(items) if choice < 1 or choice > #items then @@ -539,8 +543,8 @@ local function call_hierarchy(method) if client then client.request(method, { item = call_hierarchy_item }, nil, ctx.bufnr) else - vim.notify(string.format( - 'Client with id=%d disappeared during call hierarchy request', ctx.client_id), + vim.notify( + string.format('Client with id=%d disappeared during call hierarchy request', ctx.client_id), vim.log.levels.WARN ) end @@ -576,20 +580,25 @@ end --- Add the folder at path to the workspace folders. If {path} is --- not provided, the user will be prompted for a path using |input()|. function M.add_workspace_folder(workspace_folder) - workspace_folder = workspace_folder or npcall(vfn.input, "Workspace Folder: ", vfn.expand('%:p:h'), 'dir') - vim.api.nvim_command("redraw") - if not (workspace_folder and #workspace_folder > 0) then return end + workspace_folder = workspace_folder or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h'), 'dir') + vim.api.nvim_command('redraw') + if not (workspace_folder and #workspace_folder > 0) then + return + end if vim.fn.isdirectory(workspace_folder) == 0 then - print(workspace_folder, " is not a valid directory") + print(workspace_folder, ' is not a valid directory') return end - local params = util.make_workspace_params({{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}, {{}}) + local params = util.make_workspace_params( + { { uri = vim.uri_from_fname(workspace_folder), name = workspace_folder } }, + { {} } + ) for _, client in pairs(vim.lsp.buf_get_clients()) do local found = false for _, folder in pairs(client.workspace_folders or {}) do if folder.name == workspace_folder then found = true - print(workspace_folder, "is already part of this workspace") + print(workspace_folder, 'is already part of this workspace') break end end @@ -607,10 +616,15 @@ end --- {path} is not provided, the user will be prompted for --- a path using |input()|. function M.remove_workspace_folder(workspace_folder) - workspace_folder = workspace_folder or npcall(vfn.input, "Workspace Folder: ", vfn.expand('%:p:h')) - vim.api.nvim_command("redraw") - if not (workspace_folder and #workspace_folder > 0) then return end - local params = util.make_workspace_params({{}}, {{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}) + workspace_folder = workspace_folder or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h')) + vim.api.nvim_command('redraw') + if not (workspace_folder and #workspace_folder > 0) then + return + end + local params = util.make_workspace_params( + { {} }, + { { uri = vim.uri_from_fname(workspace_folder), name = workspace_folder } } + ) for _, client in pairs(vim.lsp.buf_get_clients()) do for idx, folder in pairs(client.workspace_folders) do if folder.name == workspace_folder then @@ -620,7 +634,7 @@ function M.remove_workspace_folder(workspace_folder) end end end - print(workspace_folder, "is not currently part of the workspace") + print(workspace_folder, 'is not currently part of the workspace') end --- Lists all symbols in the current workspace in the quickfix window. @@ -631,11 +645,11 @@ end --- ---@param query (string, optional) function M.workspace_symbol(query) - query = query or npcall(vfn.input, "Query: ") + query = query or npcall(vfn.input, 'Query: ') if query == nil then return end - local params = {query = query} + local params = { query = query } request('workspace/symbol', params) end @@ -665,7 +679,6 @@ function M.clear_references() util.buf_clear_references() end - ---@private -- --- This is not public because the main extension point is @@ -728,10 +741,11 @@ local function on_code_action_results(results, ctx, options) -- local client = vim.lsp.get_client_by_id(action_tuple[1]) local action = action_tuple[2] - if not action.edit - and client - and vim.tbl_get(client.server_capabilities, "codeActionProvider", "resolveProvider") then - + if + not action.edit + and client + and vim.tbl_get(client.server_capabilities, 'codeActionProvider', 'resolveProvider') + then client.request('codeAction/resolve', action, function(err, resolved_action) if err then vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR) @@ -761,7 +775,6 @@ local function on_code_action_results(results, ctx, options) }, on_user_choice) end - --- Requests code actions from all clients and calls the handler exactly once --- with all aggregated results ---@private @@ -769,7 +782,7 @@ local function code_action_request(params, options) local bufnr = vim.api.nvim_get_current_buf() local method = 'textDocument/codeAction' vim.lsp.buf_request_all(bufnr, method, params, function(results) - local ctx = { bufnr = bufnr, method = method, params = params} + local ctx = { bufnr = bufnr, method = method, params = params } on_code_action_results(results, ctx, options) end) end @@ -794,7 +807,7 @@ end --- (after filtering), the action is applied without user query. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction function M.code_action(options) - validate { options = { options, 't', true } } + validate({ options = { options, 't', true } }) options = options or {} -- Detect old API call code_action(context) which should now be -- code_action({ context = context} ) @@ -826,7 +839,7 @@ end ---@param end_pos ({number, number}, optional) mark-indexed position. ---Defaults to the end of the last visual selection. function M.range_code_action(context, start_pos, end_pos) - validate { context = { context, 't', true } } + validate({ context = { context, 't', true } }) context = context or {} if not context.diagnostics then context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics() @@ -841,16 +854,16 @@ end ---@param command_params table A valid `ExecuteCommandParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand function M.execute_command(command_params) - validate { + validate({ command = { command_params.command, 's' }, - arguments = { command_params.arguments, 't', true } - } + arguments = { command_params.arguments, 't', true }, + }) command_params = { - command=command_params.command, - arguments=command_params.arguments, - workDoneToken=command_params.workDoneToken, + command = command_params.command, + arguments = command_params.arguments, + workDoneToken = command_params.workDoneToken, } - request('workspace/executeCommand', command_params ) + request('workspace/executeCommand', command_params) end return M diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index 99695d2ed1..ec0aede2d3 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -12,7 +12,7 @@ local lens_cache_by_buf = setmetatable({}, { __index = function(t, b) local key = b > 0 and b or api.nvim_get_current_buf() return rawget(t, key) - end + end, }) local namespaces = setmetatable({}, { @@ -20,13 +20,12 @@ local namespaces = setmetatable({}, { local value = api.nvim_create_namespace('vim_lsp_codelens:' .. key) rawset(t, key, value) return value - end; + end, }) ---@private M.__namespaces = namespaces - ---@private local function execute_lens(lens, bufnr, client_id) local line = lens.range.start.line @@ -44,10 +43,14 @@ local function execute_lens(lens, bufnr, client_id) local command_provider = client.server_capabilities.executeCommandProvider local commands = type(command_provider) == 'table' and command_provider.commands or {} if not vim.tbl_contains(commands, command.command) then - vim.notify(string.format( - "Language server does not support command `%s`. This command may require a client extension.", command.command), - vim.log.levels.WARN) - return + vim.notify( + string.format( + 'Language server does not support command `%s`. This command may require a client extension.', + command.command + ), + vim.log.levels.WARN + ) + return end client.request('workspace/executeCommand', command, function(...) local result = vim.lsp.handlers['workspace/executeCommand'](...) @@ -56,14 +59,15 @@ local function execute_lens(lens, bufnr, client_id) end, bufnr) end - --- Return all lenses for the given buffer --- ---@param bufnr number Buffer number. 0 can be used for the current buffer. ---@return table (`CodeLens[]`) function M.get(bufnr) local lenses_by_client = lens_cache_by_buf[bufnr or 0] - if not lenses_by_client then return {} end + if not lenses_by_client then + return {} + end local lenses = {} for _, client_lenses in pairs(lenses_by_client) do vim.list_extend(lenses, client_lenses) @@ -71,7 +75,6 @@ function M.get(bufnr) return lenses end - --- Run the code lens in the current line --- function M.run() @@ -82,7 +85,7 @@ function M.run() for client, lenses in pairs(lenses_by_client) do for _, lens in pairs(lenses) do if lens.range.start.line == (line - 1) then - table.insert(options, {client=client, lens=lens}) + table.insert(options, { client = client, lens = lens }) end end end @@ -105,7 +108,6 @@ function M.run() end end - --- Display the lenses using virtual text --- ---@param lenses table of lenses to display (`CodeLens[] | null`) @@ -133,19 +135,20 @@ function M.display(lenses, bufnr, client_id) local num_line_lenses = #line_lenses for j, lens in ipairs(line_lenses) do local text = lens.command and lens.command.title or 'Unresolved lens ...' - table.insert(chunks, {text, 'LspCodeLens' }) + table.insert(chunks, { text, 'LspCodeLens' }) if j < num_line_lenses then - table.insert(chunks, {' | ', 'LspCodeLensSeparator' }) + table.insert(chunks, { ' | ', 'LspCodeLensSeparator' }) end end if #chunks > 0 then - api.nvim_buf_set_extmark(bufnr, ns, i, 0, { virt_text = chunks, - hl_mode="combine" }) + api.nvim_buf_set_extmark(bufnr, ns, i, 0, { + virt_text = chunks, + hl_mode = 'combine', + }) end end end - --- Store lenses for a specific buffer and client --- ---@param lenses table of lenses to store (`CodeLens[] | null`) @@ -158,16 +161,17 @@ function M.save(lenses, bufnr, client_id) lens_cache_by_buf[bufnr] = lenses_by_client local ns = namespaces[client_id] api.nvim_buf_attach(bufnr, false, { - on_detach = function(b) lens_cache_by_buf[b] = nil end, + on_detach = function(b) + lens_cache_by_buf[b] = nil + end, on_lines = function(_, b, _, first_lnum, last_lnum) api.nvim_buf_clear_namespace(b, ns, first_lnum, last_lnum) - end + end, }) end lenses_by_client[client_id] = lenses end - ---@private local function resolve_lenses(lenses, bufnr, client_id, callback) lenses = lenses or {} @@ -201,8 +205,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback) ns, lens.range.start.line, 0, - { virt_text = {{ lens.command.title, 'LspCodeLens' }}, - hl_mode="combine" } + { virt_text = { { lens.command.title, 'LspCodeLens' } }, hl_mode = 'combine' } ) end countdown() @@ -211,13 +214,12 @@ local function resolve_lenses(lenses, bufnr, client_id, callback) end end - --- |lsp-handler| for the method `textDocument/codeLens` --- function M.on_codelens(err, result, ctx, _) if err then active_refreshes[ctx.bufnr] = nil - local _ = log.error() and log.error("codelens", err) + local _ = log.error() and log.error('codelens', err) return end @@ -232,7 +234,6 @@ function M.on_codelens(err, result, ctx, _) end) end - --- Refresh the codelens for the current buffer --- --- It is recommended to trigger this using an autocmd or via keymap. @@ -243,7 +244,7 @@ end --- function M.refresh() local params = { - textDocument = util.make_text_document_params() + textDocument = util.make_text_document_params(), } local bufnr = api.nvim_get_current_buf() if active_refreshes[bufnr] then @@ -253,5 +254,4 @@ function M.refresh() vim.lsp.buf_request(0, 'textDocument/codeLens', params, M.on_codelens) end - return M diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 28a236cc7e..126be2a0ad 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -50,12 +50,12 @@ end ---@private local function line_byte_from_position(lines, lnum, col, offset_encoding) - if not lines or offset_encoding == "utf-8" then + if not lines or offset_encoding == 'utf-8' then return col end local line = lines[lnum + 1] - local ok, result = pcall(vim.str_byteindex, line, col, offset_encoding == "utf-16") + local ok, result = pcall(vim.str_byteindex, line, col, offset_encoding == 'utf-16') if ok then return result end @@ -75,7 +75,7 @@ local function get_buf_lines(bufnr) return end - local content = f:read("*a") + local content = f:read('*a') if not content then -- Some LSP servers report diagnostics at a directory level, in which case -- io.read() returns nil @@ -83,7 +83,7 @@ local function get_buf_lines(bufnr) return end - local lines = vim.split(content, "\n") + local lines = vim.split(content, '\n') f:close() return lines end @@ -92,10 +92,10 @@ end local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id) local buf_lines = get_buf_lines(bufnr) local client = vim.lsp.get_client_by_id(client_id) - local offset_encoding = client and client.offset_encoding or "utf-16" + local offset_encoding = client and client.offset_encoding or 'utf-16' return vim.tbl_map(function(diagnostic) local start = diagnostic.range.start - local _end = diagnostic.range["end"] + local _end = diagnostic.range['end'] return { lnum = start.line, col = line_byte_from_position(buf_lines, start.line, start.character, offset_encoding), @@ -122,14 +122,14 @@ end ---@private local function diagnostic_vim_to_lsp(diagnostics) return vim.tbl_map(function(diagnostic) - return vim.tbl_extend("keep", { + return vim.tbl_extend('keep', { -- "keep" the below fields over any duplicate fields in diagnostic.user_data.lsp range = { start = { line = diagnostic.lnum, character = diagnostic.col, }, - ["end"] = { + ['end'] = { line = diagnostic.end_lnum, character = diagnostic.end_col, }, @@ -148,10 +148,10 @@ local _client_namespaces = {} --- ---@param client_id number The id of the LSP client function M.get_namespace(client_id) - vim.validate { client_id = { client_id, 'n' } } + vim.validate({ client_id = { client_id, 'n' } }) if not _client_namespaces[client_id] then local client = vim.lsp.get_client_by_id(client_id) - local name = string.format("vim.lsp.%s.%d", client and client.name or "unknown", client_id) + local name = string.format('vim.lsp.%s.%d', client and client.name or 'unknown', client_id) _client_namespaces[client_id] = vim.api.nvim_create_namespace(name) end return _client_namespaces[client_id] @@ -203,7 +203,7 @@ function M.on_publish_diagnostics(_, result, ctx, config) for _, opt in pairs(config) do if type(opt) == 'table' then if not opt.severity and opt.severity_limit then - opt.severity = {min=severity_lsp_to_vim(opt.severity_limit)} + opt.severity = { min = severity_lsp_to_vim(opt.severity_limit) } end end end @@ -240,7 +240,6 @@ end -- Deprecated Functions {{{ - --- Save diagnostics to the current buffer. --- ---@deprecated Prefer |vim.diagnostic.set()| @@ -251,7 +250,7 @@ end ---@param client_id number ---@private function M.save(diagnostics, bufnr, client_id) - vim.deprecate('vim.lsp.diagnostic.save', 'vim.diagnostic.set', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.save', 'vim.diagnostic.set', '0.8') local namespace = M.get_namespace(client_id) vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)) end @@ -265,14 +264,14 @@ end --- If nil, diagnostics of all clients are included. ---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[]) function M.get_all(client_id) - vim.deprecate('vim.lsp.diagnostic.get_all', 'vim.diagnostic.get', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_all', 'vim.diagnostic.get', '0.8') local result = {} local namespace if client_id then namespace = M.get_namespace(client_id) end for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do - local diagnostics = diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, {namespace = namespace})) + local diagnostics = diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, { namespace = namespace })) result[bufnr] = diagnostics end return result @@ -287,8 +286,10 @@ end --- Else, return just the diagnostics associated with the client_id. ---@param predicate function|nil Optional function for filtering diagnostics function M.get(bufnr, client_id, predicate) - vim.deprecate('vim.lsp.diagnostic.get', 'vim.diagnostic.get', '0.8' ) - predicate = predicate or function() return true end + vim.deprecate('vim.lsp.diagnostic.get', 'vim.diagnostic.get', '0.8') + predicate = predicate or function() + return true + end if client_id == nil then local all_diagnostics = {} vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _) @@ -301,7 +302,7 @@ function M.get(bufnr, client_id, predicate) end local namespace = M.get_namespace(client_id) - return diagnostic_vim_to_lsp(vim.tbl_filter(predicate, vim.diagnostic.get(bufnr, {namespace=namespace}))) + return diagnostic_vim_to_lsp(vim.tbl_filter(predicate, vim.diagnostic.get(bufnr, { namespace = namespace }))) end --- Get the diagnostics by line @@ -325,7 +326,7 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id) if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end if client_id then @@ -349,7 +350,7 @@ end ---@param severity DiagnosticSeverity ---@param client_id number the client id function M.get_count(bufnr, severity, client_id) - vim.deprecate('vim.lsp.diagnostic.get_count', 'vim.diagnostic.get', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_count', 'vim.diagnostic.get', '0.8') severity = severity_lsp_to_vim(severity) local opts = { severity = severity } if client_id ~= nil then @@ -366,15 +367,15 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic function M.get_prev(opts) - vim.deprecate('vim.lsp.diagnostic.get_prev', 'vim.diagnostic.get_prev', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_prev', 'vim.diagnostic.get_prev', '0.8') if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end end - return diagnostic_vim_to_lsp({vim.diagnostic.get_prev(opts)})[1] + return diagnostic_vim_to_lsp({ vim.diagnostic.get_prev(opts) })[1] end --- Return the pos, {row, col}, for the prev diagnostic in the current buffer. @@ -384,12 +385,12 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Previous diagnostic position function M.get_prev_pos(opts) - vim.deprecate('vim.lsp.diagnostic.get_prev_pos', 'vim.diagnostic.get_prev_pos', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_prev_pos', 'vim.diagnostic.get_prev_pos', '0.8') if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end end return vim.diagnostic.get_prev_pos(opts) @@ -401,12 +402,12 @@ end --- ---@param opts table See |vim.lsp.diagnostic.goto_next()| function M.goto_prev(opts) - vim.deprecate('vim.lsp.diagnostic.goto_prev', 'vim.diagnostic.goto_prev', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.goto_prev', 'vim.diagnostic.goto_prev', '0.8') if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end end return vim.diagnostic.goto_prev(opts) @@ -419,15 +420,15 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic function M.get_next(opts) - vim.deprecate('vim.lsp.diagnostic.get_next', 'vim.diagnostic.get_next', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_next', 'vim.diagnostic.get_next', '0.8') if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end end - return diagnostic_vim_to_lsp({vim.diagnostic.get_next(opts)})[1] + return diagnostic_vim_to_lsp({ vim.diagnostic.get_next(opts) })[1] end --- Return the pos, {row, col}, for the next diagnostic in the current buffer. @@ -437,12 +438,12 @@ end ---@param opts table See |vim.lsp.diagnostic.goto_next()| ---@return table Next diagnostic position function M.get_next_pos(opts) - vim.deprecate('vim.lsp.diagnostic.get_next_pos', 'vim.diagnostic.get_next_pos', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_next_pos', 'vim.diagnostic.get_next_pos', '0.8') if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end end return vim.diagnostic.get_next_pos(opts) @@ -452,12 +453,12 @@ end --- ---@deprecated Prefer |vim.diagnostic.goto_next()| function M.goto_next(opts) - vim.deprecate('vim.lsp.diagnostic.goto_next', 'vim.diagnostic.goto_next', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.goto_next', 'vim.diagnostic.goto_next', '0.8') if opts then if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end end return vim.diagnostic.goto_next(opts) @@ -476,10 +477,10 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_signs(diagnostics, bufnr, client_id, _, opts) - vim.deprecate('vim.lsp.diagnostic.set_signs', nil , '0.8' ) + vim.deprecate('vim.lsp.diagnostic.set_signs', nil, '0.8') local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end vim.diagnostic._set_signs(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts) @@ -497,10 +498,10 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_underline(diagnostics, bufnr, client_id, _, opts) - vim.deprecate('vim.lsp.diagnostic.set_underline', nil , '0.8' ) + vim.deprecate('vim.lsp.diagnostic.set_underline', nil, '0.8') local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end return vim.diagnostic._set_underline(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts) end @@ -519,10 +520,10 @@ end --- - severity_limit (DiagnosticSeverity): --- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid. function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts) - vim.deprecate('vim.lsp.diagnostic.set_virtual_text', nil , '0.8' ) + vim.deprecate('vim.lsp.diagnostic.set_virtual_text', nil, '0.8') local namespace = M.get_namespace(client_id) if opts and not opts.severity and opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end return vim.diagnostic._set_virtual_text(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts) end @@ -538,7 +539,7 @@ end ---@return an array of [text, hl_group] arrays. This can be passed directly to --- the {virt_text} option of |nvim_buf_set_extmark()|. function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts) - vim.deprecate('vim.lsp.diagnostic.get_virtual_text_chunks_for_line', nil, '0.8' ) + vim.deprecate('vim.lsp.diagnostic.get_virtual_text_chunks_for_line', nil, '0.8') return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts) end @@ -556,14 +557,14 @@ end ---@param position table|nil The (0,0)-indexed position ---@return table {popup_bufnr, win_id} function M.show_position_diagnostics(opts, buf_nr, position) - vim.deprecate('vim.lsp.diagnostic.show_position_diagnostics', 'vim.diagnostic.open_float', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.show_position_diagnostics', 'vim.diagnostic.open_float', '0.8') opts = opts or {} - opts.scope = "cursor" + opts.scope = 'cursor' opts.pos = position if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end return vim.diagnostic.open_float(buf_nr, opts) end @@ -580,9 +581,9 @@ end ---@param client_id number|nil the client id ---@return table {popup_bufnr, win_id} function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id) - vim.deprecate('vim.lsp.diagnostic.show_line_diagnostics', 'vim.diagnostic.open_float', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.show_line_diagnostics', 'vim.diagnostic.open_float', '0.8') opts = opts or {} - opts.scope = "line" + opts.scope = 'line' opts.pos = line_nr if client_id then opts.namespace = M.get_namespace(client_id) @@ -604,7 +605,7 @@ end --- client. The default is to redraw diagnostics for all attached --- clients. function M.redraw(bufnr, client_id) - vim.deprecate('vim.lsp.diagnostic.redraw', 'vim.diagnostic.show', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.redraw', 'vim.diagnostic.show', '0.8') bufnr = get_bufnr(bufnr) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) @@ -632,12 +633,12 @@ end --- - {workspace}: (boolean, default true) --- - Set the list with workspace diagnostics function M.set_qflist(opts) - vim.deprecate('vim.lsp.diagnostic.set_qflist', 'vim.diagnostic.setqflist', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.set_qflist', 'vim.diagnostic.setqflist', '0.8') opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end if opts.client_id then opts.client_id = nil @@ -664,12 +665,12 @@ end --- - {workspace}: (boolean, default false) --- - Set the list with workspace diagnostics function M.set_loclist(opts) - vim.deprecate('vim.lsp.diagnostic.set_loclist', 'vim.diagnostic.setloclist', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.set_loclist', 'vim.diagnostic.setloclist', '0.8') opts = opts or {} if opts.severity then opts.severity = severity_lsp_to_vim(opts.severity) elseif opts.severity_limit then - opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)} + opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end if opts.client_id then opts.client_id = nil @@ -692,7 +693,7 @@ end -- send diagnostic information and the client will still process it. The -- diagnostics are simply not displayed to the user. function M.disable(bufnr, client_id) - vim.deprecate('vim.lsp.diagnostic.disable', 'vim.diagnostic.disable', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.disable', 'vim.diagnostic.disable', '0.8') if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.disable(bufnr, client.id) @@ -713,7 +714,7 @@ end --- client. The default is to enable diagnostics for all attached --- clients. function M.enable(bufnr, client_id) - vim.deprecate('vim.lsp.diagnostic.enable', 'vim.diagnostic.enable', '0.8' ) + vim.deprecate('vim.lsp.diagnostic.enable', 'vim.diagnostic.enable', '0.8') if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) M.enable(bufnr, client.id) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 5c80ed0d10..b3a253c118 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -1,6 +1,6 @@ -local log = require 'vim.lsp.log' -local protocol = require 'vim.lsp.protocol' -local util = require 'vim.lsp.util' +local log = require('vim.lsp.log') +local protocol = require('vim.lsp.protocol') +local util = require('vim.lsp.util') local vim = vim local api = vim.api @@ -12,8 +12,8 @@ local M = {} --- Writes to error buffer. ---@param ... (table of strings) Will be concatenated before being written local function err_message(...) - vim.notify(table.concat(vim.tbl_flatten{...}), vim.log.levels.ERROR) - api.nvim_command("redraw") + vim.notify(table.concat(vim.tbl_flatten({ ... })), vim.log.levels.ERROR) + api.nvim_command('redraw') end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand @@ -25,15 +25,17 @@ end local function progress_handler(_, result, ctx, _) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) - local client_name = client and client.name or string.format("id=%d", client_id) + local client_name = client and client.name or string.format('id=%d', client_id) if not client then - err_message("LSP[", client_name, "] client has shut down during progress update") + err_message('LSP[', client_name, '] client has shut down during progress update') return vim.NIL end - local val = result.value -- unspecified yet - local token = result.token -- string or number + local val = result.value -- unspecified yet + local token = result.token -- string or number - if type(val) ~= 'table' then val = { content=val } end + if type(val) ~= 'table' then + val = { content = val } + end if val.kind then if val.kind == 'begin' then client.messages.progress[token] = { @@ -42,11 +44,11 @@ local function progress_handler(_, result, ctx, _) percentage = val.percentage, } elseif val.kind == 'report' then - client.messages.progress[token].message = val.message; - client.messages.progress[token].percentage = val.percentage; + client.messages.progress[token].message = val.message + client.messages.progress[token].percentage = val.percentage elseif val.kind == 'end' then if client.messages.progress[token] == nil then - err_message("LSP[", client_name, "] received `end` message with no corresponding `begin`") + err_message('LSP[', client_name, '] received `end` message with no corresponding `begin`') else client.messages.progress[token].message = val.message client.messages.progress[token].done = true @@ -57,20 +59,20 @@ local function progress_handler(_, result, ctx, _) client.messages.progress[token].done = true end - vim.api.nvim_command("doautocmd User LspProgressUpdate") + vim.api.nvim_command('doautocmd User LspProgressUpdate') end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress M['$/progress'] = progress_handler --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create -M['window/workDoneProgress/create'] = function(_, result, ctx) +M['window/workDoneProgress/create'] = function(_, result, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) - local token = result.token -- string or number - local client_name = client and client.name or string.format("id=%d", client_id) + local token = result.token -- string or number + local client_name = client and client.name or string.format('id=%d', client_id) if not client then - err_message("LSP[", client_name, "] client has shut down while creating progress report") + err_message('LSP[', client_name, '] client has shut down while creating progress report') return vim.NIL end client.messages.progress[token] = {} @@ -79,20 +81,19 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest M['window/showMessageRequest'] = function(_, result) - local actions = result.actions print(result.message) - local option_strings = {result.message, "\nRequest Actions:"} + local option_strings = { result.message, '\nRequest Actions:' } for i, action in ipairs(actions) do local title = action.title:gsub('\r\n', '\\r\\n') title = title:gsub('\n', '\\n') - table.insert(option_strings, string.format("%d. %s", i, title)) + table.insert(option_strings, string.format('%d. %s', i, title)) end -- window/showMessageRequest can return either MessageActionItem[] or null. local choice = vim.fn.inputlist(option_strings) if choice < 1 or choice > #actions then - return vim.NIL + return vim.NIL else return actions[choice] end @@ -101,11 +102,11 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability M['client/registerCapability'] = function(_, _, ctx) local client_id = ctx.client_id - local warning_tpl = "The language server %s triggers a registerCapability ".. - "handler despite dynamicRegistration set to false. ".. - "Report upstream, this warning is harmless" + local warning_tpl = 'The language server %s triggers a registerCapability ' + .. 'handler despite dynamicRegistration set to false. ' + .. 'Report upstream, this warning is harmless' local client = vim.lsp.get_client_by_id(client_id) - local client_name = client and client.name or string.format("id=%d", client_id) + local client_name = client and client.name or string.format('id=%d', client_id) local warning = string.format(warning_tpl, client_name) log.warn(warning) return vim.NIL @@ -113,17 +114,19 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit M['workspace/applyEdit'] = function(_, workspace_edit, ctx) - if not workspace_edit then return end + if not workspace_edit then + return + end -- TODO(ashkan) Do something more with label? local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) if workspace_edit.label then - print("Workspace edit", workspace_edit.label) + print('Workspace edit', workspace_edit.label) end local status, result = pcall(util.apply_workspace_edit, workspace_edit.edit, client.offset_encoding) return { - applied = status; - failureReason = result; + applied = status, + failureReason = result, } end @@ -132,7 +135,7 @@ M['workspace/configuration'] = function(_, result, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) if not client then - err_message("LSP[", client_id, "] client has shut down after sending a workspace/configuration request") + err_message('LSP[', client_id, '] client has shut down after sending a workspace/configuration request') return end if not result.items then @@ -158,7 +161,7 @@ M['workspace/workspaceFolders'] = function(_, _, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) if not client then - err_message("LSP[id=", client_id, "] client has shut down after sending the message") + err_message('LSP[id=', client_id, '] client has shut down after sending the message') return end return client.workspace_folders or vim.NIL @@ -172,7 +175,6 @@ M['textDocument/codeLens'] = function(...) return require('vim.lsp.codelens').on_codelens(...) end - --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references M['textDocument/references'] = function(_, result, ctx, config) if not result or vim.tbl_isempty(result) then @@ -182,23 +184,22 @@ M['textDocument/references'] = function(_, result, ctx, config) config = config or {} if config.loclist then vim.fn.setloclist(0, {}, ' ', { - title = 'References'; - items = util.locations_to_items(result, client.offset_encoding); - context = ctx; + title = 'References', + items = util.locations_to_items(result, client.offset_encoding), + context = ctx, }) - api.nvim_command("lopen") + api.nvim_command('lopen') else vim.fn.setqflist({}, ' ', { - title = 'References'; - items = util.locations_to_items(result, client.offset_encoding); - context = ctx; + title = 'References', + items = util.locations_to_items(result, client.offset_encoding), + context = ctx, }) - api.nvim_command("botright copen") + api.nvim_command('botright copen') end end end - ---@private --- Return a function that converts LSP responses to list items and opens the list --- @@ -218,27 +219,26 @@ local function response_to_list(map_result, entity, title_fn) config = config or {} if config.loclist then vim.fn.setloclist(0, {}, ' ', { - title = title_fn(ctx); - items = map_result(result, ctx.bufnr); - context = ctx; + title = title_fn(ctx), + items = map_result(result, ctx.bufnr), + context = ctx, }) - api.nvim_command("lopen") + api.nvim_command('lopen') else vim.fn.setqflist({}, ' ', { - title = title_fn(ctx); - items = map_result(result, ctx.bufnr); - context = ctx; + title = title_fn(ctx), + items = map_result(result, ctx.bufnr), + context = ctx, }) - api.nvim_command("botright copen") + api.nvim_command('botright copen') end end end end - --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols', function(ctx) - local fname = vim.fn.fnamemodify(vim.uri_to_fname(ctx.params.textDocument.uri), ":.") + local fname = vim.fn.fnamemodify(vim.uri_to_fname(ctx.params.textDocument.uri), ':.') return string.format('Symbols in %s', fname) end) @@ -249,36 +249,44 @@ end) --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename M['textDocument/rename'] = function(_, result, ctx, _) - if not result then return end + if not result then + return + end local client = vim.lsp.get_client_by_id(ctx.client_id) util.apply_workspace_edit(result, client.offset_encoding) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting M['textDocument/rangeFormatting'] = function(_, result, ctx, _) - if not result then return end + if not result then + return + end local client = vim.lsp.get_client_by_id(ctx.client_id) util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting M['textDocument/formatting'] = function(_, result, ctx, _) - if not result then return end + if not result then + return + end local client = vim.lsp.get_client_by_id(ctx.client_id) util.apply_text_edits(result, ctx.bufnr, client.offset_encoding) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion M['textDocument/completion'] = function(_, result, _, _) - if vim.tbl_isempty(result or {}) then return end + if vim.tbl_isempty(result or {}) then + return + end local row, col = unpack(api.nvim_win_get_cursor(0)) - local line = assert(api.nvim_buf_get_lines(0, row-1, row, false)[1]) - local line_to_cursor = line:sub(col+1) + local line = assert(api.nvim_buf_get_lines(0, row - 1, row, false)[1]) + local line_to_cursor = line:sub(col + 1) local textMatch = vim.fn.match(line_to_cursor, '\\k*$') - local prefix = line_to_cursor:sub(textMatch+1) + local prefix = line_to_cursor:sub(textMatch + 1) local matches = util.text_document_completion_list_to_complete_items(result, prefix) - vim.fn.complete(textMatch+1, matches) + vim.fn.complete(textMatch + 1, matches) end --- |lsp-handler| for the method "textDocument/hover" @@ -307,7 +315,7 @@ function M.hover(_, result, ctx, config) vim.notify('No information available') return end - return util.open_floating_preview(markdown_lines, "markdown", config) + return util.open_floating_preview(markdown_lines, 'markdown', config) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover @@ -335,9 +343,9 @@ local function location_handler(_, result, ctx, _) if #result > 1 then vim.fn.setqflist({}, ' ', { title = 'LSP locations', - items = util.locations_to_items(result, client.offset_encoding) + items = util.locations_to_items(result, client.offset_encoding), }) - api.nvim_command("botright copen") + api.nvim_command('botright copen') end else util.jump_to_location(result, client.offset_encoding) @@ -379,7 +387,7 @@ function M.signature_help(_, result, ctx, config) return end local client = vim.lsp.get_client_by_id(ctx.client_id) - local triggers = vim.tbl_get(client.server_capabilities, "signatureHelpProvider", "triggerCharacters") + local triggers = vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters') local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype') local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers) lines = util.trim_empty_lines(lines) @@ -389,9 +397,9 @@ function M.signature_help(_, result, ctx, config) end return end - local fbuf, fwin = util.open_floating_preview(lines, "markdown", config) + local fbuf, fwin = util.open_floating_preview(lines, 'markdown', config) if hl then - api.nvim_buf_add_highlight(fbuf, -1, "LspSignatureActiveParameter", 0, unpack(hl)) + api.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', 0, unpack(hl)) end return fbuf, fwin end @@ -401,10 +409,14 @@ M['textDocument/signatureHelp'] = M.signature_help --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight M['textDocument/documentHighlight'] = function(_, result, ctx, _) - if not result then return end + if not result then + return + end local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) - if not client then return end + if not client then + return + end util.buf_highlight_references(ctx.bufnr, result, client.offset_encoding) end @@ -417,7 +429,9 @@ end ---@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`, local make_call_hierarchy_handler = function(direction) return function(_, result) - if not result then return end + if not result then + return + end local items = {} for _, call_hierarchy_call in pairs(result) do local call_hierarchy_item = call_hierarchy_call[direction] @@ -430,8 +444,8 @@ local make_call_hierarchy_handler = function(direction) }) end end - vim.fn.setqflist({}, ' ', {title = 'LSP call hierarchy', items = items}) - api.nvim_command("botright copen") + vim.fn.setqflist({}, ' ', { title = 'LSP call hierarchy', items = items }) + api.nvim_command('botright copen') end end @@ -447,15 +461,15 @@ M['window/logMessage'] = function(_, result, ctx, _) local message = result.message local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) - local client_name = client and client.name or string.format("id=%d", client_id) + local client_name = client and client.name or string.format('id=%d', client_id) if not client then - err_message("LSP[", client_name, "] client has shut down after sending ", message) + err_message('LSP[', client_name, '] client has shut down after sending ', message) end if message_type == protocol.MessageType.Error then log.error(message) elseif message_type == protocol.MessageType.Warning then log.warn(message) - elseif message_type == protocol.MessageType.Info or message_type == protocol.MessageType.Log then + elseif message_type == protocol.MessageType.Info or message_type == protocol.MessageType.Log then log.info(message) else log.debug(message) @@ -469,15 +483,15 @@ M['window/showMessage'] = function(_, result, ctx, _) local message = result.message local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) - local client_name = client and client.name or string.format("id=%d", client_id) + local client_name = client and client.name or string.format('id=%d', client_id) if not client then - err_message("LSP[", client_name, "] client has shut down after sending ", message) + err_message('LSP[', client_name, '] client has shut down after sending ', message) end if message_type == protocol.MessageType.Error then - err_message("LSP[", client_name, "] ", message) + err_message('LSP[', client_name, '] ', message) else local message_type_name = protocol.MessageType[message_type] - api.nvim_out_write(string.format("LSP[%s][%s] %s\n", client_name, message_type_name, message)) + api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message)) end return result end @@ -485,9 +499,13 @@ end -- Add boilerplate error validation and logging for all of these. for k, fn in pairs(M) do M[k] = function(err, result, ctx, config) - local _ = log.trace() and log.trace('default_handler', ctx.method, { - err = err, result = result, ctx=vim.inspect(ctx), config = config - }) + local _ = log.trace() + and log.trace('default_handler', ctx.method, { + err = err, + result = result, + ctx = vim.inspect(ctx), + config = config, + }) if err then -- LSP spec: @@ -499,7 +517,7 @@ for k, fn in pairs(M) do -- Per LSP, don't show ContentModified error to the user. if err.code ~= protocol.ErrorCodes.ContentModified then local client = vim.lsp.get_client_by_id(ctx.client_id) - local client_name = client and client.name or string.format("client_id=%d", ctx.client_id) + local client_name = client and client.name or string.format('client_id=%d', ctx.client_id) err_message(client_name .. ': ' .. tostring(err.code) .. ': ' .. err.message) end diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index ed3eea59df..74714ebc6b 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -8,20 +8,19 @@ function M.check() local log = require('vim.lsp.log') local current_log_level = log.get_level() local log_level_string = log.levels[current_log_level] - report_info(string.format("LSP log level : %s", log_level_string)) + report_info(string.format('LSP log level : %s', log_level_string)) if current_log_level < log.levels.WARN then - report_warn(string.format("Log level %s will cause degraded performance and high disk usage", log_level_string)) + report_warn(string.format('Log level %s will cause degraded performance and high disk usage', log_level_string)) end local log_path = vim.lsp.get_log_path() - report_info(string.format("Log path: %s", log_path)) + report_info(string.format('Log path: %s', log_path)) local log_size = vim.loop.fs_stat(log_path).size local report_fn = (log_size / 1000000 > 100 and report_warn or report_info) - report_fn(string.format("Log size: %d KB", log_size / 1000 )) + report_fn(string.format('Log size: %d KB', log_size / 1000)) end return M - diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index fff42fd011..66e82ecfeb 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -14,21 +14,23 @@ log.levels = vim.deepcopy(vim.log.levels) -- Default log level is warn. local current_log_level = log.levels.WARN -local log_date_format = "%F %H:%M:%S" -local format_func = function(arg) return vim.inspect(arg, {newline=''}) end +local log_date_format = '%F %H:%M:%S' +local format_func = function(arg) + return vim.inspect(arg, { newline = '' }) +end do - local path_sep = vim.loop.os_uname().version:match("Windows") and "\\" or "/" + local path_sep = vim.loop.os_uname().version:match('Windows') and '\\' or '/' ---@private local function path_join(...) - return table.concat(vim.tbl_flatten{...}, path_sep) + return table.concat(vim.tbl_flatten({ ... }), path_sep) end local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') -- TODO: Ideally the directory should be created in open_logfile(), right -- before opening the log file, but open_logfile() can be called from libuv -- callbacks, where using fn.mkdir() is not allowed. - vim.fn.mkdir(vim.fn.stdpath('cache'), "p") + vim.fn.mkdir(vim.fn.stdpath('cache'), 'p') --- Returns the log filename. ---@returns (string) log filename @@ -41,28 +43,28 @@ do --- Opens log file. Returns true if file is open, false on error local function open_logfile() -- Try to open file only once - if logfile then return true end - if openerr then return false end + if logfile then + return true + end + if openerr then + return false + end - logfile, openerr = io.open(logfilename, "a+") + logfile, openerr = io.open(logfilename, 'a+') if not logfile then - local err_msg = string.format("Failed to open LSP client log file: %s", openerr) + local err_msg = string.format('Failed to open LSP client log file: %s', openerr) vim.notify(err_msg, vim.log.levels.ERROR) return false end local log_info = vim.loop.fs_stat(logfilename) if log_info and log_info.size > 1e9 then - local warn_msg = string.format( - "LSP client log is large (%d MB): %s", - log_info.size / (1000 * 1000), - logfilename - ) + local warn_msg = string.format('LSP client log is large (%d MB): %s', log_info.size / (1000 * 1000), logfilename) vim.notify(warn_msg) end -- Start message for logging - logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format))) + logfile:write(string.format('[START][%s] LSP logging initiated\n', os.date(log_date_format))) return true end @@ -83,24 +85,36 @@ do -- ``` -- -- This way you can avoid string allocations if the log level isn't high enough. - if level ~= "OFF" then + if level ~= 'OFF' then log[level:lower()] = function(...) - local argc = select("#", ...) - if levelnr < current_log_level then return false end - if argc == 0 then return true end - if not open_logfile() then return false end - local info = debug.getinfo(2, "Sl") - local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline) + local argc = select('#', ...) + if levelnr < current_log_level then + return false + end + if argc == 0 then + return true + end + if not open_logfile() then + return false + end + local info = debug.getinfo(2, 'Sl') + local header = string.format( + '[%s][%s] ...%s:%s', + level, + os.date(log_date_format), + string.sub(info.short_src, #info.short_src - 15), + info.currentline + ) local parts = { header } for i = 1, argc do local arg = select(i, ...) if arg == nil then - table.insert(parts, "nil") + table.insert(parts, 'nil') else table.insert(parts, format_func(arg)) end end - logfile:write(table.concat(parts, '\t'), "\n") + logfile:write(table.concat(parts, '\t'), '\n') logfile:flush() end end @@ -115,10 +129,10 @@ vim.tbl_add_reverse_lookup(log.levels) ---@param level (string or number) One of `vim.lsp.log.levels` function log.set_level(level) if type(level) == 'string' then - current_log_level = assert(log.levels[level:upper()], string.format("Invalid log level: %q", level)) + current_log_level = assert(log.levels[level:upper()], string.format('Invalid log level: %q', level)) else - assert(type(level) == 'number', "level must be a number or string") - assert(log.levels[level], string.format("Invalid log level: %d", level)) + assert(type(level) == 'number', 'level must be a number or string') + assert(log.levels[level], string.format('Invalid log level: %d', level)) current_log_level = level end end @@ -132,7 +146,7 @@ end --- Sets formatting function used to format logs ---@param handle function function to apply to logging arguments, pass vim.inspect for multi-line formatting function log.set_format_func(handle) - assert(handle == vim.inspect or type(handle) == 'function', "handle must be a function") + assert(handle == vim.inspect or type(handle) == 'function', 'handle must be a function') format_func = handle end diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 8f50863360..6ecf7891c7 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -23,150 +23,150 @@ end local constants = { DiagnosticSeverity = { -- Reports an error. - Error = 1; + Error = 1, -- Reports a warning. - Warning = 2; + Warning = 2, -- Reports an information. - Information = 3; + Information = 3, -- Reports a hint. - Hint = 4; - }; + Hint = 4, + }, DiagnosticTag = { -- Unused or unnecessary code - Unnecessary = 1; + Unnecessary = 1, -- Deprecated or obsolete code - Deprecated = 2; - }; + Deprecated = 2, + }, MessageType = { -- An error message. - Error = 1; + Error = 1, -- A warning message. - Warning = 2; + Warning = 2, -- An information message. - Info = 3; + Info = 3, -- A log message. - Log = 4; - }; + Log = 4, + }, -- The file event type. FileChangeType = { -- The file got created. - Created = 1; + Created = 1, -- The file got changed. - Changed = 2; + Changed = 2, -- The file got deleted. - Deleted = 3; - }; + Deleted = 3, + }, -- The kind of a completion entry. CompletionItemKind = { - Text = 1; - Method = 2; - Function = 3; - Constructor = 4; - Field = 5; - Variable = 6; - Class = 7; - Interface = 8; - Module = 9; - Property = 10; - Unit = 11; - Value = 12; - Enum = 13; - Keyword = 14; - Snippet = 15; - Color = 16; - File = 17; - Reference = 18; - Folder = 19; - EnumMember = 20; - Constant = 21; - Struct = 22; - Event = 23; - Operator = 24; - TypeParameter = 25; - }; + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, + }, -- How a completion was triggered CompletionTriggerKind = { -- Completion was triggered by typing an identifier (24x7 code -- complete), manual invocation (e.g Ctrl+Space) or via API. - Invoked = 1; + Invoked = 1, -- Completion was triggered by a trigger character specified by -- the `triggerCharacters` properties of the `CompletionRegistrationOptions`. - TriggerCharacter = 2; + TriggerCharacter = 2, -- Completion was re-triggered as the current completion list is incomplete. - TriggerForIncompleteCompletions = 3; - }; + TriggerForIncompleteCompletions = 3, + }, -- A document highlight kind. DocumentHighlightKind = { -- A textual occurrence. - Text = 1; + Text = 1, -- Read-access of a symbol, like reading a variable. - Read = 2; + Read = 2, -- Write-access of a symbol, like writing to a variable. - Write = 3; - }; + Write = 3, + }, -- A symbol kind. SymbolKind = { - File = 1; - Module = 2; - Namespace = 3; - Package = 4; - Class = 5; - Method = 6; - Property = 7; - Field = 8; - Constructor = 9; - Enum = 10; - Interface = 11; - Function = 12; - Variable = 13; - Constant = 14; - String = 15; - Number = 16; - Boolean = 17; - Array = 18; - Object = 19; - Key = 20; - Null = 21; - EnumMember = 22; - Struct = 23; - Event = 24; - Operator = 25; - TypeParameter = 26; - }; + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + Boolean = 17, + Array = 18, + Object = 19, + Key = 20, + Null = 21, + EnumMember = 22, + Struct = 23, + Event = 24, + Operator = 25, + TypeParameter = 26, + }, -- Represents reasons why a text document is saved. TextDocumentSaveReason = { -- Manually triggered, e.g. by the user pressing save, by starting debugging, -- or by an API call. - Manual = 1; + Manual = 1, -- Automatic after a delay. - AfterDelay = 2; + AfterDelay = 2, -- When the editor lost focus. - FocusOut = 3; - }; + FocusOut = 3, + }, ErrorCodes = { -- Defined by JSON RPC - ParseError = -32700; - InvalidRequest = -32600; - MethodNotFound = -32601; - InvalidParams = -32602; - InternalError = -32603; - serverErrorStart = -32099; - serverErrorEnd = -32000; - ServerNotInitialized = -32002; - UnknownErrorCode = -32001; + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + serverErrorStart = -32099, + serverErrorEnd = -32000, + ServerNotInitialized = -32002, + UnknownErrorCode = -32001, -- Defined by the protocol. - RequestCancelled = -32800; - ContentModified = -32801; - }; + RequestCancelled = -32800, + ContentModified = -32801, + }, -- Describes the content type that a client supports in various -- result literals like `Hover`, `ParameterInfo` or `CompletionItem`. @@ -175,88 +175,88 @@ local constants = { -- are reserved for internal usage. MarkupKind = { -- Plain text is supported as a content format - PlainText = 'plaintext'; + PlainText = 'plaintext', -- Markdown is supported as a content format - Markdown = 'markdown'; - }; + Markdown = 'markdown', + }, ResourceOperationKind = { -- Supports creating new files and folders. - Create = 'create'; + Create = 'create', -- Supports renaming existing files and folders. - Rename = 'rename'; + Rename = 'rename', -- Supports deleting existing files and folders. - Delete = 'delete'; - }; + Delete = 'delete', + }, FailureHandlingKind = { -- Applying the workspace change is simply aborted if one of the changes provided -- fails. All operations executed before the failing operation stay executed. - Abort = 'abort'; + Abort = 'abort', -- All operations are executed transactionally. That means they either all -- succeed or no changes at all are applied to the workspace. - Transactional = 'transactional'; + Transactional = 'transactional', -- If the workspace edit contains only textual file changes they are executed transactionally. -- If resource changes (create, rename or delete file) are part of the change the failure -- handling strategy is abort. - TextOnlyTransactional = 'textOnlyTransactional'; + TextOnlyTransactional = 'textOnlyTransactional', -- The client tries to undo the operations already executed. But there is no -- guarantee that this succeeds. - Undo = 'undo'; - }; + Undo = 'undo', + }, -- Known error codes for an `InitializeError`; InitializeError = { -- If the protocol version provided by the client can't be handled by the server. -- @deprecated This initialize error got replaced by client capabilities. There is -- no version handshake in version 3.0x - unknownProtocolVersion = 1; - }; + unknownProtocolVersion = 1, + }, -- Defines how the host (editor) should sync document changes to the language server. TextDocumentSyncKind = { -- Documents should not be synced at all. - None = 0; + None = 0, -- Documents are synced by always sending the full content -- of the document. - Full = 1; + Full = 1, -- Documents are synced by sending the full content on open. -- After that only incremental updates to the document are -- send. - Incremental = 2; - }; + Incremental = 2, + }, WatchKind = { -- Interested in create events. - Create = 1; + Create = 1, -- Interested in change events - Change = 2; + Change = 2, -- Interested in delete events - Delete = 4; - }; + Delete = 4, + }, -- Defines whether the insert text in a completion item should be interpreted as -- plain text or a snippet. InsertTextFormat = { -- The primary text to be inserted is treated as a plain string. - PlainText = 1; + PlainText = 1, -- The primary text to be inserted is treated as a snippet. -- -- A snippet can define tab stops and placeholders with `$1`, `$2` -- and `${3:foo};`. `$0` defines the final tab stop, it defaults to -- the end of the snippet. Placeholders with equal identifiers are linked, -- that is typing in one will update others too. - Snippet = 2; - }; + Snippet = 2, + }, -- A set of predefined code action kinds CodeActionKind = { -- Empty kind. - Empty = ''; + Empty = '', -- Base kind for quickfix actions - QuickFix = 'quickfix'; + QuickFix = 'quickfix', -- Base kind for refactoring actions - Refactor = 'refactor'; + Refactor = 'refactor', -- Base kind for refactoring extraction actions -- -- Example extract actions: @@ -266,7 +266,7 @@ local constants = { -- - Extract variable -- - Extract interface from class -- - ... - RefactorExtract = 'refactor.extract'; + RefactorExtract = 'refactor.extract', -- Base kind for refactoring inline actions -- -- Example inline actions: @@ -275,7 +275,7 @@ local constants = { -- - Inline variable -- - Inline constant -- - ... - RefactorInline = 'refactor.inline'; + RefactorInline = 'refactor.inline', -- Base kind for refactoring rewrite actions -- -- Example rewrite actions: @@ -286,14 +286,14 @@ local constants = { -- - Make method static -- - Move method to base class -- - ... - RefactorRewrite = 'refactor.rewrite'; + RefactorRewrite = 'refactor.rewrite', -- Base kind for source actions -- -- Source code actions apply to the entire file. - Source = 'source'; + Source = 'source', -- Base kind for an organize imports source action - SourceOrganizeImports = 'source.organizeImports'; - }; + SourceOrganizeImports = 'source.organizeImports', + }, } for k, v in pairs(constants) do @@ -620,19 +620,19 @@ function protocol.make_client_capabilities() return { textDocument = { synchronization = { - dynamicRegistration = false; + dynamicRegistration = false, -- TODO(ashkan) Send textDocument/willSave before saving (BufWritePre) - willSave = false; + willSave = false, -- TODO(ashkan) Implement textDocument/willSaveWaitUntil - willSaveWaitUntil = false; + willSaveWaitUntil = false, -- Send textDocument/didSave after saving (BufWritePost) - didSave = true; - }; + didSave = true, + }, codeAction = { - dynamicRegistration = false; + dynamicRegistration = false, codeActionLiteralSupport = { codeActionKind = { @@ -640,138 +640,146 @@ function protocol.make_client_capabilities() local res = vim.tbl_values(protocol.CodeActionKind) table.sort(res) return res - end)(); - }; - }; - isPreferredSupport = true; - dataSupport = true; + end)(), + }, + }, + isPreferredSupport = true, + dataSupport = true, resolveSupport = { - properties = { 'edit', } - }; - }; + properties = { 'edit' }, + }, + }, completion = { - dynamicRegistration = false; + dynamicRegistration = false, completionItem = { -- Until we can actually expand snippet, move cursor and allow for true snippet experience, -- this should be disabled out of the box. -- However, users can turn this back on if they have a snippet plugin. - snippetSupport = false; + snippetSupport = false, - commitCharactersSupport = false; - preselectSupport = false; - deprecatedSupport = false; - documentationFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText }; - }; + commitCharactersSupport = false, + preselectSupport = false, + deprecatedSupport = false, + documentationFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, + }, completionItemKind = { valueSet = (function() local res = {} for k in ipairs(protocol.CompletionItemKind) do - if type(k) == 'number' then table.insert(res, k) end + if type(k) == 'number' then + table.insert(res, k) + end end return res - end)(); - }; + end)(), + }, -- TODO(tjdevries): Implement this - contextSupport = false; - }; + contextSupport = false, + }, declaration = { - linkSupport = true; - }; + linkSupport = true, + }, definition = { - linkSupport = true; - }; + linkSupport = true, + }, implementation = { - linkSupport = true; - }; + linkSupport = true, + }, typeDefinition = { - linkSupport = true; - }; + linkSupport = true, + }, hover = { - dynamicRegistration = false; - contentFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText }; - }; + dynamicRegistration = false, + contentFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, + }, signatureHelp = { - dynamicRegistration = false; + dynamicRegistration = false, signatureInformation = { - activeParameterSupport = true; - documentationFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText }; + activeParameterSupport = true, + documentationFormat = { protocol.MarkupKind.Markdown, protocol.MarkupKind.PlainText }, parameterInformation = { - labelOffsetSupport = true; - }; - }; - }; + labelOffsetSupport = true, + }, + }, + }, references = { - dynamicRegistration = false; - }; + dynamicRegistration = false, + }, documentHighlight = { - dynamicRegistration = false - }; + dynamicRegistration = false, + }, documentSymbol = { - dynamicRegistration = false; + dynamicRegistration = false, symbolKind = { valueSet = (function() local res = {} for k in ipairs(protocol.SymbolKind) do - if type(k) == 'number' then table.insert(res, k) end + if type(k) == 'number' then + table.insert(res, k) + end end return res - end)(); - }; - hierarchicalDocumentSymbolSupport = true; - }; + end)(), + }, + hierarchicalDocumentSymbolSupport = true, + }, rename = { - dynamicRegistration = false; - prepareSupport = true; - }; + dynamicRegistration = false, + prepareSupport = true, + }, publishDiagnostics = { - relatedInformation = true; + relatedInformation = true, tagSupport = { valueSet = (function() local res = {} for k in ipairs(protocol.DiagnosticTag) do - if type(k) == 'number' then table.insert(res, k) end + if type(k) == 'number' then + table.insert(res, k) + end end return res - end)(); - }; - }; - }; + end)(), + }, + }, + }, workspace = { symbol = { - dynamicRegistration = false; + dynamicRegistration = false, symbolKind = { valueSet = (function() local res = {} for k in ipairs(protocol.SymbolKind) do - if type(k) == 'number' then table.insert(res, k) end + if type(k) == 'number' then + table.insert(res, k) + end end return res - end)(); - }; - hierarchicalWorkspaceSymbolSupport = true; - }; - workspaceFolders = true; - applyEdit = true; + end)(), + }, + hierarchicalWorkspaceSymbolSupport = true, + }, + workspaceFolders = true, + applyEdit = true, workspaceEdit = { - resourceOperations = {'rename', 'create', 'delete',}, - }; - }; + resourceOperations = { 'rename', 'create', 'delete' }, + }, + }, callHierarchy = { - dynamicRegistration = false; - }; - experimental = nil; + dynamicRegistration = false, + }, + experimental = nil, window = { - workDoneProgress = true; + workDoneProgress = true, showMessage = { messageActionItem = { - additionalPropertiesSupport = false; - }; - }; + additionalPropertiesSupport = false, + }, + }, showDocument = { - support = false; - }; - }; + support = false, + }, + }, } end @@ -791,12 +799,12 @@ function protocol.resolve_capabilities(server_capabilities) willSaveWaitUntil = false, save = { includeText = false, - } + }, } elseif type(textDocumentSync) == 'number' then -- Backwards compatibility if not TextDocumentSyncKind[textDocumentSync] then - return nil, "Invalid server TextDocumentSyncKind for textDocumentSync" + return nil, 'Invalid server TextDocumentSyncKind for textDocumentSync' end server_capabilities.textDocumentSync = { openClose = true, @@ -805,10 +813,10 @@ function protocol.resolve_capabilities(server_capabilities) willSaveWaitUntil = false, save = { includeText = false, - } + }, } elseif type(textDocumentSync) ~= 'table' then - return nil, string.format("Invalid type for textDocumentSync: %q", type(textDocumentSync)) + return nil, string.format('Invalid type for textDocumentSync: %q', type(textDocumentSync)) end return server_capabilities end @@ -827,39 +835,41 @@ function protocol._resolve_capabilities_compat(server_capabilities) if textDocumentSync == nil then -- Defaults if omitted. text_document_sync_properties = { - text_document_open_close = false; - text_document_did_change = TextDocumentSyncKind.None; --- text_document_did_change = false; - text_document_will_save = false; - text_document_will_save_wait_until = false; - text_document_save = false; - text_document_save_include_text = false; + text_document_open_close = false, + text_document_did_change = TextDocumentSyncKind.None, + -- text_document_did_change = false; + text_document_will_save = false, + text_document_will_save_wait_until = false, + text_document_save = false, + text_document_save_include_text = false, } elseif type(textDocumentSync) == 'number' then -- Backwards compatibility if not TextDocumentSyncKind[textDocumentSync] then - return nil, "Invalid server TextDocumentSyncKind for textDocumentSync" + return nil, 'Invalid server TextDocumentSyncKind for textDocumentSync' end text_document_sync_properties = { - text_document_open_close = true; - text_document_did_change = textDocumentSync; - text_document_will_save = false; - text_document_will_save_wait_until = false; - text_document_save = true; - text_document_save_include_text = false; + text_document_open_close = true, + text_document_did_change = textDocumentSync, + text_document_will_save = false, + text_document_will_save_wait_until = false, + text_document_save = true, + text_document_save_include_text = false, } elseif type(textDocumentSync) == 'table' then text_document_sync_properties = { - text_document_open_close = if_nil(textDocumentSync.openClose, false); - text_document_did_change = if_nil(textDocumentSync.change, TextDocumentSyncKind.None); - text_document_will_save = if_nil(textDocumentSync.willSave, false); - text_document_will_save_wait_until = if_nil(textDocumentSync.willSaveWaitUntil, false); - text_document_save = if_nil(textDocumentSync.save, false); - text_document_save_include_text = if_nil(type(textDocumentSync.save) == 'table' - and textDocumentSync.save.includeText, false); + text_document_open_close = if_nil(textDocumentSync.openClose, false), + text_document_did_change = if_nil(textDocumentSync.change, TextDocumentSyncKind.None), + text_document_will_save = if_nil(textDocumentSync.willSave, false), + text_document_will_save_wait_until = if_nil(textDocumentSync.willSaveWaitUntil, false), + text_document_save = if_nil(textDocumentSync.save, false), + text_document_save_include_text = if_nil( + type(textDocumentSync.save) == 'table' and textDocumentSync.save.includeText, + false + ), } else - return nil, string.format("Invalid type for textDocumentSync: %q", type(textDocumentSync)) + return nil, string.format('Invalid type for textDocumentSync: %q', type(textDocumentSync)) end end general_properties.completion = server_capabilities.completionProvider ~= nil @@ -889,16 +899,18 @@ function protocol._resolve_capabilities_compat(server_capabilities) general_properties.code_lens = true general_properties.code_lens_resolve = server_capabilities.codeLensProvider.resolveProvider or false else - error("The server sent invalid codeLensProvider") + error('The server sent invalid codeLensProvider') end if server_capabilities.codeActionProvider == nil then general_properties.code_action = false - elseif type(server_capabilities.codeActionProvider) == 'boolean' - or type(server_capabilities.codeActionProvider) == 'table' then + elseif + type(server_capabilities.codeActionProvider) == 'boolean' + or type(server_capabilities.codeActionProvider) == 'table' + then general_properties.code_action = server_capabilities.codeActionProvider else - error("The server sent invalid codeActionProvider") + error('The server sent invalid codeActionProvider') end if server_capabilities.declarationProvider == nil then @@ -908,7 +920,7 @@ function protocol._resolve_capabilities_compat(server_capabilities) elseif type(server_capabilities.declarationProvider) == 'table' then general_properties.declaration = server_capabilities.declarationProvider else - error("The server sent invalid declarationProvider") + error('The server sent invalid declarationProvider') end if server_capabilities.typeDefinitionProvider == nil then @@ -918,7 +930,7 @@ function protocol._resolve_capabilities_compat(server_capabilities) elseif type(server_capabilities.typeDefinitionProvider) == 'table' then general_properties.type_definition = server_capabilities.typeDefinitionProvider else - error("The server sent invalid typeDefinitionProvider") + error('The server sent invalid typeDefinitionProvider') end if server_capabilities.implementationProvider == nil then @@ -928,7 +940,7 @@ function protocol._resolve_capabilities_compat(server_capabilities) elseif type(server_capabilities.implementationProvider) == 'table' then general_properties.implementation = server_capabilities.implementationProvider else - error("The server sent invalid implementationProvider") + error('The server sent invalid implementationProvider') end local workspace = server_capabilities.workspace @@ -936,45 +948,45 @@ function protocol._resolve_capabilities_compat(server_capabilities) if workspace == nil or workspace.workspaceFolders == nil then -- Defaults if omitted. workspace_properties = { - workspace_folder_properties = { - supported = false; - changeNotifications=false; - } + workspace_folder_properties = { + supported = false, + changeNotifications = false, + }, } elseif type(workspace.workspaceFolders) == 'table' then workspace_properties = { workspace_folder_properties = { - supported = if_nil(workspace.workspaceFolders.supported, false); - changeNotifications = if_nil(workspace.workspaceFolders.changeNotifications, false); - - } + supported = if_nil(workspace.workspaceFolders.supported, false), + changeNotifications = if_nil(workspace.workspaceFolders.changeNotifications, false), + }, } else - error("The server sent invalid workspace") + error('The server sent invalid workspace') end local signature_help_properties if server_capabilities.signatureHelpProvider == nil then signature_help_properties = { - signature_help = false; - signature_help_trigger_characters = {}; + signature_help = false, + signature_help_trigger_characters = {}, } elseif type(server_capabilities.signatureHelpProvider) == 'table' then signature_help_properties = { - signature_help = true; + signature_help = true, -- The characters that trigger signature help automatically. - signature_help_trigger_characters = server_capabilities.signatureHelpProvider.triggerCharacters or {}; + signature_help_trigger_characters = server_capabilities.signatureHelpProvider.triggerCharacters or {}, } else - error("The server sent invalid signatureHelpProvider") + error('The server sent invalid signatureHelpProvider') end - local capabilities = vim.tbl_extend("error" - , text_document_sync_properties - , signature_help_properties - , workspace_properties - , general_properties - ) + local capabilities = vim.tbl_extend( + 'error', + text_document_sync_properties, + signature_help_properties, + workspace_properties, + general_properties + ) return capabilities end diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index be2cc58f07..2dcafc92bc 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -32,9 +32,9 @@ local function env_merge(env) -- Merge. env = vim.tbl_extend('force', vim.fn.environ(), env) local final_env = {} - for k,v in pairs(env) do + for k, v in pairs(env) do assert(type(k) == 'string', 'env must be a dict') - table.insert(final_env, k..'='..tostring(v)) + table.insert(final_env, k .. '=' .. tostring(v)) end return final_env end @@ -45,10 +45,12 @@ end ---@param encoded_message (string) ---@returns (table) table containing encoded message and `Content-Length` attribute local function format_message_with_content_length(encoded_message) - return table.concat { - 'Content-Length: '; tostring(#encoded_message); '\r\n\r\n'; - encoded_message; - } + return table.concat({ + 'Content-Length: ', + tostring(#encoded_message), + '\r\n\r\n', + encoded_message, + }) end ---@private @@ -65,23 +67,25 @@ local function parse_headers(header) if line == '' then break end - local key, value = line:match("^%s*(%S+)%s*:%s*(.+)%s*$") + local key, value = line:match('^%s*(%S+)%s*:%s*(.+)%s*$') if key then key = key:lower():gsub('%-', '_') headers[key] = value else - local _ = log.error() and log.error("invalid header line %q", line) - error(string.format("invalid header line %q", line)) + local _ = log.error() and log.error('invalid header line %q', line) + error(string.format('invalid header line %q', line)) end end headers.content_length = tonumber(headers.content_length) - or error(string.format("Content-Length not found in headers. %q", header)) + or error(string.format('Content-Length not found in headers. %q', header)) return headers end -- This is the start of any possible header patterns. The gsub converts it to a -- case insensitive pattern. -local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end) +local header_start_pattern = ('content'):gsub('%w', function(c) + return '[' .. c .. c:upper() .. ']' +end) ---@private --- The actual workhorse. @@ -100,17 +104,16 @@ local function request_parser_loop() -- be searching for. -- TODO(ashkan) I'd like to remove this, but it seems permanent :( local buffer_start = buffer:find(header_start_pattern) - local headers = parse_headers(buffer:sub(buffer_start, start-1)) + local headers = parse_headers(buffer:sub(buffer_start, start - 1)) local content_length = headers.content_length -- Use table instead of just string to buffer the message. It prevents -- a ton of strings allocating. -- ref. http://www.lua.org/pil/11.6.html - local body_chunks = {buffer:sub(finish+1)} + local body_chunks = { buffer:sub(finish + 1) } local body_length = #body_chunks[1] -- Keep waiting for data until we have enough. while body_length < content_length do - local chunk = coroutine.yield() - or error("Expected more data for the body. The server may have died.") -- TODO hmm. + local chunk = coroutine.yield() or error('Expected more data for the body. The server may have died.') -- TODO hmm. table.insert(body_chunks, chunk) body_length = body_length + #chunk end @@ -123,25 +126,24 @@ local function request_parser_loop() end local body = table.concat(body_chunks) -- Yield our data. - buffer = rest..(coroutine.yield(headers, body) - or error("Expected more data for the body. The server may have died.")) -- TODO hmm. + buffer = rest + .. (coroutine.yield(headers, body) or error('Expected more data for the body. The server may have died.')) -- TODO hmm. else -- Get more data since we don't have enough. - buffer = buffer..(coroutine.yield() - or error("Expected more data for the header. The server may have died.")) -- TODO hmm. + buffer = buffer .. (coroutine.yield() or error('Expected more data for the header. The server may have died.')) -- TODO hmm. end end end --- Mapping of error codes used by the client local client_errors = { - INVALID_SERVER_MESSAGE = 1; - INVALID_SERVER_JSON = 2; - NO_RESULT_CALLBACK_FOUND = 3; - READ_ERROR = 4; - NOTIFICATION_HANDLER_ERROR = 5; - SERVER_REQUEST_HANDLER_ERROR = 6; - SERVER_RESULT_CALLBACK_ERROR = 7; + INVALID_SERVER_MESSAGE = 1, + INVALID_SERVER_JSON = 2, + NO_RESULT_CALLBACK_FOUND = 3, + READ_ERROR = 4, + NOTIFICATION_HANDLER_ERROR = 5, + SERVER_REQUEST_HANDLER_ERROR = 6, + SERVER_RESULT_CALLBACK_ERROR = 7, } client_errors = vim.tbl_add_reverse_lookup(client_errors) @@ -151,26 +153,26 @@ client_errors = vim.tbl_add_reverse_lookup(client_errors) ---@param err (table) The error object ---@returns (string) The formatted error message local function format_rpc_error(err) - validate { - err = { err, 't' }; - } + validate({ + err = { err, 't' }, + }) -- 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]) + code = string.format('code_name = %s,', protocol.ErrorCodes[err.code]) else - code = string.format("code_name = unknown, code = %s,", err.code) + code = string.format('code_name = unknown, code = %s,', err.code) end - local message_parts = {"RPC[Error]", code} + local message_parts = { 'RPC[Error]', code } if err.message then - table.insert(message_parts, "message =") - table.insert(message_parts, string.format("%q", err.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, ' ') @@ -185,11 +187,11 @@ local function rpc_response_error(code, message, data) -- TODO should this error or just pick a sane error (like InternalError)? local code_name = assert(protocol.ErrorCodes[code], 'Invalid RPC error code') return setmetatable({ - code = code; - message = message or code_name; - data = data; + code = code, + message = message or code_name, + data = data, }, { - __tostring = format_rpc_error; + __tostring = format_rpc_error, }) end @@ -220,7 +222,7 @@ end ---@param signal (number): Number describing the signal used to terminate (if ---any) function default_dispatchers.on_exit(code, signal) - local _ = log.info() and log.info("client_exit", { code = code, signal = signal }) + local _ = log.info() and log.info('client_exit', { code = code, signal = signal }) end ---@private --- Default dispatcher for client errors. @@ -258,15 +260,15 @@ end --- - {handle} A handle for low-level interaction with the LSP server process --- |vim.loop|. local function start(cmd, cmd_args, dispatchers, extra_spawn_params) - local _ = log.info() and log.info("Starting RPC client", {cmd = cmd, args = cmd_args, extra = extra_spawn_params}) - validate { - cmd = { cmd, 's' }; - cmd_args = { cmd_args, 't' }; - dispatchers = { dispatchers, 't', true }; - } + local _ = log.info() and log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) + validate({ + cmd = { cmd, 's' }, + cmd_args = { cmd_args, 't' }, + dispatchers = { dispatchers, 't', true }, + }) if extra_spawn_params and extra_spawn_params.cwd then - assert(is_dir(extra_spawn_params.cwd), "cwd must be a directory") + assert(is_dir(extra_spawn_params.cwd), 'cwd must be a directory') end if dispatchers then local user_dispatchers = dispatchers @@ -275,11 +277,11 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) local user_dispatcher = user_dispatchers[dispatch_name] if user_dispatcher then if type(user_dispatcher) ~= 'function' then - error(string.format("dispatcher.%s must be a function", dispatch_name)) + error(string.format('dispatcher.%s must be a function', dispatch_name)) end -- server_request is wrapped elsewhere. - if not (dispatch_name == 'server_request' - or dispatch_name == 'on_exit') -- TODO this blocks the loop exiting for some reason. + if + not (dispatch_name == 'server_request' or dispatch_name == 'on_exit') -- TODO this blocks the loop exiting for some reason. then user_dispatcher = schedule_wrap(user_dispatcher) end @@ -317,9 +319,9 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) dispatchers.on_exit(code, signal) end local spawn_params = { - args = cmd_args; - stdio = {stdin, stdout, stderr}; - detached = true; + args = cmd_args, + stdio = { stdin, stdout, stderr }, + detached = true, } if extra_spawn_params then spawn_params.cwd = extra_spawn_params.cwd @@ -330,11 +332,11 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end handle, pid = uv.spawn(cmd, spawn_params, onexit) if handle == nil then - local msg = string.format("Spawning language server with cmd: `%s` failed", cmd) - if string.match(pid, "ENOENT") then - msg = msg .. ". The language server is either not installed, missing from PATH, or not executable." + local msg = string.format('Spawning language server with cmd: `%s` failed', cmd) + if string.match(pid, 'ENOENT') then + msg = msg .. '. The language server is either not installed, missing from PATH, or not executable.' else - msg = msg .. string.format(" with error message: %s", pid) + msg = msg .. string.format(' with error message: %s', pid) end vim.notify(msg, vim.log.levels.WARN) return @@ -348,8 +350,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) ---@param payload table ---@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing. local function encode_and_send(payload) - local _ = log.debug() and log.debug("rpc.send", payload) - if handle == nil or handle:is_closing() then return false end + local _ = log.debug() and log.debug('rpc.send', payload) + if handle == nil or handle:is_closing() then + return false + end local encoded = vim.json.encode(payload) stdin:write(format_message_with_content_length(encoded)) return true @@ -363,22 +367,22 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) ---@param params (table): Parameters for the invoked LSP method ---@returns (bool) `true` if notification could be sent, `false` if not local function notify(method, params) - return encode_and_send { - jsonrpc = "2.0"; - method = method; - params = params; - } + return encode_and_send({ + jsonrpc = '2.0', + method = method, + params = params, + }) end ---@private --- sends an error object to the remote LSP process. local function send_response(request_id, err, result) - return encode_and_send { - id = request_id; - jsonrpc = "2.0"; - error = err; - result = result; - } + return encode_and_send({ + id = request_id, + jsonrpc = '2.0', + error = err, + result = result, + }) end -- FIXME: DOC: Should be placed on the RPC client object returned by @@ -392,18 +396,18 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) ---@param notify_reply_callback (function|nil) Callback to invoke as soon as a request is no longer pending ---@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not local function request(method, params, callback, notify_reply_callback) - validate { - callback = { callback, 'f' }; - notify_reply_callback = { notify_reply_callback, 'f', true }; - } + validate({ + callback = { callback, 'f' }, + notify_reply_callback = { notify_reply_callback, 'f', true }, + }) message_index = message_index + 1 local message_id = message_index - local result = encode_and_send { - id = message_id; - jsonrpc = "2.0"; - method = method; - params = params; - } + local result = encode_and_send({ + id = message_id, + jsonrpc = '2.0', + method = method, + params = params, + }) if result then if message_callbacks then message_callbacks[message_id] = schedule_wrap(callback) @@ -421,7 +425,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) stderr:read_start(function(_err, chunk) if chunk then - local _ = log.error() and log.error("rpc", cmd, "stderr", chunk) + local _ = log.error() and log.error('rpc', cmd, 'stderr', chunk) end end) @@ -455,7 +459,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) on_error(client_errors.INVALID_SERVER_JSON, decoded) return end - local _ = log.debug() and log.debug("rpc.receive", decoded) + local _ = log.debug() and log.debug('rpc.receive', decoded) if type(decoded.method) == 'string' and decoded.id then local err @@ -463,17 +467,30 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) -- we can still use the result. schedule(function() local status, result - status, result, err = try_call(client_errors.SERVER_REQUEST_HANDLER_ERROR, - dispatchers.server_request, decoded.method, decoded.params) - local _ = log.debug() and log.debug("server_request: callback result", { status = status, result = result, err = err }) + status, result, err = try_call( + client_errors.SERVER_REQUEST_HANDLER_ERROR, + dispatchers.server_request, + decoded.method, + decoded.params + ) + local _ = log.debug() + and log.debug('server_request: callback result', { status = status, result = result, err = err }) if status then if not (result or err) then -- TODO this can be a problem if `null` is sent for result. needs vim.NIL - error(string.format("method %q: either a result or an error must be sent to the server in response", decoded.method)) + error( + string.format( + 'method %q: either a result or an error must be sent to the server in response', + decoded.method + ) + ) end if err then - assert(type(err) == 'table', "err must be a table. Use rpc_response_error to help format errors.") - local code_name = assert(protocol.ErrorCodes[err.code], "Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.") + assert(type(err) == 'table', 'err must be a table. Use rpc_response_error to help format errors.') + local code_name = assert( + protocol.ErrorCodes[err.code], + 'Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.' + ) err.message = err.message or code_name end else @@ -483,18 +500,17 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end send_response(decoded.id, err, result) end) - -- This works because we are expecting vim.NIL here + -- This works because we are expecting vim.NIL here elseif decoded.id and (decoded.result ~= vim.NIL or decoded.error ~= vim.NIL) then - -- We sent a number, so we expect a number. local result_id = tonumber(decoded.id) -- Notify the user that a response was received for the request local notify_reply_callback = notify_reply_callbacks and notify_reply_callbacks[result_id] if notify_reply_callback then - validate { - notify_reply_callback = { notify_reply_callback, 'f' }; - } + validate({ + notify_reply_callback = { notify_reply_callback, 'f' }, + }) notify_reply_callback(result_id) notify_reply_callbacks[result_id] = nil end @@ -503,7 +519,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) if decoded.error then local mute_error = false if decoded.error.code == protocol.ErrorCodes.RequestCancelled then - local _ = log.debug() and log.debug("Received cancellation ack", decoded) + local _ = log.debug() and log.debug('Received cancellation ack', decoded) mute_error = true end @@ -523,24 +539,22 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) local callback = message_callbacks and message_callbacks[result_id] if callback then message_callbacks[result_id] = nil - validate { - callback = { callback, 'f' }; - } + validate({ + callback = { callback, 'f' }, + }) if decoded.error then decoded.error = setmetatable(decoded.error, { - __tostring = format_rpc_error; + __tostring = format_rpc_error, }) end - try_call(client_errors.SERVER_RESULT_CALLBACK_ERROR, - callback, decoded.error, decoded.result) + try_call(client_errors.SERVER_RESULT_CALLBACK_ERROR, callback, decoded.error, decoded.result) else on_error(client_errors.NO_RESULT_CALLBACK_FOUND, decoded) - local _ = log.error() and log.error("No callback found for server response id "..result_id) + local _ = log.error() and log.error('No callback found for server response id ' .. result_id) end elseif type(decoded.method) == 'string' then -- Notification - try_call(client_errors.NOTIFICATION_HANDLER_ERROR, - dispatchers.notification, decoded.method, decoded.params) + try_call(client_errors.NOTIFICATION_HANDLER_ERROR, dispatchers.notification, decoded.method, decoded.params) else -- Invalid server message on_error(client_errors.INVALID_SERVER_MESSAGE, decoded) @@ -556,7 +570,9 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) return end -- This should signal that we are done reading from the client. - if not chunk then return end + if not chunk then + return + end -- Flush anything in the parser by looping until we don't get a result -- anymore. while true do @@ -574,17 +590,17 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end) return { - pid = pid; - handle = handle; - request = request; - notify = notify + pid = pid, + handle = handle, + request = request, + notify = notify, } end return { - start = start; - rpc_response_error = rpc_response_error; - format_rpc_error = format_rpc_error; - client_errors = client_errors; + start = start, + rpc_response_error = rpc_response_error, + format_rpc_error = format_rpc_error, + client_errors = client_errors, } -- vim:sw=2 ts=2 et diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 9955fff3e2..73b4e0025a 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -79,7 +79,7 @@ local function compute_line_length(line, offset_encoding) local length local _ if offset_encoding == 'utf-16' then - _, length = str_utfindex(line) + _, length = str_utfindex(line) elseif offset_encoding == 'utf-32' then length, _ = str_utfindex(line) else @@ -100,7 +100,7 @@ local function align_end_position(line, byte, offset_encoding) -- If on the first byte, or an empty string: the trivial case if byte == 1 or #line == 0 then char = byte - -- Called in the case of extending an empty line "" -> "a" + -- Called in the case of extending an empty line "" -> "a" elseif byte == #line + 1 then char = compute_line_length(line, offset_encoding) + 1 else @@ -175,12 +175,12 @@ local function compute_start_range(prev_lines, curr_lines, firstline, lastline, end -- Convert byte to codepoint if applicable - if start_byte_idx == 1 or (#prev_line == 0 and start_byte_idx == 1)then + if start_byte_idx == 1 or (#prev_line == 0 and start_byte_idx == 1) then byte_idx = start_byte_idx char_idx = 1 elseif start_byte_idx == #prev_line + 1 then byte_idx = start_byte_idx - char_idx = compute_line_length(prev_line, offset_encoding) + 1 + char_idx = compute_line_length(prev_line, offset_encoding) + 1 else byte_idx = start_byte_idx + str_utf_start(prev_line, start_byte_idx) char_idx = byte_to_utf(prev_line, byte_idx, offset_encoding) @@ -203,14 +203,30 @@ end ---@param new_lastline integer ---@param offset_encoding string ---@returns (int, int) end_line_idx and end_col_idx of range -local function compute_end_range(prev_lines, curr_lines, start_range, firstline, lastline, new_lastline, offset_encoding) +local function compute_end_range( + prev_lines, + curr_lines, + start_range, + firstline, + lastline, + new_lastline, + offset_encoding +) -- If firstline == new_lastline, the first change occurred on a line that was deleted. -- In this case, the last_byte... if firstline == new_lastline then - return { line_idx = (lastline - new_lastline + firstline), byte_idx = 1, char_idx = 1 }, { line_idx = firstline, byte_idx = 1, char_idx = 1 } + return { line_idx = (lastline - new_lastline + firstline), byte_idx = 1, char_idx = 1 }, { + line_idx = firstline, + byte_idx = 1, + char_idx = 1, + } end if firstline == lastline then - return { line_idx = firstline, byte_idx = 1, char_idx = 1 }, { line_idx = new_lastline - lastline + firstline, byte_idx = 1, char_idx = 1 } + return { line_idx = firstline, byte_idx = 1, char_idx = 1 }, { + line_idx = new_lastline - lastline + firstline, + byte_idx = 1, + char_idx = 1, + } end -- Compare on last line, at minimum will be the start range local start_line_idx = start_range.line_idx @@ -239,9 +255,7 @@ local function compute_end_range(prev_lines, curr_lines, start_range, firstline, end for idx = 0, max_length do byte_offset = idx - if - str_byte(prev_line, prev_line_length - byte_offset) ~= str_byte(curr_line, curr_line_length - byte_offset) - then + if str_byte(prev_line, prev_line_length - byte_offset) ~= str_byte(curr_line, curr_line_length - byte_offset) then break end end @@ -281,14 +295,13 @@ end ---@param end_range table new_end_range returned by last_difference ---@returns string text extracted from defined region local function extract_text(lines, start_range, end_range, line_ending) - if not lines[start_range.line_idx] then - return "" - end + if not lines[start_range.line_idx] then + return '' + end -- Trivial case: start and end range are the same line, directly grab changed text if start_range.line_idx == end_range.line_idx then -- string.sub is inclusive, end_range is not return string.sub(lines[start_range.line_idx], start_range.byte_idx, end_range.byte_idx - 1) - else -- Handle deletion case -- Collect the changed portion of the first changed line @@ -303,7 +316,7 @@ local function extract_text(lines, start_range, end_range, line_ending) -- Collect the changed portion of the last changed line. table.insert(result, string.sub(lines[end_range.line_idx], 1, end_range.byte_idx - 1)) else - table.insert(result, "") + table.insert(result, '') end -- Add line ending between all lines diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index bb87e8372b..e8a8e06f46 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1,10 +1,10 @@ -local protocol = require 'vim.lsp.protocol' -local snippet = require 'vim.lsp._snippet' +local protocol = require('vim.lsp.protocol') +local snippet = require('vim.lsp._snippet') local vim = vim local validate = vim.validate local api = vim.api local list_extend = vim.list_extend -local highlight = require 'vim.highlight' +local highlight = require('vim.highlight') local uv = vim.loop local npcall = vim.F.npcall @@ -13,14 +13,14 @@ local split = vim.split local M = {} local default_border = { - {"", "NormalFloat"}, - {"", "NormalFloat"}, - {"", "NormalFloat"}, - {" ", "NormalFloat"}, - {"", "NormalFloat"}, - {"", "NormalFloat"}, - {"", "NormalFloat"}, - {" ", "NormalFloat"}, + { '', 'NormalFloat' }, + { '', 'NormalFloat' }, + { '', 'NormalFloat' }, + { ' ', 'NormalFloat' }, + { '', 'NormalFloat' }, + { '', 'NormalFloat' }, + { '', 'NormalFloat' }, + { ' ', 'NormalFloat' }, } ---@private @@ -35,43 +35,50 @@ local function get_border_size(opts) local width = 0 if type(border) == 'string' then - local border_size = {none = {0, 0}, single = {2, 2}, double = {2, 2}, rounded = {2, 2}, solid = {2, 2}, shadow = {1, 1}} + local border_size = { + none = { 0, 0 }, + single = { 2, 2 }, + double = { 2, 2 }, + rounded = { 2, 2 }, + solid = { 2, 2 }, + shadow = { 1, 1 }, + } if border_size[border] == nil then - error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border))) + error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) end height, width = unpack(border_size[border]) else if 8 % #border ~= 0 then - error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border))) + error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) end ---@private local function border_width(id) id = (id - 1) % #border + 1 - if type(border[id]) == "table" then + if type(border[id]) == 'table' then -- border specified as a table of return vim.fn.strdisplaywidth(border[id][1]) - elseif type(border[id]) == "string" then + elseif type(border[id]) == 'string' then -- border specified as a list of border characters return vim.fn.strdisplaywidth(border[id]) end - error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border))) + error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) end ---@private local function border_height(id) id = (id - 1) % #border + 1 - if type(border[id]) == "table" then + if type(border[id]) == 'table' then -- border specified as a table of return #border[id][1] > 0 and 1 or 0 - elseif type(border[id]) == "string" then + elseif type(border[id]) == 'string' then -- border specified as a list of border characters return #border[id] > 0 and 1 or 0 end - error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border))) + error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) end - height = height + border_height(2) -- top - height = height + border_height(6) -- bottom - width = width + border_width(4) -- right - width = width + border_width(8) -- left + height = height + border_height(2) -- top + height = height + border_height(6) -- bottom + width = width + border_width(4) -- right + width = width + border_width(8) -- left end return { height = height, width = width } @@ -89,9 +96,15 @@ end ---@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16 ---@return number `encoding` index of `index` in `line` function M._str_utfindex_enc(line, index, encoding) - if not encoding then encoding = 'utf-16' end + if not encoding then + encoding = 'utf-16' + end if encoding == 'utf-8' then - if index then return index else return #line end + if index then + return index + else + return #line + end elseif encoding == 'utf-16' then local _, col16 = vim.str_utfindex(line, index) return col16 @@ -99,7 +112,7 @@ function M._str_utfindex_enc(line, index, encoding) local col32, _ = vim.str_utfindex(line, index) return col32 else - error("Invalid encoding: " .. vim.inspect(encoding)) + error('Invalid encoding: ' .. vim.inspect(encoding)) end end @@ -111,15 +124,21 @@ end ---@param encoding string utf-8|utf-16|utf-32|nil defaults to utf-16 ---@return number byte (utf-8) index of `encoding` index `index` in `line` function M._str_byteindex_enc(line, index, encoding) - if not encoding then encoding = 'utf-16' end + if not encoding then + encoding = 'utf-16' + end if encoding == 'utf-8' then - if index then return index else return #line end + if index then + return index + else + return #line + end elseif encoding == 'utf-16' then return vim.str_byteindex(line, index, true) elseif encoding == 'utf-32' then return vim.str_byteindex(line, index) else - error("Invalid encoding: " .. vim.inspect(encoding)) + error('Invalid encoding: ' .. vim.inspect(encoding)) end end @@ -142,34 +161,38 @@ function M.set_lines(lines, A, B, new_lines) -- specifying a line number after what we would call the last line. local i_n = math.min(B[1] + 1, #lines) if not (i_0 >= 1 and i_0 <= #lines + 1 and i_n >= 1 and i_n <= #lines) then - error("Invalid range: "..vim.inspect{A = A; B = B; #lines, new_lines}) + error('Invalid range: ' .. vim.inspect({ A = A, B = B, #lines, new_lines })) end - local prefix = "" - local suffix = lines[i_n]:sub(B[2]+1) + local prefix = '' + local suffix = lines[i_n]:sub(B[2] + 1) if A[2] > 0 then prefix = lines[i_0]:sub(1, A[2]) end local n = i_n - i_0 + 1 if n ~= #new_lines then - for _ = 1, n - #new_lines do table.remove(lines, i_0) end - for _ = 1, #new_lines - n do table.insert(lines, i_0, '') end + for _ = 1, n - #new_lines do + table.remove(lines, i_0) + end + for _ = 1, #new_lines - n do + table.insert(lines, i_0, '') + end end for i = 1, #new_lines do lines[i - 1 + i_0] = new_lines[i] end if #suffix > 0 then local i = i_0 + #new_lines - 1 - lines[i] = lines[i]..suffix + lines[i] = lines[i] .. suffix end if #prefix > 0 then - lines[i_0] = prefix..lines[i_0] + lines[i_0] = prefix .. lines[i_0] end return lines end ---@private local function sort_by_key(fn) - return function(a,b) + return function(a, b) local ka, kb = fn(a), fn(b) assert(#ka == #kb) for i = 1, #ka do @@ -191,7 +214,7 @@ end ---@param rows number[] zero-indexed line numbers ---@return table a table mapping rows to lines local function get_lines(bufnr, rows) - rows = type(rows) == "table" and rows or { rows } + rows = type(rows) == 'table' and rows or { rows } -- This is needed for bufload and bufloaded if bufnr == 0 then @@ -202,7 +225,7 @@ local function get_lines(bufnr, rows) local function buf_lines() local lines = {} for _, row in pairs(rows) do - lines[row] = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { "" })[1] + lines[row] = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1] end return lines end @@ -211,7 +234,7 @@ local function get_lines(bufnr, rows) -- load the buffer if this is not a file uri -- Custom language server protocol extensions can result in servers sending URIs with custom schemes. Plugins are able to load these via `BufReadCmd` autocmds. - if uri:sub(1, 4) ~= "file" then + if uri:sub(1, 4) ~= 'file' then vim.fn.bufload(bufnr) return buf_lines() end @@ -224,8 +247,10 @@ local function get_lines(bufnr, rows) local filename = api.nvim_buf_get_name(bufnr) -- get the data from the file - local fd = uv.fs_open(filename, "r", 438) - if not fd then return "" end + local fd = uv.fs_open(filename, 'r', 438) + if not fd then + return '' + end local stat = uv.fs_fstat(fd) local data = uv.fs_read(fd, stat.size, 0) uv.fs_close(fd) @@ -242,11 +267,13 @@ local function get_lines(bufnr, rows) local found = 0 local lnum = 0 - for line in string.gmatch(data, "([^\n]*)\n?") do + for line in string.gmatch(data, '([^\n]*)\n?') do if lines[lnum] == true then lines[lnum] = line found = found + 1 - if found == need then break end + if found == need then + break + end end lnum = lnum + 1 end @@ -254,13 +281,12 @@ local function get_lines(bufnr, rows) -- change any lines we didn't find to the empty string for i, line in pairs(lines) do if line == true then - lines[i] = "" + lines[i] = '' end end return lines end - ---@private --- Gets the zero-indexed line from the given buffer. --- Works on unloaded buffers by reading the file using libuv to bypass buf reading events. @@ -273,7 +299,6 @@ local function get_line(bufnr, row) return get_lines(bufnr, { row })[row] end - ---@private --- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position --- Returns a zero-indexed column, since set_lines() does the conversion to @@ -300,30 +325,27 @@ end --- Process and return progress reports from lsp server ---@private function M.get_progress_messages() - local new_messages = {} local progress_remove = {} for _, client in ipairs(vim.lsp.get_active_clients()) do - local messages = client.messages - local data = messages - for token, ctx in pairs(data.progress) do - - local new_report = { - name = data.name, - title = ctx.title or "empty title", - message = ctx.message, - percentage = ctx.percentage, - done = ctx.done, - progress = true, - } - table.insert(new_messages, new_report) + local messages = client.messages + local data = messages + for token, ctx in pairs(data.progress) do + local new_report = { + name = data.name, + title = ctx.title or 'empty title', + message = ctx.message, + percentage = ctx.percentage, + done = ctx.done, + progress = true, + } + table.insert(new_messages, new_report) - if ctx.done then - table.insert(progress_remove, {client = client, token = token}) - end + if ctx.done then + table.insert(progress_remove, { client = client, token = token }) end - + end end for _, item in ipairs(progress_remove) do @@ -339,12 +361,14 @@ end ---@param offset_encoding string utf-8|utf-16|utf-32 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit function M.apply_text_edits(text_edits, bufnr, offset_encoding) - validate { - text_edits = { text_edits, 't', false }; - bufnr = { bufnr, 'number', false }; - offset_encoding = { offset_encoding, 'string', false }; - } - if not next(text_edits) then return end + validate({ + text_edits = { text_edits, 't', false }, + bufnr = { bufnr, 'number', false }, + offset_encoding = { offset_encoding, 'string', false }, + }) + if not next(text_edits) then + return + end if not api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end @@ -356,7 +380,11 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) index = index + 1 text_edit._index = index - if text_edit.range.start.line > text_edit.range['end'].line or text_edit.range.start.line == text_edit.range['end'].line and text_edit.range.start.character > text_edit.range['end'].character then + if + text_edit.range.start.line > text_edit.range['end'].line + or text_edit.range.start.line == text_edit.range['end'].line + and text_edit.range.start.character > text_edit.range['end'].character + then local start = text_edit.range.start text_edit.range.start = text_edit.range['end'] text_edit.range['end'] = start @@ -406,7 +434,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) start_row = text_edit.range.start.line, start_col = get_line_byte_from_position(bufnr, text_edit.range.start, offset_encoding), end_row = text_edit.range['end'].line, - end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding), + end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding), text = vim.split(text_edit.newText, '\n', true), } @@ -456,7 +484,11 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- Remove final line if needed local fix_eol = has_eol_text_edit - fix_eol = fix_eol and (api.nvim_buf_get_option(bufnr, 'eol') or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option(bufnr, 'binary'))) + fix_eol = fix_eol + and ( + api.nvim_buf_get_option(bufnr, 'eol') + or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option(bufnr, 'binary')) + ) fix_eol = fix_eol and get_line(bufnr, max - 1) == '' if fix_eol then vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {}) @@ -499,7 +531,7 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) local text_document = text_document_edit.textDocument local bufnr = vim.uri_to_bufnr(text_document.uri) if offset_encoding == nil then - vim.notify_once("apply_text_document_edit must be called with valid offset encoding", vim.log.levels.WARN) + vim.notify_once('apply_text_document_edit must be called with valid offset encoding', vim.log.levels.WARN) end -- For lists of text document edits, @@ -511,11 +543,16 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) -- `VersionedTextDocumentIdentifier`s version may be null -- https://microsoft.github.io/language-server-protocol/specification#versionedTextDocumentIdentifier - if should_check_version and (text_document.version + if + should_check_version + and ( + text_document.version and text_document.version > 0 and M.buf_versions[bufnr] - and M.buf_versions[bufnr] > text_document.version) then - print("Buffer ", text_document.uri, " newer than edits.") + and M.buf_versions[bufnr] > text_document.version + ) + then + print('Buffer ', text_document.uri, ' newer than edits.') return end @@ -551,16 +588,16 @@ end --- precedence is as follows: textEdit.newText > insertText > label --see 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 and item.textEdit.newText ~= "" then + if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= '' then local insert_text_format = protocol.InsertTextFormat[item.insertTextFormat] - if insert_text_format == "PlainText" or insert_text_format == nil then + if insert_text_format == 'PlainText' or insert_text_format == nil then return item.textEdit.newText else return M.parse_snippet(item.textEdit.newText) end - elseif item.insertText ~= nil and item.insertText ~= "" then + elseif item.insertText ~= nil and item.insertText ~= '' then local insert_text_format = protocol.InsertTextFormat[item.insertTextFormat] - if insert_text_format == "PlainText" or insert_text_format == nil then + if insert_text_format == 'PlainText' or insert_text_format == nil then return item.insertText else return M.parse_snippet(item.insertText) @@ -588,7 +625,7 @@ end ---@returns (`vim.lsp.protocol.completionItemKind`) ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion function M._get_completion_item_kind_name(completion_item_kind) - return protocol.CompletionItemKind[completion_item_kind] or "Unknown" + return protocol.CompletionItemKind[completion_item_kind] or 'Unknown' end --- Turns the result of a `textDocument/completion` request into vim-compatible @@ -619,7 +656,7 @@ function M.text_document_completion_list_to_complete_items(result, prefix) info = documentation elseif type(documentation) == 'table' and type(documentation.value) == 'string' then info = documentation.value - -- else + -- else -- TODO(ashkan) Validation handling here? end end @@ -637,9 +674,9 @@ function M.text_document_completion_list_to_complete_items(result, prefix) user_data = { nvim = { lsp = { - completion_item = completion_item - } - } + completion_item = completion_item, + }, + }, }, }) end @@ -647,7 +684,6 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return matches end - --- Rename old_fname to new_fname --- ---@param opts (table) @@ -700,7 +736,7 @@ local function delete_file(change) if opts.ignoreIfNotExists and not stat then return end - assert(stat, "Cannot delete not existing file or folder " .. fname) + assert(stat, 'Cannot delete not existing file or folder ' .. fname) local flags if stat and stat.type == 'directory' then flags = opts.recursive and 'rf' or 'd' @@ -713,7 +749,6 @@ local function delete_file(change) api.nvim_buf_delete(bufnr, { force = true }) end - --- Applies a `WorkspaceEdit`. --- ---@param workspace_edit table `WorkspaceEdit` @@ -721,22 +756,18 @@ end --see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) if offset_encoding == nil then - vim.notify_once("apply_workspace_edit must be called with valid offset encoding", vim.log.levels.WARN) + vim.notify_once('apply_workspace_edit must be called with valid offset encoding', vim.log.levels.WARN) end if workspace_edit.documentChanges then for idx, change in ipairs(workspace_edit.documentChanges) do - if change.kind == "rename" then - M.rename( - vim.uri_to_fname(change.oldUri), - vim.uri_to_fname(change.newUri), - change.options - ) + if change.kind == 'rename' then + M.rename(vim.uri_to_fname(change.oldUri), vim.uri_to_fname(change.newUri), change.options) elseif change.kind == 'create' then create_file(change) elseif change.kind == 'delete' then delete_file(change) elseif change.kind then - error(string.format("Unsupported change: %q", vim.inspect(change))) + error(string.format('Unsupported change: %q', vim.inspect(change))) else M.apply_text_document_edit(change, idx, offset_encoding) end @@ -770,7 +801,7 @@ function M.convert_input_to_markdown_lines(input, contents) if type(input) == 'string' then list_extend(contents, split_lines(input)) else - assert(type(input) == 'table', "Expected a table for Hover.contents") + assert(type(input) == 'table', 'Expected a table for Hover.contents') -- MarkupContent if input.kind then -- The kind can be either plaintext or markdown. @@ -779,22 +810,22 @@ function M.convert_input_to_markdown_lines(input, contents) -- Some servers send input.value as empty, so let's ignore this :( local value = input.value or '' - if input.kind == "plaintext" then + if input.kind == 'plaintext' then -- wrap this in a block so that stylize_markdown -- can properly process it as plaintext - value = string.format("\n%s\n", value) + value = string.format('\n%s\n', value) end -- assert(type(value) == 'string') list_extend(contents, split_lines(value)) - -- MarkupString variation 2 + -- MarkupString variation 2 elseif input.language then -- Some servers send input.value as empty, so let's ignore this :( -- assert(type(input.value) == 'string') - table.insert(contents, "```"..input.language) + table.insert(contents, '```' .. input.language) list_extend(contents, split_lines(input.value or '')) - table.insert(contents, "```") - -- By deduction, this must be MarkedString[] + table.insert(contents, '```') + -- By deduction, this must be MarkedString[] else -- Use our existing logic to handle MarkedString for _, marked_string in ipairs(input) do @@ -838,7 +869,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers local label = signature.label if ft then -- wrap inside a code block so stylize_markdown can render it properly - label = ("```%s\n%s\n```"):format(ft, label) + label = ('```%s\n%s\n```'):format(ft, label) end vim.list_extend(contents, vim.split(label, '\n', true)) if signature.documentation then @@ -846,8 +877,8 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers end if signature.parameters and #signature.parameters > 0 then local active_parameter = (signature.activeParameter or signature_help.activeParameter or 0) - if active_parameter < 0 - then active_parameter = 0 + if active_parameter < 0 then + active_parameter = 0 end -- If the activeParameter is > #parameters, then set it to the last @@ -877,7 +908,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers } --]=] if parameter.label then - if type(parameter.label) == "table" then + if type(parameter.label) == 'table' then active_hl = parameter.label else local offset = 1 @@ -890,9 +921,11 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers end for p, param in pairs(signature.parameters) do offset = signature.label:find(param.label, offset, true) - if not offset then break end + if not offset then + break + end if p == active_parameter + 1 then - active_hl = {offset - 1, offset + #parameter.label - 1} + active_hl = { offset - 1, offset + #parameter.label - 1 } break end offset = offset + #param.label + 1 @@ -920,14 +953,14 @@ end --- - zindex (string or table) override `zindex`, defaults to 50 ---@returns (table) Options function M.make_floating_popup_options(width, height, opts) - validate { - opts = { opts, 't', true }; - } + validate({ + opts = { opts, 't', true }, + }) opts = opts or {} - validate { - ["opts.offset_x"] = { opts.offset_x, 'n', true }; - ["opts.offset_y"] = { opts.offset_y, 'n', true }; - } + validate({ + ['opts.offset_x'] = { opts.offset_x, 'n', true }, + ['opts.offset_y'] = { opts.offset_y, 'n', true }, + }) local anchor = '' local row, col @@ -936,20 +969,20 @@ function M.make_floating_popup_options(width, height, opts) local lines_below = vim.fn.winheight(0) - lines_above if lines_above < lines_below then - anchor = anchor..'N' + anchor = anchor .. 'N' height = math.min(lines_below, height) row = 1 else - anchor = anchor..'S' + anchor = anchor .. 'S' height = math.min(lines_above, height) row = 0 end if vim.fn.wincol() + width + (opts.offset_x or 0) <= api.nvim_get_option('columns') then - anchor = anchor..'W' + anchor = anchor .. 'W' col = 0 else - anchor = anchor..'E' + anchor = anchor .. 'E' col = 1 end @@ -975,18 +1008,20 @@ end function M.jump_to_location(location, offset_encoding) -- location may be Location or LocationLink local uri = location.uri or location.targetUri - if uri == nil then return end + if uri == nil then + return + end if offset_encoding == nil then - vim.notify_once("jump_to_location must be called with valid offset encoding", vim.log.levels.WARN) + vim.notify_once('jump_to_location must be called with valid offset encoding', vim.log.levels.WARN) end local bufnr = vim.uri_to_bufnr(uri) -- Save position in jumplist - vim.cmd "normal! m'" + vim.cmd("normal! m'") -- Push a new item into tagstack - local from = {vim.fn.bufnr('%'), vim.fn.line('.'), vim.fn.col('.'), 0} - local items = {{tagname=vim.fn.expand(''), from=from}} - vim.fn.settagstack(vim.fn.win_getid(), {items=items}, 't') + local from = { vim.fn.bufnr('%'), vim.fn.line('.'), vim.fn.col('.'), 0 } + local items = { { tagname = vim.fn.expand(''), from = from } } + vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't') --- Jump to new location (adjusting for UTF-16 encoding of characters) api.nvim_set_current_buf(bufnr) @@ -994,9 +1029,9 @@ function M.jump_to_location(location, offset_encoding) local range = location.range or location.targetSelectionRange local row = range.start.line local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) - api.nvim_win_set_cursor(0, {row + 1, col}) + api.nvim_win_set_cursor(0, { row + 1, col }) -- Open folds under the cursor - vim.cmd("normal! zv") + vim.cmd('normal! zv') return true end @@ -1011,22 +1046,24 @@ end function M.preview_location(location, opts) -- location may be LocationLink or Location (more useful for the former) local uri = location.targetUri or location.uri - if uri == nil then return end + if uri == nil then + return + end local bufnr = vim.uri_to_bufnr(uri) if not api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end local range = location.targetRange or location.range - local contents = api.nvim_buf_get_lines(bufnr, range.start.line, range["end"].line+1, false) + local contents = api.nvim_buf_get_lines(bufnr, range.start.line, range['end'].line + 1, false) local syntax = api.nvim_buf_get_option(bufnr, 'syntax') - if syntax == "" then + if syntax == '' then -- When no syntax is set, we use filetype as fallback. This might not result -- in a valid syntax definition. See also ft detection in stylize_markdown. -- An empty syntax is more common now with TreeSitter, since TS disables syntax. syntax = api.nvim_buf_get_option(bufnr, 'filetype') end opts = opts or {} - opts.focus_id = "location" + opts.focus_id = 'location' return M.open_floating_preview(contents, syntax, opts) end @@ -1047,20 +1084,20 @@ end --- - pad_bottom number of lines to pad contents at bottom (default 0) ---@return contents table of trimmed and padded lines function M._trim(contents, opts) - validate { - contents = { contents, 't' }; - opts = { opts, 't', true }; - } + validate({ + contents = { contents, 't' }, + opts = { opts, 't', true }, + }) opts = opts or {} contents = M.trim_empty_lines(contents) if opts.pad_top then for _ = 1, opts.pad_top do - table.insert(contents, 1, "") + table.insert(contents, 1, '') end end if opts.pad_bottom then for _ = 1, opts.pad_bottom do - table.insert(contents, "") + table.insert(contents, '') end end return contents @@ -1073,7 +1110,7 @@ end local function get_markdown_fences() local fences = {} for _, fence in pairs(vim.g.markdown_fenced_languages or {}) do - local lang, syntax = fence:match("^(.*)=(.*)$") + local lang, syntax = fence:match('^(.*)=(.*)$') if lang then fences[lang] = syntax end @@ -1102,28 +1139,28 @@ end --- - separator insert separator after code block ---@returns width,height size of float function M.stylize_markdown(bufnr, contents, opts) - validate { - contents = { contents, 't' }; - opts = { opts, 't', true }; - } + validate({ + contents = { contents, 't' }, + opts = { opts, 't', true }, + }) opts = opts or {} -- table of fence types to {ft, begin, end} -- when ft is nil, we get the ft from the regex match local matchers = { - block = {nil, "```+([a-zA-Z0-9_]*)", "```+"}, - pre = {"", "
", "
"}, - code = {"", "", ""}, - text = {"text", "", ""}, + block = { nil, '```+([a-zA-Z0-9_]*)', '```+' }, + pre = { '', '
', '
' }, + code = { '', '', '' }, + text = { 'text', '', '' }, } local match_begin = function(line) for type, pattern in pairs(matchers) do - local ret = line:match(string.format("^%%s*%s%%s*$", pattern[2])) + local ret = line:match(string.format('^%%s*%s%%s*$', pattern[2])) if ret then return { type = type, - ft = pattern[1] or ret + ft = pattern[1] or ret, } end end @@ -1131,7 +1168,7 @@ function M.stylize_markdown(bufnr, contents, opts) local match_end = function(line, match) local pattern = matchers[match.type] - return line:match(string.format("^%%s*%s%%s*$", pattern[3])) + return line:match(string.format('^%%s*%s%%s*$', pattern[3])) end -- Clean up @@ -1161,25 +1198,27 @@ function M.stylize_markdown(bufnr, contents, opts) i = i + 1 end table.insert(highlights, { - ft = match.ft; - start = start + 1; - finish = #stripped; + ft = match.ft, + start = start + 1, + finish = #stripped, }) -- add a separator, but not on the last line if add_sep and i < #contents then - table.insert(stripped, "---") + table.insert(stripped, '---') markdown_lines[#stripped] = true end else -- strip any empty lines or separators prior to this separator in actual markdown - if line:match("^---+$") then - while markdown_lines[#stripped] and (stripped[#stripped]:match("^%s*$") or stripped[#stripped]:match("^---+$")) do + if line:match('^---+$') then + while + markdown_lines[#stripped] and (stripped[#stripped]:match('^%s*$') or stripped[#stripped]:match('^---+$')) + do markdown_lines[#stripped] = false table.remove(stripped, #stripped) end end -- add the line if its not an empty line following a separator - if not (line:match("^%s*$") and markdown_lines[#stripped] and stripped[#stripped]:match("^---+$")) then + if not (line:match('^%s*$') and markdown_lines[#stripped] and stripped[#stripped]:match('^---+$')) then table.insert(stripped, line) markdown_lines[#stripped] = true end @@ -1189,13 +1228,13 @@ function M.stylize_markdown(bufnr, contents, opts) end -- Compute size of float needed to show (wrapped) lines - opts.wrap_at = opts.wrap_at or (vim.wo["wrap"] and api.nvim_win_get_width(0)) + opts.wrap_at = opts.wrap_at or (vim.wo['wrap'] and api.nvim_win_get_width(0)) local width = M._make_floating_popup_size(stripped, opts) - local sep_line = string.rep("─", math.min(width, opts.wrap_at or width)) + local sep_line = string.rep('─', math.min(width, opts.wrap_at or width)) for l in pairs(markdown_lines) do - if stripped[l]:match("^---+$") then + if stripped[l]:match('^---+$') then stripped[l] = sep_line end end @@ -1209,24 +1248,28 @@ function M.stylize_markdown(bufnr, contents, opts) local langs = {} local fences = get_markdown_fences() local function apply_syntax_to_region(ft, start, finish) - if ft == "" then - vim.cmd(string.format("syntax region markdownCode start=+\\%%%dl+ end=+\\%%%dl+ keepend extend", start, finish + 1)) + if ft == '' then + vim.cmd( + string.format('syntax region markdownCode start=+\\%%%dl+ end=+\\%%%dl+ keepend extend', start, finish + 1) + ) return end ft = fences[ft] or ft - local name = ft..idx + local name = ft .. idx idx = idx + 1 - local lang = "@"..ft:upper() + local lang = '@' .. ft:upper() if not langs[lang] then -- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set - pcall(vim.api.nvim_buf_del_var, bufnr, "current_syntax") + pcall(vim.api.nvim_buf_del_var, bufnr, 'current_syntax') -- TODO(ashkan): better validation before this. - if not pcall(vim.cmd, string.format("syntax include %s syntax/%s.vim", lang, ft)) then + if not pcall(vim.cmd, string.format('syntax include %s syntax/%s.vim', lang, ft)) then return end langs[lang] = true end - vim.cmd(string.format("syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend", name, start, finish + 1, lang)) + vim.cmd( + string.format('syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend', name, start, finish + 1, lang) + ) end -- needs to run in the buffer for the regions to work @@ -1237,13 +1280,13 @@ function M.stylize_markdown(bufnr, contents, opts) local last = 1 for _, h in ipairs(highlights) do if last < h.start then - apply_syntax_to_region("lsp_markdown", last, h.start - 1) + apply_syntax_to_region('lsp_markdown', last, h.start - 1) end apply_syntax_to_region(h.ft, h.start, h.finish) last = h.finish + 1 end if last <= #stripped then - apply_syntax_to_region("lsp_markdown", last, #stripped) + apply_syntax_to_region('lsp_markdown', last, #stripped) end end) @@ -1258,23 +1301,33 @@ end ---@param bufnrs table list of buffers where the preview window will remain visible ---@see |autocmd-events| local function close_preview_autocmd(events, winnr, bufnrs) - local augroup = 'preview_window_'..winnr + local augroup = 'preview_window_' .. winnr -- close the preview window when entered a buffer that is not -- the floating window buffer or the buffer that spawned it - vim.cmd(string.format([[ + vim.cmd(string.format( + [[ augroup %s autocmd! autocmd BufEnter * lua vim.lsp.util._close_preview_window(%d, {%s}) augroup end - ]], augroup, winnr, table.concat(bufnrs, ','))) + ]], + augroup, + winnr, + table.concat(bufnrs, ',') + )) if #events > 0 then - vim.cmd(string.format([[ + vim.cmd(string.format( + [[ augroup %s autocmd %s lua vim.lsp.util._close_preview_window(%d) augroup end - ]], augroup, table.concat(events, ','), winnr)) + ]], + augroup, + table.concat(events, ','), + winnr + )) end end @@ -1290,13 +1343,17 @@ function M._close_preview_window(winnr, bufnrs) return end - local augroup = 'preview_window_'..winnr - vim.cmd(string.format([[ + local augroup = 'preview_window_' .. winnr + vim.cmd(string.format( + [[ augroup %s autocmd! augroup end augroup! %s - ]], augroup, augroup)) + ]], + augroup, + augroup + )) pcall(vim.api.nvim_win_close, winnr, true) end) end @@ -1313,10 +1370,10 @@ end --- - max_height maximal height of floating window ---@returns width,height size of float function M._make_floating_popup_size(contents, opts) - validate { - contents = { contents, 't' }; - opts = { opts, 't', true }; - } + validate({ + contents = { contents, 't' }, + opts = { opts, 't', true }, + }) opts = opts or {} local width = opts.width @@ -1360,11 +1417,11 @@ function M._make_floating_popup_size(contents, opts) if vim.tbl_isempty(line_widths) then for _, line in ipairs(contents) do local line_width = vim.fn.strdisplaywidth(line) - height = height + math.ceil(line_width/wrap_at) + height = height + math.ceil(line_width / wrap_at) end else for i = 1, #contents do - height = height + math.max(1, math.ceil(line_widths[i]/wrap_at)) + height = height + math.max(1, math.ceil(line_widths[i] / wrap_at)) end end end @@ -1398,16 +1455,16 @@ end ---@returns bufnr,winnr buffer and window number of the newly created floating ---preview window function M.open_floating_preview(contents, syntax, opts) - validate { - contents = { contents, 't' }; - syntax = { syntax, 's', true }; - opts = { opts, 't', true }; - } + validate({ + contents = { contents, 't' }, + syntax = { syntax, 's', true }, + opts = { opts, 't', true }, + }) opts = opts or {} opts.wrap = opts.wrap ~= false -- wrapping by default opts.stylize_markdown = opts.stylize_markdown ~= false opts.focus = opts.focus ~= false - opts.close_events = opts.close_events or {"CursorMoved", "CursorMovedI", "InsertCharPre"} + opts.close_events = opts.close_events or { 'CursorMoved', 'CursorMovedI', 'InsertCharPre' } local bufnr = api.nvim_get_current_buf() @@ -1416,7 +1473,7 @@ function M.open_floating_preview(contents, syntax, opts) -- Go back to previous window if we are in a focusable one local current_winnr = api.nvim_get_current_win() if npcall(api.nvim_win_get_var, current_winnr, opts.focus_id) then - api.nvim_command("wincmd p") + api.nvim_command('wincmd p') return bufnr, current_winnr end do @@ -1424,7 +1481,7 @@ function M.open_floating_preview(contents, syntax, opts) if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then -- focus and return the existing buf, win api.nvim_set_current_win(win) - api.nvim_command("stopinsert") + api.nvim_command('stopinsert') return api.nvim_win_get_buf(win), win end end @@ -1432,14 +1489,13 @@ function M.open_floating_preview(contents, syntax, opts) -- check if another floating preview already exists for this buffer -- and close it if needed - local existing_float = npcall(api.nvim_buf_get_var, bufnr, "lsp_floating_preview") + local existing_float = npcall(api.nvim_buf_get_var, bufnr, 'lsp_floating_preview') if existing_float and api.nvim_win_is_valid(existing_float) then api.nvim_win_close(existing_float, true) end local floating_bufnr = api.nvim_create_buf(false, true) - local do_stylize = syntax == "markdown" and opts.stylize_markdown - + local do_stylize = syntax == 'markdown' and opts.stylize_markdown -- Clean up input: trim empty lines from the end, pad contents = M._trim(contents, opts) @@ -1475,26 +1531,32 @@ function M.open_floating_preview(contents, syntax, opts) api.nvim_buf_set_option(floating_bufnr, 'modifiable', false) api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe') - api.nvim_buf_set_keymap(floating_bufnr, "n", "q", "bdelete", {silent = true, noremap = true, nowait = true}) - close_preview_autocmd(opts.close_events, floating_winnr, {floating_bufnr, bufnr}) + api.nvim_buf_set_keymap( + floating_bufnr, + 'n', + 'q', + 'bdelete', + { silent = true, noremap = true, nowait = true } + ) + close_preview_autocmd(opts.close_events, floating_winnr, { floating_bufnr, bufnr }) -- save focus_id if opts.focus_id then api.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr) end - api.nvim_buf_set_var(bufnr, "lsp_floating_preview", floating_winnr) + api.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr) return floating_bufnr, floating_winnr end do --[[ References ]] - local reference_ns = api.nvim_create_namespace("vim_lsp_references") + local reference_ns = api.nvim_create_namespace('vim_lsp_references') --- Removes document highlights from a buffer. --- ---@param bufnr number Buffer id function M.buf_clear_references(bufnr) - validate { bufnr = {bufnr, 'n', true} } + validate({ bufnr = { bufnr, 'n', true } }) api.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1) end @@ -1505,35 +1567,41 @@ do --[[ References ]] ---@param offset_encoding string One of "utf-8", "utf-16", "utf-32". ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight function M.buf_highlight_references(bufnr, references, offset_encoding) - validate { - bufnr = {bufnr, 'n', true}, - offset_encoding = { offset_encoding, 'string', false }; - } + validate({ + bufnr = { bufnr, 'n', true }, + offset_encoding = { offset_encoding, 'string', false }, + }) for _, reference in ipairs(references) do - local start_line, start_char = reference["range"]["start"]["line"], reference["range"]["start"]["character"] - local end_line, end_char = reference["range"]["end"]["line"], reference["range"]["end"]["character"] + local start_line, start_char = reference['range']['start']['line'], reference['range']['start']['character'] + local end_line, end_char = reference['range']['end']['line'], reference['range']['end']['character'] - local start_idx = get_line_byte_from_position(bufnr, { line = start_line, character = start_char }, offset_encoding) + local start_idx = get_line_byte_from_position( + bufnr, + { line = start_line, character = start_char }, + offset_encoding + ) local end_idx = get_line_byte_from_position(bufnr, { line = start_line, character = end_char }, offset_encoding) local document_highlight_kind = { - [protocol.DocumentHighlightKind.Text] = "LspReferenceText"; - [protocol.DocumentHighlightKind.Read] = "LspReferenceRead"; - [protocol.DocumentHighlightKind.Write] = "LspReferenceWrite"; + [protocol.DocumentHighlightKind.Text] = 'LspReferenceText', + [protocol.DocumentHighlightKind.Read] = 'LspReferenceRead', + [protocol.DocumentHighlightKind.Write] = 'LspReferenceWrite', } - local kind = reference["kind"] or protocol.DocumentHighlightKind.Text - highlight.range(bufnr, - reference_ns, - document_highlight_kind[kind], - { start_line, start_idx }, - { end_line, end_idx }, - { priority = vim.highlight.priorities.user }) + local kind = reference['kind'] or protocol.DocumentHighlightKind.Text + highlight.range( + bufnr, + reference_ns, + document_highlight_kind[kind], + { start_line, start_idx }, + { end_line, end_idx }, + { priority = vim.highlight.priorities.user } + ) end end end local position_sort = sort_by_key(function(v) - return {v.start.line, v.start.character} + return { v.start.line, v.start.character } end) --- Returns the items with the byte position calculated correctly and in sorted @@ -1547,7 +1615,7 @@ end) ---@returns (table) list of items function M.locations_to_items(locations, offset_encoding) if offset_encoding == nil then - vim.notify_once("locations_to_items must be called with valid offset encoding", vim.log.levels.WARN) + vim.notify_once('locations_to_items must be called with valid offset encoding', vim.log.levels.WARN) end local items = {} @@ -1556,16 +1624,15 @@ function M.locations_to_items(locations, offset_encoding) local v = {} rawset(t, k, v) return v - end; + end, }) for _, d in ipairs(locations) do -- locations may be Location or LocationLink local uri = d.uri or d.targetUri local range = d.range or d.targetSelectionRange - table.insert(grouped[uri], {start = range.start}) + table.insert(grouped[uri], { start = range.start }) end - local keys = vim.tbl_keys(grouped) table.sort(keys) -- TODO(ashkan) I wish we could do this lazily. @@ -1588,13 +1655,13 @@ function M.locations_to_items(locations, offset_encoding) for _, temp in ipairs(rows) do local pos = temp.start local row = pos.line - local line = lines[row] or "" + local line = lines[row] or '' local col = M._str_byteindex_enc(line, pos.character, offset_encoding) table.insert(items, { filename = filename, lnum = row + 1, - col = col + 1; - text = line; + col = col + 1, + text = line, }) end end @@ -1609,10 +1676,10 @@ end --- ---@param items (table) list of items function M.set_loclist(items, win_id) - vim.api.nvim_echo({{'vim.lsp.util.set_loclist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.api.nvim_echo({ { 'vim.lsp.util.set_loclist is deprecated. See :h deprecated', 'WarningMsg' } }, true, {}) vim.fn.setloclist(win_id or 0, {}, ' ', { - title = 'Language Server'; - items = items; + title = 'Language Server', + items = items, }) end @@ -1623,10 +1690,10 @@ end --- ---@param items (table) list of items function M.set_qflist(items) - vim.api.nvim_echo({{'vim.lsp.util.set_qflist is deprecated. See :h deprecated', 'WarningMsg'}}, true, {}) + vim.api.nvim_echo({ { 'vim.lsp.util.set_qflist is deprecated. See :h deprecated', 'WarningMsg' } }, true, {}) vim.fn.setqflist({}, ' ', { - title = 'Language Server'; - items = items; + title = 'Language Server', + items = items, }) end @@ -1634,7 +1701,7 @@ end -- the client must handle it properly even if it receives a value outside the specification. -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol function M._get_symbol_kind_name(symbol_kind) - return protocol.SymbolKind[symbol_kind] or "Unknown" + return protocol.SymbolKind[symbol_kind] or 'Unknown' end --- Converts symbols to quickfix list items. @@ -1652,7 +1719,7 @@ function M.symbols_to_items(symbols, bufnr) lnum = range.start.line + 1, col = range.start.character + 1, kind = kind, - text = '['..kind..'] '..symbol.name, + text = '[' .. kind .. '] ' .. symbol.name, }) elseif symbol.selectionRange then -- DocumentSymbole type local kind = M._get_symbol_kind_name(symbol.kind) @@ -1662,7 +1729,7 @@ function M.symbols_to_items(symbols, bufnr) lnum = symbol.selectionRange.start.line + 1, col = symbol.selectionRange.start.character + 1, kind = kind, - text = '['..kind..'] '..symbol.name + text = '[' .. kind .. '] ' .. symbol.name, }) if symbol.children then for _, v in ipairs(_symbols_to_items(symbol.children, _items, _bufnr)) do @@ -1707,12 +1774,12 @@ end ---@param lines (table) list of lines ---@returns (string) filetype or 'markdown' if it was unchanged. function M.try_trim_markdown_code_blocks(lines) - local language_id = lines[1]:match("^```(.*)") + local language_id = lines[1]:match('^```(.*)') if language_id then local has_inner_code_fence = false for i = 2, (#lines - 1) do local line = lines[i] - if line:sub(1,3) == '```' then + if line:sub(1, 3) == '```' then has_inner_code_fence = true break end @@ -1736,14 +1803,14 @@ local function make_position_param(window, offset_encoding) local row, col = unpack(api.nvim_win_get_cursor(window)) offset_encoding = offset_encoding or M._get_offset_encoding(buf) row = row - 1 - local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1] + local line = api.nvim_buf_get_lines(buf, row, row + 1, true)[1] if not line then - return { line = 0; character = 0; } + return { line = 0, character = 0 } end col = _str_utfindex_enc(line, col, offset_encoding) - return { line = row; character = col; } + return { line = row, character = col } end --- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position. @@ -1757,8 +1824,8 @@ function M.make_position_params(window, offset_encoding) local buf = vim.api.nvim_win_get_buf(window) offset_encoding = offset_encoding or M._get_offset_encoding(buf) return { - textDocument = M.make_text_document_params(buf); - position = make_position_param(window, offset_encoding) + textDocument = M.make_text_document_params(buf), + position = make_position_param(window, offset_encoding), } end @@ -1766,16 +1833,16 @@ end ---@param bufnr (number) buffer handle or 0 for current, defaults to current ---@returns (string) encoding first client if there is one, nil otherwise function M._get_offset_encoding(bufnr) - validate { - bufnr = {bufnr, 'n', true}; - } + validate({ + bufnr = { bufnr, 'n', true }, + }) local offset_encoding for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do if client.offset_encoding == nil then vim.notify_once( - string.format("Client (id: %s) offset_encoding is nil. Do not unset offset_encoding.", client.id), + string.format('Client (id: %s) offset_encoding is nil. Do not unset offset_encoding.', client.id), vim.log.levels.ERROR ) end @@ -1783,7 +1850,10 @@ function M._get_offset_encoding(bufnr) if not offset_encoding then offset_encoding = this_offset_encoding elseif offset_encoding ~= this_offset_encoding then - vim.notify("warning: multiple different client offset_encodings detected for buffer, this is not supported yet", vim.log.levels.WARN) + vim.notify( + 'warning: multiple different client offset_encodings detected for buffer, this is not supported yet', + vim.log.levels.WARN + ) end end @@ -1805,7 +1875,7 @@ function M.make_range_params(window, offset_encoding) local position = make_position_param(window, offset_encoding) return { textDocument = M.make_text_document_params(buf), - range = { start = position; ["end"] = position; } + range = { start = position, ['end'] = position }, } end @@ -1821,11 +1891,11 @@ end ---@returns { textDocument = { uri = `current_file_uri` }, range = { start = ---`start_position`, end = `end_position` } } function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding) - validate { - start_pos = {start_pos, 't', true}; - end_pos = {end_pos, 't', true}; - offset_encoding = {offset_encoding, 's', true}; - } + validate({ + start_pos = { start_pos, 't', true }, + end_pos = { end_pos, 't', true }, + offset_encoding = { offset_encoding, 's', true }, + }) bufnr = bufnr or vim.api.nvim_get_current_buf() offset_encoding = offset_encoding or M._get_offset_encoding(bufnr) local A = list_extend({}, start_pos or api.nvim_buf_get_mark(bufnr, '<')) @@ -1835,10 +1905,10 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding) B[1] = B[1] - 1 -- account for offset_encoding. if A[2] > 0 then - A = {A[1], M.character_offset(bufnr, A[1], A[2], offset_encoding)} + A = { A[1], M.character_offset(bufnr, A[1], A[2], offset_encoding) } end if B[2] > 0 then - B = {B[1], M.character_offset(bufnr, B[1], B[2], offset_encoding)} + B = { B[1], M.character_offset(bufnr, B[1], B[2], offset_encoding) } end -- we need to offset the end character position otherwise we loose the last -- character of the selection, as LSP end position is exclusive @@ -1849,9 +1919,9 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding) return { textDocument = M.make_text_document_params(bufnr), range = { - start = {line = A[1], character = A[2]}, - ['end'] = {line = B[1], character = B[2]} - } + start = { line = A[1], character = A[2] }, + ['end'] = { line = B[1], character = B[2] }, + }, } end @@ -1868,7 +1938,7 @@ end ---@param added ---@param removed function M.make_workspace_params(added, removed) - return { event = { added = added; removed = removed; } } + return { event = { added = added, removed = removed } } end --- Returns indentation size. --- @@ -1876,7 +1946,7 @@ end ---@param bufnr (number|nil): Buffer handle, defaults to current ---@returns (number) indentation size function M.get_effective_tabstop(bufnr) - validate { bufnr = {bufnr, 'n', true} } + validate({ bufnr = { bufnr, 'n', true } }) local bo = bufnr and vim.bo[bufnr] or vim.bo local sw = bo.shiftwidth return (sw == 0 and bo.tabstop) or sw @@ -1888,14 +1958,14 @@ end ---@returns `DocumentFormattingParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) - validate { options = {options, 't', true} } + validate({ options = { options, 't', true } }) options = vim.tbl_extend('keep', options or {}, { - tabSize = M.get_effective_tabstop(); - insertSpaces = vim.bo.expandtab; + tabSize = M.get_effective_tabstop(), + insertSpaces = vim.bo.expandtab, }) return { - textDocument = { uri = vim.uri_from_bufnr(0) }; - options = options; + textDocument = { uri = vim.uri_from_bufnr(0) }, + options = options, } end @@ -1909,7 +1979,7 @@ end function M.character_offset(buf, row, col, offset_encoding) local line = get_line(buf, row) if offset_encoding == nil then - vim.notify_once("character_offset must be called with valid offset encoding", vim.log.levels.WARN) + vim.notify_once('character_offset must be called with valid offset encoding', vim.log.levels.WARN) end -- If the col is past the EOL, use the line length. if col > #line then diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 172fac3a88..d9dc77e219 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -16,7 +16,7 @@ local vim = vim or {} --- ---@param orig table Table to copy ---@returns New table of copied keys and (nested) values. -function vim.deepcopy(orig) end -- luacheck: no unused +function vim.deepcopy(orig) end -- luacheck: no unused vim.deepcopy = (function() local function _id(v) return v @@ -24,7 +24,9 @@ vim.deepcopy = (function() local deepcopy_funcs = { table = function(orig, cache) - if cache[orig] then return cache[orig] end + if cache[orig] then + return cache[orig] + end local copy = {} cache[orig] = copy @@ -46,7 +48,7 @@ vim.deepcopy = (function() if f then return f(orig, cache or {}) else - error("Cannot deepcopy object of type "..type(orig)) + error('Cannot deepcopy object of type ' .. type(orig)) end end end)() @@ -62,14 +64,14 @@ end)() ---@param plain If `true` use `sep` literally (passed to String.find) ---@returns Iterator over the split components function vim.gsplit(s, sep, plain) - vim.validate{s={s,'s'},sep={sep,'s'},plain={plain,'b',true}} + vim.validate({ s = { s, 's' }, sep = { sep, 's' }, plain = { plain, 'b', true } }) local start = 1 local done = false local function _pass(i, j, ...) if i then - assert(j+1 > start, "Infinite loop detected") + assert(j + 1 > start, 'Infinite loop detected') local seg = s:sub(start, i - 1) start = j + 1 return seg, ... @@ -87,7 +89,7 @@ function vim.gsplit(s, sep, plain) if start == #s then done = true end - return _pass(start+1, start) + return _pass(start + 1, start) end return _pass(s:find(sep, start, plain)) end @@ -119,7 +121,7 @@ function vim.split(s, sep, kwargs) -- Support old signature for backward compatibility plain = kwargs else - vim.validate { kwargs = {kwargs, 't', true} } + vim.validate({ kwargs = { kwargs, 't', true } }) kwargs = kwargs or {} plain = kwargs.plain trimempty = kwargs.trimempty @@ -128,7 +130,7 @@ function vim.split(s, sep, kwargs) local t = {} local skip = trimempty for c in vim.gsplit(s, sep, plain) do - if c ~= "" then + if c ~= '' then skip = false end @@ -139,7 +141,7 @@ function vim.split(s, sep, kwargs) if trimempty then for i = #t, 1, -1 do - if t[i] ~= "" then + if t[i] ~= '' then break end table.remove(t, i) @@ -157,7 +159,7 @@ end ---@param t Table ---@returns list of keys function vim.tbl_keys(t) - assert(type(t) == 'table', string.format("Expected table, got %s", type(t))) + assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) local keys = {} for k, _ in pairs(t) do @@ -172,7 +174,7 @@ end ---@param t Table ---@returns list of values function vim.tbl_values(t) - assert(type(t) == 'table', string.format("Expected table, got %s", type(t))) + assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) local values = {} for _, v in pairs(t) do @@ -186,7 +188,7 @@ end ---@param func function or callable table ---@param t table function vim.tbl_map(func, t) - vim.validate{func={func,'c'},t={t,'t'}} + vim.validate({ func = { func, 'c' }, t = { t, 't' } }) local rettab = {} for k, v in pairs(t) do @@ -200,7 +202,7 @@ end ---@param func function or callable table ---@param t table function vim.tbl_filter(func, t) - vim.validate{func={func,'c'},t={t,'t'}} + vim.validate({ func = { func, 'c' }, t = { t, 't' } }) local rettab = {} for _, entry in pairs(t) do @@ -217,9 +219,9 @@ end ---@param value Value to compare ---@returns true if `t` contains `value` function vim.tbl_contains(t, value) - vim.validate{t={t,'t'}} + vim.validate({ t = { t, 't' } }) - for _,v in ipairs(t) do + for _, v in ipairs(t) do if v == value then return true end @@ -233,23 +235,23 @@ end --- ---@param t Table to check function vim.tbl_isempty(t) - assert(type(t) == 'table', string.format("Expected table, got %s", type(t))) + assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) return next(t) == nil end --- we only merge empty tables or tables that are not a list ---@private local function can_merge(v) - return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) + return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) end local function tbl_extend(behavior, deep_extend, ...) - if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then - error('invalid "behavior": '..tostring(behavior)) + if behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force' then + error('invalid "behavior": ' .. tostring(behavior)) end if select('#', ...) < 2 then - error('wrong number of arguments (given '..tostring(1 + select('#', ...))..', expected at least 3)') + error('wrong number of arguments (given ' .. tostring(1 + select('#', ...)) .. ', expected at least 3)') end local ret = {} @@ -259,15 +261,15 @@ local function tbl_extend(behavior, deep_extend, ...) for i = 1, select('#', ...) do local tbl = select(i, ...) - vim.validate{["after the second argument"] = {tbl,'t'}} + vim.validate({ ['after the second argument'] = { tbl, 't' } }) if tbl then for k, v in pairs(tbl) do if deep_extend and can_merge(v) and can_merge(ret[k]) then ret[k] = tbl_extend(behavior, true, ret[k], v) elseif behavior ~= 'force' and ret[k] ~= nil then if behavior == 'error' then - error('key found in more than one map: '..k) - end -- Else behavior is "keep". + error('key found in more than one map: ' .. k) + end -- Else behavior is "keep". else ret[k] = v end @@ -311,8 +313,12 @@ end ---@param b second value ---@returns `true` if values are equals, else `false`. function vim.deep_equal(a, b) - if a == b then return true end - if type(a) ~= type(b) then return false end + if a == b then + return true + end + if type(a) ~= type(b) then + return false + end if type(a) == 'table' then for k, v in pairs(a) do if not vim.deep_equal(v, b[k]) then @@ -340,7 +346,13 @@ function vim.tbl_add_reverse_lookup(o) for _, k in ipairs(keys) do local v = o[k] if o[v] then - error(string.format("The reverse lookup found an existing value for %q while processing key %q", tostring(v), tostring(k))) + error( + string.format( + 'The reverse lookup found an existing value for %q while processing key %q', + tostring(v), + tostring(k) + ) + ) end o[v] = k end @@ -361,7 +373,7 @@ end --- ---@returns nested value indexed by key if it exists, else nil function vim.tbl_get(o, ...) - local keys = {...} + local keys = { ... } if #keys == 0 then return end @@ -389,12 +401,12 @@ end ---@param finish Final index on src. defaults to #src ---@returns dst function vim.list_extend(dst, src, start, finish) - vim.validate { - dst = {dst, 't'}; - src = {src, 't'}; - start = {start, 'n', true}; - finish = {finish, 'n', true}; - } + vim.validate({ + dst = { dst, 't' }, + src = { src, 't' }, + start = { start, 'n', true }, + finish = { finish, 'n', true }, + }) for i = start or 1, finish or #src do table.insert(dst, src[i]) end @@ -414,7 +426,7 @@ function vim.tbl_flatten(t) local n = #_t for i = 1, n do local v = _t[i] - if type(v) == "table" then + if type(v) == 'table' then _tbl_flatten(v) elseif v then table.insert(result, v) @@ -441,7 +453,7 @@ function vim.tbl_islist(t) local count = 0 for k, _ in pairs(t) do - if type(k) == "number" then + if type(k) == 'number' then count = count + 1 else return false @@ -471,10 +483,12 @@ end ---@param t Table ---@returns Number that is the number of the value in table function vim.tbl_count(t) - vim.validate{t={t,'t'}} + vim.validate({ t = { t, 't' } }) local count = 0 - for _ in pairs(t) do count = count + 1 end + for _ in pairs(t) do + count = count + 1 + end return count end @@ -487,7 +501,7 @@ end function vim.list_slice(list, start, finish) local new_list = {} for i = start or 1, finish or #list do - new_list[#new_list+1] = list[i] + new_list[#new_list + 1] = list[i] end return new_list end @@ -498,7 +512,7 @@ end ---@param s String to trim ---@returns String with whitespace removed from its beginning and end function vim.trim(s) - vim.validate{s={s,'s'}} + vim.validate({ s = { s, 's' } }) return s:match('^%s*(.*%S)') or '' end @@ -508,7 +522,7 @@ end ---@param s String to escape ---@returns %-escaped pattern string function vim.pesc(s) - vim.validate{s={s,'s'}} + vim.validate({ s = { s, 's' } }) return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1') end @@ -518,7 +532,7 @@ end ---@param prefix (string) a prefix ---@return (boolean) true if `prefix` is a prefix of s function vim.startswith(s, prefix) - vim.validate { s = {s, 's'}; prefix = {prefix, 's'}; } + vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } }) return s:sub(1, #prefix) == prefix end @@ -528,7 +542,7 @@ end ---@param suffix (string) a suffix ---@return (boolean) true if `suffix` is a suffix of s function vim.endswith(s, suffix) - vim.validate { s = {s, 's'}; suffix = {suffix, 's'}; } + vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } }) return #suffix == 0 or s:sub(-#suffix) == suffix end @@ -582,18 +596,24 @@ end --- only if the argument is valid. Can optionally return an additional --- informative error message as the second returned value. --- - msg: (optional) error string if validation fails -function vim.validate(opt) end -- luacheck: no unused +function vim.validate(opt) end -- luacheck: no unused do local type_names = { - ['table'] = 'table', t = 'table', - ['string'] = 'string', s = 'string', - ['number'] = 'number', n = 'number', - ['boolean'] = 'boolean', b = 'boolean', - ['function'] = 'function', f = 'function', - ['callable'] = 'callable', c = 'callable', - ['nil'] = 'nil', - ['thread'] = 'thread', + ['table'] = 'table', + t = 'table', + ['string'] = 'string', + s = 'string', + ['number'] = 'number', + n = 'number', + ['boolean'] = 'boolean', + b = 'boolean', + ['function'] = 'function', + f = 'function', + ['callable'] = 'callable', + c = 'callable', + ['nil'] = 'nil', + ['thread'] = 'thread', ['userdata'] = 'userdata', } @@ -612,21 +632,21 @@ do return false, string.format('opt[%s]: expected table, got %s', param_name, type(spec)) end - local val = spec[1] -- Argument value. - local types = spec[2] -- Type name, or callable. + local val = spec[1] -- Argument value. + local types = spec[2] -- Type name, or callable. local optional = (true == spec[3]) if type(types) == 'string' then - types = {types} + types = { types } end if vim.is_callable(types) then -- Check user-provided validation function. local valid, optional_message = types(val) if not valid then - local error_message = string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), tostring(val)) + local error_message = string.format('%s: expected %s, got %s', param_name, (spec[3] or '?'), tostring(val)) if optional_message ~= nil then - error_message = error_message .. string.format(". Info: %s", optional_message) + error_message = error_message .. string.format('. Info: %s', optional_message) end return false, error_message @@ -646,10 +666,10 @@ do end end if not success then - return false, string.format("%s: expected %s, got %s", param_name, table.concat(types, '|'), type(val)) + return false, string.format('%s: expected %s, got %s', param_name, table.concat(types, '|'), type(val)) end else - return false, string.format("invalid type name: %s", tostring(types)) + return false, string.format('invalid type name: %s', tostring(types)) end end @@ -668,9 +688,13 @@ end ---@param f Any object ---@return true if `f` is callable, else false function vim.is_callable(f) - if type(f) == 'function' then return true end + if type(f) == 'function' then + return true + end local m = getmetatable(f) - if m == nil then return false end + if m == nil then + return false + end return type(m.__call) == 'function' end diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 55398d8180..70f2c425ed 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -1,32 +1,32 @@ local a = vim.api -local query = require'vim.treesitter.query' -local language = require'vim.treesitter.language' -local LanguageTree = require'vim.treesitter.languagetree' +local query = require('vim.treesitter.query') +local language = require('vim.treesitter.language') +local LanguageTree = require('vim.treesitter.languagetree') -- TODO(bfredl): currently we retain parsers for the lifetime of the buffer. -- Consider use weak references to release parser if all plugins are done with -- it. local parsers = {} -local M = vim.tbl_extend("error", query, language) +local M = vim.tbl_extend('error', query, language) M.language_version = vim._ts_get_language_version() M.minimum_language_version = vim._ts_get_minimum_language_version() setmetatable(M, { - __index = function (t, k) - if k == "highlighter" then - t[k] = require'vim.treesitter.highlighter' - return t[k] - elseif k == "language" then - t[k] = require"vim.treesitter.language" - return t[k] - elseif k == "query" then - t[k] = require"vim.treesitter.query" - return t[k] - end - end - }) + __index = function(t, k) + if k == 'highlighter' then + t[k] = require('vim.treesitter.highlighter') + return t[k] + elseif k == 'language' then + t[k] = require('vim.treesitter.language') + return t[k] + elseif k == 'query' then + t[k] = require('vim.treesitter.query') + return t[k] + end + end, +}) --- Creates a new parser. --- @@ -63,7 +63,11 @@ function M._create_parser(bufnr, lang, opts) self:_on_reload(...) end - a.nvim_buf_attach(self:source(), false, {on_bytes=bytes_cb, on_detach=detach_cb, on_reload=reload_cb, preview=true}) + a.nvim_buf_attach( + self:source(), + false, + { on_bytes = bytes_cb, on_detach = detach_cb, on_reload = reload_cb, preview = true } + ) self:parse() @@ -87,7 +91,7 @@ function M.get_parser(bufnr, lang, opts) bufnr = a.nvim_get_current_buf() end if lang == nil then - lang = a.nvim_buf_get_option(bufnr, "filetype") + lang = a.nvim_buf_get_option(bufnr, 'filetype') end if parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then @@ -105,10 +109,10 @@ end ---@param lang The language of this string ---@param opts Options to pass to the created language tree function M.get_string_parser(str, lang, opts) - vim.validate { + vim.validate({ str = { str, 'string' }, - lang = { lang, 'string' } - } + lang = { lang, 'string' }, + }) language.require_language(lang) return LanguageTree.new(str, lang, opts) diff --git a/runtime/lua/vim/treesitter/health.lua b/runtime/lua/vim/treesitter/health.lua index 53ccc6e88d..aa9db6b71b 100644 --- a/runtime/lua/vim/treesitter/health.lua +++ b/runtime/lua/vim/treesitter/health.lua @@ -15,24 +15,22 @@ function M.check() local report_error = vim.fn['health#report_error'] local parsers = M.list_parsers() - report_info(string.format("Runtime ABI version : %d", ts.language_version)) + report_info(string.format('Runtime ABI version : %d', ts.language_version)) for _, parser in pairs(parsers) do - local parsername = vim.fn.fnamemodify(parser, ":t:r") + local parsername = vim.fn.fnamemodify(parser, ':t:r') local is_loadable, ret = pcall(ts.language.require_language, parsername) if not is_loadable then - report_error(string.format("Impossible to load parser for %s: %s", parsername, ret)) + report_error(string.format('Impossible to load parser for %s: %s', parsername, ret)) elseif ret then local lang = ts.language.inspect_language(parsername) - report_ok(string.format("Loaded parser for %s: ABI version %d", - parsername, lang._abi_version)) + report_ok(string.format('Loaded parser for %s: ABI version %d', parsername, lang._abi_version)) else - report_error(string.format("Unable to load parser for %s", parsername)) + report_error(string.format('Unable to load parser for %s', parsername)) end end end return M - diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 0ec4ab37ec..453fed0576 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -1,5 +1,5 @@ local a = vim.api -local query = require"vim.treesitter.query" +local query = require('vim.treesitter.query') -- support reload for quick experimentation local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {} @@ -10,13 +10,13 @@ TSHighlighter.active = TSHighlighter.active or {} local TSHighlighterQuery = {} TSHighlighterQuery.__index = TSHighlighterQuery -local ns = a.nvim_create_namespace("treesitter/highlighter") +local ns = a.nvim_create_namespace('treesitter/highlighter') local _default_highlights = {} local _link_default_highlight_once = function(from, to) if not _default_highlights[from] then _default_highlights[from] = true - vim.cmd(string.format("highlight default link %s %s", from, to)) + vim.cmd(string.format('highlight default link %s %s', from, to)) end return from @@ -31,65 +31,65 @@ local subcapture_fallback = { shortened = shortened:match('(.*)%.') rtn = shortened and rawget(self, shortened) end - rawset(self, capture, rtn or "__notfound") + rawset(self, capture, rtn or '__notfound') return rtn - end + end, } TSHighlighter.hl_map = setmetatable({ - ["error"] = "Error", - ["text.underline"] = "Underlined", - ["todo"] = "Todo", - ["debug"] = "Debug", - --- Miscs - ["comment"] = "Comment", - ["punctuation.delimiter"] = "Delimiter", - ["punctuation.bracket"] = "Delimiter", - ["punctuation.special"] = "Delimiter", - --- Constants - ["constant"] = "Constant", - ["constant.builtin"] = "Special", - ["constant.macro"] = "Define", - ["define"] = "Define", - ["macro"] = "Macro", - ["string"] = "String", - ["string.regex"] = "String", - ["string.escape"] = "SpecialChar", - ["character"] = "Character", - ["character.special"] = "SpecialChar", - ["number"] = "Number", - ["boolean"] = "Boolean", - ["float"] = "Float", - --- Functions - ["function"] = "Function", - ["function.special"] = "Function", - ["function.builtin"] = "Special", - ["function.macro"] = "Macro", - ["parameter"] = "Identifier", - ["method"] = "Function", - ["field"] = "Identifier", - ["property"] = "Identifier", - ["constructor"] = "Special", - --- Keywords - ["conditional"] = "Conditional", - ["repeat"] = "Repeat", - ["label"] = "Label", - ["operator"] = "Operator", - ["keyword"] = "Keyword", - ["exception"] = "Exception", - - ["type"] = "Type", - ["type.builtin"] = "Type", - ["type.qualifier"] = "Type", - ["type.definition"] = "Typedef", - ["storageclass"] = "StorageClass", - ["structure"] = "Structure", - ["include"] = "Include", - ["preproc"] = "PreProc", + ['error'] = 'Error', + ['text.underline'] = 'Underlined', + ['todo'] = 'Todo', + ['debug'] = 'Debug', + + -- Miscs + ['comment'] = 'Comment', + ['punctuation.delimiter'] = 'Delimiter', + ['punctuation.bracket'] = 'Delimiter', + ['punctuation.special'] = 'Delimiter', + + -- Constants + ['constant'] = 'Constant', + ['constant.builtin'] = 'Special', + ['constant.macro'] = 'Define', + ['define'] = 'Define', + ['macro'] = 'Macro', + ['string'] = 'String', + ['string.regex'] = 'String', + ['string.escape'] = 'SpecialChar', + ['character'] = 'Character', + ['character.special'] = 'SpecialChar', + ['number'] = 'Number', + ['boolean'] = 'Boolean', + ['float'] = 'Float', + + -- Functions + ['function'] = 'Function', + ['function.special'] = 'Function', + ['function.builtin'] = 'Special', + ['function.macro'] = 'Macro', + ['parameter'] = 'Identifier', + ['method'] = 'Function', + ['field'] = 'Identifier', + ['property'] = 'Identifier', + ['constructor'] = 'Special', + + -- Keywords + ['conditional'] = 'Conditional', + ['repeat'] = 'Repeat', + ['label'] = 'Label', + ['operator'] = 'Operator', + ['keyword'] = 'Keyword', + ['exception'] = 'Exception', + + ['type'] = 'Type', + ['type.builtin'] = 'Type', + ['type.qualifier'] = 'Type', + ['type.definition'] = 'Typedef', + ['storageclass'] = 'StorageClass', + ['structure'] = 'Structure', + ['include'] = 'Include', + ['preproc'] = 'PreProc', }, subcapture_fallback) ---@private @@ -113,13 +113,13 @@ function TSHighlighterQuery.new(lang, query_string) rawset(table, capture, id) return id - end + end, }) if query_string then self._query = query.parse_query(lang, query_string) else - self._query = query.get_query(lang, "highlights") + self._query = query.get_query(lang, 'highlights') end return self @@ -152,17 +152,23 @@ end function TSHighlighter.new(tree, opts) local self = setmetatable({}, TSHighlighter) - if type(tree:source()) ~= "number" then - error("TSHighlighter can not be used with a string parser source.") + if type(tree:source()) ~= 'number' then + error('TSHighlighter can not be used with a string parser source.') end opts = opts or {} self.tree = tree - tree:register_cbs { - on_changedtree = function(...) self:on_changedtree(...) end; - on_bytes = function(...) self:on_bytes(...) end; - on_detach = function(...) self:on_detach(...) end; - } + tree:register_cbs({ + on_changedtree = function(...) + self:on_changedtree(...) + end, + on_bytes = function(...) + self:on_bytes(...) + end, + on_detach = function(...) + self:on_detach(...) + end, + }) self.bufnr = tree:source() self.edit_count = 0 @@ -181,7 +187,7 @@ function TSHighlighter.new(tree, opts) end end - a.nvim_buf_set_option(self.bufnr, "syntax", "") + a.nvim_buf_set_option(self.bufnr, 'syntax', '') TSHighlighter.active[self.bufnr] = self @@ -190,7 +196,7 @@ function TSHighlighter.new(tree, opts) -- syntax FileType autocmds. Later on we should integrate with the -- `:syntax` and `set syntax=...` machinery properly. if vim.g.syntax_on ~= 1 then - vim.api.nvim_command("runtime! syntax/synload.vim") + vim.api.nvim_command('runtime! syntax/synload.vim') end self.tree:parse() @@ -210,7 +216,7 @@ function TSHighlighter:get_highlight_state(tstree) if not self._highlight_states[tstree] then self._highlight_states[tstree] = { next_row = 0, - iter = nil + iter = nil, } end @@ -235,7 +241,7 @@ end ---@private function TSHighlighter:on_changedtree(changes) for _, ch in ipairs(changes or {}) do - a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3]+1) + a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1) end end @@ -253,19 +259,25 @@ end ---@private local function on_line_impl(self, buf, line) self.tree:for_each_tree(function(tstree, tree) - if not tstree then return end + if not tstree then + return + end local root_node = tstree:root() local root_start_row, _, root_end_row, _ = root_node:range() -- Only worry about trees within the line range - if root_start_row > line or root_end_row < line then return end + if root_start_row > line or root_end_row < line then + return + end local state = self:get_highlight_state(tstree) local highlighter_query = self:get_query(tree:lang()) -- Some injected languages may not have highlight queries. - if not highlighter_query:query() then return end + if not highlighter_query:query() then + return + end if state.iter == nil then state.iter = highlighter_query:query():iter_captures(root_node, self.bufnr, line, root_end_row + 1) @@ -274,19 +286,22 @@ local function on_line_impl(self, buf, line) while line >= state.next_row do local capture, node, metadata = state.iter() - if capture == nil then break end + if capture == nil then + break + end local start_row, start_col, end_row, end_col = node:range() local hl = highlighter_query.hl_cache[capture] if hl and end_row >= line then - a.nvim_buf_set_extmark(buf, ns, start_row, start_col, - { end_line = end_row, end_col = end_col, - hl_group = hl, - ephemeral = true, - priority = tonumber(metadata.priority) or 100, -- Low but leaves room below - conceal = metadata.conceal, - }) + a.nvim_buf_set_extmark(buf, ns, start_row, start_col, { + end_line = end_row, + end_col = end_col, + hl_group = hl, + ephemeral = true, + priority = tonumber(metadata.priority) or 100, -- Low but leaves room below + conceal = metadata.conceal, + }) end if start_row > line then state.next_row = start_row @@ -298,7 +313,9 @@ end ---@private function TSHighlighter._on_line(_, _win, buf, line, _) local self = TSHighlighter.active[buf] - if not self then return end + if not self then + return + end on_line_impl(self, buf, line) end @@ -324,9 +341,9 @@ function TSHighlighter._on_win(_, _win, buf, _topline) end a.nvim_set_decoration_provider(ns, { - on_buf = TSHighlighter._on_buf; - on_win = TSHighlighter._on_win; - on_line = TSHighlighter._on_line; + on_buf = TSHighlighter._on_buf, + on_win = TSHighlighter._on_win, + on_line = TSHighlighter._on_line, }) return TSHighlighter diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index 8b106108df..dfb6f5be84 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -22,13 +22,15 @@ function M.require_language(lang, path, silent) end -- TODO(bfredl): help tag? - error("no parser for '"..lang.."' language, see :help treesitter-parsers") + error("no parser for '" .. lang .. "' language, see :help treesitter-parsers") end path = paths[1] end if silent then - return pcall(function() vim._ts_add_language(path, lang) end) + return pcall(function() + vim._ts_add_language(path, lang) + end) else vim._ts_add_language(path, lang) end diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index b83df65151..2157112d2f 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -1,6 +1,6 @@ local a = vim.api -local query = require'vim.treesitter.query' -local language = require'vim.treesitter.language' +local query = require('vim.treesitter.query') +local language = require('vim.treesitter.language') local LanguageTree = {} LanguageTree.__index = LanguageTree @@ -32,9 +32,10 @@ function LanguageTree.new(source, lang, opts) _regions = {}, _trees = {}, _opts = opts, - _injection_query = injections[lang] - and query.parse_query(lang, injections[lang]) - or query.get_query(lang, "injections"), + _injection_query = injections[lang] and query.parse_query(lang, injections[lang]) or query.get_query( + lang, + 'injections' + ), _valid = false, _parser = vim._create_ts_parser(lang), _callbacks = { @@ -42,11 +43,10 @@ function LanguageTree.new(source, lang, opts) bytes = {}, detach = {}, child_added = {}, - child_removed = {} + child_removed = {}, }, }, LanguageTree) - return self end @@ -264,11 +264,11 @@ end ---@param regions A list of regions this tree should manage and parse. function LanguageTree:set_included_regions(regions) -- TODO(vigoux): I don't think string parsers are useful for now - if type(self._source) == "number" then + if type(self._source) == 'number' then -- Transform the tables from 4 element long to 6 element long (with byte offset) for _, region in ipairs(regions) do for i, range in ipairs(region) do - if type(range) == "table" and #range == 4 then + if type(range) == 'table' and #range == 4 then local start_row, start_col, end_row, end_col = unpack(range) -- Easy case, this is a buffer parser -- TODO(vigoux): proper byte computation here, and account for EOL ? @@ -303,7 +303,9 @@ end --- instead of using the entire nodes range. ---@private function LanguageTree:_get_injections() - if not self._injection_query then return {} end + if not self._injection_query then + return {} + end local injections = {} @@ -311,7 +313,9 @@ function LanguageTree:_get_injections() local root_node = tree:root() local start_line, _, end_line, _ = root_node:range() - for pattern, match, metadata in self._injection_query:iter_matches(root_node, self._source, start_line, end_line+1) do + for pattern, match, metadata in + self._injection_query:iter_matches(root_node, self._source, start_line, end_line + 1) + do local lang = nil local ranges = {} local combined = metadata.combined @@ -322,8 +326,8 @@ function LanguageTree:_get_injections() local content = metadata.content -- Allow for captured nodes to be used - if type(content) == "number" then - content = {match[content]} + if type(content) == 'number' then + content = { match[content] } end if content then @@ -342,15 +346,15 @@ function LanguageTree:_get_injections() local name = self._injection_query.captures[id] -- Lang should override any other language tag - if name == "language" and not lang then + if name == 'language' and not lang then lang = query.get_node_text(node, self._source) - elseif name == "combined" then + elseif name == 'combined' then combined = true - elseif name == "content" and #ranges == 0 then + elseif name == 'content' and #ranges == 0 then table.insert(ranges, node) - -- Ignore any tags that start with "_" - -- Allows for other tags to be used in matches - elseif string.sub(name, 1, 1) ~= "_" then + -- Ignore any tags that start with "_" + -- Allows for other tags to be used in matches + elseif string.sub(name, 1, 1) ~= '_' then if not lang then lang = name end @@ -414,10 +418,19 @@ function LanguageTree:_do_callback(cb_name, ...) end ---@private -function LanguageTree:_on_bytes(bufnr, changed_tick, - start_row, start_col, start_byte, - old_row, old_col, old_byte, - new_row, new_col, new_byte) +function LanguageTree:_on_bytes( + bufnr, + changed_tick, + start_row, + start_col, + start_byte, + old_row, + old_col, + old_byte, + new_row, + new_col, + new_byte +) self:invalidate() local old_end_col = old_col + ((old_row == 0) and start_col or 0) @@ -426,16 +439,33 @@ function LanguageTree:_on_bytes(bufnr, changed_tick, -- Edit all trees recursively, together BEFORE emitting a bytes callback. -- In most cases this callback should only be called from the root tree. self:for_each_tree(function(tree) - tree:edit(start_byte,start_byte+old_byte,start_byte+new_byte, - start_row, start_col, - start_row+old_row, old_end_col, - start_row+new_row, new_end_col) + tree:edit( + start_byte, + start_byte + old_byte, + start_byte + new_byte, + start_row, + start_col, + start_row + old_row, + old_end_col, + start_row + new_row, + new_end_col + ) end) - self:_do_callback('bytes', bufnr, changed_tick, - start_row, start_col, start_byte, - old_row, old_col, old_byte, - new_row, new_col, new_byte) + self:_do_callback( + 'bytes', + bufnr, + changed_tick, + start_row, + start_col, + start_byte, + old_row, + old_col, + old_byte, + new_row, + new_col, + new_byte + ) end ---@private @@ -443,7 +473,6 @@ function LanguageTree:_on_reload() self:invalidate(true) end - ---@private function LanguageTree:_on_detach(...) self:invalidate(true) @@ -459,7 +488,9 @@ end --- - `on_child_added` : emitted when a child is added to the tree. --- - `on_child_removed` : emitted when a child is removed from the tree. function LanguageTree:register_cbs(cbs) - if not cbs then return end + if not cbs then + return + end if cbs.on_changedtree then table.insert(self._callbacks.changedtree, cbs.on_changedtree) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 8383551b5f..3c4c8fdb96 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -1,5 +1,5 @@ local a = vim.api -local language = require'vim.treesitter.language' +local language = require('vim.treesitter.language') -- query: pattern matching on trees -- predicate matching is implemented in lua @@ -43,7 +43,9 @@ function M.get_query_files(lang, query_name, is_included) local query_path = string.format('queries/%s/%s.scm', lang, query_name) local lang_files = dedupe_files(a.nvim_get_runtime_file(query_path, true)) - if #lang_files == 0 then return {} end + if #lang_files == 0 then + return {} + end local base_langs = {} @@ -52,7 +54,7 @@ function M.get_query_files(lang, query_name, is_included) -- ;+ inherits: ({language},)*{language} -- -- {language} ::= {lang} | ({lang}) - local MODELINE_FORMAT = "^;+%s*inherits%s*:?%s*([a-z_,()]+)%s*$" + local MODELINE_FORMAT = '^;+%s*inherits%s*:?%s*([a-z_,()]+)%s*$' for _, file in ipairs(lang_files) do local modeline = safe_read(file, '*l') @@ -62,7 +64,7 @@ function M.get_query_files(lang, query_name, is_included) if langlist then for _, incllang in ipairs(vim.split(langlist, ',', true)) do - local is_optional = incllang:match("%(.*%)") + local is_optional = incllang:match('%(.*%)') if is_optional then if not is_included then @@ -90,7 +92,7 @@ end local function read_query_files(filenames) local contents = {} - for _,filename in ipairs(filenames) do + for _, filename in ipairs(filenames) do table.insert(contents, safe_read(filename, '*a')) end @@ -142,7 +144,7 @@ local query_cache = setmetatable({}, { __index = function(tbl, key) rawset(tbl, key, {}) return rawget(tbl, key) - end + end, }) --- Parse {query} as a string. (If the query is in a file, the caller @@ -185,7 +187,7 @@ function M.get_node_text(node, source) local start_row, start_col, start_byte = node:start() local end_row, end_col, end_byte = node:end_() - if type(source) == "number" then + if type(source) == 'number' then local lines local eof_row = a.nvim_buf_line_count(source) if start_row >= eof_row then @@ -201,56 +203,56 @@ function M.get_node_text(node, source) if #lines > 0 then if #lines == 1 then - lines[1] = string.sub(lines[1], start_col+1, end_col) + lines[1] = string.sub(lines[1], start_col + 1, end_col) else - lines[1] = string.sub(lines[1], start_col+1) + lines[1] = string.sub(lines[1], start_col + 1) lines[#lines] = string.sub(lines[#lines], 1, end_col) end end - return table.concat(lines, "\n") - elseif type(source) == "string" then - return source:sub(start_byte+1, end_byte) + return table.concat(lines, '\n') + elseif type(source) == 'string' then + return source:sub(start_byte + 1, end_byte) end end -- Predicate handler receive the following arguments -- (match, pattern, bufnr, predicate) local predicate_handlers = { - ["eq?"] = function(match, _, source, predicate) - local node = match[predicate[2]] - local node_text = M.get_node_text(node, source) - - local str - if type(predicate[3]) == "string" then - -- (#eq? @aa "foo") - str = predicate[3] - else - -- (#eq? @aa @bb) - str = M.get_node_text(match[predicate[3]], source) - end + ['eq?'] = function(match, _, source, predicate) + local node = match[predicate[2]] + local node_text = M.get_node_text(node, source) - if node_text ~= str or str == nil then - return false - end + local str + if type(predicate[3]) == 'string' then + -- (#eq? @aa "foo") + str = predicate[3] + else + -- (#eq? @aa @bb) + str = M.get_node_text(match[predicate[3]], source) + end + + if node_text ~= str or str == nil then + return false + end - return true + return true end, - ["lua-match?"] = function(match, _, source, predicate) - local node = match[predicate[2]] - local regex = predicate[3] - return string.find(M.get_node_text(node, source), regex) + ['lua-match?'] = function(match, _, source, predicate) + local node = match[predicate[2]] + local regex = predicate[3] + return string.find(M.get_node_text(node, source), regex) end, - ["match?"] = (function() - local magic_prefixes = {['\\v']=true, ['\\m']=true, ['\\M']=true, ['\\V']=true} + ['match?'] = (function() + local magic_prefixes = { ['\\v'] = true, ['\\m'] = true, ['\\M'] = true, ['\\V'] = true } ---@private local function check_magic(str) - if string.len(str) < 2 or magic_prefixes[string.sub(str,1,2)] then + if string.len(str) < 2 or magic_prefixes[string.sub(str, 1, 2)] then return str end - return '\\v'..str + return '\\v' .. str end local compiled_vim_regexes = setmetatable({}, { @@ -258,7 +260,7 @@ local predicate_handlers = { local res = vim.regex(check_magic(pattern)) rawset(t, pattern, res) return res - end + end, }) return function(match, _, source, pred) @@ -268,11 +270,11 @@ local predicate_handlers = { end end)(), - ["contains?"] = function(match, _, source, predicate) + ['contains?'] = function(match, _, source, predicate) local node = match[predicate[2]] local node_text = M.get_node_text(node, source) - for i=3,#predicate do + for i = 3, #predicate do if string.find(node_text, predicate[i], 1, true) then return true end @@ -281,19 +283,19 @@ local predicate_handlers = { return false end, - ["any-of?"] = function(match, _, source, predicate) + ['any-of?'] = function(match, _, source, predicate) local node = match[predicate[2]] local node_text = M.get_node_text(node, source) -- Since 'predicate' will not be used by callers of this function, use it -- to store a string set built from the list of words to check against. - local string_set = predicate["string_set"] + local string_set = predicate['string_set'] if not string_set then string_set = {} - for i=3,#predicate do + for i = 3, #predicate do string_set[predicate[i]] = true end - predicate["string_set"] = string_set + predicate['string_set'] = string_set end return string_set[node_text] @@ -301,15 +303,14 @@ local predicate_handlers = { } -- As we provide lua-match? also expose vim-match? -predicate_handlers["vim-match?"] = predicate_handlers["match?"] - +predicate_handlers['vim-match?'] = predicate_handlers['match?'] -- Directives store metadata or perform side effects against a match. -- Directives should always end with a `!`. -- Directive handler receive the following arguments -- (match, pattern, bufnr, predicate, metadata) local directive_handlers = { - ["set!"] = function(_, _, _, pred, metadata) + ['set!'] = function(_, _, _, pred, metadata) if #pred == 4 then -- (#set! @capture "key" "value") local capture = pred[2] @@ -324,9 +325,9 @@ local directive_handlers = { end, -- Shifts the range of a node. -- Example: (#offset! @_node 0 1 0 -1) - ["offset!"] = function(match, _, _, pred, metadata) + ['offset!'] = function(match, _, _, pred, metadata) local offset_node = match[pred[2]] - local range = {offset_node:range()} + local range = { offset_node:range() } local start_row_offset = pred[3] or 0 local start_col_offset = pred[4] or 0 local end_row_offset = pred[5] or 0 @@ -339,9 +340,9 @@ local directive_handlers = { -- If this produces an invalid range, we just skip it. if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then - metadata.content = {range} + metadata.content = { range } end - end + end, } --- Adds a new predicate to be used in queries @@ -351,7 +352,7 @@ local directive_handlers = { --- signature will be (match, pattern, bufnr, predicate) function M.add_predicate(name, handler, force) if predicate_handlers[name] and not force then - error(string.format("Overriding %s", name)) + error(string.format('Overriding %s', name)) end predicate_handlers[name] = handler @@ -364,7 +365,7 @@ end --- signature will be (match, pattern, bufnr, predicate) function M.add_directive(name, handler, force) if directive_handlers[name] and not force then - error(string.format("Overriding %s", name)) + error(string.format('Overriding %s', name)) end directive_handlers[name] = handler @@ -387,7 +388,7 @@ end ---@private local function is_directive(name) - return string.sub(name, -1) == "!" + return string.sub(name, -1) == '!' end ---@private @@ -404,7 +405,7 @@ function Query:match_preds(match, pattern, source) -- Skip over directives... they will get processed after all the predicates. if not is_directive(pred[1]) then - if string.sub(pred[1], 1, 4) == "not-" then + if string.sub(pred[1], 1, 4) == 'not-' then pred_name = string.sub(pred[1], 5) is_not = true else @@ -415,7 +416,7 @@ function Query:match_preds(match, pattern, source) local handler = predicate_handlers[pred_name] if not handler then - error(string.format("No handler for %s", pred[1])) + error(string.format('No handler for %s', pred[1])) return false end @@ -438,7 +439,7 @@ function Query:apply_directives(match, pattern, source, metadata) local handler = directive_handlers[pred[1]] if not handler then - error(string.format("No handler for %s", pred[1])) + error(string.format('No handler for %s', pred[1])) return end @@ -447,7 +448,6 @@ function Query:apply_directives(match, pattern, source, metadata) end end - --- Returns the start and stop value if set else the node's range. -- When the node's range is used, the stop is incremented by 1 -- to make the search inclusive. @@ -492,7 +492,7 @@ end ---@returns The matching capture id ---@returns The captured node function Query:iter_captures(node, source, start, stop) - if type(source) == "number" and source == 0 then + if type(source) == 'number' and source == 0 then source = vim.api.nvim_get_current_buf() end @@ -549,7 +549,7 @@ end ---@returns The matching pattern id ---@returns The matching match function Query:iter_matches(node, source, start, stop) - if type(source) == "number" and source == 0 then + if type(source) == 'number' and source == 0 then source = vim.api.nvim_get_current_buf() end diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 165dada1b8..77bca7f6c4 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -37,12 +37,12 @@ local M = {} --- function M.select(items, opts, on_choice) - vim.validate { + vim.validate({ items = { items, 'table', false }, on_choice = { on_choice, 'function', false }, - } + }) opts = opts or {} - local choices = {opts.prompt or 'Select one of:'} + local choices = { opts.prompt or 'Select one of:' } local format_item = opts.format_item or tostring for i, item in pairs(items) do table.insert(choices, string.format('%d: %s', i, format_item(item))) @@ -83,9 +83,9 @@ end --- end) --- function M.input(opts, on_confirm) - vim.validate { + vim.validate({ on_confirm = { on_confirm, 'function', false }, - } + }) opts = opts or {} local input = vim.fn.input(opts) diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua index 11b661cd1a..d6b0b7410e 100644 --- a/runtime/lua/vim/uri.lua +++ b/runtime/lua/vim/uri.lua @@ -3,7 +3,6 @@ -- https://tools.ietf.org/html/rfc2732 -- https://tools.ietf.org/html/rfc2396 - local uri_decode do local schar = string.char @@ -14,7 +13,7 @@ do return schar(tonumber(hex, 16)) end uri_decode = function(str) - return str:gsub("%%([a-fA-F0-9][a-fA-F0-9])", hex_to_char) + return str:gsub('%%([a-fA-F0-9][a-fA-F0-9])', hex_to_char) end end @@ -23,33 +22,36 @@ do local PATTERNS = { --- RFC 2396 -- https://tools.ietf.org/html/rfc2396#section-2.2 - rfc2396 = "^A-Za-z0-9%-_.!~*'()"; + rfc2396 = "^A-Za-z0-9%-_.!~*'()", --- RFC 2732 -- https://tools.ietf.org/html/rfc2732 - rfc2732 = "^A-Za-z0-9%-_.!~*'()[]"; + rfc2732 = "^A-Za-z0-9%-_.!~*'()[]", --- RFC 3986 -- https://tools.ietf.org/html/rfc3986#section-2.2 - rfc3986 = "^A-Za-z0-9%-._~!$&'()*+,;=:@/"; + rfc3986 = "^A-Za-z0-9%-._~!$&'()*+,;=:@/", } local sbyte, tohex = string.byte if jit then - tohex = require'bit'.tohex + tohex = require('bit').tohex else - tohex = function(b) return string.format("%02x", b) end + tohex = function(b) + return string.format('%02x', b) + end end ---@private local function percent_encode_char(char) - return "%"..tohex(sbyte(char), 2) + return '%' .. tohex(sbyte(char), 2) end uri_encode = function(text, rfc) - if not text then return end + if not text then + return + end local pattern = PATTERNS[rfc] or PATTERNS.rfc3986 - return text:gsub("(["..pattern.."])", percent_encode_char) + return text:gsub('([' .. pattern .. '])', percent_encode_char) end end - ---@private local function is_windows_file_uri(uri) return uri:match('^file:/+[a-zA-Z]:') ~= nil @@ -59,16 +61,16 @@ end ---@param path string Path to file ---@return string URI local function uri_from_fname(path) - local volume_path, fname = path:match("^([a-zA-Z]:)(.*)") + local volume_path, fname = path:match('^([a-zA-Z]:)(.*)') local is_windows = volume_path ~= nil if is_windows then - path = volume_path..uri_encode(fname:gsub("\\", "/")) + path = volume_path .. uri_encode(fname:gsub('\\', '/')) else path = uri_encode(path) end - local uri_parts = {"file://"} + local uri_parts = { 'file://' } if is_windows then - table.insert(uri_parts, "/") + table.insert(uri_parts, '/') end table.insert(uri_parts, path) return table.concat(uri_parts) @@ -82,11 +84,11 @@ local WINDOWS_URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9.+-]*):[a-zA-Z]:.*' ---@return string URI local function uri_from_bufnr(bufnr) local fname = vim.api.nvim_buf_get_name(bufnr) - local volume_path = fname:match("^([a-zA-Z]:).*") + local volume_path = fname:match('^([a-zA-Z]:).*') local is_windows = volume_path ~= nil local scheme if is_windows then - fname = fname:gsub("\\", "/") + fname = fname:gsub('\\', '/') scheme = fname:match(WINDOWS_URI_SCHEME_PATTERN) else scheme = fname:match(URI_SCHEME_PATTERN) -- cgit From c55867b46d6758c4ff2e55d1bfb4cfc163182a12 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 9 May 2022 18:08:04 +0200 Subject: docs(lsp): fix description of `only` in vim.lsp.buf.code_action() (#18492) --- runtime/lua/vim/lsp/buf.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 6666b3c044..9b34a551b7 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -783,8 +783,8 @@ end --- - diagnostics (table|nil): --- LSP `Diagnostic[]`. Inferred from the current --- position if not provided. ---- - only (string|nil): ---- LSP `CodeActionKind` used to filter the code actions. +--- - only (table|nil): +--- List of LSP `CodeActionKind`s used to filter the code actions. --- Most language servers support values like `refactor` --- or `quickfix`. --- - filter (function|nil): @@ -817,8 +817,8 @@ end --- - diagnostics: (table|nil) --- LSP `Diagnostic[]`. Inferred from the current --- position if not provided. ---- - only: (string|nil) ---- LSP `CodeActionKind` used to filter the code actions. +--- - only: (table|nil) +--- List of LSP `CodeActionKind`s used to filter the code actions. --- Most language servers support values like `refactor` --- or `quickfix`. ---@param start_pos ({number, number}, optional) mark-indexed position. -- cgit From a6f4cfdefa6937b7a0a364277a8157d483631f6d Mon Sep 17 00:00:00 2001 From: adrian5 Date: Wed, 11 May 2022 18:23:46 +0200 Subject: docs(api): improve shared lua functions docs (#17933) --- runtime/lua/vim/shared.lua | 142 +++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 68 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index d9dc77e219..9bbe356f03 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -15,7 +15,7 @@ local vim = vim or {} --- copied and will throw an error. --- ---@param orig table Table to copy ----@returns New table of copied keys and (nested) values. +---@return table Table of copied keys and (nested) values. function vim.deepcopy(orig) end -- luacheck: no unused vim.deepcopy = (function() local function _id(v) @@ -59,10 +59,10 @@ end)() ---@see https://www.lua.org/pil/20.2.html ---@see http://lua-users.org/wiki/StringLibraryTutorial --- ----@param s String to split ----@param sep Separator string or pattern ----@param plain If `true` use `sep` literally (passed to String.find) ----@returns Iterator over the split components +---@param s string String to split +---@param sep string Separator or pattern +---@param plain boolean If `true` use `sep` literally (passed to string.find) +---@return function Iterator over the split components function vim.gsplit(s, sep, plain) vim.validate({ s = { s, 's' }, sep = { sep, 's' }, plain = { plain, 'b', true } }) @@ -107,13 +107,13 @@ end --- ---@see |vim.gsplit()| --- ----@param s String to split ----@param sep Separator string or pattern ----@param kwargs Keyword arguments: +---@param s string String to split +---@param sep string Separator or pattern +---@param kwargs table Keyword arguments: --- - plain: (boolean) If `true` use `sep` literally (passed to string.find) --- - trimempty: (boolean) If `true` remove empty items from the front --- and back of the list ----@returns List-like table of the split components. +---@return table List of split components function vim.split(s, sep, kwargs) local plain local trimempty = false @@ -156,8 +156,8 @@ end --- ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@param t Table ----@returns list of keys +---@param t table Table +---@return table List of keys function vim.tbl_keys(t) assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) @@ -171,8 +171,8 @@ end --- Return a list of all values used in a table. --- However, the order of the return table of values is not guaranteed. --- ----@param t Table ----@returns list of values +---@param t table Table +---@return table List of values function vim.tbl_values(t) assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) @@ -185,8 +185,9 @@ end --- Apply a function to all values of a table. --- ----@param func function or callable table ----@param t table +---@param func function|table Function or callable table +---@param t table Table +---@return table Table of transformed values function vim.tbl_map(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) @@ -199,8 +200,9 @@ end --- Filter a table using a predicate function --- ----@param func function or callable table ----@param t table +---@param func function|table Function or callable table +---@param t table Table +---@return table Table of filtered values function vim.tbl_filter(func, t) vim.validate({ func = { func, 'c' }, t = { t, 't' } }) @@ -215,9 +217,9 @@ end --- Checks if a list-like (vector) table contains `value`. --- ----@param t Table to check ----@param value Value to compare ----@returns true if `t` contains `value` +---@param t table Table to check +---@param value any Value to compare +---@return boolean `true` if `t` contains `value` function vim.tbl_contains(t, value) vim.validate({ t = { t, 't' } }) @@ -233,13 +235,14 @@ end --- ---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@param t Table to check +---@param t table Table to check +---@return boolean `true` if `t` is empty function vim.tbl_isempty(t) assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) return next(t) == nil end ---- we only merge empty tables or tables that are not a list +--- We only merge empty tables or tables that are not a list ---@private local function can_merge(v) return type(v) == 'table' and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) @@ -283,11 +286,12 @@ end --- ---@see |extend()| --- ----@param behavior Decides what to do if a key is found in more than one map: +---@param behavior string Decides what to do if a key is found in more than one map: --- - "error": raise an error --- - "keep": use value from the leftmost map --- - "force": use value from the rightmost map ----@param ... Two or more map-like tables. +---@param ... table Two or more map-like tables +---@return table Merged table function vim.tbl_extend(behavior, ...) return tbl_extend(behavior, false, ...) end @@ -296,22 +300,23 @@ end --- ---@see |tbl_extend()| --- ----@param behavior Decides what to do if a key is found in more than one map: +---@param behavior string Decides what to do if a key is found in more than one map: --- - "error": raise an error --- - "keep": use value from the leftmost map --- - "force": use value from the rightmost map ----@param ... Two or more map-like tables. +---@param ... table Two or more map-like tables +---@return table Merged table function vim.tbl_deep_extend(behavior, ...) return tbl_extend(behavior, true, ...) end --- Deep compare values for equality --- ---- Tables are compared recursively unless they both provide the `eq` methamethod. +--- Tables are compared recursively unless they both provide the `eq` metamethod. --- All other types are compared using the equality `==` operator. ----@param a first value ----@param b second value ----@returns `true` if values are equals, else `false`. +---@param a any First value +---@param b any Second value +---@return boolean `true` if values are equals, else `false` function vim.deep_equal(a, b) if a == b then return true @@ -338,9 +343,10 @@ end --- Add the reverse lookup values to an existing table. --- For example: --- ``tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`` --- ---Do note that it *modifies* the input. ----@param o table The table to add the reverse to. +--- +--- Note that this *modifies* the input. +---@param o table Table to add the reverse to +---@return table o function vim.tbl_add_reverse_lookup(o) local keys = vim.tbl_keys(o) for _, k in ipairs(keys) do @@ -361,17 +367,17 @@ end --- Index into a table (first argument) via string keys passed as subsequent arguments. --- Return `nil` if the key does not exist. ---_ +--- --- Examples: ---
 ---  vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true
 ---  vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil
 --- 
--- ----@param o Table to index ----@param ... Optional strings (0 or more, variadic) via which to index the table +---@param o table Table to index +---@param ... string Optional strings (0 or more, variadic) via which to index the table --- ----@returns nested value indexed by key if it exists, else nil +---@return any Nested value indexed by key (if it exists), else nil function vim.tbl_get(o, ...) local keys = { ... } if #keys == 0 then @@ -395,11 +401,11 @@ end --- ---@see |vim.tbl_extend()| --- ----@param dst list which will be modified and appended to. ----@param src list from which values will be inserted. ----@param start Start index on src. defaults to 1 ----@param finish Final index on src. defaults to #src ----@returns dst +---@param dst table List which will be modified and appended to +---@param src table List from which values will be inserted +---@param start number Start index on src. Defaults to 1 +---@param finish number Final index on src. Defaults to `#src` +---@return table dst function vim.list_extend(dst, src, start, finish) vim.validate({ dst = { dst, 't' }, @@ -418,8 +424,8 @@ end --- ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ----@param t List-like table ----@returns Flattened copy of the given list-like table. +---@param t table List-like table +---@return table Flattened copy of the given list-like table function vim.tbl_flatten(t) local result = {} local function _tbl_flatten(_t) @@ -443,8 +449,8 @@ end --- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result, --- for example from |rpcrequest()| or |vim.fn|. --- ----@param t Table ----@returns `true` if array-like table, else `false`. +---@param t table Table +---@return boolean `true` if array-like table, else `false` function vim.tbl_islist(t) if type(t) ~= 'table' then return false @@ -480,8 +486,8 @@ end --- --- ---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua ----@param t Table ----@returns Number that is the number of the value in table +---@param t table Table +---@return number Number of non-nil values in table function vim.tbl_count(t) vim.validate({ t = { t, 't' } }) @@ -494,10 +500,10 @@ end --- Creates a copy of a table containing only elements from start to end (inclusive) --- ----@param list table table ----@param start integer Start range of slice ----@param finish integer End range of slice ----@returns Copy of table sliced from start to finish (inclusive) +---@param list table Table +---@param start number Start range of slice +---@param finish number End range of slice +---@return table Copy of table sliced from start to finish (inclusive) function vim.list_slice(list, start, finish) local new_list = {} for i = start or 1, finish or #list do @@ -509,8 +515,8 @@ end --- Trim whitespace (Lua pattern "%s") from both sides of a string. --- ---@see https://www.lua.org/pil/20.2.html ----@param s String to trim ----@returns String with whitespace removed from its beginning and end +---@param s string String to trim +---@return string String with whitespace removed from its beginning and end function vim.trim(s) vim.validate({ s = { s, 's' } }) return s:match('^%s*(.*%S)') or '' @@ -519,8 +525,8 @@ end --- Escapes magic chars in a Lua pattern. --- ---@see https://github.com/rxi/lume ----@param s String to escape ----@returns %-escaped pattern string +---@param s string String to escape +---@return string %-escaped pattern string function vim.pesc(s) vim.validate({ s = { s, 's' } }) return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1') @@ -528,9 +534,9 @@ end --- Tests if `s` starts with `prefix`. --- ----@param s (string) a string ----@param prefix (string) a prefix ----@return (boolean) true if `prefix` is a prefix of s +---@param s string String +---@param prefix string Prefix to match +---@return boolean `true` if `prefix` is a prefix of `s` function vim.startswith(s, prefix) vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } }) return s:sub(1, #prefix) == prefix @@ -538,9 +544,9 @@ end --- Tests if `s` ends with `suffix`. --- ----@param s (string) a string ----@param suffix (string) a suffix ----@return (boolean) true if `suffix` is a suffix of s +---@param s string String +---@param suffix string Suffix to match +---@return boolean `true` if `suffix` is a suffix of `s` function vim.endswith(s, suffix) vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } }) return #suffix == 0 or s:sub(-#suffix) == suffix @@ -582,7 +588,7 @@ end --- --- --- ----@param opt table of parameter names to validations. Each key is a parameter +---@param opt table Names of parameters to validate. Each key is a parameter --- name; each value is a tuple in one of these forms: --- 1. (arg_value, type_name, optional) --- - arg_value: argument value @@ -632,8 +638,8 @@ do return false, string.format('opt[%s]: expected table, got %s', param_name, type(spec)) end - local val = spec[1] -- Argument value. - local types = spec[2] -- Type name, or callable. + local val = spec[1] -- Argument value + local types = spec[2] -- Type name, or callable local optional = (true == spec[3]) if type(types) == 'string' then @@ -641,7 +647,7 @@ do end if vim.is_callable(types) then - -- Check user-provided validation function. + -- Check user-provided validation function local valid, optional_message = types(val) if not valid then local error_message = string.format('%s: expected %s, got %s', param_name, (spec[3] or '?'), tostring(val)) @@ -685,8 +691,8 @@ do end --- Returns true if object `f` can be called as a function. --- ----@param f Any object ----@return true if `f` is callable, else false +---@param f any Any object +---@return boolean `true` if `f` is callable, else `false` function vim.is_callable(f) if type(f) == 'function' then return true -- cgit From 2bbd588e73c4c0c17e497fafd281ceba382b9e4d Mon Sep 17 00:00:00 2001 From: Famiu Haque Date: Thu, 12 May 2022 19:34:38 +0600 Subject: feat(lua): vim.cmd() with kwargs acts like nvim_cmd() #18523 --- runtime/lua/vim/_editor.lua | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 9bdbf6d1c7..98921463b3 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -284,9 +284,33 @@ vim.funcref = function(viml_func_name) return vim.fn[viml_func_name] end --- An easier alias for commands. -vim.cmd = function(command) - return vim.api.nvim_exec(command, false) +--- Execute Vim script commands. +--- +--- Example: +---
+---   vim.cmd('echo 42')
+---   vim.cmd([[
+---     augroup My_group
+---       autocmd!
+---       autocmd FileType c setlocal cindent
+---     augroup END
+---   ]])
+---   vim.cmd({ cmd = 'echo', args = { '"foo"' } })
+--- 
+--- +---@param command string|table Command(s) to execute. +--- If a string, executes multiple lines of Vim script at once. In this +--- case, it is an alias to |nvim_exec()|, where `output` is set to +--- false. Thus it works identical to |:source|. +--- If a table, executes a single command. In this case, it is an alias +--- to |nvim_cmd()| where `opts` is empty. +---@see |ex-cmd-index| +function vim.cmd(command) + if type(command) == 'table' then + return vim.api.nvim_cmd(command, {}) + else + return vim.api.nvim_exec(command, false) + end end -- These are the vim.env/v/g/o/bo/wo variable magic accessors. -- cgit From 78a1e6bc0060eec1afa7de099c4cee35ca35527f Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 6 Sep 2021 20:35:34 +0300 Subject: feat(defaults): session data in $XDG_STATE_HOME #15583 See: https://gitlab.freedesktop.org/xdg/xdg-specs/-/commit/4f2884e16db35f2962d9b64312917c81be5cb54b - Move session persistent data to $XDG_STATE_HOME Change 'directory', 'backupdir', 'undodir', 'viewdir' and 'shadafile' default location to $XDG_STATE_HOME/nvim. - Move logs to $XDG_STATE_HOME, too. - Add stdpath('log') support. Fixes: #14805 --- runtime/lua/vim/lsp/log.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 66e82ecfeb..29cb27d373 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -25,12 +25,12 @@ do local function path_join(...) return table.concat(vim.tbl_flatten({ ... }), path_sep) end - local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') + local logfilename = path_join(vim.fn.stdpath('log'), 'lsp.log') -- TODO: Ideally the directory should be created in open_logfile(), right -- before opening the log file, but open_logfile() can be called from libuv -- callbacks, where using fn.mkdir() is not allowed. - vim.fn.mkdir(vim.fn.stdpath('cache'), 'p') + vim.fn.mkdir(vim.fn.stdpath('log'), 'p') --- Returns the log filename. ---@returns (string) log filename -- cgit From a9d25e94725d5cfc41c2fabff22b2284e109fa0c Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Thu, 12 May 2022 18:48:02 +0200 Subject: fix(lsp): perform client side filtering of code actions (#18392) Implement filtering of actions based on the kind when passing the 'only' parameter to code_action(). Action kinds are hierachical with a '.' as the separator, and the filter thus allows, for example, both 'quickfix' and 'quickfix.foo' when requestiong only 'quickfix'. Fix https://github.com/neovim/neovim/pull/18221#issuecomment-1110179121 --- runtime/lua/vim/lsp/buf.lua | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 1cfbcd1259..b0bf2c6e5b 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -691,10 +691,38 @@ end --- `codeAction/resolve` local function on_code_action_results(results, ctx, options) local action_tuples = {} - local filter = options and options.filter + + ---@private + local function action_filter(a) + -- filter by specified action kind + if options and options.context and options.context.only then + if not a.kind then + return false + end + local found = false + for _, o in ipairs(options.context.only) do + -- action kinds are hierachical with . as a separator: when requesting only + -- 'quickfix' this filter allows both 'quickfix' and 'quickfix.foo', for example + if a.kind:find('^' .. o .. '$') or a.kind:find('^' .. o .. '%.') then + found = true + break + end + end + if not found then + return false + end + end + -- filter by user function + if options and options.filter and not options.filter(a) then + return false + end + -- no filter removed this action + return true + end + for client_id, result in pairs(results) do for _, action in pairs(result.result or {}) do - if not filter or filter(action) then + if action_filter(action) then table.insert(action_tuples, { client_id, action }) end end -- cgit From a33caf9b45f8d0832e9de07669fbc33ed4efafd9 Mon Sep 17 00:00:00 2001 From: kevinhwang91 Date: Fri, 13 May 2022 14:16:47 +0800 Subject: perf(_editor): no need to stop inside vim.defer_fn uv_run: 1. remove timer handle from heap 2. will start again if repeat is not 0 --- runtime/lua/vim/_editor.lua | 1 - 1 file changed, 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 98921463b3..ac9adada39 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -406,7 +406,6 @@ function vim.defer_fn(fn, timeout) timeout, 0, vim.schedule_wrap(function() - timer:stop() timer:close() fn() -- cgit From e501e4ed4ba86da12a9b4747fdc326b8366a38be Mon Sep 17 00:00:00 2001 From: ii14 <59243201+ii14@users.noreply.github.com> Date: Mon, 16 May 2022 03:07:36 +0200 Subject: feat(lua): add traceback to vim.deprecate #18575 --- runtime/lua/vim/_editor.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 98921463b3..dc25d68f61 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -446,11 +446,14 @@ do ---@param msg string Content of the notification to show to the user. ---@param level number|nil One of the values from |vim.log.levels|. ---@param opts table|nil Optional parameters. Unused by default. - function vim.notify_once(msg, level, opts) -- luacheck: no unused args + ---@return boolean true if message was displayed, else false + function vim.notify_once(msg, level, opts) if not notified[msg] then vim.notify(msg, level, opts) notified[msg] = true + return true end + return false end end @@ -784,12 +787,15 @@ end --- be removed. ---@param plugin string|nil Plugin name that the function will be removed --- from. Defaults to "Nvim". -function vim.deprecate(name, alternative, version, plugin) +---@param backtrace boolean|nil Prints backtrace. Defaults to true. +function vim.deprecate(name, alternative, version, plugin, backtrace) local message = name .. ' is deprecated' plugin = plugin or 'Nvim' message = alternative and (message .. ', use ' .. alternative .. ' instead.') or message message = message .. ' See :h deprecated\nThis function will be removed in ' .. plugin .. ' version ' .. version - vim.notify_once(message, vim.log.levels.WARN) + if vim.notify_once(message, vim.log.levels.WARN) and backtrace ~= false then + vim.notify(debug.traceback('', 2):sub(2), vim.log.levels.WARN) + end end require('vim._meta') -- cgit From 7ffa9073a39652658ffd9cefb039d9ad76af61ca Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Tue, 17 May 2022 19:48:45 +0200 Subject: refactor(runtime): convert more dist#ft functions to lua (#18430) --- runtime/lua/vim/filetype.lua | 100 +++---- runtime/lua/vim/filetype/detect.lua | 573 ++++++++++++++++++++++++++++++++---- 2 files changed, 565 insertions(+), 108 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index fed0231ae9..8321e0b11e 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -810,11 +810,11 @@ local extension = { R = function(path, bufnr) require('vim.filetype.detect').r(bufnr) end, - asm = function() - vim.fn['dist#ft#FTasm']() + asm = function(path, bufnr) + require('vim.filetype.detect').asm(bufnr) end, - bas = function() - vim.fn['dist#ft#FTbas']() + bas = function(path, bufnr) + require('vim.filetype.detect').bas(bufnr) end, bi = function() vim.fn['dist#ft#FTbas']() @@ -828,11 +828,11 @@ local extension = { btm = function(path, bufnr) return require('vim.filetype.detect').btm(bufnr) end, - c = function() - vim.fn['dist#ft#FTlpc']() + c = function(path, bufnr) + return require('vim.filetype.detect').lpc(bufnr) end, - ch = function() - vim.fn['dist#ft#FTchange']() + ch = function(path, bufnr) + return require('vim.filetype.detect').change(bufnr) end, com = function() vim.fn['dist#ft#BindzoneCheck']('dcl') @@ -843,8 +843,8 @@ local extension = { csh = function() vim.fn['dist#ft#CSH']() end, - d = function() - vim.fn['dist#ft#DtraceCheck']() + d = function(path, bufnr) + return require('vim.filetype.detect').dtrace(bufnr) end, db = function() vim.fn['dist#ft#BindzoneCheck']('') @@ -862,30 +862,30 @@ local extension = { vim.fn['dist#ft#SetFileTypeSH']('bash') end, ent = function(path, bufnr) - return require('vim.filetype.detect').ent(bufnr) + require('vim.filetype.detect').ent(bufnr) end, env = function() vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) end, eu = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + require('vim.filetype.detect').euphoria(bufnr) end, ew = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + require('vim.filetype.detect').euphoria(bufnr) end, ex = function(path, bufnr) - return require('vim.filetype.detect').ex(bufnr) + require('vim.filetype.detect').ex(bufnr) end, exu = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + require('vim.filetype.detect').euphoria(bufnr) end, exw = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + require('vim.filetype.detect').euphoria(bufnr) end, frm = function(path, bufnr) require('vim.filetype.detect').frm(bufnr) end, - fs = function() + fs = function(path, bufnr) vim.fn['dist#ft#FTfs']() end, h = function(path, bufnr) @@ -897,8 +897,8 @@ local extension = { html = function() vim.fn['dist#ft#FThtml']() end, - i = function() - vim.fn['dist#ft#FTprogress_asm']() + i = function(path, bufnr) + require('vim.filetype.detect').progress_asm(bufnr) end, idl = function(path, bufnr) require('vim.filetype.detect').idl(bufnr) @@ -912,26 +912,26 @@ local extension = { ksh = function() vim.fn['dist#ft#SetFileTypeSH']('ksh') end, - lst = function() - vim.fn['dist#ft#FTasm']() + lst = function(path, bufnr) + require('vim.filetype.detect').asm(bufnr) end, - m = function() - vim.fn['dist#ft#FTm']() + m = function(path, bufnr) + require('vim.filetype.detect').m(bufnr) end, - mac = function() - vim.fn['dist#ft#FTasm']() + mac = function(path, bufnr) + require('vim.filetype.detect').asm(bufnr) end, mc = function(path, bufnr) require('vim.filetype.detect').mc(bufnr) end, - mm = function() - vim.fn['dist#ft#FTmm']() + mm = function(path, bufnr) + require('vim.filetype.detect').mm(bufnr) end, mms = function(path, bufnr) require('vim.filetype.detect').mms(bufnr) end, - p = function() - vim.fn['dist#ft#FTprogress_pascal']() + p = function(path, bufnr) + require('vim.filetype.detect').progress_pascal(bufnr) end, patch = function(path, bufnr) local firstline = getline(bufnr, 1) @@ -959,8 +959,8 @@ local extension = { rdf = function(path, bufnr) require('vim.filetype.detect').redif(bufnr) end, - rules = function() - vim.fn['dist#ft#FTRules']() + rules = function(path, bufnr) + require('vim.filetype.detect').rules(path, bufnr) end, sc = function(path, bufnr) require('vim.filetype.detect').sc(bufnr) @@ -1559,13 +1559,13 @@ local pattern = { ['%.zlog.*'] = starsetf('zsh'), ['%.zsh.*'] = starsetf('zsh'), ['.*%.[1-9]'] = function(path, bufnr) - return require('vim.filetype.detect').nroff(bufnr) + require('vim.filetype.detect').nroff(bufnr) end, - ['.*%.[aA]'] = function() - vim.fn['dist#ft#FTasm']() + ['.*%.[aA]'] = function(path, bufnr) + require('vim.filetype.detect').asm(bufnr) end, - ['.*%.[sS]'] = function() - vim.fn['dist#ft#FTasm']() + ['.*%.[sS]'] = function(path, bufnr) + require('vim.filetype.detect').asm(bufnr) end, ['.*%.properties_.._.._.*'] = starsetf('jproperties'), ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), @@ -1575,8 +1575,8 @@ local pattern = { ['.*/Xresources/.*'] = starsetf('xdefaults'), ['.*/app%-defaults/.*'] = starsetf('xdefaults'), ['.*/bind/db%..*'] = starsetf('bindzone'), - ['.*/debian/patches/.*'] = function() - vim.fn['dist#ft#Dep3patch']() + ['.*/debian/patches/.*'] = function(path, bufnr) + require('vim.filetype.detect').dep3patch(path, bufnr) end, ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'), ['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'), @@ -1680,24 +1680,24 @@ local pattern = { return 'git' end end, - ['.*%.[Cc][Ff][Gg]'] = function() - vim.fn['dist#ft#FTcfg']() + ['.*%.[Cc][Ff][Gg]'] = function(path, bufnr) + require('vim.filetype.detect').cfg(bufnr) end, - ['.*%.[Dd][Aa][Tt]'] = function() - vim.fn['dist#ft#FTdat']() + ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr) + require('vim.filetype.detect').dat(bufnr) end, - ['.*%.[Mm][Oo][Dd]'] = function() - vim.fn['dist#ft#FTmod']() + ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr) + require('vim.filetype.detect').mod(path, bufnr) end, - ['.*%.[Ss][Rr][Cc]'] = function() - vim.fn['dist#ft#FTsrc']() + ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr) + require('vim.filetype.detect').src(bufnr) end, ['.*%.[Ss][Uu][Bb]'] = 'krl', - ['.*%.[Pp][Rr][Gg]'] = function() - vim.fn['dist#ft#FTprg']() + ['.*%.[Pp][Rr][Gg]'] = function(path, bufnr) + require('vim.filetype.detect').prg(bufnr) end, - ['.*%.[Ss][Yy][Ss]'] = function() - vim.fn['dist#ft#FTsys']() + ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr) + require('vim.filetype.detect').sys(bufnr) end, -- Neovim only ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 4c363e7403..da59625353 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -1,15 +1,28 @@ +-- Contains filetype detection functions converted to Lua from Vim's autoload/runtime/dist/ft.vim file. + +-- Here are a few guidelines to follow when porting a new function: +-- * Sort the function alphabetically and omit 'ft' or 'check' from the new function name. +-- * Use ':find' instead of ':match' / ':sub' if possible. +-- * When '=~' is used to match a pattern, there are two possibilities: +-- - If the pattern only contains lowercase characters, treat the comparison as case-insensitive. +-- - Otherwise, treat it as case-sensitive. +-- (Basically, we apply 'smartcase': if upper case characters are used in the original pattern, then +-- it's likely that case does matter). +-- * When '\k', '\<' or '\>' is used in a pattern, use the 'matchregex' function. +-- Note that vim.regex is case-sensitive by default, so add the '\c' flag if only lowercase letters +-- are present in the pattern: +-- Example: +-- `if line =~ '^\s*unwind_protect\>'` => `if matchregex(line, [[\c^\s*unwind_protect\>]])` + local M = {} ---@private -local function getlines(bufnr, start_lnum, end_lnum, opts) +local function getlines(bufnr, start_lnum, end_lnum) if not end_lnum then -- Return a single line as a string return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] end - - local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) - opts = opts or {} - return opts.concat and (table.concat(lines) or '') or lines + return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) end ---@private @@ -22,16 +35,103 @@ local function findany(s, patterns) return false end +---@private +local function nextnonblank(bufnr, start_lnum) + for _, line in ipairs(getlines(bufnr, start_lnum, -1)) do + if not line:find('^%s*$') then + return line + end + end + return nil +end + +---@private +local matchregex = (function() + local cache = {} + return function(line, pattern) + if line == nil then + return nil + end + if not cache[pattern] then + cache[pattern] = vim.regex(pattern) + end + return cache[pattern]:match_str(line) + end +end)() + -- luacheck: push no unused args -- luacheck: push ignore 122 -function M.asm(path, bufnr) end +-- This function checks for the kind of assembly that is wanted by the user, or +-- can be detected from the first five lines of the file. +function M.asm(bufnr) + -- Make sure b:asmsyntax exists + if not vim.b[bufnr].asmsyntax then + vim.b[bufnr].asmsyntax = '' + end -function M.asm_syntax(path, bufnr) end + if vim.b[bufnr].asmsyntax == '' then + M.asm_syntax(bufnr) + end -function M.bas(path, bufnr) end + -- If b:asmsyntax still isn't set, default to asmsyntax or GNU + if vim.b[bufnr].asmsyntax == '' then + if vim.g.asmsyntax and vim.g.asmsyntax ~= 0 then + vim.b[bufnr].asmsyntax = vim.g.asmsyntax + else + vim.b[bufnr].asmsyntax = 'asm' + end + end + vim.bo[bufnr].filetype = vim.fn.fnameescape(vim.b[bufnr].asmsyntax) +end + +-- Checks the first 5 lines for a asmsyntax=foo override. +-- Only whitespace characters can be present immediately before or after this statement. +function M.asm_syntax(bufnr) + local lines = table.concat(getlines(bufnr, 1, 5), ' '):lower() + local match = lines:match('%sasmsyntax=([a-zA-Z0-9]+)%s') + if match then + vim.b['asmsyntax'] = match + elseif findany(lines, { '%.title', '%.ident', '%.macro', '%.subtitle', '%.library' }) then + vim.b['asmsyntax'] = 'vmasm' + end +end -function M.bindzone(path, bufnr) end +local visual_basic_content = { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform', 'begin vb%.usercontrol' } + +-- See frm() for Visual Basic form file detection +function M.bas(bufnr) + if vim.g.filetype_bas then + vim.bo[bufnr].filetype = vim.g.filetype_bas + return + end + + -- Most frequent FreeBASIC-specific keywords in distro files + local fb_keywords = + [[\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!]] + local fb_preproc = + [[\c^\s*\%(#\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\)]] + + local fb_comment = "^%s*/'" + -- OPTION EXPLICIT, without the leading underscore, is common to many dialects + local qb64_preproc = [[\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)]] + + for _, line in ipairs(getlines(bufnr, 1, 100)) do + if line:find(fb_comment) or matchregex(line, fb_preproc) or matchregex(line, fb_keywords) then + vim.bo[bufnr].filetype = 'freebasic' + return + elseif matchregex(line, qb64_preproc) then + vim.bo[bufnr].filetype = 'qb64' + return + elseif findany(line:lower(), visual_basic_content) then + vim.bo[bufnr].filetype = 'vb' + return + end + end + vim.bo[bufnr].filetype = 'basic' +end + +function M.bindzone(bufnr, default_ft) end function M.btm(bufnr) if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then @@ -47,14 +147,11 @@ local function is_rapid(bufnr, extension) local line = getlines(bufnr, 1):lower() return findany(line, { 'eio:cfg', 'mmc:cfg', 'moc:cfg', 'proc:cfg', 'sio:cfg', 'sys:cfg' }) end - local first = '^%s*module%s+%S+%s*' - -- Called from mod, prg or sys functions - for _, line in ipairs(getlines(bufnr, 1, -1)) do - if not line:find('^%s*$') then - return findany(line:lower(), { '^%s*%%%%%%', first .. '(', first .. '$' }) - end + local line = nextnonblank(bufnr, 1) + if line then + -- Called from mod, prg or sys functions + return matchregex(line:lower(), [[\c\v^\s*%(\%{3}|module\s+\k+\s*%(\(|$))]]) end - -- Only found blank lines return false end @@ -68,17 +165,110 @@ function M.cfg(bufnr) end end -function M.change(path, bufnr) end +-- This function checks if one of the first ten lines start with a '@'. In +-- that case it is probably a change file. +-- If the first line starts with # or ! it's probably a ch file. +-- If a line has "main", "include", "//" or "/*" it's probably ch. +-- Otherwise CHILL is assumed. +function M.change(bufnr) + local first_line = getlines(bufnr, 1) + if findany(first_line, { '^#', '^!' }) then + vim.bo[bufnr].filetype = 'ch' + return + end + for _, line in ipairs(getlines(bufnr, 1, 10)) do + if line:find('^@') then + vim.bo[bufnr].filetype = 'change' + return + end + if line:find('MODULE') then + vim.bo[bufnr].filetype = 'chill' + return + elseif findany(line:lower(), { 'main%s*%(', '#%s*include', '//' }) then + vim.bo[bufnr].filetype = 'ch' + return + end + end + vim.bo[bufnr].filetype = 'chill' +end function M.csh(path, bufnr) end -function M.dat(path, bufnr) end +-- Determine if a *.dat file is Kuka Robot Language +-- TODO: this one fails for some reason, so I omitted it. #18219 should be merged first. +function M.dat(bufnr) + -- if vim.g.filetype_dat then + -- vim.bo[bufnr].filetype = vim.g.filetype_dat + -- return + -- end + -- local line = nextnonblank(bufnr, 1):lower() + -- if findany(line, { "^%s*&%w+", "^%s*defdat" }) then + -- vim.bo[bufnr].filetype = "krl" + -- end +end -function M.dep3patch(path, bufnr) end +-- This function is called for all files under */debian/patches/*, make sure not +-- to non-dep3patch files, such as README and other text files. +function M.dep3patch(path, bufnr) + local file_name = vim.fn.fnamemodify(path, ':t') + if file_name == 'series' then + return + end -function M.dtrace(path, bufnr) end + for _, line in ipairs(getlines(bufnr, 1, 100)) do + if + findany(line, { + '^Description:', + '^Subject:', + '^Origin:', + '^Bug:', + '^Forwarded:', + '^Author:', + '^From:', + '^Reviewed%-by:', + '^Acked%-by:', + '^Last%-Updated:', + '^Applied%-Upstream:', + }) + then + vim.bo[bufnr].filetype = 'dep3patch' + return + elseif line:find('^%-%-%-') then + -- End of headers found. stop processing + return + end + end +end -function M.e(path, bufnr) end +function M.dtrace(bufnr) + local did_filetype = vim.fn.did_filetype() + if did_filetype and did_filetype ~= 0 then + -- Filetype was already detected + return + end + for _, line in ipairs(getlines(bufnr, 1, 100)) do + if matchregex(line, [[\c^module\>\|^import\>]]) then + -- D files often start with a module and/or import statement. + vim.bo[bufnr].filetype = 'd' + return + elseif findany(line, { '^#!%S+dtrace', '#pragma%s+D%s+option', ':%S-:%S-:' }) then + vim.bo[bufnr].filetype = 'dtrace' + return + end + end + vim.bo[bufnr].filetype = 'd' +end + +function M.e(path, bufnr) + if vim.g.filetype_euphoria then + vim.bo[bufnr].filetype = vim.g.filetype_euphoria + return + end + -- TODO: WIP + -- for _, line in ipairs(getlines(bufnr, 1, 100)) do + -- if line:find("^$") + -- end +end -- This function checks for valid cl syntax in the first five lines. -- Look for either an opening comment, '#', or a block start, '{'. @@ -110,8 +300,7 @@ function M.ex(bufnr) vim.bo[bufnr].filetype = vim.g.filetype_euphoria else for _, line in ipairs(getlines(bufnr, 1, 100)) do - -- TODO: in the Vim regex, \> is used to match the end of the word, can this be omitted? - if findany(line, { '^%-%-', '^ifdef', '^include' }) then + if matchregex(line, [[\c^--\|^ifdef\>\|^include\>]]) then vim.bo[bufnr].filetype = 'euphoria3' return end @@ -138,22 +327,34 @@ end function M.frm(bufnr) if vim.g.filetype_frm then vim.bo[bufnr].filetype = vim.g.filetype_frm + return + end + local lines = table.concat(getlines(bufnr, 1, 5)):lower() + if findany(lines, visual_basic_content) then + vim.bo[bufnr].filetype = 'vb' else - -- Always ignore case - local lines = getlines(bufnr, 1, 5, { concat = true }):lower() - if findany(lines, { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform' }) then - vim.bo[bufnr].filetype = 'vb' - else - vim.bo[bufnr].filetype = 'form' - end + vim.bo[bufnr].filetype = 'form' end end -function M.fs(path, bufnr) end +-- Distinguish between Forth and F#. +function M.fs(bufnr) + -- TODO: WIP + -- if vim.g.filetype_fs then + -- vim.bo[bufnr].filetype = vim.g.filetype_fs + -- return + -- end + -- local line = nextnonblank(bufnr, 1) + -- if findany(line, { '^%s*.?%( ', '^%s*\\G? ', '^\\$', '^%s*: %S' }) then + -- vim.bo[bufnr].filetype = 'forth' + -- else + -- vim.bo[bufnr].filetype = 'fsharp' + -- end +end function M.header(bufnr) for _, line in ipairs(getlines(bufnr, 1, 200)) do - if findany(line, { '^@interface', '^@end', '^@class' }) then + if findany(line:lower(), { '^@interface', '^@end', '^@class' }) then if vim.g.c_syntax_for_h then vim.bo[bufnr].filetype = 'objc' else @@ -171,11 +372,22 @@ function M.header(bufnr) end end +function M.html(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 10)) do + if matchregex(line, [[\\|{#\s\+]]) then + vim.bo[bufnr].filetype = 'htmldjango' + return + end + end + vim.bo[bufnr].filetype = 'html' +end + function M.idl(bufnr) for _, line in ipairs(getlines(bufnr, 1, 50)) do - -- Always ignore case - line = line:lower() - if findany(line, { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then + if findany(line:lower(), { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then vim.bo[bufnr].filetype = 'msidl' return end @@ -198,11 +410,83 @@ function M.inp(bufnr) end end -function M.lpc(path, bufnr) end +function M.lpc(bufnr) + if vim.g.lpc_syntax_for_c then + for _, line in ipairs(getlines(bufnr, 1, 12)) do + if + findany(line, { + '^//', + '^inherit', + '^private', + '^protected', + '^nosave', + '^string', + '^object', + '^mapping', + '^mixed', + }) + then + vim.bo[bufnr].filetype = 'lpc' + return + end + end + end + vim.bo[bufnr].filetype = 'c' +end -function M.lprolog(path, bufnr) end +function M.m(bufnr) + if vim.g.filetype_m then + vim.bo[bufnr].filetype = vim.g.filetype_m + return + end -function M.m(path, bufnr) end + -- Excluding end(for|function|if|switch|while) common to Murphi + local octave_block_terminators = + [[\]] + local objc_preprocessor = [[\c^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>]] + + -- Whether we've seen a multiline comment leader + local saw_comment = false + for _, line in ipairs(getlines(bufnr, 1, 100)) do + if line:find('^%s*/%*') then + -- /* ... */ is a comment in Objective C and Murphi, so we can't conclude + -- it's either of them yet, but track this as a hint in case we don't see + -- anything more definitive. + saw_comment = true + end + if line:find('^%s*//') or matchregex(line, [[\c^\s*@import\>]]) or matchregex(line, objc_preprocessor) then + vim.bo[bufnr].filetype = 'objc' + return + end + if + findany(line, { '^%s*#', '^%s*%%!' }) + or matchregex(line, [[\c^\s*unwind_protect\>]]) + or matchregex(line, [[\c\%(^\|;\)\s*]] .. octave_block_terminators) + then + vim.bo[bufnr].filetype = 'octave' + return + elseif line:find('^%s*%%') then + vim.bo[bufnr].filetype = 'matlab' + return + elseif line:find('^%s*%(%*') then + vim.bo[bufnr].filetype = 'mma' + return + elseif matchregex(line, [[\c^\s*\(\(type\|var\)\>\|--\)]]) then + vim.bo[bufnr].filetype = 'murphi' + return + end + end + + if saw_comment then + -- We didn't see anything definitive, but this looks like either Objective C + -- or Murphi based on the comment leader. Assume the former as it is more + -- common. + vim.bo[bufnr].filetype = 'objc' + else + -- Default is Matlab + vim.bo[bufnr].filetype = 'matlab' + end +end -- Rely on the file to start with a comment. -- MS message text files use ';', Sendmail files use '#' or 'dnl' @@ -221,7 +505,15 @@ function M.mc(bufnr) vim.bo[bufnr].filetype = 'm4' end -function M.mm(path, bufnr) end +function M.mm(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 20)) do + if matchregex(line, [[\c^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)]]) then + vim.bo[bufnr].filetype = 'objcpp' + return + end + end + vim.bo[bufnr].filetype = 'nroff' +end function M.mms(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do @@ -236,35 +528,129 @@ function M.mms(bufnr) vim.bo[bufnr].filetype = 'mmix' end -function M.mod(path, bufnr) end +-- Returns true if file content looks like LambdaProlog +local function is_lprolog(bufnr) + -- Skip apparent comments and blank lines, what looks like + -- LambdaProlog comment may be RAPID header + for _, line in ipairs(getlines(bufnr, 1, -1)) do + -- The second pattern matches a LambdaProlog comment + if not findany(line, { '^%s*$', '^%s*%%' }) then + -- The pattern must not catch a go.mod file + return matchregex(line, [[\c\]] + +function M.pp(bufnr) + -- TODO: WIP + + -- if vim.g.filetype_pp then + -- vim.bo[bufnr].filetype = vim.g.filetype_pp + -- return + -- end + -- local first_line = nextnonblank(bufnr, 1):lower() + -- if findany(first_line, { pascal_comments, pascal_keywords }) then + -- vim.bo[bufnr].filetype = "pascal" + -- else + -- vim.bo[bufnr].filetype = "puppet" + -- end +end + +function M.prg(bufnr) + if vim.g.filetype_prg then + vim.bo[bufnr].filetype = vim.g.filetype_prg + elseif is_rapid(bufnr) then + vim.bo[bufnr].filetype = 'rapid' + else + -- Nothing recognized, assume Clipper + vim.bo[bufnr].filetype = 'clipper' + end +end -function M.prg(path, bufnr) end +-- This function checks for an assembly comment in the first ten lines. +-- If not found, assume Progress. +function M.progress_asm(bufnr) + if vim.g.filetype_i then + vim.bo[bufnr].filetype = vim.g.filetype_i + return + end -function M.progress_asm(path, bufnr) end + for _, line in ipairs(getlines(bufnr, 1, 10)) do + if line:find('^%s*;') or line:find('^/%*') then + return M.asm(bufnr) + elseif not line:find('^%s*$') or line:find('^/%*') then + -- Not an empty line: doesn't look like valid assembly code + -- or it looks like a Progress /* comment. + break + end + end + vim.bo[bufnr].filetype = 'progress' +end function M.progress_cweb(bufnr) if vim.g.filetype_w then vim.bo[bufnr].filetype = vim.g.filetype_w else - if getlines(bufnr, 1):find('^&ANALYZE') or getlines(bufnr, 3):find('^&GLOBAL%-DEFINE') then + if getlines(bufnr, 1):lower():find('^&analyze') or getlines(bufnr, 3):lower():find('^&global%-define') then vim.bo[bufnr].filetype = 'progress' else vim.bo[bufnr].filetype = 'cweb' @@ -272,15 +658,33 @@ function M.progress_cweb(bufnr) end end -function M.progress_pascal(path, bufnr) end +-- This function checks for valid Pascal syntax in the first 10 lines. +-- Look for either an opening comment or a program start. +-- If not found, assume Progress. +function M.progress_pascal(bufnr) + if vim.g.filetype_p then + vim.bo[bufnr].filetype = vim.g.filetype_p + return + end + for _, line in ipairs(getlines(bufnr, 1, 10)) do + if findany(line, pascal_comments) or matchregex(line, pascal_keywords) then + vim.bo[bufnr].filetype = 'pascal' + return + elseif not line:find('^%s*$') or line:find('^/%*') then + -- Not an empty line: Doesn't look like valid Pascal code. + -- Or it looks like a Progress /* comment + break + end + end + vim.bo[bufnr].filetype = 'progress' +end function M.proto(path, bufnr) end function M.r(bufnr) local lines = getlines(bufnr, 1, 50) - -- TODO: \< / \> which match the beginning / end of a word -- Rebol is easy to recognize, check for that first - if table.concat(lines):lower():find('rebol') then + if matchregex(table.concat(lines), [[\c\]]) then vim.bo[bufnr].filetype = 'rebol' return end @@ -315,7 +719,43 @@ function M.redif(bufnr) end end -function M.rules(path, bufnr) end +local udev_rules_pattern = '^%s*udev_rules%s*=%s*"([%^"]+)/*".*' +function M.rules(path, bufnr) + path = path:lower() + if + findany(path, { + '/etc/udev/.*%.rules$', + '/etc/udev/rules%.d/.*$.rules$', + '/usr/lib/udev/.*%.rules$', + '/usr/lib/udev/rules%.d/.*%.rules$', + '/lib/udev/.*%.rules$', + '/lib/udev/rules%.d/.*%.rules$', + }) + then + vim.bo[bufnr].filetype = 'udevrules' + elseif path:find('^/etc/ufw/') then + -- Better than hog + vim.bo[bufnr].filetype = 'conf' + elseif findany(path, { '^/etc/polkit%-1/rules%.d', '/usr/share/polkit%-1/rules%.d' }) then + vim.bo[bufnr].filetype = 'javascript' + else + local ok, config_lines = pcall(vim.fn.readfile, '/etc/udev/udev.conf') + if not ok then + vim.bo[bufnr].filetype = 'hog' + return + end + local dir = vim.fn.expand(path, ':h') + for _, line in ipairs(config_lines) do + local match = line:match(udev_rules_pattern) + local udev_rules = line:gsub(udev_rules_pattern, match, 1) + if dir == udev_rules then + vim.bo[bufnr].filetype = 'udevrules' + return + end + end + vim.bo[bufnr].filetype = 'hog' + end +end -- This function checks the first 25 lines of file extension "sc" to resolve -- detection between scala and SuperCollider @@ -359,9 +799,27 @@ function M.sql(bufnr) end end -function M.src(path, bufnr) end +-- Determine if a *.src file is Kuka Robot Language +function M.src(bufnr) + if vim.g.filetype_src then + vim.bo[bufnr].filetype = vim.g.filetype_src + return + end + local line = nextnonblank(bufnr, 1) + if matchregex(line, [[\c\v^\s*%(\&\w+|%(global\s+)?def%(fct)?>)]]) then + vim.bo[bufnr].filetype = 'krl' + end +end -function M.sys(path, bufnr) end +function M.sys(bufnr) + if vim.g.filetype_sys then + vim.bo[bufnr].filetype = vim.g.filetype_sys + elseif is_rapid(bufnr) then + vim.bo[bufnr].filetype = 'rapid' + else + vim.bo[bufnr].filetype = 'bat' + end +end function M.tex(path, bufnr) end @@ -380,8 +838,8 @@ end function M.xml(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do + local is_docbook4 = line:find(' is used to match the end of the word after "class", - -- can this be omitted? - if findany(line, { '^%s*#', '^%class', '^%s*#%s*include' }) then + if matchregex(line, [[\c^\s*\(#\|class\>\)]]) and not line:lower():find('^%s*#%s*include') then vim.bo[bufnr].filetype = 'racc' + return end end vim.bo[bufnr].filetype = 'yacc' -- cgit From 38cbca3eeadca86f1431ea7a97f498f6a9cd33c8 Mon Sep 17 00:00:00 2001 From: Noval Maulana Date: Wed, 18 May 2022 01:11:14 +0700 Subject: fix(health): handle non-existent log file #18610 Problem: vim.lsp: require("vim.lsp.health").check() ======================================================================== - ERROR: Failed to run healthcheck for "vim.lsp" plugin. Exception: function health#check, line 20 Vim(eval):E5108: Error executing lua ...m/HEAD-6613f58/share/nvim/runtime/lua/vim/lsp/health.lua:20: attempt to index a nil value stack traceback: ...m/HEAD-6613f58/share/nvim/runtime/lua/vim/lsp/health.lua:20: in function 'check' [string "luaeval()"]:1: in main chunk Solution: Check for nil. fix #18602 --- runtime/lua/vim/lsp/health.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index 74714ebc6b..bf8fe0932e 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -17,7 +17,8 @@ function M.check() local log_path = vim.lsp.get_log_path() report_info(string.format('Log path: %s', log_path)) - local log_size = vim.loop.fs_stat(log_path).size + local log_file = vim.loop.fs_stat(log_path) + local log_size = log_file and log_file.size or 0 local report_fn = (log_size / 1000000 > 100 and report_warn or report_info) report_fn(string.format('Log size: %d KB', log_size / 1000)) -- cgit From 2ffafc7aa91fb1d9a71fff12051e40961a7b7f69 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 9 May 2022 12:00:27 -0600 Subject: feat(lsp): add LspAttach and LspDetach autocommands The current approach of using `on_attach` callbacks for configuring buffers for LSP is suboptimal: 1. It does not use the standard Nvim interface for driving and hooking into events (i.e. autocommands) 2. There is no way for "third parties" (e.g. plugins) to hook into the event. This means that *all* buffer configuration must go into the user-supplied on_attach callback. This also makes it impossible for these configurations to be modular, since it all must happen in the same place. 3. There is currently no way to do something when a client detaches from a buffer (there is no `on_detach` callback). The solution is to use the traditional method of event handling in Nvim: autocommands. When a LSP client is attached to a buffer, fire a `LspAttach`. Likewise, when a client detaches from a buffer fire a `LspDetach` event. This enables plugins to easily add LSP-specific configuration to buffers as well as enabling users to make their own configurations more modular (e.g. by creating multiple LspAttach autocommands that each do something unique). --- runtime/lua/vim/lsp.lua | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index e99a7c282c..cfa6a91cbb 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1,5 +1,3 @@ -local if_nil = vim.F.if_nil - local default_handlers = require('vim.lsp.handlers') local log = require('vim.lsp.log') local lsp_rpc = require('vim.lsp.rpc') @@ -8,11 +6,16 @@ local util = require('vim.lsp.util') local sync = require('vim.lsp.sync') local vim = vim -local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option = - vim.api.nvim_err_writeln, vim.api.nvim_buf_get_lines, vim.api.nvim_command, vim.api.nvim_buf_get_option +local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option, nvim_exec_autocmds = + vim.api.nvim_err_writeln, + vim.api.nvim_buf_get_lines, + vim.api.nvim_command, + vim.api.nvim_buf_get_option, + vim.api.nvim_exec_autocmds local uv = vim.loop local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend local validate = vim.validate +local if_nil = vim.F.if_nil local lsp = { protocol = protocol, @@ -867,15 +870,27 @@ function lsp.start_client(config) pcall(config.on_exit, code, signal, client_id) end + for bufnr, client_ids in pairs(all_buffer_active_clients) do + if client_ids[client_id] then + vim.schedule(function() + nvim_exec_autocmds('LspDetach', { + buffer = bufnr, + modeline = false, + data = { client_id = client_id }, + }) + + local namespace = vim.lsp.diagnostic.get_namespace(client_id) + vim.diagnostic.reset(namespace, bufnr) + end) + + client_ids[client_id] = nil + end + end + active_clients[client_id] = nil uninitialized_clients[client_id] = nil - lsp.diagnostic.reset(client_id, all_buffer_active_clients) changetracking.reset(client_id) - for _, client_ids in pairs(all_buffer_active_clients) do - client_ids[client_id] = nil - end - if code ~= 0 or (signal ~= 0 and signal ~= 15) then local msg = string.format('Client %s quit with exit code %s and signal %s', client_id, code, signal) vim.schedule(function() @@ -1213,6 +1228,13 @@ function lsp.start_client(config) ---@param bufnr (number) Buffer number function client._on_attach(bufnr) text_document_did_open_handler(bufnr, client) + + nvim_exec_autocmds('LspAttach', { + buffer = bufnr, + modeline = false, + data = { client_id = client.id }, + }) + if config.on_attach then -- TODO(ashkan) handle errors. pcall(config.on_attach, client, bufnr) @@ -1359,6 +1381,12 @@ function lsp.buf_detach_client(bufnr, client_id) return end + nvim_exec_autocmds('LspDetach', { + buffer = bufnr, + modeline = false, + data = { client_id = client_id }, + }) + changetracking.reset_buf(client, bufnr) if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then -- cgit From ed93186ee22b852580ed8a255ed2104e020cf11c Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Mon, 16 May 2022 16:44:55 -0600 Subject: feat(lsp): add filter to vim.lsp.get_active_clients() Allow get_active_clients() to filter on client name, id, or buffer. This (soft) deprecates lsp.buf_get_clients(). --- runtime/lua/vim/lsp.lua | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index cfa6a91cbb..07987ee003 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1463,11 +1463,29 @@ function lsp.stop_client(client_id, force) end end ---- Gets all active clients. +--- Get active clients. --- ----@returns Table of |vim.lsp.client| objects -function lsp.get_active_clients() - return vim.tbl_values(active_clients) +---@param filter (table|nil) A table with key-value pairs used to filter the +--- returned clients. The available keys are: +--- - id (number): Only return clients with the given id +--- - bufnr (number): Only return clients attached to this buffer +--- - name (string): Only return clients with the given name +---@returns (table) List of |vim.lsp.client| objects +function lsp.get_active_clients(filter) + validate({ filter = { filter, 't', true } }) + + filter = filter or {} + + local clients = {} + + local t = filter.bufnr and (all_buffer_active_clients[resolve_bufnr(filter.bufnr)] or {}) or active_clients + for client_id in pairs(t) do + local client = active_clients[client_id] + if (filter.id == nil or client.id == filter.id) and (filter.name == nil or client.name == filter.name) then + clients[#clients + 1] = client + end + end + return clients end function lsp._vim_exit_handler() @@ -1842,12 +1860,13 @@ end --- is a |vim.lsp.client| object. --- ---@param bufnr (optional, number): Buffer handle, or 0 for current +---@returns (table) Table of (client_id, client) pairs +---@deprecated Use |vim.lsp.get_active_clients()| instead. function lsp.buf_get_clients(bufnr) - bufnr = resolve_bufnr(bufnr) local result = {} - for_each_buffer_client(bufnr, function(client, client_id) - result[client_id] = client - end) + for _, client in ipairs(lsp.get_active_clients({ bufnr = resolve_bufnr(bufnr) })) do + result[client.id] = client + end return result end -- cgit From f66a60805dd5480982d1b12a263724cfd56b1bfe Mon Sep 17 00:00:00 2001 From: Denys Date: Mon, 9 May 2022 18:01:21 +0200 Subject: docs: correct description of LanguageTree:contains() --- runtime/lua/vim/treesitter/languagetree.lua | 2 -- 1 file changed, 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index b83df65151..af878aed0e 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -497,8 +497,6 @@ end --- Determines whether {range} is contained in this language tree --- ---- This goes down the tree to recursively check children. ---- ---@param range A range, that is a `{ start_line, start_col, end_line, end_col }` table. function LanguageTree:contains(range) for _, tree in pairs(self._trees) do -- cgit From fec944142bbbe5ed07867c9409c1e07598a1ef99 Mon Sep 17 00:00:00 2001 From: Denys Date: Tue, 10 May 2022 10:00:04 +0200 Subject: refactor: simple logic in tree_contains() --- runtime/lua/vim/treesitter/languagetree.lua | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index af878aed0e..c23ac4468d 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -488,11 +488,7 @@ local function tree_contains(tree, range) local start_fits = start_row < range[1] or (start_row == range[1] and start_col <= range[2]) local end_fits = end_row > range[3] or (end_row == range[3] and end_col >= range[4]) - if start_fits and end_fits then - return true - end - - return false + return start_fits and end_fits end --- Determines whether {range} is contained in this language tree -- cgit From 3eea66d65a75c83cbd6bd7ec2aa0886781c807c9 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 18 May 2022 20:03:24 +0100 Subject: feat(lsp): option to reuse_win for jump actions (#18577) --- runtime/lua/vim/lsp/buf.lua | 31 +++++++++++++++++++++++++------ runtime/lua/vim/lsp/handlers.lua | 8 +++++--- runtime/lua/vim/lsp/util.lua | 29 ++++++++++++++++++++++------- 3 files changed, 52 insertions(+), 16 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index b0bf2c6e5b..80350bcb71 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -63,26 +63,45 @@ function M.hover() request('textDocument/hover', params) end +---@private +local function request_with_options(name, params, options) + local req_handler + if options then + req_handler = function(err, result, ctx, config) + local client = vim.lsp.get_client_by_id(ctx.client_id) + local handler = client.handlers[name] or vim.lsp.handlers[name] + handler(err, result, ctx, vim.tbl_extend('force', config or {}, options)) + end + end + request(name, params, req_handler) +end + --- Jumps to the declaration of the symbol under the cursor. ---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead. --- -function M.declaration() +---@param options table|nil additional options +--- - reuse_win: (boolean) Jump to existing window if buffer is already open. +function M.declaration(options) local params = util.make_position_params() - request('textDocument/declaration', params) + request_with_options('textDocument/declaration', params, options) end --- Jumps to the definition of the symbol under the cursor. --- -function M.definition() +---@param options table|nil additional options +--- - reuse_win: (boolean) Jump to existing window if buffer is already open. +function M.definition(options) local params = util.make_position_params() - request('textDocument/definition', params) + request_with_options('textDocument/definition', params, options) end --- Jumps to the definition of the type of the symbol under the cursor. --- -function M.type_definition() +---@param options table|nil additional options +--- - reuse_win: (boolean) Jump to existing window if buffer is already open. +function M.type_definition(options) local params = util.make_position_params() - request('textDocument/typeDefinition', params) + request_with_options('textDocument/typeDefinition', params, options) end --- Lists all the implementations for the symbol under the cursor in the diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index b3a253c118..61cc89dcac 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -327,18 +327,20 @@ M['textDocument/hover'] = M.hover ---@param result (table) result of LSP method; a location or a list of locations. ---@param ctx (table) table containing the context of the request, including the method ---(`textDocument/definition` can return `Location` or `Location[]` -local function location_handler(_, result, ctx, _) +local function location_handler(_, result, ctx, config) if result == nil or vim.tbl_isempty(result) then local _ = log.info() and log.info(ctx.method, 'No location found') return nil end local client = vim.lsp.get_client_by_id(ctx.client_id) + config = config or {} + -- 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], client.offset_encoding) + util.jump_to_location(result[1], client.offset_encoding, config.reuse_win) if #result > 1 then vim.fn.setqflist({}, ' ', { @@ -348,7 +350,7 @@ local function location_handler(_, result, ctx, _) api.nvim_command('botright copen') end else - util.jump_to_location(result, client.offset_encoding) + util.jump_to_location(result, client.offset_encoding, config.reuse_win) end end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index e8a8e06f46..0b0d48d15e 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -684,6 +684,16 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return matches end +---@private +--- Like vim.fn.bufwinid except it works across tabpages. +local function bufwinid(bufnr) + for _, win in ipairs(api.nvim_list_wins()) do + if api.nvim_win_get_buf(win) == bufnr then + return win + end + end +end + --- Rename old_fname to new_fname --- ---@param opts (table) @@ -708,10 +718,9 @@ function M.rename(old_fname, new_fname, opts) assert(ok, err) local newbuf = vim.fn.bufadd(new_fname) - for _, win in pairs(api.nvim_list_wins()) do - if api.nvim_win_get_buf(win) == oldbuf then - api.nvim_win_set_buf(win, newbuf) - end + local win = bufwinid(oldbuf) + if win then + api.nvim_win_set_buf(win, newbuf) end api.nvim_buf_delete(oldbuf, { force = true }) end @@ -1004,8 +1013,9 @@ end --- ---@param location table (`Location`|`LocationLink`) ---@param offset_encoding string utf-8|utf-16|utf-32 (required) +---@param reuse_win boolean Jump to existing window if buffer is already opened. ---@returns `true` if the jump succeeded -function M.jump_to_location(location, offset_encoding) +function M.jump_to_location(location, offset_encoding, reuse_win) -- location may be Location or LocationLink local uri = location.uri or location.targetUri if uri == nil then @@ -1024,8 +1034,13 @@ function M.jump_to_location(location, offset_encoding) vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't') --- Jump to new location (adjusting for UTF-16 encoding of characters) - api.nvim_set_current_buf(bufnr) - api.nvim_buf_set_option(bufnr, 'buflisted', true) + local win = reuse_win and bufwinid(bufnr) + if win then + api.nvim_set_current_win(win) + else + api.nvim_set_current_buf(bufnr) + api.nvim_buf_set_option(bufnr, 'buflisted', true) + end local range = location.range or location.targetSelectionRange local row = range.start.line local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) -- cgit From a4862cbb5fe4fb368a679adf198506a56a104413 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Fri, 20 May 2022 13:11:23 +0200 Subject: fix(lsp): only send diagnostics from current buffer in code_action() (#18639) Fix vim.lsp.buf.(range_)code_action() to only send diagnostics belonging to the current buffer and not to other files in the workspace. --- runtime/lua/vim/lsp/buf.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 80350bcb71..1207da094a 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -863,7 +863,8 @@ function M.code_action(options) end local context = options.context or {} if not context.diagnostics then - context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics() + local bufnr = vim.api.nvim_get_current_buf() + context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr) end local params = util.make_range_params() params.context = context @@ -889,7 +890,8 @@ function M.range_code_action(context, start_pos, end_pos) validate({ context = { context, 't', true } }) context = context or {} if not context.diagnostics then - context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics() + local bufnr = vim.api.nvim_get_current_buf() + context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr) end local params = util.make_given_range_params(start_pos, end_pos) params.context = context -- cgit From 976f32aa7a5d62b7bf5d9c3cdcaf81ff373c0570 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 21 May 2022 09:51:03 +0200 Subject: refactor: add warnings for deprecated functions (#18662) --- runtime/lua/vim/lsp/util.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0b0d48d15e..4663cf9f09 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1691,7 +1691,7 @@ end --- ---@param items (table) list of items function M.set_loclist(items, win_id) - vim.api.nvim_echo({ { 'vim.lsp.util.set_loclist is deprecated. See :h deprecated', 'WarningMsg' } }, true, {}) + vim.deprecate('vim.lsp.util.set_loclist', 'setloclist', '0.8') vim.fn.setloclist(win_id or 0, {}, ' ', { title = 'Language Server', items = items, @@ -1705,7 +1705,7 @@ end --- ---@param items (table) list of items function M.set_qflist(items) - vim.api.nvim_echo({ { 'vim.lsp.util.set_qflist is deprecated. See :h deprecated', 'WarningMsg' } }, true, {}) + vim.deprecate('vim.lsp.util.set_qflist', 'setqflist', '0.8') vim.fn.setqflist({}, ' ', { title = 'Language Server', items = items, -- cgit From 52623ce9353bac2b4a82c0197c5a08202e74b156 Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Sun, 22 May 2022 20:16:04 +0200 Subject: refactor(runtime): convert the remaining dist#ft functions to lua (#18623) --- runtime/lua/vim/filetype.lua | 343 +++++++++++------------ runtime/lua/vim/filetype/detect.lua | 530 ++++++++++++++++++++++-------------- 2 files changed, 494 insertions(+), 379 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 8321e0b11e..c9e81b53d7 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -786,8 +786,8 @@ local extension = { zut = 'zimbutempl', zsh = 'zsh', vala = 'vala', - E = function() - vim.fn['dist#ft#FTe']() + E = function(path, bufnr) + return require('vim.filetype.detect').e(bufnr) end, EU = function(path, bufnr) return require('vim.filetype.detect').euphoria(bufnr) @@ -804,26 +804,26 @@ local extension = { EXW = function(path, bufnr) return require('vim.filetype.detect').euphoria(bufnr) end, - PL = function() - vim.fn['dist#ft#FTpl']() + PL = function(path, bufnr) + return require('vim.filetype.detect').pl(bufnr) end, R = function(path, bufnr) - require('vim.filetype.detect').r(bufnr) + return require('vim.filetype.detect').r(bufnr) end, asm = function(path, bufnr) - require('vim.filetype.detect').asm(bufnr) + return require('vim.filetype.detect').asm(bufnr) end, bas = function(path, bufnr) - require('vim.filetype.detect').bas(bufnr) + return require('vim.filetype.detect').bas(bufnr) end, - bi = function() - vim.fn['dist#ft#FTbas']() + bi = function(path, bufnr) + return require('vim.filetype.detect').bas(bufnr) end, - bm = function() - vim.fn['dist#ft#FTbas']() + bm = function(path, bufnr) + return require('vim.filetype.detect').bas(bufnr) end, - bash = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + bash = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, btm = function(path, bufnr) return require('vim.filetype.detect').btm(bufnr) @@ -834,104 +834,104 @@ local extension = { ch = function(path, bufnr) return require('vim.filetype.detect').change(bufnr) end, - com = function() - vim.fn['dist#ft#BindzoneCheck']('dcl') + com = function(path, bufnr) + return require('vim.filetype.detect').bindzone(bufnr, 'dcl') end, - cpt = function() - vim.fn['dist#ft#FThtml']() + cpt = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) end, - csh = function() - vim.fn['dist#ft#CSH']() + csh = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, d = function(path, bufnr) return require('vim.filetype.detect').dtrace(bufnr) end, - db = function() - vim.fn['dist#ft#BindzoneCheck']('') + db = function(path, bufnr) + return require('vim.filetype.detect').bindzone(bufnr, '') end, - dtml = function() - vim.fn['dist#ft#FThtml']() + dtml = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) end, - e = function() - vim.fn['dist#ft#FTe']() + e = function(path, bufnr) + return require('vim.filetype.detect').e(bufnr) end, - ebuild = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ebuild = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - eclass = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + eclass = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, ent = function(path, bufnr) - require('vim.filetype.detect').ent(bufnr) + return require('vim.filetype.detect').ent(bufnr) end, - env = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + env = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, eu = function(path, bufnr) - require('vim.filetype.detect').euphoria(bufnr) + return require('vim.filetype.detect').euphoria(bufnr) end, ew = function(path, bufnr) - require('vim.filetype.detect').euphoria(bufnr) + return require('vim.filetype.detect').euphoria(bufnr) end, ex = function(path, bufnr) - require('vim.filetype.detect').ex(bufnr) + return require('vim.filetype.detect').ex(bufnr) end, exu = function(path, bufnr) - require('vim.filetype.detect').euphoria(bufnr) + return require('vim.filetype.detect').euphoria(bufnr) end, exw = function(path, bufnr) - require('vim.filetype.detect').euphoria(bufnr) + return require('vim.filetype.detect').euphoria(bufnr) end, frm = function(path, bufnr) - require('vim.filetype.detect').frm(bufnr) + return require('vim.filetype.detect').frm(bufnr) end, fs = function(path, bufnr) - vim.fn['dist#ft#FTfs']() + return require('vim.filetype.detect').fs(bufnr) end, h = function(path, bufnr) - require('vim.filetype.detect').header(bufnr) + return require('vim.filetype.detect').header(bufnr) end, - htm = function() - vim.fn['dist#ft#FThtml']() + htm = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) end, - html = function() - vim.fn['dist#ft#FThtml']() + html = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) end, i = function(path, bufnr) - require('vim.filetype.detect').progress_asm(bufnr) + return require('vim.filetype.detect').progress_asm(bufnr) end, idl = function(path, bufnr) - require('vim.filetype.detect').idl(bufnr) + return require('vim.filetype.detect').idl(bufnr) end, - inc = function() - vim.fn['dist#ft#FTinc']() + inc = function(path, bufnr) + return require('vim.filetype.detect').inc(bufnr) end, inp = function(path, bufnr) - require('vim.filetype.detect').inp(bufnr) + return require('vim.filetype.detect').inp(bufnr) end, - ksh = function() - vim.fn['dist#ft#SetFileTypeSH']('ksh') + ksh = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'ksh') end, lst = function(path, bufnr) - require('vim.filetype.detect').asm(bufnr) + return require('vim.filetype.detect').asm(bufnr) end, m = function(path, bufnr) - require('vim.filetype.detect').m(bufnr) + return require('vim.filetype.detect').m(bufnr) end, mac = function(path, bufnr) - require('vim.filetype.detect').asm(bufnr) + return require('vim.filetype.detect').asm(bufnr) end, mc = function(path, bufnr) - require('vim.filetype.detect').mc(bufnr) + return require('vim.filetype.detect').mc(bufnr) end, mm = function(path, bufnr) - require('vim.filetype.detect').mm(bufnr) + return require('vim.filetype.detect').mm(bufnr) end, mms = function(path, bufnr) - require('vim.filetype.detect').mms(bufnr) + return require('vim.filetype.detect').mms(bufnr) end, p = function(path, bufnr) - require('vim.filetype.detect').progress_pascal(bufnr) + return require('vim.filetype.detect').progress_pascal(bufnr) end, patch = function(path, bufnr) local firstline = getline(bufnr, 1) @@ -941,65 +941,65 @@ local extension = { return 'diff' end end, - pl = function() - vim.fn['dist#ft#FTpl']() + pl = function(path, bufnr) + return require('vim.filetype.detect').pl(bufnr) end, - pp = function() - vim.fn['dist#ft#FTpp']() + pp = function(path, bufnr) + return require('vim.filetype.detect').pp(bufnr) end, - pro = function() - vim.fn['dist#ft#ProtoCheck']('idlang') + pro = function(path, bufnr) + return require('vim.filetype.detect').proto(bufnr, 'idlang') end, - pt = function() - vim.fn['dist#ft#FThtml']() + pt = function(path, bufnr) + return require('vim.filetype.detect').html('idlang') end, r = function(path, bufnr) - require('vim.filetype.detect').r(bufnr) + return require('vim.filetype.detect').r(bufnr) end, rdf = function(path, bufnr) - require('vim.filetype.detect').redif(bufnr) + return require('vim.filetype.detect').redif(bufnr) end, rules = function(path, bufnr) - require('vim.filetype.detect').rules(path, bufnr) + return require('vim.filetype.detect').rules(path, bufnr) end, sc = function(path, bufnr) - require('vim.filetype.detect').sc(bufnr) + return require('vim.filetype.detect').sc(bufnr) end, scd = function(path, bufnr) - require('vim.filetype.detect').scd(bufnr) + return require('vim.filetype.detect').scd(bufnr) end, - sh = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + sh = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, - shtml = function() - vim.fn['dist#ft#FThtml']() + shtml = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) end, sql = function(path, bufnr) - require('vim.filetype.detect').sql(bufnr) + return require('vim.filetype.detect').sql(bufnr) end, - stm = function() - vim.fn['dist#ft#FThtml']() + stm = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) end, - tcsh = function() - vim.fn['dist#ft#SetFileTypeShell']('tcsh') + tcsh = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, - tex = function() - vim.fn['dist#ft#FTtex']() + tex = function(path, bufnr) + return require('vim.filetype.detect').tex(path, bufnr) end, tf = function(path, bufnr) - require('vim.filetype.detect').tf(bufnr) + return require('vim.filetype.detect').tf(bufnr) end, w = function(path, bufnr) - require('vim.filetype.detect').progress_cweb(bufnr) + return require('vim.filetype.detect').progress_cweb(bufnr) end, xml = function(path, bufnr) - require('vim.filetype.detect').xml(bufnr) + return require('vim.filetype.detect').xml(bufnr) end, y = function(path, bufnr) - require('vim.filetype.detect').y(bufnr) + return require('vim.filetype.detect').y(bufnr) end, zsql = function(path, bufnr) - require('vim.filetype.detect').sql(bufnr) + return require('vim.filetype.detect').sql(bufnr) end, txt = function(path, bufnr) --helpfiles match *.txt, but should have a modeline as last line @@ -1075,16 +1075,16 @@ local filename = { exports = 'exports', ['.fetchmailrc'] = 'fetchmail', fvSchemes = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, fvSolution = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, fvConstraints = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, fvModels = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, fstab = 'fstab', mtab = 'fstab', @@ -1300,63 +1300,63 @@ local filename = { ['.zcompdump'] = 'zsh', ['.zshenv'] = 'zsh', ['.zfbfmarks'] = 'zsh', - ['.alias'] = function() - vim.fn['dist#ft#CSH']() + ['.alias'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, - ['.bashrc'] = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ['.bashrc'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - ['.cshrc'] = function() - vim.fn['dist#ft#CSH']() + ['.cshrc'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, - ['.env'] = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + ['.env'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, - ['.kshrc'] = function() - vim.fn['dist#ft#SetFileTypeSH']('ksh') + ['.kshrc'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'ksh') end, - ['.login'] = function() - vim.fn['dist#ft#CSH']() + ['.login'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, - ['.profile'] = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + ['.profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, - ['.tcshrc'] = function() - vim.fn['dist#ft#SetFileTypeShell']('tcsh') + ['.tcshrc'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, - ['/etc/profile'] = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + ['/etc/profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, - APKBUILD = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + APKBUILD = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - PKGBUILD = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + PKGBUILD = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - ['bash.bashrc'] = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ['bash.bashrc'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - bashrc = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + bashrc = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, crontab = starsetf('crontab'), - ['csh.cshrc'] = function() - vim.fn['dist#ft#CSH']() + ['csh.cshrc'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, - ['csh.login'] = function() - vim.fn['dist#ft#CSH']() + ['csh.login'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, - ['csh.logout'] = function() - vim.fn['dist#ft#CSH']() + ['csh.logout'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, - ['indent.pro'] = function() - vim.fn['dist#ft#ProtoCheck']('indent') + ['indent.pro'] = function(path, bufnr) + return require('vim.filetype.detect').proto(bufnr, 'indent') end, - ['tcsh.login'] = function() - vim.fn['dist#ft#SetFileTypeShell']('tcsh') + ['tcsh.login'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, - ['tcsh.tcshrc'] = function() - vim.fn['dist#ft#SetFileTypeShell']('tcsh') + ['tcsh.tcshrc'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, -- END FILENAME } @@ -1528,44 +1528,44 @@ local pattern = { ['.*/etc/xdg/menus/.*%.menu'] = 'xml', ['.*Xmodmap'] = 'xmodmap', ['.*/etc/zprofile'] = 'zsh', - ['%.bash[_-]aliases'] = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ['%.bash[_-]aliases'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - ['%.bash[_-]logout'] = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ['%.bash[_-]logout'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - ['%.bash[_-]profile'] = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ['%.bash[_-]profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - ['%.cshrc.*'] = function() - vim.fn['dist#ft#CSH']() + ['%.cshrc.*'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, ['%.gtkrc.*'] = starsetf('gtkrc'), - ['%.kshrc.*'] = function() - vim.fn['dist#ft#SetFileTypeSH']('ksh') + ['%.kshrc.*'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'ksh') end, - ['%.login.*'] = function() - vim.fn['dist#ft#CSH']() + ['%.login.*'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) end, ['%.neomuttrc.*'] = starsetf('neomuttrc'), - ['%.profile.*'] = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + ['%.profile.*'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, ['%.reminders.*'] = starsetf('remind'), - ['%.tcshrc.*'] = function() - vim.fn['dist#ft#SetFileTypeShell']('tcsh') + ['%.tcshrc.*'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, ['%.zcompdump.*'] = starsetf('zsh'), ['%.zlog.*'] = starsetf('zsh'), ['%.zsh.*'] = starsetf('zsh'), ['.*%.[1-9]'] = function(path, bufnr) - require('vim.filetype.detect').nroff(bufnr) + return require('vim.filetype.detect').nroff(bufnr) end, ['.*%.[aA]'] = function(path, bufnr) - require('vim.filetype.detect').asm(bufnr) + return require('vim.filetype.detect').asm(bufnr) end, ['.*%.[sS]'] = function(path, bufnr) - require('vim.filetype.detect').asm(bufnr) + return require('vim.filetype.detect').asm(bufnr) end, ['.*%.properties_.._.._.*'] = starsetf('jproperties'), ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), @@ -1576,7 +1576,7 @@ local pattern = { ['.*/app%-defaults/.*'] = starsetf('xdefaults'), ['.*/bind/db%..*'] = starsetf('bindzone'), ['.*/debian/patches/.*'] = function(path, bufnr) - require('vim.filetype.detect').dep3patch(path, bufnr) + return require('vim.filetype.detect').dep3patch(path, bufnr) end, ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'), ['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'), @@ -1592,8 +1592,8 @@ local pattern = { ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'), ['.*/etc/modprobe%..*'] = starsetf('modconf'), ['.*/etc/pam%.d/.*'] = starsetf('pamconf'), - ['.*/etc/profile'] = function() - vim.fn['dist#ft#SetFileTypeSH'](vim.fn.getline(1)) + ['.*/etc/profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, ['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'), ['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'), @@ -1621,8 +1621,8 @@ local pattern = { ['access%.conf.*'] = starsetf('apache'), ['apache%.conf.*'] = starsetf('apache'), ['apache2%.conf.*'] = starsetf('apache'), - ['bash%-fc[-%.]'] = function() - vim.fn['dist#ft#SetFileTypeSH']('bash') + ['bash%-fc[-%.]'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, ['cabal%.project%..*'] = starsetf('cabalproject'), ['crontab%..*'] = starsetf('crontab'), @@ -1650,28 +1650,28 @@ local pattern = { ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail', ['/tmp/SLRN[0-9A-Z.]+'] = 'mail', ['[a-zA-Z0-9].*Dict'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['[a-zA-Z0-9].*Dict%..*'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['[a-zA-Z].*Properties'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['[a-zA-Z].*Properties%..*'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['.*Transport%..*'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['.*/constant/g'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['.*/0/.*'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['.*/0%.orig/.*'] = function(path, bufnr) - require('vim.filetype.detect').foam(bufnr) + return require('vim.filetype.detect').foam(bufnr) end, ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), ['.*%.git/.*'] = function(path, bufnr) @@ -1680,24 +1680,29 @@ local pattern = { return 'git' end end, - ['.*%.[Cc][Ff][Gg]'] = function(path, bufnr) - require('vim.filetype.detect').cfg(bufnr) - end, + ['.*%.[Cc][Ff][Gg]'] = { + function(path, bufnr) + return require('vim.filetype.detect').cfg(bufnr) + end, + -- Decrease the priority to avoid conflicts with more specific patterns + -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. + { priority = -1 }, + }, ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr) - require('vim.filetype.detect').dat(bufnr) + return require('vim.filetype.detect').dat(bufnr) end, ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr) - require('vim.filetype.detect').mod(path, bufnr) + return require('vim.filetype.detect').mod(path, bufnr) end, ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr) - require('vim.filetype.detect').src(bufnr) + return require('vim.filetype.detect').src(bufnr) end, ['.*%.[Ss][Uu][Bb]'] = 'krl', ['.*%.[Pp][Rr][Gg]'] = function(path, bufnr) - require('vim.filetype.detect').prg(bufnr) + return require('vim.filetype.detect').prg(bufnr) end, ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr) - require('vim.filetype.detect').sys(bufnr) + return require('vim.filetype.detect').sys(bufnr) end, -- Neovim only ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index da59625353..1721923c18 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -27,6 +27,9 @@ end ---@private local function findany(s, patterns) + if s == nil then + return false + end for _, v in ipairs(patterns) do if s:find(v) then return true @@ -82,7 +85,7 @@ function M.asm(bufnr) vim.b[bufnr].asmsyntax = 'asm' end end - vim.bo[bufnr].filetype = vim.fn.fnameescape(vim.b[bufnr].asmsyntax) + return vim.fn.fnameescape(vim.b[bufnr].asmsyntax) end -- Checks the first 5 lines for a asmsyntax=foo override. @@ -102,8 +105,7 @@ local visual_basic_content = { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform', -- See frm() for Visual Basic form file detection function M.bas(bufnr) if vim.g.filetype_bas then - vim.bo[bufnr].filetype = vim.g.filetype_bas - return + return vim.g.filetype_bas end -- Most frequent FreeBASIC-specific keywords in distro files @@ -118,26 +120,30 @@ function M.bas(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do if line:find(fb_comment) or matchregex(line, fb_preproc) or matchregex(line, fb_keywords) then - vim.bo[bufnr].filetype = 'freebasic' - return + return 'freebasic' elseif matchregex(line, qb64_preproc) then - vim.bo[bufnr].filetype = 'qb64' - return + return 'qb64' elseif findany(line:lower(), visual_basic_content) then - vim.bo[bufnr].filetype = 'vb' - return + return 'vb' end end - vim.bo[bufnr].filetype = 'basic' + return 'basic' end -function M.bindzone(bufnr, default_ft) end +function M.bindzone(bufnr, default) + local lines = table.concat(getlines(bufnr, 1, 4)) + if findany(lines, { '^; <<>> DiG [0-9%.]+.* <<>>', '%$ORIGIN', '%$TTL', 'IN%s+SOA' }) then + return 'bindzone' + else + return default + end +end function M.btm(bufnr) if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then - vim.bo[bufnr].filetype = 'dosbatch' + return 'dosbatch' else - vim.bo[bufnr].filetype = 'btm' + return 'btm' end end @@ -157,11 +163,11 @@ end function M.cfg(bufnr) if vim.g.filetype_cfg then - vim.bo[bufnr].filetype = vim.g.filetype_cfg + return vim.g.filetype_cfg elseif is_rapid(bufnr, 'cfg') then - vim.bo[bufnr].filetype = 'rapid' + return 'rapid' else - vim.bo[bufnr].filetype = 'cfg' + return 'cfg' end end @@ -173,38 +179,44 @@ end function M.change(bufnr) local first_line = getlines(bufnr, 1) if findany(first_line, { '^#', '^!' }) then - vim.bo[bufnr].filetype = 'ch' - return + return 'ch' end for _, line in ipairs(getlines(bufnr, 1, 10)) do if line:find('^@') then - vim.bo[bufnr].filetype = 'change' - return + return 'change' end if line:find('MODULE') then - vim.bo[bufnr].filetype = 'chill' - return + return 'chill' elseif findany(line:lower(), { 'main%s*%(', '#%s*include', '//' }) then - vim.bo[bufnr].filetype = 'ch' - return + return 'ch' end end - vim.bo[bufnr].filetype = 'chill' + return 'chill' end -function M.csh(path, bufnr) end +function M.csh(path, bufnr) + if vim.fn.did_filetype() then + -- Filetype was already detected + return + end + if vim.g.filetype_csh then + return M.shell(path, bufnr, vim.g.filetype_csh) + elseif string.find(vim.o.shell, 'tcsh') then + return M.shell(path, bufnr, 'tcsh') + else + return M.shell(path, bufnr, 'csh') + end +end -- Determine if a *.dat file is Kuka Robot Language --- TODO: this one fails for some reason, so I omitted it. #18219 should be merged first. function M.dat(bufnr) - -- if vim.g.filetype_dat then - -- vim.bo[bufnr].filetype = vim.g.filetype_dat - -- return - -- end - -- local line = nextnonblank(bufnr, 1):lower() - -- if findany(line, { "^%s*&%w+", "^%s*defdat" }) then - -- vim.bo[bufnr].filetype = "krl" - -- end + if vim.g.filetype_dat then + return vim.g.filetype_dat + end + local line = nextnonblank(bufnr, 1) + if matchregex(line, [[\c\v^\s*%(\&\w+|defdat>)]]) then + return 'krl' + end end -- This function is called for all files under */debian/patches/*, make sure not @@ -231,8 +243,7 @@ function M.dep3patch(path, bufnr) '^Applied%-Upstream:', }) then - vim.bo[bufnr].filetype = 'dep3patch' - return + return 'dep3patch' elseif line:find('^%-%-%-') then -- End of headers found. stop processing return @@ -249,25 +260,24 @@ function M.dtrace(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do if matchregex(line, [[\c^module\>\|^import\>]]) then -- D files often start with a module and/or import statement. - vim.bo[bufnr].filetype = 'd' - return + return 'd' elseif findany(line, { '^#!%S+dtrace', '#pragma%s+D%s+option', ':%S-:%S-:' }) then - vim.bo[bufnr].filetype = 'dtrace' - return + return 'dtrace' end end - vim.bo[bufnr].filetype = 'd' + return 'd' end -function M.e(path, bufnr) +function M.e(bufnr) if vim.g.filetype_euphoria then - vim.bo[bufnr].filetype = vim.g.filetype_euphoria - return + return vim.g.filetype_euphoria end - -- TODO: WIP - -- for _, line in ipairs(getlines(bufnr, 1, 100)) do - -- if line:find("^$") - -- end + for _, line in ipairs(getlines(bufnr, 1, 100)) do + if findany(line, { "^%s*<'%s*$", "^%s*'>%s*$" }) then + return 'specman' + end + end + return 'eiffel' end -- This function checks for valid cl syntax in the first five lines. @@ -276,36 +286,34 @@ end function M.ent(bufnr) for _, line in ipairs(getlines(bufnr, 1, 5)) do if line:find('^%s*[#{]') then - vim.bo[bufnr].filetype = 'cl' - return + return 'cl' elseif not line:find('^%s*$') then -- Not a blank line, not a comment, and not a block start, -- so doesn't look like valid cl code. break end end - vim.bo[bufnr].filetype = 'dtd' + return 'dtd' end function M.euphoria(bufnr) if vim.g.filetype_euphoria then - vim.bo[bufnr].filetype = vim.g.filetype_euphoria + return vim.g.filetype_euphoria else - vim.bo[bufnr].filetype = 'euphoria3' + return 'euphoria3' end end function M.ex(bufnr) if vim.g.filetype_euphoria then - vim.bo[bufnr].filetype = vim.g.filetype_euphoria + return vim.g.filetype_euphoria else for _, line in ipairs(getlines(bufnr, 1, 100)) do if matchregex(line, [[\c^--\|^ifdef\>\|^include\>]]) then - vim.bo[bufnr].filetype = 'euphoria3' - return + return 'euphoria3' end end - vim.bo[bufnr].filetype = 'elixir' + return 'elixir' end end @@ -318,93 +326,110 @@ function M.foam(bufnr) if line:find('^FoamFile') then foam_file = true elseif foam_file and line:find('^%s*object') then - vim.bo[bufnr].filetype = 'foam' - return + return 'foam' end end end function M.frm(bufnr) if vim.g.filetype_frm then - vim.bo[bufnr].filetype = vim.g.filetype_frm - return + return vim.g.filetype_frm end local lines = table.concat(getlines(bufnr, 1, 5)):lower() if findany(lines, visual_basic_content) then - vim.bo[bufnr].filetype = 'vb' + return 'vb' else - vim.bo[bufnr].filetype = 'form' + return 'form' end end -- Distinguish between Forth and F#. function M.fs(bufnr) - -- TODO: WIP - -- if vim.g.filetype_fs then - -- vim.bo[bufnr].filetype = vim.g.filetype_fs - -- return - -- end - -- local line = nextnonblank(bufnr, 1) - -- if findany(line, { '^%s*.?%( ', '^%s*\\G? ', '^\\$', '^%s*: %S' }) then - -- vim.bo[bufnr].filetype = 'forth' - -- else - -- vim.bo[bufnr].filetype = 'fsharp' - -- end + if vim.g.filetype_fs then + return vim.g.filetype_fs + end + local line = nextnonblank(bufnr, 1) + if findany(line, { '^%s*%.?%( ', '^%s*\\G? ', '^\\$', '^%s*: %S' }) then + return 'forth' + else + return 'fsharp' + end end function M.header(bufnr) for _, line in ipairs(getlines(bufnr, 1, 200)) do if findany(line:lower(), { '^@interface', '^@end', '^@class' }) then if vim.g.c_syntax_for_h then - vim.bo[bufnr].filetype = 'objc' + return 'objc' else - vim.bo[bufnr].filetype = 'objcpp' + return 'objcpp' end - return end end if vim.g.c_syntax_for_h then - vim.bo[bufnr].filetype = 'c' + return 'c' elseif vim.g.ch_syntax_for_h then - vim.bo[bufnr].filetype = 'ch' + return 'ch' else - vim.bo[bufnr].filetype = 'cpp' + return 'cpp' end end function M.html(bufnr) for _, line in ipairs(getlines(bufnr, 1, 10)) do if matchregex(line, [[\\|{#\s\+]]) then - vim.bo[bufnr].filetype = 'htmldjango' - return + return 'htmldjango' end end - vim.bo[bufnr].filetype = 'html' + return 'html' end function M.idl(bufnr) for _, line in ipairs(getlines(bufnr, 1, 50)) do if findany(line:lower(), { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then - vim.bo[bufnr].filetype = 'msidl' - return + return 'msidl' end end - vim.bo[bufnr].filetype = 'idl' + return 'idl' end -function M.inc(path, bufnr) end +local pascal_comments = { '^%s*{', '^%s*%(%*', '^%s*//' } +local pascal_keywords = [[\c^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>]] + +function M.inc(bufnr) + if vim.g.filetype_inc then + return vim.g.filetype_inc + end + local lines = table.concat(getlines(bufnr, 1, 3)) + if lines:lower():find('perlscript') then + return 'aspperl' + elseif lines:find('<%%') then + return 'aspvbs' + elseif lines:find('<%?') then + return 'php' + -- Pascal supports // comments but they're vary rarely used for file + -- headers so assume POV-Ray + elseif findany(lines, { '^%s{', '^%s%(%*' }) or matchregex(lines, pascal_keywords) then + return 'pascal' + else + M.asm_syntax(bufnr) + if vim.b[bufnr].asm_syntax then + return vim.fn.fnameescape(vim.b[bufnr].asm_syntax) + else + return 'pov' + end + end +end function M.inp(bufnr) if getlines(bufnr, 1):find('^%*') then - vim.bo[bufnr].filetype = 'abaqus' + return 'abaqus' else for _, line in ipairs(getlines(bufnr, 1, 500)) do if line:lower():find('^header surface data') then - vim.bo[bufnr].filetype = 'trasys' - return + return 'trasys' end end end @@ -426,18 +451,16 @@ function M.lpc(bufnr) '^mixed', }) then - vim.bo[bufnr].filetype = 'lpc' - return + return 'lpc' end end end - vim.bo[bufnr].filetype = 'c' + return 'c' end function M.m(bufnr) if vim.g.filetype_m then - vim.bo[bufnr].filetype = vim.g.filetype_m - return + return vim.g.filetype_m end -- Excluding end(for|function|if|switch|while) common to Murphi @@ -455,25 +478,20 @@ function M.m(bufnr) saw_comment = true end if line:find('^%s*//') or matchregex(line, [[\c^\s*@import\>]]) or matchregex(line, objc_preprocessor) then - vim.bo[bufnr].filetype = 'objc' - return + return 'objc' end if findany(line, { '^%s*#', '^%s*%%!' }) or matchregex(line, [[\c^\s*unwind_protect\>]]) or matchregex(line, [[\c\%(^\|;\)\s*]] .. octave_block_terminators) then - vim.bo[bufnr].filetype = 'octave' - return + return 'octave' elseif line:find('^%s*%%') then - vim.bo[bufnr].filetype = 'matlab' - return + return 'matlab' elseif line:find('^%s*%(%*') then - vim.bo[bufnr].filetype = 'mma' - return + return 'mma' elseif matchregex(line, [[\c^\s*\(\(type\|var\)\>\|--\)]]) then - vim.bo[bufnr].filetype = 'murphi' - return + return 'murphi' end end @@ -481,10 +499,10 @@ function M.m(bufnr) -- We didn't see anything definitive, but this looks like either Objective C -- or Murphi based on the comment leader. Assume the former as it is more -- common. - vim.bo[bufnr].filetype = 'objc' + return 'objc' else -- Default is Matlab - vim.bo[bufnr].filetype = 'matlab' + return 'matlab' end end @@ -494,38 +512,33 @@ function M.mc(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do if findany(line:lower(), { '^%s*#', '^%s*dnl' }) then -- Sendmail .mc file - vim.bo[bufnr].filetype = 'm4' - return + return 'm4' elseif line:find('^%s*;') then - vim.bo[bufnr].filetype = 'msmessages' - return + return 'msmessages' end end -- Default: Sendmail .mc file - vim.bo[bufnr].filetype = 'm4' + return 'm4' end function M.mm(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do if matchregex(line, [[\c^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)]]) then - vim.bo[bufnr].filetype = 'objcpp' - return + return 'objcpp' end end - vim.bo[bufnr].filetype = 'nroff' + return 'nroff' end function M.mms(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do if findany(line, { '^%s*%%', '^%s*//', '^%*' }) then - vim.bo[bufnr].filetype = 'mmix' - return + return 'mmix' elseif line:find('^%s*#') then - vim.bo[bufnr].filetype = 'make' - return + return 'make' end end - vim.bo[bufnr].filetype = 'mmix' + return 'mmix' end -- Returns true if file content looks like LambdaProlog @@ -544,18 +557,18 @@ end -- Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod function M.mod(path, bufnr) if vim.g.filetype_mod then - vim.bo[bufnr].filetype = vim.g.filetype_mod + return vim.g.filetype_mod elseif is_lprolog(bufnr) then - vim.bo[bufnr].filetype = 'lprolog' + return 'lprolog' elseif matchregex(nextnonblank(bufnr, 1), [[\%(\]] +function M.pl(bufnr) + if vim.g.filetype_pl then + return vim.g.filetype_pl + end + -- Recognize Prolog by specific text in the first non-empty line; + -- require a blank after the '%' because Perl uses "%list" and "%translate" + local line = nextnonblank(bufnr, 1) + if + line and line:find(':%-') + or matchregex(line, [[\c\]]) + or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' }) + then + return 'prolog' + else + return 'perl' + end +end function M.pp(bufnr) - -- TODO: WIP - - -- if vim.g.filetype_pp then - -- vim.bo[bufnr].filetype = vim.g.filetype_pp - -- return - -- end - -- local first_line = nextnonblank(bufnr, 1):lower() - -- if findany(first_line, { pascal_comments, pascal_keywords }) then - -- vim.bo[bufnr].filetype = "pascal" - -- else - -- vim.bo[bufnr].filetype = "puppet" - -- end + if vim.g.filetype_pp then + return vim.g.filetype_pp + end + local line = nextnonblank(bufnr, 1) + if findany(line, pascal_comments) or matchregex(line, pascal_keywords) then + return 'pascal' + else + return 'puppet' + end end function M.prg(bufnr) if vim.g.filetype_prg then - vim.bo[bufnr].filetype = vim.g.filetype_prg + return vim.g.filetype_prg elseif is_rapid(bufnr) then - vim.bo[bufnr].filetype = 'rapid' + return 'rapid' else -- Nothing recognized, assume Clipper - vim.bo[bufnr].filetype = 'clipper' + return 'clipper' end end @@ -630,8 +649,7 @@ end -- If not found, assume Progress. function M.progress_asm(bufnr) if vim.g.filetype_i then - vim.bo[bufnr].filetype = vim.g.filetype_i - return + return vim.g.filetype_i end for _, line in ipairs(getlines(bufnr, 1, 10)) do @@ -643,17 +661,17 @@ function M.progress_asm(bufnr) break end end - vim.bo[bufnr].filetype = 'progress' + return 'progress' end function M.progress_cweb(bufnr) if vim.g.filetype_w then - vim.bo[bufnr].filetype = vim.g.filetype_w + return vim.g.filetype_w else if getlines(bufnr, 1):lower():find('^&analyze') or getlines(bufnr, 3):lower():find('^&global%-define') then - vim.bo[bufnr].filetype = 'progress' + return 'progress' else - vim.bo[bufnr].filetype = 'cweb' + return 'cweb' end end end @@ -663,58 +681,65 @@ end -- If not found, assume Progress. function M.progress_pascal(bufnr) if vim.g.filetype_p then - vim.bo[bufnr].filetype = vim.g.filetype_p - return + return vim.g.filetype_p end for _, line in ipairs(getlines(bufnr, 1, 10)) do if findany(line, pascal_comments) or matchregex(line, pascal_keywords) then - vim.bo[bufnr].filetype = 'pascal' - return + return 'pascal' elseif not line:find('^%s*$') or line:find('^/%*') then -- Not an empty line: Doesn't look like valid Pascal code. -- Or it looks like a Progress /* comment break end end - vim.bo[bufnr].filetype = 'progress' + return 'progress' end -function M.proto(path, bufnr) end +-- Distinguish between "default" and Cproto prototype file. +function M.proto(bufnr, default) + -- Cproto files have a comment in the first line and a function prototype in + -- the second line, it always ends in ";". Indent files may also have + -- comments, thus we can't match comments to see the difference. + -- IDL files can have a single ';' in the second line, require at least one + -- character before the ';'. + if getlines(bufnr, 2):find('.;$') then + return 'cpp' + else + return default + end +end function M.r(bufnr) local lines = getlines(bufnr, 1, 50) -- Rebol is easy to recognize, check for that first if matchregex(table.concat(lines), [[\c\]]) then - vim.bo[bufnr].filetype = 'rebol' - return + return 'rebol' end for _, line in ipairs(lines) do -- R has # comments if line:find('^%s*#') then - vim.bo[bufnr].filetype = 'r' - return + return 'r' end -- Rexx has /* comments */ if line:find('^%s*/%*') then - vim.bo[bufnr].filetype = 'rexx' - return + return 'rexx' end end -- Nothing recognized, use user default or assume R if vim.g.filetype_r then - vim.bo[bufnr].filetype = vim.g.filetype_r + return vim.g.filetype_r else -- Rexx used to be the default, but R appears to be much more popular. - vim.bo[bufnr].filetype = 'r' + return 'r' end end function M.redif(bufnr) for _, line in ipairs(getlines(bufnr, 1, 5)) do if line:lower():find('^template%-type:') then - vim.bo[bufnr].filetype = 'redif' + return 'redif' end end end @@ -732,28 +757,26 @@ function M.rules(path, bufnr) '/lib/udev/rules%.d/.*%.rules$', }) then - vim.bo[bufnr].filetype = 'udevrules' + return 'udevrules' elseif path:find('^/etc/ufw/') then -- Better than hog - vim.bo[bufnr].filetype = 'conf' + return 'conf' elseif findany(path, { '^/etc/polkit%-1/rules%.d', '/usr/share/polkit%-1/rules%.d' }) then - vim.bo[bufnr].filetype = 'javascript' + return 'javascript' else local ok, config_lines = pcall(vim.fn.readfile, '/etc/udev/udev.conf') if not ok then - vim.bo[bufnr].filetype = 'hog' - return + return 'hog' end local dir = vim.fn.expand(path, ':h') for _, line in ipairs(config_lines) do local match = line:match(udev_rules_pattern) local udev_rules = line:gsub(udev_rules_pattern, match, 1) if dir == udev_rules then - vim.bo[bufnr].filetype = 'udevrules' - return + return 'udevrules' end end - vim.bo[bufnr].filetype = 'hog' + return 'hog' end end @@ -767,11 +790,10 @@ function M.sc(bufnr) { '[A-Za-z0-9]*%s:%s[A-Za-z0-9]', 'var%s<', 'classvar%s<', '%^this.*', '|%w*|', '%+%s%w*%s{', '%*ar%s' } ) then - vim.bo[bufnr].filetype = 'supercollider' - return + return 'supercollider' end end - vim.bo[bufnr].filetype = 'scala' + return 'scala' end -- This function checks the first line of file extension "scd" to resolve @@ -781,47 +803,140 @@ function M.scd(bufnr) local opt = [[%s+"[^"]*"]] local line = getlines(bufnr, 1) if findany(line, { first .. '$', first .. opt .. '$', first .. opt .. opt .. '$' }) then - vim.bo[bufnr].filetype = 'scdoc' + return 'scdoc' else - vim.bo[bufnr].filetype = 'supercollider' + return 'supercollider' end end -function M.sh(path, bufnr) end +-- Also called from filetype.lua +function M.sh(path, bufnr, name) + if vim.fn.did_filetype() or path:find(vim.g.ft_ignore_pat) then + -- Filetype was already detected or detection should be skipped + return + end -function M.shell(path, bufnr) end + if matchregex(name, [[\]]) then + -- Some .sh scripts contain #!/bin/csh. + return M.shell(path, bufnr, 'csh') + -- Some .sh scripts contain #!/bin/tcsh. + elseif matchregex(name, [[\]]) then + return M.shell(path, bufnr, 'tcsh') + -- Some .sh scripts contain #!/bin/zsh. + elseif matchregex(name, [[\]]) then + return M.shell(path, bufnr, 'zsh') + elseif matchregex(name, [[\]]) then + vim.b[bufnr].is_kornshell = 1 + vim.b[bufnr].is_bash = nil + vim.b[bufnr].is_sh = nil + elseif vim.g.bash_is_sh or matchregex(name, [[\]]) or matchregex(name, [[\]]) then + vim.b[bufnr].is_bash = 1 + vim.b[bufnr].is_kornshell = nil + vim.b[bufnr].is_sh = nil + elseif matchregex(name, [[\]]) then + vim.b[bufnr].is_sh = 1 + vim.b[bufnr].is_kornshell = nil + vim.b[bufnr].is_bash = nil + end + return M.shell(path, bufnr, 'sh') +end + +-- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl. +-- Also called from scripts.vim, thus can't be local to this script. [TODO] +function M.shell(path, bufnr, name) + if vim.fn.did_filetype() or matchregex(path, vim.g.ft_ignore_pat) then + -- Filetype was already detected or detection should be skipped + return + end + local prev_line = '' + for _, line in ipairs(getlines(bufnr, 2, -1)) do + line = line:lower() + if line:find('%s*exec%s') and not prev_line:find('^%s*#.*\\$') then + -- Found an "exec" line after a comment with continuation + local n = line:gsub('%s*exec%s+([^ ]*/)?', '', 1) + if matchregex(n, [[\c\)]]) then - vim.bo[bufnr].filetype = 'krl' + return 'krl' end end function M.sys(bufnr) if vim.g.filetype_sys then - vim.bo[bufnr].filetype = vim.g.filetype_sys + return vim.g.filetype_sys elseif is_rapid(bufnr) then - vim.bo[bufnr].filetype = 'rapid' + return 'rapid' else - vim.bo[bufnr].filetype = 'bat' + return 'bat' end end -function M.tex(path, bufnr) end +-- Choose context, plaintex, or tex (LaTeX) based on these rules: +-- 1. Check the first line of the file for "%&". +-- 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords. +-- 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc. +function M.tex(path, bufnr) + local format = getlines(bufnr, 1):find('^%%&%s*(%a+)') + if format then + format = format:lower():gsub('pdf', '', 1) + if format == 'tex' then + return 'tex' + elseif format == 'plaintex' then + return 'plaintex' + end + elseif path:lower():find('tex/context/.*/.*%.tex') then + return 'context' + else + local lpat = [[documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>]] + local cpat = + [[start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>]] + + for i, l in ipairs(getlines(bufnr, 1, 1000)) do + -- Find first non-comment line + if not l:find('^%s*%%%S') then + -- Check the next thousand lines for a LaTeX or ConTeXt keyword. + for _, line in ipairs(getlines(bufnr, i + 1, i + 1000)) do + local lpat_match, cpat_match = matchregex(line, [[\c^\s*\\\%(]] .. lpat .. [[\)\|^\s*\\\(]] .. cpat .. [[\)]]) + if lpat_match then + return 'tex' + elseif cpat_match then + return 'context' + end + end + end + end + -- TODO: add AMSTeX, RevTex, others? + if not vim.g.tex_flavor or vim.g.tex_flavor == 'plain' then + return 'plaintex' + elseif vim.g.tex_flavor == 'context' then + return 'context' + else + -- Probably LaTeX + return 'tex' + end + end +end -- Determine if a *.tf file is TF mud client or terraform function M.tf(bufnr) @@ -829,11 +944,10 @@ function M.tf(bufnr) -- Assume terraform file on a non-empty line (not whitespace-only) -- and when the first non-whitespace character is not a ; or / if not line:find('^%s*$') and not line:find('^%s*[;/]') then - vim.bo[bufnr].filetype = 'terraform' - return + return 'terraform' end end - vim.bo[bufnr].filetype = 'tf' + return 'tf' end function M.xml(bufnr) @@ -844,29 +958,25 @@ function M.xml(bufnr) if is_docbook4 or is_docbook5 then vim.b[bufnr].docbk_type = 'xml' vim.b[bufnr].docbk_ver = is_docbook4 and 4 or 5 - vim.bo[bufnr].filetype = 'docbk' - return + return 'docbk' end if line:find([[xmlns:xbl="http://www.mozilla.org/xbl"]]) then - vim.bo[bufnr].filetype = 'xbl' - return + return 'xbl' end end - vim.bo[bufnr].filetype = 'xml' + return 'xml' end function M.y(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do if line:find('^%s*%%') then - vim.bo[bufnr].filetype = 'yacc' - return + return 'yacc' end if matchregex(line, [[\c^\s*\(#\|class\>\)]]) and not line:lower():find('^%s*#%s*include') then - vim.bo[bufnr].filetype = 'racc' - return + return 'racc' end end - vim.bo[bufnr].filetype = 'yacc' + return 'yacc' end -- luacheck: pop -- cgit From 378615b8ee9440edb9ab7c71d847d03d52c61b2f Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 22 May 2022 13:21:44 -0600 Subject: fix(lsp): do not detach LSP servers on Windows #18703 Detaching the process seems to have unintended side effects on Windows, so only do it by default on non-Windows platforms. Ref: https://github.com/neovim/nvim-lspconfig/issues/1907 Closes https://github.com/neovim/nvim-lspconfig/pull/1913 --- runtime/lua/vim/lsp/rpc.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 2dcafc92bc..ad2498fb6f 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -4,6 +4,8 @@ local log = require('vim.lsp.log') local protocol = require('vim.lsp.protocol') local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap +local is_win = uv.os_uname().version:find('Windows') + ---@private --- Checks whether a given path exists and is a directory. ---@param filename (string) path to check @@ -321,7 +323,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) local spawn_params = { args = cmd_args, stdio = { stdin, stdout, stderr }, - detached = true, + detached = not is_win, } if extra_spawn_params then spawn_params.cwd = extra_spawn_params.cwd -- cgit From 5eaf9ef8110aa2e05042385d56916a804bb61a05 Mon Sep 17 00:00:00 2001 From: notomo Date: Tue, 24 May 2022 09:55:03 +0900 Subject: fix(filetype): correct vim.fn.did_filetype() handling (#18725) --- runtime/lua/vim/filetype/detect.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 1721923c18..f195693dcf 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -62,6 +62,11 @@ local matchregex = (function() end end)() +---@private +local did_filetype = function() + return vim.fn.did_filetype() ~= 0 +end + -- luacheck: push no unused args -- luacheck: push ignore 122 @@ -195,7 +200,7 @@ function M.change(bufnr) end function M.csh(path, bufnr) - if vim.fn.did_filetype() then + if did_filetype() then -- Filetype was already detected return end @@ -252,8 +257,7 @@ function M.dep3patch(path, bufnr) end function M.dtrace(bufnr) - local did_filetype = vim.fn.did_filetype() - if did_filetype and did_filetype ~= 0 then + if did_filetype() then -- Filetype was already detected return end @@ -811,7 +815,7 @@ end -- Also called from filetype.lua function M.sh(path, bufnr, name) - if vim.fn.did_filetype() or path:find(vim.g.ft_ignore_pat) then + if did_filetype() or path:find(vim.g.ft_ignore_pat) then -- Filetype was already detected or detection should be skipped return end @@ -844,7 +848,7 @@ end -- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl. -- Also called from scripts.vim, thus can't be local to this script. [TODO] function M.shell(path, bufnr, name) - if vim.fn.did_filetype() or matchregex(path, vim.g.ft_ignore_pat) then + if did_filetype() or matchregex(path, vim.g.ft_ignore_pat) then -- Filetype was already detected or detection should be skipped return end -- cgit From c6d6b8c7eb180f56e87e1427958f91a867f5cc8c Mon Sep 17 00:00:00 2001 From: Elton Leander Pinto Date: Wed, 25 May 2022 12:47:49 -0400 Subject: fix(lsp): respect global syntax setting in open float preview (#15225) --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 4663cf9f09..63e9342b1a 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1477,7 +1477,7 @@ function M.open_floating_preview(contents, syntax, opts) }) opts = opts or {} opts.wrap = opts.wrap ~= false -- wrapping by default - opts.stylize_markdown = opts.stylize_markdown ~= false + opts.stylize_markdown = opts.stylize_markdown ~= false and vim.g.syntax_on ~= nil opts.focus = opts.focus ~= false opts.close_events = opts.close_events or { 'CursorMoved', 'CursorMovedI', 'InsertCharPre' } -- cgit From fa3492c5f7645feb979c767046b6ff335ea9d6ca Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Wed, 25 May 2022 19:38:01 +0200 Subject: feat(lsp)!: turn format filter into predicate (#18458) This makes the common use case easier. If one really needs access to all clients, they can create a filter function which manually calls `get_active_clients`. --- runtime/lua/vim/lsp/buf.lua | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 1207da094a..0e86bff4f2 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -177,20 +177,15 @@ end --- - bufnr (number|nil): --- Restrict formatting to the clients attached to the given buffer, defaults to the current --- buffer (0). +--- --- - filter (function|nil): ---- Predicate to filter clients used for formatting. Receives the list of clients attached ---- to bufnr as the argument and must return the list of clients on which to request ---- formatting. Example: +--- Predicate used to filter clients. Receives a client as argument and must return a +--- boolean. Clients matching the predicate are included. Example: --- ---
 ---         -- Never request typescript-language-server for formatting
 ---         vim.lsp.buf.format {
----           filter = function(clients)
----             return vim.tbl_filter(
----               function(client) return client.name ~= "tsserver" end,
----               clients
----             )
----           end
+---           filter = function(client) return client.name ~= "tsserver" end
 ---         }
 ---         
--- @@ -207,18 +202,14 @@ end function M.format(options) options = options or {} local bufnr = options.bufnr or vim.api.nvim_get_current_buf() - local clients = vim.lsp.buf_get_clients(bufnr) + local clients = vim.lsp.get_active_clients({ + id = options.id, + bufnr = bufnr, + name = options.name, + }) if options.filter then - clients = options.filter(clients) - elseif options.id then - clients = vim.tbl_filter(function(client) - return client.id == options.id - end, clients) - elseif options.name then - clients = vim.tbl_filter(function(client) - return client.name == options.name - end, clients) + clients = vim.tbl_filter(options.filter, clients) end clients = vim.tbl_filter(function(client) -- cgit From 8c4e62351f67dd6a44f67f3a2b6f3a3551acf475 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Wed, 25 May 2022 11:45:45 -0600 Subject: refactor(lsp): remove redundant client cleanup (#18744) The client state is cleaned up both in client.stop() as well as in the client.on_exit() handler. Technically, the client has not actually stopped until the on_exit handler is called, so we should just do this cleanup there and remove it from client.stop(). --- runtime/lua/vim/lsp.lua | 6 ------ 1 file changed, 6 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 07987ee003..dac2860690 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1188,12 +1188,6 @@ function lsp.start_client(config) --- ---@param force (bool, optional) function client.stop(force) - lsp.diagnostic.reset(client_id, all_buffer_active_clients) - changetracking.reset(client_id) - for _, client_ids in pairs(all_buffer_active_clients) do - client_ids[client_id] = nil - end - local handle = rpc.handle if handle:is_closing() then return -- cgit From 068fb748e18f7907e2e2b9363b009fe5f3288f02 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Thu, 26 May 2022 02:07:58 +0200 Subject: vim-patch:8.2.5015: Hoon and Moonscript files are not recognized (#18747) Problem: Hoon and Moonscript files are not recognized. Solution: Add filetype patterns. (Goc Dundar, closes vim/vim#10478) https://github.com/vim/vim/commit/bf82df0dd48a26404b92a596498b6892c9572c53 --- runtime/lua/vim/filetype.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c9e81b53d7..c26a43f776 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -283,6 +283,7 @@ local extension = { hjson = 'hjson', hog = 'hog', hws = 'hollywood', + hoon = 'hoon', htt = 'httest', htb = 'httest', iba = 'ibasic', @@ -418,6 +419,7 @@ local extension = { tsc = 'monk', isc = 'monk', moo = 'moo', + moon = 'moonscript', mp = 'mp', mof = 'msidl', odl = 'msidl', @@ -1058,6 +1060,7 @@ local filename = { ['.dircolors'] = 'dircolors', ['/etc/dnsmasq.conf'] = 'dnsmasq', Containerfile = 'dockerfile', + dockerfile = 'dockerfile', Dockerfile = 'dockerfile', npmrc = 'dosini', ['/etc/yum.conf'] = 'dosini', -- cgit From e8ada41b63ebd916a44240de661faa64a1d0c941 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 26 May 2022 12:28:50 +0200 Subject: feat(lsp): turn rename filter into a predicate (#18745) Same as https://github.com/neovim/neovim/pull/18458 but for rename --- runtime/lua/vim/lsp/buf.lua | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 0e86bff4f2..bcfaecdfcc 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -377,23 +377,20 @@ end --- name using |vim.ui.input()|. ---@param options table|nil additional options --- - filter (function|nil): ---- Predicate to filter clients used for rename. ---- Receives the attached clients as argument and must return a list of ---- clients. +--- Predicate used to filter clients. Receives a client as argument and +--- must return a boolean. Clients matching the predicate are included. --- - name (string|nil): --- Restrict clients used for rename to ones where client.name matches --- this field. function M.rename(new_name, options) options = options or {} local bufnr = options.bufnr or vim.api.nvim_get_current_buf() - local clients = vim.lsp.buf_get_clients(bufnr) - + local clients = vim.lsp.get_active_clients({ + bufnr = bufnr, + name = options.name, + }) if options.filter then - clients = options.filter(clients) - elseif options.name then - clients = vim.tbl_filter(function(client) - return client.name == options.name - end, clients) + clients = vim.tbl_filter(options.filter, clients) end -- Clients must at least support rename, prepareRename is optional -- cgit From eab4d03a3264b2afaf803ed839fa25bc4e7acedd Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 28 May 2022 18:22:18 +0100 Subject: fix(treesitter): offset directive associates range with capture (#18276) Previously the `offset!` directive populated the metadata in such a way that the new range could be attributed to a specific capture. #14046 made it so the directive simply stored just the new range in the metadata and information about what capture the range is based from is lost. This change reverts that whilst also correcting the docs. --- runtime/lua/vim/treesitter/languagetree.lua | 21 ++++++++++++++++----- runtime/lua/vim/treesitter/query.lua | 27 +++++++++++++++++++-------- 2 files changed, 35 insertions(+), 13 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 57d8c5fd21..5a05a29da8 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -295,6 +295,14 @@ function LanguageTree:included_regions() return self._regions end +---@private +local function get_node_range(node, id, metadata) + if metadata[id] and metadata[id].range then + return metadata[id].range + end + return { node:range() } +end + --- Gets language injection points by language. --- --- This is where most of the injection processing occurs. @@ -327,10 +335,10 @@ function LanguageTree:_get_injections() -- Allow for captured nodes to be used if type(content) == 'number' then - content = { match[content] } + content = { match[content]:range() } end - if content then + if type(content) == 'table' and #content >= 4 then vim.list_extend(ranges, content) end end @@ -351,7 +359,7 @@ function LanguageTree:_get_injections() elseif name == 'combined' then combined = true elseif name == 'content' and #ranges == 0 then - table.insert(ranges, node) + table.insert(ranges, get_node_range(node, id, metadata)) -- Ignore any tags that start with "_" -- Allows for other tags to be used in matches elseif string.sub(name, 1, 1) ~= '_' then @@ -360,7 +368,7 @@ function LanguageTree:_get_injections() end if #ranges == 0 then - table.insert(ranges, node) + table.insert(ranges, get_node_range(node, id, metadata)) end end end @@ -397,7 +405,10 @@ function LanguageTree:_get_injections() for _, entry in pairs(patterns) do if entry.combined then - table.insert(result[lang], vim.tbl_flatten(entry.regions)) + local regions = vim.tbl_map(function(e) + return vim.tbl_flatten(e) + end, entry.regions) + table.insert(result[lang], regions) else for _, ranges in ipairs(entry.regions) do table.insert(result[lang], ranges) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 3c4c8fdb96..0cc2b6d2a4 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -313,20 +313,22 @@ local directive_handlers = { ['set!'] = function(_, _, _, pred, metadata) if #pred == 4 then -- (#set! @capture "key" "value") - local capture = pred[2] - if not metadata[capture] then - metadata[capture] = {} + local _, capture_id, key, value = unpack(pred) + if not metadata[capture_id] then + metadata[capture_id] = {} end - metadata[capture][pred[3]] = pred[4] + metadata[capture_id][key] = value else + local _, key, value = unpack(pred) -- (#set! "key" "value") - metadata[pred[2]] = pred[3] + metadata[key] = value end end, -- Shifts the range of a node. -- Example: (#offset! @_node 0 1 0 -1) ['offset!'] = function(match, _, _, pred, metadata) - local offset_node = match[pred[2]] + local capture_id = pred[2] + local offset_node = match[capture_id] local range = { offset_node:range() } local start_row_offset = pred[3] or 0 local start_col_offset = pred[4] or 0 @@ -340,7 +342,10 @@ local directive_handlers = { -- If this produces an invalid range, we just skip it. if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then - metadata.content = { range } + if not metadata[capture_id] then + metadata[capture_id] = {} + end + metadata[capture_id].range = range end end, } @@ -360,9 +365,14 @@ end --- Adds a new directive to be used in queries --- +--- Handlers can set match level data by setting directly on the +--- metadata object `metadata.key = value`, additionally, handlers +--- can set node level data by using the capture id on the +--- metadata table `metadata[capture_id].key = value` +--- ---@param name the name of the directive, without leading # ---@param handler the handler function to be used ---- signature will be (match, pattern, bufnr, predicate) +--- signature will be (match, pattern, bufnr, predicate, metadata) function M.add_directive(name, handler, force) if directive_handlers[name] and not force then error(string.format('Overriding %s', name)) @@ -371,6 +381,7 @@ function M.add_directive(name, handler, force) directive_handlers[name] = handler end +--- Lists the currently available directives to use in queries. ---@return The list of supported directives. function M.list_directives() return vim.tbl_keys(directive_handlers) -- cgit From b66e9e0baaea6bec52da4bea8eb7ae2c1db3b9f5 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 22 Apr 2022 14:12:08 +0200 Subject: feat(filetype): convert more patterns to filetype.lua --- runtime/lua/vim/filetype.lua | 178 +++++++++++++++++++++++++++++++++++- runtime/lua/vim/filetype/detect.lua | 71 ++++++++++++++ 2 files changed, 245 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c26a43f776..7a8f7187b9 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -23,12 +23,15 @@ local function starsetf(ft) end ---@private -local function getline(bufnr, lnum) - return api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, false)[1] or '' +local function getline(bufnr, start_lnum, end_lnum) + end_lnum = end_lnum or start_lnum + local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) + return table.concat(lines) or '' end -- Filetypes based on file extension -- luacheck: push no unused args +---@diagnostic disable: unused-local local extension = { -- BEGIN EXTENSION ['8th'] = '8th', @@ -52,8 +55,17 @@ local extension = { art = 'art', asciidoc = 'asciidoc', adoc = 'asciidoc', + asa = function(path, bufnr) + if vim.g.filetype_asa then + return vim.g.filetype_asa + end + return 'aspvbs' + end, ['asn1'] = 'asn', asn = 'asn', + asp = function(path, bufnr) + return require('vim.filetype.detect').asp(bufnr) + end, atl = 'atlas', as = 'atlas', ahk = 'autohotkey', @@ -92,7 +104,6 @@ local extension = { cho = 'chordpro', chordpro = 'chordpro', eni = 'cl', - dcl = 'clean', icl = 'clean', cljx = 'clojure', clj = 'clojure', @@ -129,7 +140,7 @@ local extension = { hxx = 'cpp', hpp = 'cpp', cpp = function(path, bufnr) - if vim.g.cynlib_syntax_for_cc then + if vim.g.cynlib_syntax_for_cpp then return 'cynlib' end return 'cpp' @@ -688,6 +699,16 @@ local extension = { bbl = 'tex', latex = 'tex', sty = 'tex', + cls = function(path, bufnr) + local line = getline(bufnr, 1) + if line:find('^%%') then + return 'tex' + elseif line:find('^#') and line:lower():find('rexx') then + return 'rexx' + else + return 'st' + end + end, texi = 'texinfo', txi = 'texinfo', texinfo = 'texinfo', @@ -766,6 +787,12 @@ local extension = { csproj = 'xml', wpl = 'xml', xmi = 'xml', + xpm = function(path, bufnr) + if getline(bufnr, 1):find('XPM2') then + return 'xpm2' + end + return 'xpm' + end, ['xpm2'] = 'xpm2', xqy = 'xquery', xqm = 'xquery', @@ -1009,6 +1036,145 @@ local extension = { return 'text' end end, + cmd = function(path, bufnr) + if getline(bufnr, 1):find('^/%*') then + return 'rexx' + end + return 'dosbatch' + end, + rul = function(path, bufnr) + return require('vim.filetype.detect').rul(bufnr) + end, + cpy = function(path, bufnr) + if getline(bufnr, 1):find('^##') then + return 'python' + end + return 'cobol' + end, + dsl = function(path, bufnr) + if getline(bufnr, 1):find('^%s*') then + return 'xml' + end + return 'smil' + end, + smi = function(path, bufnr) + return require('vim.filetype.detect').smi(bufnr) + end, + install = function(path, bufnr) + if getline(bufnr, 1):lower():find('<%?php') then + return 'php' + end + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + pm = function(path, bufnr) + local line = getline(bufnr, 1) + if line:find('XPM2') then + return 'xpm2' + elseif line:find('XPM') then + return 'xpm' + else + return 'perl' + end + end, + me = function(path, bufnr) + local filename = vim.fn.fnamemodify(path, ':t'):lower() + if filename ~= 'read.me' and filename ~= 'click.me' then + return 'nroff' + end + end, + reg = function(path, bufnr) + local line = getline(bufnr, 1):lower() + if line:find('^regedit[0-9]*%s*$') or line:find('^windows registry editor version %d*%.%d*%s*$') then + return 'registry' + end + end, + decl = function(path, bufnr) + return require('vim.filetype.detect').decl(bufnr) + end, + dec = function(path, bufnr) + return require('vim.filetype.detect').decl(bufnr) + end, + dcl = function(path, bufnr) + local decl = require('vim.filetype.detect').decl(bufnr) + if decl then + return decl + end + return 'clean' + end, + web = function(path, bufnr) + return require('vim.filetype.detect').web(bufnr) + end, + ttl = function(path, bufnr) + local line = getline(bufnr, 1):lower() + if line:find('^@?prefix') or line:find('^@?base') then + return 'turtle' + end + return 'teraterm' + end, + am = function(path, bufnr) + if not path:lower():find('makefile%.am$') then + return 'elf' + end + end, + ['m4'] = function(path, bufnr) + local path_lower = path:lower() + if not path_lower:find('html%.m4$') and not path_lower:find('fvwm2rc') then + return 'm4' + end + end, + hw = function(path, bufnr) + return require('vim.filetype.detect').hw(bufnr) + end, + module = function(path, bufnr) + return require('vim.filetype.detect').hw(bufnr) + end, + pkg = function(path, bufnr) + return require('vim.filetype.detect').hw(bufnr) + end, + ms = function(path, bufnr) + if not require('vim.filetype.detect').nroff(bufnr) then + return 'xmath' + end + end, + t = function(path, bufnr) + if not require('vim.filetype.detect').nroff(bufnr) and not require('vim.filetype.detect').perl(path, bufnr) then + return 'tads' + end + end, + class = function(path, bufnr) + -- Check if not a Java class (starts with '\xca\xfe\xba\xbe') + if not getline(bufnr, 1):find('^\202\254\186\190') then + return 'stata' + end + end, + sgml = function(path, bufnr) + return require('vim.filetype.detect').sgml(bufnr) + end, + sgm = function(path, bufnr) + return require('vim.filetype.detect').sgml(bufnr) + end, + rc = function(path, bufnr) + if not path:find('/etc/Muttrc%.d/') then + return 'rc' + end + end, + rch = function(path, bufnr) + if not path:find('/etc/Muttrc%.d/') then + return 'rc' + end + end, -- END EXTENSION } @@ -1421,6 +1587,7 @@ local pattern = { ['.*/boot/grub/grub%.conf'] = 'grub', ['.*/boot/grub/menu%.lst'] = 'grub', ['.*/etc/grub%.conf'] = 'grub', + [vim.env.VIMRUNTIME .. '/doc/.*%.txt'] = 'help', ['hg%-editor%-.*%.txt'] = 'hgcommit', ['.*/etc/host%.conf'] = 'hostconf', ['.*/etc/hosts%.deny'] = 'hostsaccess', @@ -1475,6 +1642,7 @@ local pattern = { ['.*/etc/passwd'] = 'passwd', ['.*/etc/passwd%.edit'] = 'passwd', ['.*/etc/shadow-'] = 'passwd', + ['.*%.php%d'] = 'php', ['.*/%.pinforc'] = 'pinfo', ['.*/etc/pinforc'] = 'pinfo', ['.*/etc/protocols'] = 'protocols', @@ -1707,6 +1875,8 @@ local pattern = { ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr) return require('vim.filetype.detect').sys(bufnr) end, + ['%.?gitolite%.rc'] = 'perl', + ['example%.gitolite%.rc'] = 'perl', -- Neovim only ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries -- END PATTERN diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index f195693dcf..b35303eefc 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -983,6 +983,77 @@ function M.y(bufnr) return 'yacc' end +function M.decl(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 3)) do + if line:lower():find('^]]) then + return 'edif' + else + return 'clojure' + end +end + +function M.smi(bufnr) + local line = getlines(bufnr, 1) + if matchregex(line, [[\c\]]) then + return 'smil' + else + return 'mib' + end +end + +function M.hw(bufnr) + if getlines(bufnr, 1):lower():find('<%?php') then + return 'php' + end + return 'virata' +end -- luacheck: pop -- luacheck: pop -- cgit From 1a20aed3fb35e00f96aa18abb69d35912c9e119d Mon Sep 17 00:00:00 2001 From: Chris Kipp Date: Tue, 31 May 2022 13:19:45 +0200 Subject: fix(lsp): include cancellable in progress message table (#18809) Currently the `title`, `message` and `percentage` is stored for a progress, but there is also an optional `cancellable` that comes in with both the `WorkDoneProgressBegin` and also `WorkDoneProgressReport`. This change also stores that value so that a plugin can access it when they do a lookup in `client.messages`. --- runtime/lua/vim/lsp/handlers.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 61cc89dcac..935f4b64f8 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -40,10 +40,12 @@ local function progress_handler(_, result, ctx, _) if val.kind == 'begin' then client.messages.progress[token] = { title = val.title, + cancellable = val.cancellable, message = val.message, percentage = val.percentage, } elseif val.kind == 'report' then + client.messages.progress[token].cancellable = val.cancellable client.messages.progress[token].message = val.message client.messages.progress[token].percentage = val.percentage elseif val.kind == 'end' then -- cgit From e6652821bd32e4ff8d62a0b67fc2041a5f41e252 Mon Sep 17 00:00:00 2001 From: Javier Lopez Date: Tue, 31 May 2022 13:10:18 -0500 Subject: refactor(checkhealth)!: rename to vim.health, move logic to Lua #18720 - Complete function: There was lots of unnecessary C code for the complete function, therefore moving it to Lua and use all the plumbing we have in place to retrieve the results. - Moving the module: It's important we keep nvim lua modules name spaced, avoids conflict with plugins, luarocks, etc. --- runtime/lua/vim/_editor.lua | 1 + runtime/lua/vim/health.lua | 47 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 runtime/lua/vim/health.lua (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index e6ab48f30d..c8a0aa8260 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -49,6 +49,7 @@ for k, v in pairs({ diagnostic = true, keymap = true, ui = true, + health = true, }) do vim._submodules[k] = v end diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua new file mode 100644 index 0000000000..67c5c3b37f --- /dev/null +++ b/runtime/lua/vim/health.lua @@ -0,0 +1,47 @@ +local M = {} + +function M.report_start(msg) + vim.fn['health#report_start'](msg) +end + +function M.report_info(msg) + vim.fn['health#report_info'](msg) +end + +function M.report_ok(msg) + vim.fn['health#report_ok'](msg) +end + +function M.report_warn(msg, ...) + vim.fn['health#report_warn'](msg, ...) +end + +function M.report_error(msg, ...) + vim.fn['health#report_error'](msg, ...) +end + +local path2name = function(path) + if path:match('%.lua$') then + -- Lua: transform "../lua/vim/lsp/health.lua" into "vim.lsp" + return path:gsub('.-lua[%\\%/]', '', 1):gsub('[%\\%/]', '.'):gsub('%.health.-$', '') + else + -- Vim: transform "../autoload/health/provider.vim" into "provider" + return vim.fn.fnamemodify(path, ':t:r') + end +end + +local PATTERNS = { '/autoload/health/*.vim', '/lua/**/**/health.lua', '/lua/**/**/health/init.lua' } +-- :checkhealth completion function used by ex_getln.c get_healthcheck_names() +M._complete = function() + local names = vim.tbl_flatten(vim.tbl_map(function(pattern) + return vim.tbl_map(path2name, vim.api.nvim_get_runtime_file(pattern, true)) + end, PATTERNS)) + -- Remove duplicates + local unique = {} + vim.tbl_map(function(f) + unique[f] = true + end, names) + return vim.tbl_keys(unique) +end + +return M -- cgit From 67cbaf58c41a3db19c5014587e72d06be9e3d58e Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sun, 15 May 2022 14:38:19 -0600 Subject: feat(fs): add vim.fs.parents() vim.fs.parents() is a Lua iterator that returns the next parent directory of the given file or directory on each iteration. --- runtime/lua/vim/_editor.lua | 1 + runtime/lua/vim/fs.lua | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 runtime/lua/vim/fs.lua (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index c8a0aa8260..453aa6ac81 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -50,6 +50,7 @@ for k, v in pairs({ keymap = true, ui = true, health = true, + fs = true, }) do vim._submodules[k] = v end diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua new file mode 100644 index 0000000000..08d2e495d2 --- /dev/null +++ b/runtime/lua/vim/fs.lua @@ -0,0 +1,35 @@ +local M = {} + +--- Iterate over all the parents of the given file or directory. +--- +--- Example: +---
+--- local root_dir
+--- for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
+---   if vim.fn.isdirectory(dir .. "/.git") == 1 then
+---     root_dir = dir
+---     break
+---   end
+--- end
+---
+--- if root_dir then
+---   print("Found git repository at", root_dir)
+--- end
+--- 
+--- +---@param start (string) Initial file or directory. +---@return (function) Iterator +function M.parents(start) + return function(_, dir) + local parent = vim.fn.fnamemodify(dir, ":h") + if parent == dir then + return nil + end + + return parent + end, + nil, + start +end + +return M -- cgit From c5526a27c3b61acb33b7c3c3fe518d8f1e0b602f Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sun, 15 May 2022 19:53:23 -0600 Subject: feat(fs): add vim.fs.dirname() --- runtime/lua/vim/fs.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 08d2e495d2..a3b7321cc9 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -21,7 +21,7 @@ local M = {} ---@return (function) Iterator function M.parents(start) return function(_, dir) - local parent = vim.fn.fnamemodify(dir, ":h") + local parent = M.dirname(dir) if parent == dir then return nil end @@ -32,4 +32,12 @@ function M.parents(start) start end +--- Return the parent directory of the given file or directory +--- +---@param file (string) File or directory +---@return (string) Parent directory of {file} +function M.dirname(file) + return vim.fn.fnamemodify(file, ':h') +end + return M -- cgit From b740709431f5e68dac5238d455f9f86d5a564f36 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sun, 15 May 2022 19:55:18 -0600 Subject: feat(fs): add vim.fs.basename() --- runtime/lua/vim/fs.lua | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index a3b7321cc9..29ce394a38 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -40,4 +40,12 @@ function M.dirname(file) return vim.fn.fnamemodify(file, ':h') end +--- Return the basename of the given file or directory +--- +---@param file (string) File or directory +---@return (string) Basename of {file} +function M.basename(file) + return vim.fn.fnamemodify(file, ':t') +end + return M -- cgit From 2a62bec37ced51678ff914700d7165605d5a0d53 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sun, 15 May 2022 20:10:12 -0600 Subject: feat(fs): add vim.fs.dir() This function is modeled after the path.dir() function from Penlight and the luafilesystem module. --- runtime/lua/vim/fs.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 29ce394a38..c28b06536b 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -48,4 +48,17 @@ function M.basename(file) return vim.fn.fnamemodify(file, ':t') end +--- Return an iterator over the files and directories located in {path} +--- +---@param path (string) An absolute or relative path to the directory to iterate +--- over +---@return Iterator over files and directories in {path}. Each iteration yields +--- two values: name and type. Each "name" is the basename of the file or +--- directory relative to {path}. Type is one of "file" or "directory". +function M.dir(path) + return function(fs) + return vim.loop.fs_scandir_next(fs) + end, vim.loop.fs_scandir(path) +end + return M -- cgit From f271d706611049bc53a6a439b310fe60bf0fab13 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Sun, 15 May 2022 20:37:35 -0600 Subject: feat(fs): add vim.fs.find() This is a pure Lua implementation of the Vim findfile() and finddir() functions without the special syntax. --- runtime/lua/vim/fs.lua | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index c28b06536b..4519f2a1e4 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -61,4 +61,121 @@ function M.dir(path) end, vim.loop.fs_scandir(path) end +--- Find files or directories in the given path. +--- +--- Finds any files or directories given in {names} starting from {path}. If +--- {upward} is "true" then the search traverses upward through parent +--- directories; otherwise, the search traverses downward. Note that downward +--- searches are recursive and may search through many directories! If {stop} +--- is non-nil, then the search stops when the directory given in {stop} is +--- reached. The search terminates when {limit} (default 1) matches are found. +--- The search can be narrowed to find only files or or only directories by +--- specifying {type} to be "file" or "directory", respectively. +--- +---@param names (string|table) Names of the files and directories to find. Must +--- be base names, paths and globs are not supported. +---@param opts (table) Optional keyword arguments: +--- - path (string): Path to begin searching from. If +--- omitted, the current working directory is used. +--- - upward (boolean, default false): If true, search +--- upward through parent directories. Otherwise, +--- search through child directories +--- (recursively). +--- - stop (string): Stop searching when this directory is +--- reached. The directory itself is not searched. +--- - type (string): Find only files ("file") or +--- directories ("directory"). If omitted, both +--- files and directories that match {name} are +--- included. +--- - limit (number, default 1): Stop the search after +--- finding this many matches. Use `math.huge` to +--- place no limit on the number of matches. +---@return (table) The paths of all matching files or directories +function M.find(names, opts) + opts = opts or {} + vim.validate({ + names = { names, { 's', 't' } }, + path = { opts.path, 's', true }, + upward = { opts.upward, 'b', true }, + stop = { opts.stop, 's', true }, + type = { opts.type, 's', true }, + limit = { opts.limit, 'n', true }, + }) + + names = type(names) == 'string' and { names } or names + + local path = opts.path or vim.loop.cwd() + local stop = opts.stop + local limit = opts.limit or 1 + + local matches = {} + + ---@private + local function add(match) + matches[#matches + 1] = match + if #matches == limit then + return true + end + end + + if opts.upward then + ---@private + local function test(p) + local t = {} + for _, name in ipairs(names) do + local f = p .. '/' .. name + local stat = vim.loop.fs_stat(f) + if stat and (not opts.type or opts.type == stat.type) then + t[#t + 1] = f + end + end + + return t + end + + for _, match in ipairs(test(path)) do + if add(match) then + return matches + end + end + + for parent in M.parents(path) do + if stop and parent == stop then + break + end + + for _, match in ipairs(test(parent)) do + if add(match) then + return matches + end + end + end + else + local dirs = { path } + while #dirs > 0 do + local dir = table.remove(dirs, 1) + if stop and dir == stop then + break + end + + for other, type in M.dir(dir) do + local f = dir .. '/' .. other + for _, name in ipairs(names) do + if name == other and (not opts.type or opts.type == type) then + if add(f) then + return matches + end + end + end + + if type == 'directory' then + dirs[#dirs + 1] = f + end + end + end + end + + return matches +end + return M -- cgit From 046b4ed461cb78b8b302a6403cc7ea64ad6b6085 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Tue, 17 May 2022 08:49:33 -0600 Subject: feat(fs): add vim.fs.normalize() --- runtime/lua/vim/fs.lua | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 4519f2a1e4..9bf38f7bc3 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -51,14 +51,14 @@ end --- Return an iterator over the files and directories located in {path} --- ---@param path (string) An absolute or relative path to the directory to iterate ---- over +--- over. The path is first normalized |vim.fs.normalize()|. ---@return Iterator over files and directories in {path}. Each iteration yields --- two values: name and type. Each "name" is the basename of the file or --- directory relative to {path}. Type is one of "file" or "directory". function M.dir(path) return function(fs) return vim.loop.fs_scandir_next(fs) - end, vim.loop.fs_scandir(path) + end, vim.loop.fs_scandir(M.normalize(path)) end --- Find files or directories in the given path. @@ -178,4 +178,28 @@ function M.find(names, opts) return matches end +--- Normalize a path to a standard format. A tilde (~) character at the +--- beginning of the path is expanded to the user's home directory and any +--- backslash (\\) characters are converted to forward slashes (/). Environment +--- variables are also expanded. +--- +--- Example: +---
+--- vim.fs.normalize('C:\\Users\\jdoe')
+--- => 'C:/Users/jdoe'
+---
+--- vim.fs.normalize('~/src/neovim')
+--- => '/home/jdoe/src/neovim'
+---
+--- vim.fs.normalize('$XDG_CONFIG_HOME/nvim/init.vim')
+--- => '/Users/jdoe/.config/nvim/init.vim'
+--- 
+--- +---@param path (string) Path to normalize +---@return (string) Normalized path +function M.normalize(path) + vim.validate({ path = { path, 's' } }) + return (path:gsub('^~/', vim.env.HOME .. '/'):gsub('%$([%w_]+)', vim.env):gsub('\\', '/')) +end + return M -- cgit From d837b6d50cbb7e90ac8f77a9e1ac2a69acae02c1 Mon Sep 17 00:00:00 2001 From: Javier Lopez Date: Wed, 1 Jun 2022 09:10:10 -0500 Subject: fix(checkhealth): skip vim.health #18816 Problem: https://github.com/neovim/neovim/pull/18720#issuecomment-1142614996 The vim.health module is detected as a healthcheck, which produces spurious errors: vim: require("vim.health").check() ======================================================================== - ERROR: Failed to run healthcheck for "vim" plugin. Exception: function health#check, line 20 Vim(eval):E5108: Error executing lua [string "luaeval()"]:1: attempt to call field 'check' (a nil value) stack traceback: [string "luaeval()"]:1: in main chunk Solution: Skip vim.health when discovering healthchecks. --- runtime/lua/vim/health.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/health.lua b/runtime/lua/vim/health.lua index 67c5c3b37f..b875da0abc 100644 --- a/runtime/lua/vim/health.lua +++ b/runtime/lua/vim/health.lua @@ -41,6 +41,8 @@ M._complete = function() vim.tbl_map(function(f) unique[f] = true end, names) + -- vim.health is this file, which is not a healthcheck + unique['vim'] = nil return vim.tbl_keys(unique) end -- cgit From 209824ce2c6d37332079e6e213d4b8e257d7d53b Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Wed, 1 Jun 2022 18:56:18 +0200 Subject: fix(lsp): adjust offset encoding in lsp.buf.rename() (#18829) Fix a bug in lsp.buf.rename() where the range returned by the server in textDocument/prepareRename was interpreted as a byte range directly, instead of taking the negotiated offset encoding into account. This caused the placeholder value in vim.ui.input to be incorrect in some cases, for example when non-ascii characters are used earlier on the same line. --- runtime/lua/vim/lsp/buf.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index bcfaecdfcc..0b2e1c9b8d 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -408,13 +408,13 @@ function M.rename(new_name, options) local cword = vfn.expand('') ---@private - local function get_text_at_range(range) + local function get_text_at_range(range, offset_encoding) return vim.api.nvim_buf_get_text( bufnr, range.start.line, - range.start.character, + util._get_line_byte_from_position(bufnr, range.start, offset_encoding), range['end'].line, - range['end'].character, + util._get_line_byte_from_position(bufnr, range['end'], offset_encoding), {} )[1] end @@ -461,9 +461,9 @@ function M.rename(new_name, options) if result.placeholder then prompt_opts.default = result.placeholder elseif result.start then - prompt_opts.default = get_text_at_range(result) + prompt_opts.default = get_text_at_range(result, client.offset_encoding) elseif result.range then - prompt_opts.default = get_text_at_range(result.range) + prompt_opts.default = get_text_at_range(result.range, client.offset_encoding) else prompt_opts.default = cword end -- cgit From d5651a4183da8dfc71508850e429a7f0b99979f7 Mon Sep 17 00:00:00 2001 From: Wsevolod Date: Thu, 2 Jun 2022 10:49:57 +0300 Subject: fix(lua): stop pending highlight.on_yank timer, if any (#18824) When yanking another range while previous yank is still highlighted, the pending timer could clear the highlight almost immediately (especially when using larger `timeout`, i.e. 2000) --- runtime/lua/vim/highlight.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 22b67aee88..36e3c2ad20 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -64,6 +64,7 @@ function M.range(bufnr, ns, higroup, start, finish, opts) end local yank_ns = api.nvim_create_namespace('hlyank') +local yank_timer --- Highlight the yanked region --- --- use from init.vim via @@ -113,6 +114,9 @@ function M.on_yank(opts) local bufnr = api.nvim_get_current_buf() api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) + if yank_timer then + yank_timer:close() + end local pos1 = vim.fn.getpos("'[") local pos2 = vim.fn.getpos("']") @@ -129,7 +133,8 @@ function M.on_yank(opts) { regtype = event.regtype, inclusive = event.inclusive, priority = M.priorities.user } ) - vim.defer_fn(function() + yank_timer = vim.defer_fn(function() + yank_timer = nil if api.nvim_buf_is_valid(bufnr) then api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) end -- cgit From 26966688aa622b448e3ef46d8f1155d57b099211 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 2 Jun 2022 17:35:16 +0200 Subject: fix(treesitter): correct region for string parser (#18794) fixes injections for string parsers after https://github.com/neovim/neovim/commit/eab4d03a3264b2afaf803ed839fa25bc4e7acedd --- runtime/lua/vim/treesitter/languagetree.lua | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 5a05a29da8..767573e345 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -261,22 +261,27 @@ end --- --- Note, this call invalidates the tree and requires it to be parsed again. --- ----@param regions A list of regions this tree should manage and parse. +---@param regions (table) list of regions this tree should manage and parse. function LanguageTree:set_included_regions(regions) - -- TODO(vigoux): I don't think string parsers are useful for now - if type(self._source) == 'number' then - -- Transform the tables from 4 element long to 6 element long (with byte offset) - for _, region in ipairs(regions) do - for i, range in ipairs(region) do - if type(range) == 'table' and #range == 4 then - local start_row, start_col, end_row, end_col = unpack(range) + -- Transform the tables from 4 element long to 6 element long (with byte offset) + for _, region in ipairs(regions) do + for i, range in ipairs(region) do + if type(range) == 'table' and #range == 4 then + local start_row, start_col, end_row, end_col = unpack(range) + local start_byte = 0 + local end_byte = 0 + -- TODO(vigoux): proper byte computation here, and account for EOL ? + if type(self._source) == 'number' then -- Easy case, this is a buffer parser - -- TODO(vigoux): proper byte computation here, and account for EOL ? - local start_byte = a.nvim_buf_get_offset(self._source, start_row) + start_col - local end_byte = a.nvim_buf_get_offset(self._source, end_row) + end_col - - region[i] = { start_row, start_col, start_byte, end_row, end_col, end_byte } + start_byte = a.nvim_buf_get_offset(self._source, start_row) + start_col + end_byte = a.nvim_buf_get_offset(self._source, end_row) + end_col + elseif type(self._source) == 'string' then + -- string parser, single `\n` delimited string + start_byte = vim.fn.byteidx(self._source, start_col) + end_byte = vim.fn.byteidx(self._source, end_col) end + + region[i] = { start_row, start_col, start_byte, end_row, end_col, end_byte } end end end -- cgit From 69774e317982edbe943c7d75cb0369fc001dec39 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 3 Jun 2022 14:59:19 +0200 Subject: feat(lsp): add a start function (#18631) A alternative/subset of https://github.com/neovim/neovim/pull/18506 that should be forward compatible with a potential project system. Configuration of LSP clients (without lspconfig) now looks like this: vim.lsp.start({ name = 'my-server-name', cmd = {'name-of-language-server-executable'}, root_dir = vim.fs.dirname(vim.fs.find({'setup.py', 'pyproject.toml'}, { upward = true })[1]), }) --- runtime/lua/vim/fs.lua | 3 +++ runtime/lua/vim/lsp.lua | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 9bf38f7bc3..6f9c48ca24 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -37,6 +37,9 @@ end ---@param file (string) File or directory ---@return (string) Parent directory of {file} function M.dirname(file) + if file == nil then + return nil + end return vim.fn.fnamemodify(file, ':h') end diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index dac2860690..6bf772ed65 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -4,6 +4,7 @@ local lsp_rpc = require('vim.lsp.rpc') local protocol = require('vim.lsp.protocol') local util = require('vim.lsp.util') local sync = require('vim.lsp.sync') +local api = vim.api local vim = vim local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option, nvim_exec_autocmds = @@ -662,6 +663,77 @@ function lsp.client() error() end +--- Create a new LSP client and start a language server or reuses an already +--- running client if one is found matching `name` and `root_dir`. +--- Attaches the current buffer to the client. +--- +--- Example: +--- +---
+--- vim.lsp.start({
+---    name = 'my-server-name',
+---    cmd = {'name-of-language-server-executable'},
+---    root_dir = vim.fs.dirname(vim.fs.find({'pyproject.toml', 'setup.py'}, { upward = true })[1]),
+--- })
+--- 
+--- +--- See |lsp.start_client| for all available options. The most important are: +--- +--- `name` is an arbitrary name for the LSP client. It should be unique per +--- language server. +--- +--- `cmd` the command as list - used to start the language server. +--- The command must be present in the `$PATH` environment variable or an +--- absolute path to the executable. Shell constructs like `~` are *NOT* expanded. +--- +--- `root_dir` path to the project root. +--- By default this is used to decide if an existing client should be re-used. +--- The example above uses |vim.fs.find| and |vim.fs.dirname| to detect the +--- root by traversing the file system upwards starting +--- from the current directory until either a `pyproject.toml` or `setup.py` +--- file is found. +--- +--- `workspace_folders` a list of { uri:string, name: string } tables. +--- The project root folders used by the language server. +--- If `nil` the property is derived from the `root_dir` for convenience. +--- +--- Language servers use this information to discover metadata like the +--- dependencies of your project and they tend to index the contents within the +--- project folder. +--- +--- +--- To ensure a language server is only started for languages it can handle, +--- make sure to call |vim.lsp.start| within a |FileType| autocmd. +--- Either use |:au|, |nvim_create_autocmd()| or put the call in a +--- `ftplugin/.lua` (See |ftplugin-name|) +--- +---@param config table Same configuration as documented in |lsp.start_client()| +---@param opts nil|table Optional keyword arguments: +--- - reuse_client (fun(client: client, config: table): boolean) +--- Predicate used to decide if a client should be re-used. +--- Used on all running clients. +--- The default implementation re-uses a client if name +--- and root_dir matches. +---@return number client_id +function lsp.start(config, opts) + opts = opts or {} + local reuse_client = opts.reuse_client + or function(client, conf) + return client.config.root_dir == conf.root_dir and client.name == conf.name + end + config.name = config.name or (config.cmd[1] and vim.fs.basename(config.cmd[1])) or nil + local bufnr = api.nvim_get_current_buf() + for _, client in pairs(lsp.get_active_clients()) do + if reuse_client(client, config) then + lsp.buf_attach_client(bufnr, client.id) + return client.id + end + end + local client_id = lsp.start_client(config) + lsp.buf_attach_client(bufnr, client_id) + return client_id +end + -- FIXME: DOC: Currently all methods on the `vim.lsp.client` object are -- documented twice: Here, and on the methods themselves (e.g. -- `client.request()`). This is a workaround for the vimdoc generator script -- cgit From c6d747e6a5227e17556c62e16ed054398eb1a89a Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 3 Jun 2022 18:16:11 +0200 Subject: feat(lsp): send didChangeConfiguration after init (#18847) Most LSP servers require the notification to correctly load the settings and for those who don't it doesn't cause any harm. So far this is done in lspconfig, but with the addition of vim.lsp.start it should be part of core. --- runtime/lua/vim/lsp.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 6bf772ed65..361bcec04b 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1117,6 +1117,10 @@ function lsp.start_client(config) end end + if next(config.settings) then + client.notify('workspace/didChangeConfiguration', { settings = config.settings }) + end + if config.on_init then local status, err = pcall(config.on_init, client, result) if not status then -- cgit From 86cc33a46412081779b8e6d147c76a2d4d0d7f0f Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Fri, 3 Jun 2022 21:52:59 -0600 Subject: fix(filetype): fix typo in starsetf function (#18856) --- runtime/lua/vim/filetype.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 7a8f7187b9..fea8ec7c9f 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -6,11 +6,11 @@ local M = {} local function starsetf(ft) return { function(path) - if not vim.g.fg_ignore_pat then + if not vim.g.ft_ignore_pat then return ft end - local re = vim.regex(vim.g.fg_ignore_pat) + local re = vim.regex(vim.g.ft_ignore_pat) if re:match_str(path) then return ft end -- cgit From ff20d40321399fa187bd350f9619cf6418d7eb6e Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sat, 4 Jun 2022 05:56:36 +0200 Subject: docs: fix typos (#18269) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: zeertzjq Co-authored-by: Dan Sully Co-authored-by: saher Co-authored-by: Stephan Seitz Co-authored-by: Benedikt Müller Co-authored-by: Andrey Mishchenko Co-authored-by: Famiu Haque Co-authored-by: Oliver Marriott --- runtime/lua/vim/lsp.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 361bcec04b..8bf736a2ca 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -836,7 +836,7 @@ end --- server in the initialize request. Invalid/empty values will default to "off" ---@param flags: A table with flags for the client. The current (experimental) flags are: --- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits ---- - debounce_text_changes (number, default nil): Debounce didChange +--- - debounce_text_changes (number, default 150): Debounce didChange --- notifications to the server by the given number in milliseconds. No debounce --- occurs if nil --- - exit_timeout (number, default 500): Milliseconds to wait for server to -- cgit From e6fa4cca24cb16b9cecb41b9ecdb8c9bc349886b Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Sat, 4 Jun 2022 09:49:01 +0200 Subject: vim-patch:8.2.5054: no good filetype for conf files similar to dosini (#18851) Problem: No good filetype for conf files similar to dosini. Solution: Add the confini filetype. (closes vim/vim#10510) https://github.com/vim/vim/commit/635f48010dcf6d97f3a65b4785e1726ad386d3eb --- runtime/lua/vim/filetype.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index fea8ec7c9f..f5c29639c6 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1230,9 +1230,10 @@ local filename = { Dockerfile = 'dockerfile', npmrc = 'dosini', ['/etc/yum.conf'] = 'dosini', - ['/etc/pacman.conf'] = 'conf', ['.npmrc'] = 'dosini', ['.editorconfig'] = 'dosini', + ['/etc/pacman.conf'] = 'confini', + ['mpv.conf'] = 'confini', dune = 'dune', jbuild = 'dune', ['dune-workspace'] = 'dune', @@ -1558,7 +1559,7 @@ local pattern = { ['.*/etc/DIR_COLORS'] = 'dircolors', ['.*/etc/dnsmasq%.conf'] = 'dnsmasq', ['php%.ini%-.*'] = 'dosini', - ['.*/etc/pacman%.conf'] = 'conf', + ['.*/etc/pacman%.conf'] = 'confini', ['.*/etc/yum%.conf'] = 'dosini', ['.*lvs'] = 'dracula', ['.*lpe'] = 'dracula', -- cgit From 9961a9702e75d80e6d37637182f361320e690002 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sat, 4 Jun 2022 16:23:43 +0800 Subject: fix(lsp): set buflisted before switching to buffer (#18854) --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 63e9342b1a..b041385c9c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1038,8 +1038,8 @@ function M.jump_to_location(location, offset_encoding, reuse_win) if win then api.nvim_set_current_win(win) else - api.nvim_set_current_buf(bufnr) api.nvim_buf_set_option(bufnr, 'buflisted', true) + api.nvim_set_current_buf(bufnr) end local range = location.range or location.targetSelectionRange local row = range.start.line -- cgit From 545dc82c1b22709c83ec23e9450f245f9ff1babc Mon Sep 17 00:00:00 2001 From: bfredl Date: Sat, 4 Jun 2022 11:08:25 +0200 Subject: perf(tests): don't invoke nvim_get_all_options_info until needed This call alone is responible of 40 000 000 out of 80 000 000 individual alloc/free calls in the test suite. --- runtime/lua/vim/_meta.lua | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 1706956bca..59cf837a1d 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -10,29 +10,39 @@ local SET_TYPES = setmetatable({ GLOBAL = 2, }, { __index = error }) -local options_info = {} -for _, v in pairs(a.nvim_get_all_options_info()) do - options_info[v.name] = v - if v.shortname ~= '' then - options_info[v.shortname] = v +local options_info = nil +local buf_options = nil +local glb_options = nil +local win_options = nil + +local function _setup() + if options_info ~= nil then + return + end + options_info = {} + for _, v in pairs(a.nvim_get_all_options_info()) do + options_info[v.name] = v + if v.shortname ~= '' then + options_info[v.shortname] = v + end end -end -local get_scoped_options = function(scope) - local result = {} - for name, option_info in pairs(options_info) do - if option_info.scope == scope then - result[name] = true + local function get_scoped_options(scope) + local result = {} + for name, option_info in pairs(options_info) do + if option_info.scope == scope then + result[name] = true + end end + + return result end - return result + buf_options = get_scoped_options('buf') + glb_options = get_scoped_options('global') + win_options = get_scoped_options('win') end -local buf_options = get_scoped_options('buf') -local glb_options = get_scoped_options('global') -local win_options = get_scoped_options('win') - local function make_meta_accessor(get, set, del, validator) validator = validator or function() return true @@ -90,6 +100,7 @@ do -- buffer option accessor return make_meta_accessor(get, set, nil, function(k) if type(k) == 'string' then + _setup() if win_options[k] then error(string.format([['%s' is a window option, not a buffer option. See ":help %s"]], k, k)) elseif glb_options[k] then @@ -119,6 +130,7 @@ do -- window option accessor return make_meta_accessor(get, set, nil, function(k) if type(k) == 'string' then + _setup() if buf_options[k] then error(string.format([['%s' is a buffer option, not a window option. See ":help %s"]], k, k)) elseif glb_options[k] then @@ -610,6 +622,7 @@ local create_option_metatable = function(set_type) local set_mt, option_mt local make_option = function(name, value) + _setup() local info = assert(options_info[name], 'Not a valid option name: ' .. name) if type(value) == 'table' and getmetatable(value) == option_mt then -- cgit From e4df1c9b9e61e79234684d30ca700b42f82bc34a Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Sun, 5 Jun 2022 16:43:32 +0200 Subject: fix(lsp): fix multi client handling in code action (#18869) Fixes https://github.com/neovim/neovim/issues/18860 --- runtime/lua/vim/lsp/buf.lua | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 0b2e1c9b8d..fa8ee23805 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -752,7 +752,14 @@ local function on_code_action_results(results, ctx, options) enriched_ctx.client_id = client.id fn(command, enriched_ctx) else - M.execute_command(command) + -- Not using command directly to exclude extra properties, + -- see https://github.com/python-lsp/python-lsp-server/issues/146 + local params = { + command = command.command, + arguments = command.arguments, + workDoneToken = command.workDoneToken, + } + client.request('workspace/executeCommand', params, nil, ctx.bufnr) end end end -- cgit From 41a49dd9c8e4362c24a3699ec2be746af4623449 Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Mon, 6 Jun 2022 17:25:33 +0200 Subject: refactor(runtime): port remaining patterns from filetype.vim to filetype.lua (#18814) --- runtime/lua/vim/filetype.lua | 319 ++++++++++++++++++++++++++++++++++-- runtime/lua/vim/filetype/detect.lua | 113 ++++++------- 2 files changed, 360 insertions(+), 72 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index f5c29639c6..c091e2f35c 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -3,21 +3,22 @@ local api = vim.api local M = {} ---@private -local function starsetf(ft) +local function starsetf(ft, opts) return { - function(path) + function(path, bufnr) + local f = type(ft) == 'function' and ft(path, bufnr) or ft if not vim.g.ft_ignore_pat then - return ft + return f end local re = vim.regex(vim.g.ft_ignore_pat) - if re:match_str(path) then - return ft + if not re:match_str(path) then + return f end end, { -- Starset matches should always have lowest priority - priority = -math.huge, + priority = (opts and opts.priority) or -math.huge, }, } end @@ -29,8 +30,73 @@ local function getline(bufnr, start_lnum, end_lnum) return table.concat(lines) or '' end --- Filetypes based on file extension +---@private +--- Get a single line or line-range from the buffer. +--- +---@param bufnr number|nil The buffer to get the lines from +---@param start_lnum number The line number of the first line (inclusive, 1-based) +---@param end_lnum number|nil The line number of the last line (inclusive, 1-based) +---@return table|string Array of lines, or string when end_lnum is omitted +function M.getlines(bufnr, start_lnum, end_lnum) + if not end_lnum then + -- Return a single line as a string + return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] + end + return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) +end + +---@private +--- Check whether a string matches any of the given Lua patterns. +--- +---@param s string The string to check +---@param patterns table A list of Lua patterns +---@return boolean `true` if s matched a pattern, else `false` +function M.findany(s, patterns) + if s == nil then + return false + end + for _, v in ipairs(patterns) do + if s:find(v) then + return true + end + end + return false +end + +---@private +--- Get the next non-whitespace line in the buffer. +--- +---@param bufnr number The buffer to get the line from +---@param start_lnum number The line number of the first line to start from (inclusive, 1-based) +---@return string|nil The first non-blank line if found or `nil` otherwise +function M.nextnonblank(bufnr, start_lnum) + for _, line in ipairs(M.getlines(bufnr, start_lnum, -1)) do + if not line:find('^%s*$') then + return line + end + end + return nil +end + +---@private +--- Check whether the given string matches the Vim regex pattern. +M.matchregex = (function() + local cache = {} + return function(s, pattern) + if s == nil then + return nil + end + if not cache[pattern] then + cache[pattern] = vim.regex(pattern) + end + return cache[pattern]:match_str(s) + end +end)() + -- luacheck: push no unused args +-- luacheck: push ignore 122 + +-- Filetypes based on file extension ---@diagnostic disable: unused-local local extension = { -- BEGIN EXTENSION @@ -178,6 +244,7 @@ local extension = { diff = 'diff', rej = 'diff', Dockerfile = 'dockerfile', + dockerfile = 'dockerfile', bat = 'dosbatch', wrap = 'dosini', ini = 'dosini', @@ -1032,7 +1099,7 @@ local extension = { end, txt = function(path, bufnr) --helpfiles match *.txt, but should have a modeline as last line - if not getline(bufnr, -1):match('vim:.*ft=help') then + if not getline(bufnr, -1):find('vim:.*ft=help') then return 'text' end end, @@ -1175,6 +1242,67 @@ local extension = { return 'rc' end end, + control = function(path, bufnr) + return require('vim.filetype.detect').control(bufnr) + end, + copyright = function(path, bufnr) + return require('vim.filetype.detect').copyright(bufnr) + end, + -- Ignored extensions + bak = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + ['dpkg-dist'] = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + ['dpkg-old'] = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + ['dpkg-new'] = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + ['dpkg-bak'] = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + new = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + old = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + orig = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + pacsave = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + pacnew = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + rpmsave = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + rmpnew = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, + ['in'] = function(path, bufnr) + if vim.fs.basename(path) ~= 'configure.in' then + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end + end, -- END EXTENSION } @@ -1196,8 +1324,9 @@ local filename = { ['named.root'] = 'bindzone', WORKSPACE = 'bzl', BUILD = 'bzl', - ['cabal.config'] = 'cabalconfig', ['cabal.project'] = 'cabalproject', + [vim.env.HOME .. '/cabal.config'] = 'cabalconfig', + ['cabal.config'] = 'cabalconfig', calendar = 'calendar', catalog = 'catalog', ['/etc/cdrdao.conf'] = 'cdrdaoconf', @@ -1355,6 +1484,9 @@ local filename = { ['/etc/nanorc'] = 'nanorc', Neomuttrc = 'neomuttrc', ['.netrc'] = 'netrc', + NEWS = function(path, bufnr) + return require('vim.filetype.detect').news(bufnr) + end, ['.ocamlinit'] = 'ocaml', ['.octaverc'] = 'octave', octaverc = 'octave', @@ -1380,15 +1512,28 @@ local filename = { ['/etc/pinforc'] = 'pinfo', ['/.pinforc'] = 'pinfo', ['.povrayrc'] = 'povini', + ['printcap'] = function(path, bufnr) + vim.b[bufnr].ptcap_type = 'print' + return 'ptcap' + end, + ['termcap'] = function(path, bufnr) + vim.b[bufnr].ptcap_type = 'term' + return 'ptcap' + end, ['.procmailrc'] = 'procmail', ['.procmail'] = 'procmail', ['/etc/protocols'] = 'protocols', + ['INDEX'] = function(path, bufnr) + return require('vim.filetype.detect').psf(bufnr) + end, + ['INFO'] = function(path, bufnr) + return require('vim.filetype.detect').psf(bufnr) + end, ['.pythonstartup'] = 'python', ['.pythonrc'] = 'python', SConstruct = 'python', ratpoisonrc = 'ratpoison', ['.ratpoisonrc'] = 'ratpoison', - v = 'rcs', inputrc = 'readline', ['.inputrc'] = 'readline', ['.reminders'] = 'remind', @@ -1458,6 +1603,14 @@ local filename = { ['.Xpdefaults'] = 'xdefaults', ['xdm-config'] = 'xdefaults', ['.Xdefaults'] = 'xdefaults', + ['xorg.conf'] = function(path, bufnr) + vim.b[bufnr].xf86conf_xfree86_version = 4 + return 'xf86conf' + end, + ['xorg.conf-4'] = function(path, bufnr) + vim.b[bufnr].xf86conf_xfree86_version = 4 + return 'xf86conf' + end, ['/etc/xinetd.conf'] = 'xinetd', fglrxrc = 'xml', ['/etc/blkid.tab'] = 'xml', @@ -1528,6 +1681,9 @@ local filename = { ['tcsh.tcshrc'] = function(path, bufnr) return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, + ['XF86Config'] = function(path, bufnr) + return require('vim.filetype.detect').xf86conf(bufnr) + end, -- END FILENAME } @@ -1544,12 +1700,22 @@ local pattern = { ['.*bsd'] = 'bsdl', ['bzr_log%..*'] = 'bzr', ['.*enlightenment/.*%.cfg'] = 'c', + ['.*/%.calendar/.*'] = starsetf('calendar'), + ['.*/share/calendar/.*/calendar%..*'] = starsetf('calendar'), + ['.*/share/calendar/calendar%..*'] = starsetf('calendar'), ['.*/etc/defaults/cdrdao'] = 'cdrdaoconf', ['.*/etc/cdrdao%.conf'] = 'cdrdaoconf', ['.*/etc/default/cdrdao'] = 'cdrdaoconf', ['.*hgrc'] = 'cfg', ['.*%.%.ch'] = 'chill', ['.*%.cmake%.in'] = 'cmake', + -- */cmus/rc and */.cmus/rc + ['.*/%.?cmus/rc'] = 'cmusrc', + -- */cmus/*.theme and */.cmus/*.theme + ['.*/%.?cmus/.*%.theme'] = 'cmusrc', + ['.*/%.cmus/autosave'] = 'cmusrc', + ['.*/%.cmus/command%-history'] = 'cmusrc', + ['cvs%d+'] = 'cvs', ['.*/debian/changelog'] = 'debchangelog', ['.*/debian/control'] = 'debcontrol', ['.*/debian/copyright'] = 'debcopyright', @@ -1572,11 +1738,26 @@ local pattern = { ['.*/%.config/git/config'] = 'gitconfig', ['.*%.git/config%.worktree'] = 'gitconfig', ['.*%.git/worktrees/.*/config%.worktree'] = 'gitconfig', + ['.*/git/config'] = function(path, bufnr) + if vim.env.XDG_CONFIG_HOME and path:find(vim.env.XDG_CONFIG_HOME .. '/git/config') then + return 'gitconfig' + end + end, ['%.gitsendemail%.msg%.......'] = 'gitsendemail', ['gkrellmrc_.'] = 'gkrellmrc', ['.*/usr/.*/gnupg/options%.skel'] = 'gpg', ['.*/%.gnupg/options'] = 'gpg', ['.*/%.gnupg/gpg%.conf'] = 'gpg', + ['.*/options'] = function(path, bufnr) + if vim.env.GNUPGHOME and path:find(vim.env.GNUPGHOME .. '/options') then + return 'gpg' + end + end, + ['.*/gpg%.conf'] = function(path, bufnr) + if vim.env.GNUPGHOME and path:find(vim.env.GNUPGHOME .. '/gpg%.conf') then + return 'gpg' + end + end, ['.*/etc/group'] = 'group', ['.*/etc/gshadow'] = 'group', ['.*/etc/group%.edit'] = 'group', @@ -1647,6 +1828,12 @@ local pattern = { ['.*/%.pinforc'] = 'pinfo', ['.*/etc/pinforc'] = 'pinfo', ['.*/etc/protocols'] = 'protocols', + ['.*printcap.*'] = starsetf(function(path, bufnr) + if vim.fn.did_filetype() == 0 then + vim.b[bufnr].ptcap_type = 'print' + return 'ptcap' + end + end), ['.*baseq[2-3]/.*%.cfg'] = 'quake', ['.*quake[1-3]/.*%.cfg'] = 'quake', ['.*id1/.*%.cfg'] = 'quake', @@ -1671,9 +1858,33 @@ local pattern = { ['.*%.swift%.gyb'] = 'swiftgyb', ['.*/etc/sysctl%.conf'] = 'sysctl', ['.*/etc/sysctl%.d/.*%.conf'] = 'sysctl', + ['.*/systemd/.*%.automount'] = 'systemd', + ['.*/systemd/.*%.dnssd'] = 'systemd', + ['.*/systemd/.*%.link'] = 'systemd', + ['.*/systemd/.*%.mount'] = 'systemd', + ['.*/systemd/.*%.netdev'] = 'systemd', + ['.*/systemd/.*%.network'] = 'systemd', + ['.*/systemd/.*%.nspawn'] = 'systemd', + ['.*/systemd/.*%.path'] = 'systemd', + ['.*/systemd/.*%.service'] = 'systemd', + ['.*/systemd/.*%.slice'] = 'systemd', + ['.*/systemd/.*%.socket'] = 'systemd', + ['.*/systemd/.*%.swap'] = 'systemd', + ['.*/systemd/.*%.target'] = 'systemd', + ['.*/systemd/.*%.timer'] = 'systemd', ['.*/etc/systemd/.*%.conf%.d/.*%.conf'] = 'systemd', ['.*/%.config/systemd/user/.*%.d/.*%.conf'] = 'systemd', ['.*/etc/systemd/system/.*%.d/.*%.conf'] = 'systemd', + ['.*/etc/systemd/system/.*%.d/%.#.*'] = 'systemd', + ['.*/etc/systemd/system/%.#.*'] = 'systemd', + ['.*/%.config/systemd/user/.*%.d/%.#.*'] = 'systemd', + ['.*/%.config/systemd/user/%.#.*'] = 'systemd', + ['.*termcap.*'] = starsetf(function(path, bufnr) + if vim.fn.did_filetype() == 0 then + vim.b[bufnr].ptcap_type = 'term' + return 'ptcap' + end + end), ['.*%.t%.html'] = 'tilde', ['%.?tmux.*%.conf'] = 'tmux', ['%.?tmux.*%.conf.*'] = { 'tmux', { priority = -1 } }, @@ -1719,7 +1930,19 @@ local pattern = { ['%.login.*'] = function(path, bufnr) return require('vim.filetype.detect').csh(path, bufnr) end, - ['%.neomuttrc.*'] = starsetf('neomuttrc'), + ['Muttrc.*'] = starsetf('muttrc'), + ['Muttngrc.*'] = starsetf('muttrc'), + -- muttrc* and .muttrc* + ['%.?muttrc.*'] = starsetf('muttrc'), + -- muttngrc* and .muttngrc* + ['%.?muttngrc.*'] = starsetf('muttrc'), + ['.*/%.mutt/muttrc.*'] = starsetf('muttrc'), + ['.*/%.muttng/muttrc.*'] = starsetf('muttrc'), + ['.*/%.muttng/muttngrc.*'] = starsetf('muttrc'), + ['Neomuttrc.*'] = starsetf('neomuttrc'), + -- neomuttrc* and .neomuttrc* + ['%.?neomuttrc.*'] = starsetf('neomuttrc'), + ['.*/%.neomutt/neomuttrc.*'] = starsetf('neomuttrc'), ['%.profile.*'] = function(path, bufnr) return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) end, @@ -1742,8 +1965,15 @@ local pattern = { ['.*%.properties_.._.._.*'] = starsetf('jproperties'), ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), ['.*/%.fvwm/.*'] = starsetf('fvwm'), + ['.*fvwmrc.*'] = starsetf(function(path, bufnr) + vim.b[bufnr].fvwm_version = 1 + return 'fvwm' + end), + ['.*fvwm95.*%.hook'] = starsetf(function(path, bufnr) + vim.b[bufnr].fvwm_version = 1 + return 'fvwm' + end), ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), - ['.*/%.neomutt/neomuttrc.*'] = starsetf('neomuttrc'), ['.*/Xresources/.*'] = starsetf('xdefaults'), ['.*/app%-defaults/.*'] = starsetf('xdefaults'), ['.*/bind/db%..*'] = starsetf('bindzone'), @@ -1763,6 +1993,11 @@ local pattern = { ['.*/etc/httpd/sites%-.*/.*'] = starsetf('apache'), ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'), ['.*/etc/modprobe%..*'] = starsetf('modconf'), + ['.*/etc/modutils/.*'] = starsetf(function(path, bufnr) + if vim.fn.executable(vim.fn.expand(path)) ~= 1 then + return 'modconf' + end + end), ['.*/etc/pam%.d/.*'] = starsetf('pamconf'), ['.*/etc/profile'] = function(path, bufnr) return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) @@ -1785,7 +2020,6 @@ local pattern = { ['Dockerfile%..*'] = starsetf('dockerfile'), ['JAM.*%..*'] = starsetf('jam'), ['Kconfig%..*'] = starsetf('kconfig'), - ['Neomuttrc.*'] = starsetf('neomuttrc'), ['Prl.*%..*'] = starsetf('jam'), ['Xresources.*'] = starsetf('xdefaults'), ['[mM]akefile.*'] = starsetf('make'), @@ -1802,7 +2036,8 @@ local pattern = { ['gtkrc.*'] = starsetf('gtkrc'), ['httpd%.conf.*'] = starsetf('apache'), ['lilo%.conf.*'] = starsetf('lilo'), - ['neomuttrc.*'] = starsetf('neomuttrc'), + ['Muttrc'] = 'muttrc', + ['Muttngrc'] = 'muttrc', ['proftpd%.conf.*'] = starsetf('apachestyle'), ['reportbug%-.*'] = starsetf('mail'), ['sgml%.catalog.*'] = starsetf('catalog'), @@ -1816,8 +2051,8 @@ local pattern = { ['%.article%.%d+'] = 'mail', ['pico%.%d+'] = 'mail', ['mutt%-.*%-%w+'] = 'mail', - ['neomutt%-.*%-%w+'] = 'mail', ['muttng%-.*%-%w+'] = 'mail', + ['neomutt%-.*%-%w+'] = 'mail', ['mutt' .. string.rep('[%w_-]', 6)] = 'mail', ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail', ['/tmp/SLRN[0-9A-Z.]+'] = 'mail', @@ -1861,7 +2096,7 @@ local pattern = { { priority = -1 }, }, ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr) - return require('vim.filetype.detect').dat(bufnr) + return require('vim.filetype.detect').dat(path, bufnr) end, ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr) return require('vim.filetype.detect').mod(path, bufnr) @@ -1880,9 +2115,61 @@ local pattern = { ['example%.gitolite%.rc'] = 'perl', -- Neovim only ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries + ['.*,v'] = 'rcs', + ['.*/xorg%.conf%.d/.*%.conf'] = function(path, bufnr) + vim.b[bufnr].xf86conf_xfree86_version = 4 + return 'xf86config' + end, + -- Increase priority to run before the pattern below + ['XF86Config%-4'] = starsetf(function(path, bufnr) + vim.b[bufnr].xf86conf_xfree86_version = 4 + return 'xf86config' + end, { priority = -math.huge + 1 }), + ['XF86Config.*'] = starsetf(function(path, bufnr) + vim.b[bufnr].xf86conf_xfree86_version = 4 + return require('vim.filetype.detect').xf86conf(bufnr) + end), + ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr) + local line = getline(bufnr, 1):lower() + if line:find('; urgency=') then + return 'debchangelog' + else + return 'changelog' + end + end), + ['.*fvwm2rc.*'] = starsetf(function(path, bufnr) + if vim.fn.fnamemodify(path, ':e') == 'm4' then + return 'fvwm2m4' + else + vim.b[bufnr].fvwm_version = 2 + return 'fvwm' + end + end), + ['.*%.[Ll][Oo][Gg]'] = function(path, bufnr) + -- Innovation Data Processing + -- (refactor of filetype.vim since the patterns are case-insensitive) + path = path:lower() + if M.findany(path, { 'upstream%.log', 'upstream%..*%.log', '.*%.upstream%.log', 'upstream%-.*%.log' }) then + return 'upstreamlog' + elseif M.findany(path, { 'upstreaminstall%.log', 'upstreaminstall%..*%.log', '.*%.upstreaminstall%.log' }) then + return 'upstreaminstalllog' + elseif M.findany(path, { 'usserver%.log', 'usserver%..*%.log', '.*%.usserver%.log' }) then + return 'usserverlog' + elseif M.findany(path, { 'usw2kagt%.log', 'usws2kagt%..*%.log', '.*%.usws2kagt%.log' }) then + return 'usw2kagtlog' + end + end, + -- Ignored extension + ['.*~'] = function(path, bufnr) + local short = path:gsub('~$', '', 1) + if path ~= short and short ~= '' then + return M.match(vim.fn.fnameescape(short), bufnr) + end + end, -- END PATTERN } -- luacheck: pop +-- luacheck: pop ---@private local function sort_by_priority(t) diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index b35303eefc..2cc75b026e 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -16,56 +16,10 @@ local M = {} ----@private -local function getlines(bufnr, start_lnum, end_lnum) - if not end_lnum then - -- Return a single line as a string - return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] - end - return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) -end - ----@private -local function findany(s, patterns) - if s == nil then - return false - end - for _, v in ipairs(patterns) do - if s:find(v) then - return true - end - end - return false -end - ----@private -local function nextnonblank(bufnr, start_lnum) - for _, line in ipairs(getlines(bufnr, start_lnum, -1)) do - if not line:find('^%s*$') then - return line - end - end - return nil -end - ----@private -local matchregex = (function() - local cache = {} - return function(line, pattern) - if line == nil then - return nil - end - if not cache[pattern] then - cache[pattern] = vim.regex(pattern) - end - return cache[pattern]:match_str(line) - end -end)() - ----@private -local did_filetype = function() - return vim.fn.did_filetype() ~= 0 -end +local getlines = vim.filetype.getlines +local findany = vim.filetype.findany +local nextnonblank = vim.filetype.nextnonblank +local matchregex = vim.filetype.matchregex -- luacheck: push no unused args -- luacheck: push ignore 122 @@ -200,7 +154,7 @@ function M.change(bufnr) end function M.csh(path, bufnr) - if did_filetype() then + if vim.fn.did_filetype() ~= 0 then -- Filetype was already detected return end @@ -213,11 +167,15 @@ function M.csh(path, bufnr) end end --- Determine if a *.dat file is Kuka Robot Language -function M.dat(bufnr) +function M.dat(path, bufnr) + -- Innovation data processing + if findany(path:lower(), { '^upstream%.dat$', '^upstream%..*%.dat$', '^.*%.upstream%.dat$' }) then + return 'upstreamdat' + end if vim.g.filetype_dat then return vim.g.filetype_dat end + -- Determine if a *.dat file is Kuka Robot Language local line = nextnonblank(bufnr, 1) if matchregex(line, [[\c\v^\s*%(\&\w+|defdat>)]]) then return 'krl' @@ -257,7 +215,7 @@ function M.dep3patch(path, bufnr) end function M.dtrace(bufnr) - if did_filetype() then + if vim.fn.did_filetype() ~= 0 then -- Filetype was already detected return end @@ -815,7 +773,7 @@ end -- Also called from filetype.lua function M.sh(path, bufnr, name) - if did_filetype() or path:find(vim.g.ft_ignore_pat) then + if vim.fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then -- Filetype was already detected or detection should be skipped return end @@ -848,7 +806,7 @@ end -- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl. -- Also called from scripts.vim, thus can't be local to this script. [TODO] function M.shell(path, bufnr, name) - if did_filetype() or matchregex(path, vim.g.ft_ignore_pat) then + if vim.fn.did_filetype() ~= 0 or matchregex(path, vim.g.ft_ignore_pat) then -- Filetype was already detected or detection should be skipped return end @@ -1054,6 +1012,49 @@ function M.hw(bufnr) end return 'virata' end + +function M.news(bufnr) + if getlines(bufnr, 1):lower():find('; urgency=') then + return 'debchangelog' + end +end + +-- Debian Control +function M.control(bufnr) + if getlines(bufnr, 1):find('^Source:') then + return 'debcontrol' + end +end + +-- Debian Copyright +function M.copyright(bufnr) + if getlines(bufnr, 1):find('^Format:') then + return 'debcopyright' + end +end + +-- Software Distributor Product Specification File (POSIX 1387.2-1995) +function M.psf(bufnr) + local line = getlines(bufnr, 1):lower() + if + findany( + line, + { '^%s*distribution%s*$', '^%s*installed_software%s*$', '^%s*root%s*$', '^%s*bundle%s*$', '^%s*product%s*$' } + ) + then + return 'psf' + end +end + +-- XFree86 config +function M.xfree86(bufnr) + local line = getlines(bufnr, 1) + if matchregex(line, [[\]]) then + vim.b[bufnr].xf86conf_xfree86_version = 3 + return 'xf86conf' + end +end + -- luacheck: pop -- luacheck: pop -- cgit From 94181ad7dcb75e1e188164276696434e03302a21 Mon Sep 17 00:00:00 2001 From: mohsen <36933074+smoka7@users.noreply.github.com> Date: Wed, 8 Jun 2022 23:25:39 +0430 Subject: fix(diagnostic): check for negative column value (#18868) --- runtime/lua/vim/diagnostic.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index bb12362234..afc0a4095c 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -398,10 +398,19 @@ local function get_diagnostics(bufnr, opts, clamp) if not opts.lnum or d.lnum == opts.lnum then if clamp and vim.api.nvim_buf_is_loaded(b) then local line_count = buf_line_count[b] - 1 - if d.lnum > line_count or d.end_lnum > line_count or d.lnum < 0 or d.end_lnum < 0 then + if + d.lnum > line_count + or d.end_lnum > line_count + or d.lnum < 0 + or d.end_lnum < 0 + or d.col < 0 + or d.end_col < 0 + then d = vim.deepcopy(d) d.lnum = math.max(math.min(d.lnum, line_count), 0) d.end_lnum = math.max(math.min(d.end_lnum, line_count), 0) + d.col = math.max(d.col, 0) + d.end_col = math.max(d.end_col, 0) end end table.insert(diagnostics, d) -- cgit From 58323b1fe2e494cf6a75f108780e21c08996c08e Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 9 Jun 2022 13:12:36 -0600 Subject: feat(filetype): remove side effects from vim.filetype.match (#18894) Many filetypes from filetype.vim set buffer-local variables, meaning vim.filetype.match cannot be used without side effects. Instead of setting these buffer-local variables in the filetype detection functions themselves, have vim.filetype.match return an optional function value that, when called, sets these variables. This allows vim.filetype.match to work without side effects. --- runtime/lua/vim/filetype.lua | 127 ++++++++++++++++++++++-------------- runtime/lua/vim/filetype/detect.lua | 83 +++++++++++++---------- 2 files changed, 127 insertions(+), 83 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c091e2f35c..536580c604 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -26,7 +26,7 @@ end ---@private local function getline(bufnr, start_lnum, end_lnum) end_lnum = end_lnum or start_lnum - local lines = vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) + local lines = api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) return table.concat(lines) or '' end @@ -40,9 +40,9 @@ end function M.getlines(bufnr, start_lnum, end_lnum) if not end_lnum then -- Return a single line as a string - return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] + return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] end - return vim.api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) + return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) end ---@private @@ -1513,12 +1513,14 @@ local filename = { ['/.pinforc'] = 'pinfo', ['.povrayrc'] = 'povini', ['printcap'] = function(path, bufnr) - vim.b[bufnr].ptcap_type = 'print' - return 'ptcap' + return 'ptcap', function(b) + vim.b[b].ptcap_type = 'print' + end end, ['termcap'] = function(path, bufnr) - vim.b[bufnr].ptcap_type = 'term' - return 'ptcap' + return 'ptcap', function(b) + vim.b[b].ptcap_type = 'term' + end end, ['.procmailrc'] = 'procmail', ['.procmail'] = 'procmail', @@ -1604,12 +1606,14 @@ local filename = { ['xdm-config'] = 'xdefaults', ['.Xdefaults'] = 'xdefaults', ['xorg.conf'] = function(path, bufnr) - vim.b[bufnr].xf86conf_xfree86_version = 4 - return 'xf86conf' + return 'xf86conf', function(b) + vim.b[b].xf86conf_xfree86_version = 4 + end end, ['xorg.conf-4'] = function(path, bufnr) - vim.b[bufnr].xf86conf_xfree86_version = 4 - return 'xf86conf' + return 'xf86conf', function(b) + vim.b[b].xf86conf_xfree86_version = 4 + end end, ['/etc/xinetd.conf'] = 'xinetd', fglrxrc = 'xml', @@ -1662,7 +1666,7 @@ local filename = { bashrc = function(path, bufnr) return require('vim.filetype.detect').sh(path, bufnr, 'bash') end, - crontab = starsetf('crontab'), + crontab = 'crontab', ['csh.cshrc'] = function(path, bufnr) return require('vim.filetype.detect').csh(path, bufnr) end, @@ -1682,7 +1686,7 @@ local filename = { return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, ['XF86Config'] = function(path, bufnr) - return require('vim.filetype.detect').xf86conf(bufnr) + return require('vim.filetype.detect').xfree86(bufnr) end, -- END FILENAME } @@ -1830,8 +1834,9 @@ local pattern = { ['.*/etc/protocols'] = 'protocols', ['.*printcap.*'] = starsetf(function(path, bufnr) if vim.fn.did_filetype() == 0 then - vim.b[bufnr].ptcap_type = 'print' - return 'ptcap' + return 'ptcap', function(b) + vim.b[b].ptcap_type = 'print' + end end end), ['.*baseq[2-3]/.*%.cfg'] = 'quake', @@ -1881,8 +1886,9 @@ local pattern = { ['.*/%.config/systemd/user/%.#.*'] = 'systemd', ['.*termcap.*'] = starsetf(function(path, bufnr) if vim.fn.did_filetype() == 0 then - vim.b[bufnr].ptcap_type = 'term' - return 'ptcap' + return 'ptcap', function(b) + vim.b[b].ptcap_type = 'term' + end end end), ['.*%.t%.html'] = 'tilde', @@ -1966,12 +1972,14 @@ local pattern = { ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), ['.*/%.fvwm/.*'] = starsetf('fvwm'), ['.*fvwmrc.*'] = starsetf(function(path, bufnr) - vim.b[bufnr].fvwm_version = 1 - return 'fvwm' + return 'fvwm', function(b) + vim.b[b].fvwm_version = 1 + end end), ['.*fvwm95.*%.hook'] = starsetf(function(path, bufnr) - vim.b[bufnr].fvwm_version = 1 - return 'fvwm' + return 'fvwm', function(b) + vim.b[b].fvwm_version = 1 + end end), ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), ['.*/Xresources/.*'] = starsetf('xdefaults'), @@ -2117,17 +2125,18 @@ local pattern = { ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries ['.*,v'] = 'rcs', ['.*/xorg%.conf%.d/.*%.conf'] = function(path, bufnr) - vim.b[bufnr].xf86conf_xfree86_version = 4 - return 'xf86config' + return 'xf86config', function(b) + vim.b[b].xf86conf_xfree86_version = 4 + end end, -- Increase priority to run before the pattern below - ['XF86Config%-4'] = starsetf(function(path, bufnr) - vim.b[bufnr].xf86conf_xfree86_version = 4 - return 'xf86config' + ['XF86Config%-4.*'] = starsetf(function(path, bufnr) + return 'xf86conf', function(b) + vim.b[b].xf86conf_xfree86_version = 4 + end end, { priority = -math.huge + 1 }), ['XF86Config.*'] = starsetf(function(path, bufnr) - vim.b[bufnr].xf86conf_xfree86_version = 4 - return require('vim.filetype.detect').xf86conf(bufnr) + return require('vim.filetype.detect').xfree86(bufnr) end), ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr) local line = getline(bufnr, 1):lower() @@ -2141,8 +2150,9 @@ local pattern = { if vim.fn.fnamemodify(path, ':e') == 'm4' then return 'fvwm2m4' else - vim.b[bufnr].fvwm_version = 2 - return 'fvwm' + return 'fvwm', function(b) + vim.b[b].fvwm_version = 2 + end end end), ['.*%.[Ll][Oo][Gg]'] = function(path, bufnr) @@ -2220,7 +2230,9 @@ end --- filetype directly) or a function. If a function, it takes the full path and --- buffer number of the file as arguments (along with captures from the matched --- pattern, if any) and should return a string that will be used as the ---- buffer's filetype. +--- buffer's filetype. Optionally, the function can return a second function +--- value which, when called, modifies the state of the buffer. This can be used +--- to, for example, set filetype-specific buffer variables. --- --- Filename patterns can specify an optional priority to resolve cases when a --- file path matches multiple patterns. Higher priorities are matched first. @@ -2238,7 +2250,10 @@ end --- foo = "fooscript", --- bar = function(path, bufnr) --- if some_condition() then ---- return "barscript" +--- return "barscript", function(bufnr) +--- -- Set a buffer variable +--- vim.b[bufnr].barscript_version = 2 +--- end --- end --- return "bar" --- end, @@ -2283,13 +2298,13 @@ end ---@private local function dispatch(ft, path, bufnr, ...) + local on_detect if type(ft) == 'function' then - ft = ft(path, bufnr, ...) + ft, on_detect = ft(path, bufnr, ...) end if type(ft) == 'string' then - api.nvim_buf_set_option(bufnr, 'filetype', ft) - return true + return ft, on_detect end -- Any non-falsey value (that is, anything other than 'nil' or 'false') will @@ -2314,11 +2329,20 @@ local function match_pattern(name, path, tail, pat) return matches end ---- Set the filetype for the given buffer from a file name. +--- Find the filetype for the given filename and buffer. --- ---@param name string File name (can be an absolute or relative path) ---@param bufnr number|nil The buffer to set the filetype for. Defaults to the current buffer. +---@return string|nil If a match was found, the matched filetype. +---@return function|nil A function that modifies buffer state when called (for example, to set some +--- filetype specific buffer variables). The function accepts a buffer number as +--- its only argument. function M.match(name, bufnr) + vim.validate({ + name = { name, 's' }, + bufnr = { bufnr, 'n', true }, + }) + -- When fired from the main filetypedetect autocommand the {bufnr} argument is omitted, so we use -- the current buffer. The {bufnr} argument is provided to allow extensibility in case callers -- wish to perform filetype detection on buffers other than the current one. @@ -2326,16 +2350,20 @@ function M.match(name, bufnr) name = normalize_path(name) + local ft, on_detect + -- First check for the simple case where the full path exists as a key local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p')) - if dispatch(filename[path], path, bufnr) then - return + ft, on_detect = dispatch(filename[path], path, bufnr) + if ft then + return ft, on_detect end -- Next check against just the file name local tail = vim.fn.fnamemodify(name, ':t') - if dispatch(filename[tail], path, bufnr) then - return + ft, on_detect = dispatch(filename[tail], path, bufnr) + if ft then + return ft, on_detect end -- Next, check the file path against available patterns with non-negative priority @@ -2348,19 +2376,21 @@ function M.match(name, bufnr) break end - local ft = v[k][1] + local filetype = v[k][1] local matches = match_pattern(name, path, tail, k) if matches then - if dispatch(ft, path, bufnr, matches) then - return + ft, on_detect = dispatch(filetype, path, bufnr, matches) + if ft then + return ft, on_detect end end end -- Next, check file extension local ext = vim.fn.fnamemodify(name, ':e') - if dispatch(extension[ext], path, bufnr) then - return + ft, on_detect = dispatch(extension[ext], path, bufnr) + if ft then + return ft, on_detect end -- Finally, check patterns with negative priority @@ -2368,11 +2398,12 @@ function M.match(name, bufnr) local v = pattern_sorted[i] local k = next(v) - local ft = v[k][1] + local filetype = v[k][1] local matches = match_pattern(name, path, tail, k) if matches then - if dispatch(ft, path, bufnr, matches) then - return + ft, on_detect = dispatch(filetype, path, bufnr, matches) + if ft then + return ft, on_detect end end end diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 2cc75b026e..7e5ed0f4d1 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -27,24 +27,22 @@ local matchregex = vim.filetype.matchregex -- This function checks for the kind of assembly that is wanted by the user, or -- can be detected from the first five lines of the file. function M.asm(bufnr) - -- Make sure b:asmsyntax exists - if not vim.b[bufnr].asmsyntax then - vim.b[bufnr].asmsyntax = '' - end - - if vim.b[bufnr].asmsyntax == '' then - M.asm_syntax(bufnr) + local syntax = vim.b[bufnr].asmsyntax + if not syntax or syntax == '' then + syntax = M.asm_syntax(bufnr) end -- If b:asmsyntax still isn't set, default to asmsyntax or GNU - if vim.b[bufnr].asmsyntax == '' then + if not syntax or syntax == '' then if vim.g.asmsyntax and vim.g.asmsyntax ~= 0 then - vim.b[bufnr].asmsyntax = vim.g.asmsyntax + syntax = vim.g.asmsyntax else - vim.b[bufnr].asmsyntax = 'asm' + syntax = 'asm' end end - return vim.fn.fnameescape(vim.b[bufnr].asmsyntax) + return syntax, function(b) + vim.b[b].asmsyntax = syntax + end end -- Checks the first 5 lines for a asmsyntax=foo override. @@ -53,9 +51,9 @@ function M.asm_syntax(bufnr) local lines = table.concat(getlines(bufnr, 1, 5), ' '):lower() local match = lines:match('%sasmsyntax=([a-zA-Z0-9]+)%s') if match then - vim.b['asmsyntax'] = match + return match elseif findany(lines, { '%.title', '%.ident', '%.macro', '%.subtitle', '%.library' }) then - vim.b['asmsyntax'] = 'vmasm' + return 'vmasm' end end @@ -376,12 +374,13 @@ function M.inc(bufnr) elseif findany(lines, { '^%s{', '^%s%(%*' }) or matchregex(lines, pascal_keywords) then return 'pascal' else - M.asm_syntax(bufnr) - if vim.b[bufnr].asm_syntax then - return vim.fn.fnameescape(vim.b[bufnr].asm_syntax) - else + local syntax = M.asm_syntax(bufnr) + if not syntax or syntax == '' then return 'pov' end + return syntax, function(b) + vim.b[b].asmsyntax = syntax + end end end @@ -778,6 +777,8 @@ function M.sh(path, bufnr, name) return end + local on_detect + if matchregex(name, [[\]]) then -- Some .sh scripts contain #!/bin/csh. return M.shell(path, bufnr, 'csh') @@ -788,19 +789,25 @@ function M.sh(path, bufnr, name) elseif matchregex(name, [[\]]) then return M.shell(path, bufnr, 'zsh') elseif matchregex(name, [[\]]) then - vim.b[bufnr].is_kornshell = 1 - vim.b[bufnr].is_bash = nil - vim.b[bufnr].is_sh = nil + on_detect = function(b) + vim.b[b].is_kornshell = 1 + vim.b[b].is_bash = nil + vim.b[b].is_sh = nil + end elseif vim.g.bash_is_sh or matchregex(name, [[\]]) or matchregex(name, [[\]]) then - vim.b[bufnr].is_bash = 1 - vim.b[bufnr].is_kornshell = nil - vim.b[bufnr].is_sh = nil + on_detect = function(b) + vim.b[b].is_bash = 1 + vim.b[b].is_kornshell = nil + vim.b[b].is_sh = nil + end elseif matchregex(name, [[\]]) then - vim.b[bufnr].is_sh = 1 - vim.b[bufnr].is_kornshell = nil - vim.b[bufnr].is_bash = nil + on_detect = function(b) + vim.b[b].is_sh = 1 + vim.b[b].is_kornshell = nil + vim.b[b].is_bash = nil + end end - return M.shell(path, bufnr, 'sh') + return M.shell(path, bufnr, 'sh'), on_detect end -- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl. @@ -918,9 +925,11 @@ function M.xml(bufnr) line = line:lower() local is_docbook5 = line:find([[ xmlns="http://docbook.org/ns/docbook"]]) if is_docbook4 or is_docbook5 then - vim.b[bufnr].docbk_type = 'xml' - vim.b[bufnr].docbk_ver = is_docbook4 and 4 or 5 - return 'docbk' + return 'docbk', + function(b) + vim.b[b].docbk_type = 'xml' + vim.b[b].docbk_ver = is_docbook4 and 4 or 5 + end end if line:find([[xmlns:xbl="http://www.mozilla.org/xbl"]]) then return 'xbl' @@ -954,9 +963,10 @@ function M.sgml(bufnr) if lines:find('linuxdoc') then return 'smgllnx' elseif lines:find(']]) then - vim.b[bufnr].xf86conf_xfree86_version = 3 - return 'xf86conf' + on_detect = function(b) + vim.b[b].xf86conf_xfree86_version = 3 + end end + return 'xf86conf', on_detect end -- luacheck: pop -- cgit From 7f8f8d6cb7874369c36553cd8cc500de1b572b31 Mon Sep 17 00:00:00 2001 From: rhcher Date: Tue, 14 Jun 2022 01:31:48 +0800 Subject: feat(lsp): sort codelens if multiple item per line (#18951) --- runtime/lua/vim/lsp/codelens.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index ec0aede2d3..4fa02c8db2 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -133,6 +133,9 @@ function M.display(lenses, bufnr, client_id) api.nvim_buf_clear_namespace(bufnr, ns, i, i + 1) local chunks = {} local num_line_lenses = #line_lenses + table.sort(line_lenses, function(a, b) + return a.range.start.character < b.range.start.character + end) for j, lens in ipairs(line_lenses) do local text = lens.command and lens.command.title or 'Unresolved lens ...' table.insert(chunks, { text, 'LspCodeLens' }) -- cgit From 6de7f32d52822c3c09d24720efc65efe97a6e698 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Wed, 15 Jun 2022 02:49:54 +0200 Subject: docs: fix typos (#18866) docs: fix typos and similarly insignificant changes Co-authored-by: zeertzjq Co-authored-by: smjonas Co-authored-by: kanreki <32443233+kanreki@users.noreply.github.com> --- runtime/lua/vim/lsp/buf.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index fa8ee23805..97c30bc46a 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -708,7 +708,7 @@ local function on_code_action_results(results, ctx, options) end local found = false for _, o in ipairs(options.context.only) do - -- action kinds are hierachical with . as a separator: when requesting only + -- action kinds are hierarchical with . as a separator: when requesting only -- 'quickfix' this filter allows both 'quickfix' and 'quickfix.foo', for example if a.kind:find('^' .. o .. '$') or a.kind:find('^' .. o .. '%.') then found = true -- cgit From 0e8186bdd8699fb20ad70e28813c3603f9ff0ece Mon Sep 17 00:00:00 2001 From: notomo Date: Thu, 16 Jun 2022 11:39:55 +0900 Subject: fix(lua): highlight.on_yank can close timer in twice #18976 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steps to reproduce: 1. setting `vim.highlight.on_yank` ``` vim.api.nvim_create_autocmd({ "TextYankPost" }, { pattern = { "*" }, callback = function() vim.highlight.on_yank({ timeout = 200 }) end, }) ``` 2. repeat typing `yeye` ... 3. causes the following error. ``` Error executing vim.schedule lua callback: vim/_editor.lua:0: handle 0x01e96970 is already closing stack traceback: [C]: in function 'close' vim/_editor.lua: in function '' vim/_editor.lua: in function ``` 📝 Test result before fix: [----------] Global test environment setup. [----------] Running tests from test/functional/lua/highlight_spec.lua [ RUN ] vim.highlight.on_yank does not show errors even if buffer is wiped before timeout: 15.07 ms OK [ RUN ] vim.highlight.on_yank does not show errors even if executed between timeout and clearing highlight: 15.07 ms ERR test/helpers.lua:73: Expected objects to be the same. Passed in: (string) 'Error executing vim.schedule lua callback: vim/_editor.lua:0: handle 0x02025260 is already closing stack traceback: [C]: in function 'close' vim/_editor.lua: in function '' vim/_editor.lua: in function ' Expected: (string) '' --- runtime/lua/vim/_editor.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index 453aa6ac81..f7dcc3a81b 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -408,7 +408,9 @@ function vim.defer_fn(fn, timeout) timeout, 0, vim.schedule_wrap(function() - timer:close() + if not timer:is_closing() then + timer:close() + end fn() end) -- cgit From 8780076a78fcb16d73c3debb244cbf85b01e795b Mon Sep 17 00:00:00 2001 From: kevinhwang91 Date: Thu, 26 May 2022 23:29:31 +0800 Subject: fix(treesitter): new iter if folded --- runtime/lua/vim/treesitter/highlighter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 453fed0576..d3da300e96 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -279,7 +279,7 @@ local function on_line_impl(self, buf, line) return end - if state.iter == nil then + if state.iter == nil or state.next_row < line then state.iter = highlighter_query:query():iter_captures(root_node, self.bufnr, line, root_end_row + 1) end -- cgit From 87a68b6a3ab483c6b126fa8071066a112f9386a3 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Wed, 25 May 2022 11:17:46 -0600 Subject: refactor: use nvim_{get,set}_option_value for vim.{b,w}o `nvim_get_option_value` and `nvim_set_option_value` better handle unsetting local options. For instance, this is currently not possible: vim.bo.tagfunc = nil This does not work because 'tagfunc' is marked as "local to buffer" and does not have a fallback global option. However, using :setlocal *does* work as expected :setlocal tagfunc= `nvim_set_option_value` behaves more like :set and :setlocal (by design), so using these as the underlying API functions beneath vim.bo and vim.wo makes those two tables act more like :setlocal. Note that vim.o *already* uses `nvim_set_option_value` under the hood, so that vim.o behaves like :set. --- runtime/lua/vim/_meta.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 59cf837a1d..715a7e5561 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -91,11 +91,11 @@ do -- buffer option accessor return new_buf_opt_accessor(k) end - return a.nvim_buf_get_option(bufnr or 0, k) + return a.nvim_get_option_value(k, { buf = bufnr or 0 }) end local function set(k, v) - return a.nvim_buf_set_option(bufnr or 0, k, v) + return a.nvim_set_option_value(k, v, { buf = bufnr or 0 }) end return make_meta_accessor(get, set, nil, function(k) @@ -121,11 +121,11 @@ do -- window option accessor if winnr == nil and type(k) == 'number' then return new_win_opt_accessor(k) end - return a.nvim_win_get_option(winnr or 0, k) + return a.nvim_get_option_value(k, { win = winnr or 0 }) end local function set(k, v) - return a.nvim_win_set_option(winnr or 0, k, v) + return a.nvim_set_option_value(k, v, { win = winnr or 0 }) end return make_meta_accessor(get, set, nil, function(k) -- cgit From e3b51d584266100d423d46059bd80d0789c61118 Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Tue, 21 Jun 2022 19:29:52 +0200 Subject: refactor(runtime): refactor filetype.lua (#18813) Move some filetype detection functions to detect.lua, sort patterns by detected filetype. --- runtime/lua/vim/filetype.lua | 1235 ++++++++++++++++------------------- runtime/lua/vim/filetype/detect.lua | 411 +++++++----- 2 files changed, 820 insertions(+), 826 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 536580c604..320d6a2a5b 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -23,13 +23,6 @@ local function starsetf(ft, opts) } end ----@private -local function getline(bufnr, start_lnum, end_lnum) - end_lnum = end_lnum or start_lnum - local lines = api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) - return table.concat(lines) or '' -end - ---@private --- Get a single line or line-range from the buffer. --- @@ -127,6 +120,15 @@ local extension = { end return 'aspvbs' end, + asm = function(path, bufnr) + return require('vim.filetype.detect').asm(bufnr) + end, + lst = function(path, bufnr) + return require('vim.filetype.detect').asm(bufnr) + end, + mac = function(path, bufnr) + return require('vim.filetype.detect').asm(bufnr) + end, ['asn1'] = 'asn', asn = 'asn', asp = function(path, bufnr) @@ -142,14 +144,32 @@ local extension = { ref = 'b', imp = 'b', mch = 'b', + bas = function(path, bufnr) + return require('vim.filetype.detect').bas(bufnr) + end, + bi = function(path, bufnr) + return require('vim.filetype.detect').bas(bufnr) + end, + bm = function(path, bufnr) + return require('vim.filetype.detect').bas(bufnr) + end, bc = 'bc', bdf = 'bdf', beancount = 'beancount', bib = 'bib', + com = function(path, bufnr) + return require('vim.filetype.detect').bindzone(bufnr, 'dcl') + end, + db = function(path, bufnr) + return require('vim.filetype.detect').bindzone(bufnr, '') + end, bicep = 'bicep', bl = 'blank', bsdl = 'bsdl', bst = 'bst', + btm = function(path, bufnr) + return (vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0) and 'dosbatch' or 'btm' + end, bzl = 'bzl', bazel = 'bzl', BUILD = 'bzl', @@ -163,6 +183,9 @@ local extension = { hgrc = 'cfg', chf = 'ch', chai = 'chaiscript', + ch = function(path, bufnr) + return require('vim.filetype.detect').change(bufnr) + end, chs = 'chaskell', chopro = 'chordpro', crd = 'chordpro', @@ -184,15 +207,22 @@ local extension = { atg = 'coco', recipe = 'conaryrecipe', hook = function(path, bufnr) - if getline(bufnr, 1) == '[Trigger]' then - return 'conf' - end + return M.getlines(bufnr, 1) == '[Trigger]' and 'conf' end, mklx = 'context', mkiv = 'context', mkii = 'context', mkxl = 'context', mkvi = 'context', + control = function(path, bufnr) + return require('vim.filetype.detect').control(bufnr) + end, + copyright = function(path, bufnr) + return require('vim.filetype.detect').copyright(bufnr) + end, + csh = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, moc = 'cpp', hh = 'cpp', tlh = 'cpp', @@ -206,16 +236,10 @@ local extension = { hxx = 'cpp', hpp = 'cpp', cpp = function(path, bufnr) - if vim.g.cynlib_syntax_for_cpp then - return 'cynlib' - end - return 'cpp' + return vim.g.cynlib_syntax_for_cpp and 'cynlib' or 'cpp' end, cc = function(path, bufnr) - if vim.g.cynlib_syntax_for_cc then - return 'cynlib' - end - return 'cpp' + return vim.g.cynlib_syntax_for_cc and 'cynlib' or 'cpp' end, crm = 'crm', csx = 'cs', @@ -237,6 +261,15 @@ local extension = { drt = 'dart', ds = 'datascript', dcd = 'dcd', + decl = function(path, bufnr) + return require('vim.filetype.detect').decl(bufnr) + end, + dec = function(path, bufnr) + return require('vim.filetype.detect').decl(bufnr) + end, + dcl = function(path, bufnr) + return require('vim.filetype.detect').decl(bufnr) or 'clean' + end, def = 'def', desc = 'desc', directory = 'desktop', @@ -253,17 +286,40 @@ local extension = { drac = 'dracula', drc = 'dracula', dtd = 'dtd', + d = function(path, bufnr) + return require('vim.filetype.detect').dtrace(bufnr) + end, dts = 'dts', dtsi = 'dts', dylan = 'dylan', intr = 'dylanintr', lid = 'dylanlid', + e = function(path, bufnr) + return require('vim.filetype.detect').e(bufnr) + end, + E = function(path, bufnr) + return require('vim.filetype.detect').e(bufnr) + end, ecd = 'ecd', + edf = 'edif', + edfi = 'edif', + edo = 'edif', + edn = function(path, bufnr) + return require('vim.filetype.detect').edn(bufnr) + end, eex = 'eelixir', leex = 'eelixir', + am = function(path, bufnr) + if not path:lower():find('makefile%.am$') then + return 'elf' + end + end, exs = 'elixir', elm = 'elm', elv = 'elvish', + ent = function(path, bufnr) + return require('vim.filetype.detect').ent(bufnr) + end, epp = 'epuppet', erl = 'erlang', hrl = 'erlang', @@ -273,6 +329,36 @@ local extension = { ec = 'esqlc', EC = 'esqlc', strl = 'esterel', + eu = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + EU = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + ew = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + EW = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + EX = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + exu = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + EXU = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + exw = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + EXW = function(path, bufnr) + return vim.g.filetype_euphoria or 'euphoria3' + end, + ex = function(path, bufnr) + return require('vim.filetype.detect').ex(bufnr) + end, exp = 'expect', factor = 'factor', fal = 'falcon', @@ -308,7 +394,13 @@ local extension = { ['f08'] = 'fortran', fpc = 'fpcmake', fsl = 'framescript', + frm = function(path, bufnr) + return require('vim.filetype.detect').frm(bufnr) + end, fb = 'freebasic', + fs = function(path, bufnr) + return require('vim.filetype.detect').fs(bufnr) + end, fsi = 'fsharp', fsx = 'fsharp', fusion = 'fusion', @@ -350,6 +442,9 @@ local extension = { ht = 'haste', htpp = 'hastepreproc', hb = 'hb', + h = function(path, bufnr) + return require('vim.filetype.detect').header(bufnr) + end, sum = 'hercules', errsum = 'hercules', ev = 'hercules', @@ -362,14 +457,56 @@ local extension = { hog = 'hog', hws = 'hollywood', hoon = 'hoon', + cpt = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, + dtml = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, + htm = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, + html = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, + pt = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, + shtml = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, + stm = function(path, bufnr) + return require('vim.filetype.detect').html(bufnr) + end, htt = 'httest', htb = 'httest', + hw = function(path, bufnr) + return require('vim.filetype.detect').hw(bufnr) + end, + module = function(path, bufnr) + return require('vim.filetype.detect').hw(bufnr) + end, + pkg = function(path, bufnr) + return require('vim.filetype.detect').hw(bufnr) + end, iba = 'ibasic', ibi = 'ibasic', icn = 'icon', + idl = function(path, bufnr) + return require('vim.filetype.detect').idl(bufnr) + end, + inc = function(path, bufnr) + return require('vim.filetype.detect').inc(bufnr) + end, inf = 'inform', INF = 'inform', ii = 'initng', + inp = function(path, bufnr) + return require('vim.filetype.detect').inp(bufnr) + end, + ms = function(path, bufnr) + return require('vim.filetype.detect').nroff(bufnr) or 'xmath' + end, iss = 'iss', mst = 'ist', ist = 'ist', @@ -445,14 +582,26 @@ local extension = { lou = 'lout', ulpc = 'lpc', lpc = 'lpc', + c = function(path, bufnr) + return require('vim.filetype.detect').lpc(bufnr) + end, sig = 'lprolog', lsl = 'lsl', lss = 'lss', nse = 'lua', rockspec = 'lua', lua = 'lua', - quake = 'm3quake', + m = function(path, bufnr) + return require('vim.filetype.detect').m(bufnr) + end, at = 'm4', + mc = function(path, bufnr) + return require('vim.filetype.detect').mc(bufnr) + end, + quake = 'm3quake', + ['m4'] = function(path, bufnr) + return require('vim.filetype.detect').m4(path) + end, eml = 'mail', mk = 'make', mak = 'make', @@ -487,8 +636,14 @@ local extension = { mib = 'mib', mix = 'mix', mixal = 'mix', + mm = function(path, bufnr) + return require('vim.filetype.detect').mm(bufnr) + end, nb = 'mma', mmp = 'mmp', + mms = function(path, bufnr) + return require('vim.filetype.detect').mms(bufnr) + end, DEF = 'modula2', ['m2'] = 'modula2', mi = 'modula2', @@ -559,6 +714,9 @@ local extension = { pike = 'pike', pmod = 'pike', rcp = 'pilrc', + PL = function(path, bufnr) + return require('vim.filetype.detect').pl(bufnr) + end, pli = 'pli', ['pl1'] = 'pli', ['p36'] = 'plm', @@ -604,6 +762,9 @@ local extension = { ptl = 'python', ql = 'ql', qll = 'ql', + R = function(path, bufnr) + return require('vim.filetype.detect').r(bufnr) + end, rad = 'radiance', mat = 'radiance', ['pod6'] = 'raku', @@ -685,6 +846,24 @@ local extension = { sdl = 'sdl', sed = 'sed', sexp = 'sexplib', + bash = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ebuild = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + eclass = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + env = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, + ksh = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'ksh') + end, + sh = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, sieve = 'sieve', siv = 'sieve', sil = 'sil', @@ -767,14 +946,7 @@ local extension = { latex = 'tex', sty = 'tex', cls = function(path, bufnr) - local line = getline(bufnr, 1) - if line:find('^%%') then - return 'tex' - elseif line:find('^#') and line:lower():find('rexx') then - return 'rexx' - else - return 'st' - end + return require('vim.filetype.detect').cls(bufnr) end, texi = 'texinfo', txi = 'texinfo', @@ -793,11 +965,7 @@ local extension = { tutor = 'tutor', twig = 'twig', ts = function(path, bufnr) - if getline(bufnr, 1):find('<%?xml') then - return 'xml' - else - return 'typescript' - end + return M.getlines(bufnr, 1):find('<%?xml') and 'xml' or 'typescript' end, tsx = 'typescriptreact', uc = 'uc', @@ -855,10 +1023,7 @@ local extension = { wpl = 'xml', xmi = 'xml', xpm = function(path, bufnr) - if getline(bufnr, 1):find('XPM2') then - return 'xpm2' - end - return 'xpm' + return M.getlines(bufnr, 1):find('XPM2') and 'xpm2' or 'xpm' end, ['xpm2'] = 'xpm2', xqy = 'xquery', @@ -882,211 +1047,62 @@ local extension = { zut = 'zimbutempl', zsh = 'zsh', vala = 'vala', - E = function(path, bufnr) - return require('vim.filetype.detect').e(bufnr) + web = function(path, bufnr) + return require('vim.filetype.detect').web(bufnr) end, - EU = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + pl = function(path, bufnr) + return require('vim.filetype.detect').pl(bufnr) end, - EW = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + pp = function(path, bufnr) + return require('vim.filetype.detect').pp(bufnr) end, - EX = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + i = function(path, bufnr) + return require('vim.filetype.detect').progress_asm(bufnr) end, - EXU = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + w = function(path, bufnr) + return require('vim.filetype.detect').progress_cweb(bufnr) end, - EXW = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) + p = function(path, bufnr) + return require('vim.filetype.detect').progress_pascal(bufnr) end, - PL = function(path, bufnr) - return require('vim.filetype.detect').pl(bufnr) + pro = function(path, bufnr) + return require('vim.filetype.detect').proto(bufnr, 'idlang') end, - R = function(path, bufnr) + patch = function(path, bufnr) + return require('vim.filetype.detect').patch(bufnr) + end, + r = function(path, bufnr) return require('vim.filetype.detect').r(bufnr) end, - asm = function(path, bufnr) - return require('vim.filetype.detect').asm(bufnr) + rdf = function(path, bufnr) + return require('vim.filetype.detect').redif(bufnr) end, - bas = function(path, bufnr) - return require('vim.filetype.detect').bas(bufnr) + rules = function(path, bufnr) + return require('vim.filetype.detect').rules(path) end, - bi = function(path, bufnr) - return require('vim.filetype.detect').bas(bufnr) + sc = function(path, bufnr) + return require('vim.filetype.detect').sc(bufnr) end, - bm = function(path, bufnr) - return require('vim.filetype.detect').bas(bufnr) + scd = function(path, bufnr) + return require('vim.filetype.detect').scd(bufnr) end, - bash = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + tcsh = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') end, - btm = function(path, bufnr) - return require('vim.filetype.detect').btm(bufnr) + sql = function(path, bufnr) + return vim.g.filetype_sql and vim.g.filetype_sql or 'sql' end, - c = function(path, bufnr) - return require('vim.filetype.detect').lpc(bufnr) + zsql = function(path, bufnr) + return vim.g.filetype_sql and vim.g.filetype_sql or 'sql' end, - ch = function(path, bufnr) - return require('vim.filetype.detect').change(bufnr) + tex = function(path, bufnr) + return require('vim.filetype.detect').tex(path, bufnr) end, - com = function(path, bufnr) - return require('vim.filetype.detect').bindzone(bufnr, 'dcl') + tf = function(path, bufnr) + return require('vim.filetype.detect').tf(bufnr) end, - cpt = function(path, bufnr) - return require('vim.filetype.detect').html(bufnr) - end, - csh = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - d = function(path, bufnr) - return require('vim.filetype.detect').dtrace(bufnr) - end, - db = function(path, bufnr) - return require('vim.filetype.detect').bindzone(bufnr, '') - end, - dtml = function(path, bufnr) - return require('vim.filetype.detect').html(bufnr) - end, - e = function(path, bufnr) - return require('vim.filetype.detect').e(bufnr) - end, - ebuild = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - eclass = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ent = function(path, bufnr) - return require('vim.filetype.detect').ent(bufnr) - end, - env = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - eu = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) - end, - ew = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) - end, - ex = function(path, bufnr) - return require('vim.filetype.detect').ex(bufnr) - end, - exu = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) - end, - exw = function(path, bufnr) - return require('vim.filetype.detect').euphoria(bufnr) - end, - frm = function(path, bufnr) - return require('vim.filetype.detect').frm(bufnr) - end, - fs = function(path, bufnr) - return require('vim.filetype.detect').fs(bufnr) - end, - h = function(path, bufnr) - return require('vim.filetype.detect').header(bufnr) - end, - htm = function(path, bufnr) - return require('vim.filetype.detect').html(bufnr) - end, - html = function(path, bufnr) - return require('vim.filetype.detect').html(bufnr) - end, - i = function(path, bufnr) - return require('vim.filetype.detect').progress_asm(bufnr) - end, - idl = function(path, bufnr) - return require('vim.filetype.detect').idl(bufnr) - end, - inc = function(path, bufnr) - return require('vim.filetype.detect').inc(bufnr) - end, - inp = function(path, bufnr) - return require('vim.filetype.detect').inp(bufnr) - end, - ksh = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'ksh') - end, - lst = function(path, bufnr) - return require('vim.filetype.detect').asm(bufnr) - end, - m = function(path, bufnr) - return require('vim.filetype.detect').m(bufnr) - end, - mac = function(path, bufnr) - return require('vim.filetype.detect').asm(bufnr) - end, - mc = function(path, bufnr) - return require('vim.filetype.detect').mc(bufnr) - end, - mm = function(path, bufnr) - return require('vim.filetype.detect').mm(bufnr) - end, - mms = function(path, bufnr) - return require('vim.filetype.detect').mms(bufnr) - end, - p = function(path, bufnr) - return require('vim.filetype.detect').progress_pascal(bufnr) - end, - patch = function(path, bufnr) - local firstline = getline(bufnr, 1) - if string.find(firstline, '^From ' .. string.rep('%x', 40) .. '+ Mon Sep 17 00:00:00 2001$') then - return 'gitsendemail' - else - return 'diff' - end - end, - pl = function(path, bufnr) - return require('vim.filetype.detect').pl(bufnr) - end, - pp = function(path, bufnr) - return require('vim.filetype.detect').pp(bufnr) - end, - pro = function(path, bufnr) - return require('vim.filetype.detect').proto(bufnr, 'idlang') - end, - pt = function(path, bufnr) - return require('vim.filetype.detect').html('idlang') - end, - r = function(path, bufnr) - return require('vim.filetype.detect').r(bufnr) - end, - rdf = function(path, bufnr) - return require('vim.filetype.detect').redif(bufnr) - end, - rules = function(path, bufnr) - return require('vim.filetype.detect').rules(path, bufnr) - end, - sc = function(path, bufnr) - return require('vim.filetype.detect').sc(bufnr) - end, - scd = function(path, bufnr) - return require('vim.filetype.detect').scd(bufnr) - end, - sh = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - shtml = function(path, bufnr) - return require('vim.filetype.detect').html(bufnr) - end, - sql = function(path, bufnr) - return require('vim.filetype.detect').sql(bufnr) - end, - stm = function(path, bufnr) - return require('vim.filetype.detect').html(bufnr) - end, - tcsh = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') - end, - tex = function(path, bufnr) - return require('vim.filetype.detect').tex(path, bufnr) - end, - tf = function(path, bufnr) - return require('vim.filetype.detect').tf(bufnr) - end, - w = function(path, bufnr) - return require('vim.filetype.detect').progress_cweb(bufnr) + txt = function(path, bufnr) + return require('vim.filetype.detect').txt(bufnr) end, xml = function(path, bufnr) return require('vim.filetype.detect').xml(bufnr) @@ -1094,137 +1110,51 @@ local extension = { y = function(path, bufnr) return require('vim.filetype.detect').y(bufnr) end, - zsql = function(path, bufnr) - return require('vim.filetype.detect').sql(bufnr) - end, - txt = function(path, bufnr) - --helpfiles match *.txt, but should have a modeline as last line - if not getline(bufnr, -1):find('vim:.*ft=help') then - return 'text' - end - end, cmd = function(path, bufnr) - if getline(bufnr, 1):find('^/%*') then - return 'rexx' - end - return 'dosbatch' + return M.getlines(bufnr, 1):find('^/%*') and 'rexx' or 'dosbatch' end, rul = function(path, bufnr) return require('vim.filetype.detect').rul(bufnr) end, cpy = function(path, bufnr) - if getline(bufnr, 1):find('^##') then - return 'python' - end - return 'cobol' + return M.getlines(bufnr, 1):find('^##') and 'python' or 'cobol' end, dsl = function(path, bufnr) - if getline(bufnr, 1):find('^%s*') then - return 'xml' - end - return 'smil' + return M.getlines(bufnr, 1):find('<%?%s*xml.*%?>') and 'xml' or 'smil' end, smi = function(path, bufnr) return require('vim.filetype.detect').smi(bufnr) end, install = function(path, bufnr) - if getline(bufnr, 1):lower():find('<%?php') then - return 'php' - end - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').install(path, bufnr) end, pm = function(path, bufnr) - local line = getline(bufnr, 1) - if line:find('XPM2') then - return 'xpm2' - elseif line:find('XPM') then - return 'xpm' - else - return 'perl' - end + return require('vim.filetype.detect').pm(bufnr) end, me = function(path, bufnr) - local filename = vim.fn.fnamemodify(path, ':t'):lower() - if filename ~= 'read.me' and filename ~= 'click.me' then - return 'nroff' - end + return require('vim.filetype.detect').me(path) end, reg = function(path, bufnr) - local line = getline(bufnr, 1):lower() - if line:find('^regedit[0-9]*%s*$') or line:find('^windows registry editor version %d*%.%d*%s*$') then - return 'registry' - end - end, - decl = function(path, bufnr) - return require('vim.filetype.detect').decl(bufnr) - end, - dec = function(path, bufnr) - return require('vim.filetype.detect').decl(bufnr) - end, - dcl = function(path, bufnr) - local decl = require('vim.filetype.detect').decl(bufnr) - if decl then - return decl - end - return 'clean' - end, - web = function(path, bufnr) - return require('vim.filetype.detect').web(bufnr) + return require('vim.filetype.detect').reg(bufnr) end, ttl = function(path, bufnr) - local line = getline(bufnr, 1):lower() - if line:find('^@?prefix') or line:find('^@?base') then - return 'turtle' - end - return 'teraterm' - end, - am = function(path, bufnr) - if not path:lower():find('makefile%.am$') then - return 'elf' - end + return require('vim.filetype.detect').ttl(bufnr) end, - ['m4'] = function(path, bufnr) - local path_lower = path:lower() - if not path_lower:find('html%.m4$') and not path_lower:find('fvwm2rc') then - return 'm4' - end - end, - hw = function(path, bufnr) - return require('vim.filetype.detect').hw(bufnr) - end, - module = function(path, bufnr) - return require('vim.filetype.detect').hw(bufnr) - end, - pkg = function(path, bufnr) - return require('vim.filetype.detect').hw(bufnr) - end, - ms = function(path, bufnr) - if not require('vim.filetype.detect').nroff(bufnr) then - return 'xmath' + rc = function(path, bufnr) + if not path:find('/etc/Muttrc%.d/') then + return 'rc' end end, - t = function(path, bufnr) - if not require('vim.filetype.detect').nroff(bufnr) and not require('vim.filetype.detect').perl(path, bufnr) then - return 'tads' + rch = function(path, bufnr) + if not path:find('/etc/Muttrc%.d/') then + return 'rc' end end, class = function(path, bufnr) - -- Check if not a Java class (starts with '\xca\xfe\xba\xbe') - if not getline(bufnr, 1):find('^\202\254\186\190') then - return 'stata' - end + require('vim.filetype.detect').class(bufnr) end, sgml = function(path, bufnr) return require('vim.filetype.detect').sgml(bufnr) @@ -1232,27 +1162,20 @@ local extension = { sgm = function(path, bufnr) return require('vim.filetype.detect').sgml(bufnr) end, - rc = function(path, bufnr) - if not path:find('/etc/Muttrc%.d/') then - return 'rc' - end - end, - rch = function(path, bufnr) - if not path:find('/etc/Muttrc%.d/') then - return 'rc' + t = function(path, bufnr) + if not require('vim.filetype.detect').nroff(bufnr) and not require('vim.filetype.detect').perl(path, bufnr) then + return 'tads' end end, - control = function(path, bufnr) - return require('vim.filetype.detect').control(bufnr) - end, - copyright = function(path, bufnr) - return require('vim.filetype.detect').copyright(bufnr) - end, -- Ignored extensions bak = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') return M.match(root, bufnr) end, + ['dpkg-bak'] = function(path, bufnr) + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end, ['dpkg-dist'] = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') return M.match(root, bufnr) @@ -1265,9 +1188,11 @@ local extension = { local root = vim.fn.fnamemodify(path, ':r') return M.match(root, bufnr) end, - ['dpkg-bak'] = function(path, bufnr) - local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + ['in'] = function(path, bufnr) + if vim.fs.basename(path) ~= 'configure.in' then + local root = vim.fn.fnamemodify(path, ':r') + return M.match(root, bufnr) + end end, new = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') @@ -1297,12 +1222,6 @@ local extension = { local root = vim.fn.fnamemodify(path, ':r') return M.match(root, bufnr) end, - ['in'] = function(path, bufnr) - if vim.fs.basename(path) ~= 'configure.in' then - local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) - end - end, -- END EXTENSION } @@ -1322,6 +1241,13 @@ local filename = { ['.arch-inventory'] = 'arch', ['GNUmakefile.am'] = 'automake', ['named.root'] = 'bindzone', + ['.*/bind/db%..*'] = starsetf('bindzone'), + ['.*/named/db%..*'] = starsetf('bindzone'), + ['cabal%.project%..*'] = starsetf('cabalproject'), + ['sgml%.catalog.*'] = starsetf('catalog'), + ['/etc/hostname%..*'] = starsetf('config'), + ['.*/etc/cron%.d/.*'] = starsetf('crontab'), + ['crontab%..*'] = starsetf('crontab'), WORKSPACE = 'bzl', BUILD = 'bzl', ['cabal.project'] = 'cabalproject', @@ -1335,21 +1261,43 @@ local filename = { ['/etc/defaults/cdrdao'] = 'cdrdaoconf', ['cfengine.conf'] = 'cfengine', ['CMakeLists.txt'] = 'cmake', - ['auto.master'] = 'conf', - ['configure.in'] = 'config', - ['configure.ac'] = 'config', - ['.cvsrc'] = 'cvsrc', - ['/debian/changelog'] = 'debchangelog', - ['changelog.dch'] = 'debchangelog', - ['changelog.Debian'] = 'debchangelog', - ['NEWS.dch'] = 'debchangelog', - ['NEWS.Debian'] = 'debchangelog', - ['/debian/control'] = 'debcontrol', - ['/debian/copyright'] = 'debcopyright', - ['/etc/apt/sources.list'] = 'debsources', - ['denyhosts.conf'] = 'denyhosts', - ['dict.conf'] = 'dictconf', - ['.dictrc'] = 'dictconf', + ['.alias'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['.cshrc'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['.login'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['csh.cshrc'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['csh.login'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['csh.logout'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['auto.master'] = 'conf', + ['configure.in'] = 'config', + ['configure.ac'] = 'config', + crontab = 'crontab', + ['.cvsrc'] = 'cvsrc', + ['/debian/changelog'] = 'debchangelog', + ['changelog.dch'] = 'debchangelog', + ['changelog.Debian'] = 'debchangelog', + ['NEWS.dch'] = 'debchangelog', + ['NEWS.Debian'] = 'debchangelog', + ['/debian/control'] = 'debcontrol', + ['/debian/copyright'] = 'debcopyright', + ['/etc/apt/sources.list'] = 'debsources', + ['denyhosts.conf'] = 'denyhosts', + ['.*/debian/patches/.*'] = function(path, bufnr) + return require('vim.filetype.detect').dep3patch(path, bufnr) + end, + ['dict.conf'] = 'dictconf', + ['.dictrc'] = 'dictconf', ['/etc/DIR_COLORS'] = 'dircolors', ['.dir_colors'] = 'dircolors', ['.dircolors'] = 'dircolors', @@ -1524,6 +1472,9 @@ local filename = { end, ['.procmailrc'] = 'procmail', ['.procmail'] = 'procmail', + ['indent.pro'] = function(path, bufnr) + return require('vim.filetype.detect').proto(bufnr, 'indent') + end, ['/etc/protocols'] = 'protocols', ['INDEX'] = function(path, bufnr) return require('vim.filetype.detect').psf(bufnr) @@ -1551,9 +1502,46 @@ local filename = { ['.screenrc'] = 'screen', ['/etc/sensors3.conf'] = 'sensors', ['/etc/sensors.conf'] = 'sensors', + ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), ['/etc/services'] = 'services', ['/etc/serial.conf'] = 'setserial', ['/etc/udev/cdsymlinks.conf'] = 'sh', + ['bash.bashrc'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + bashrc = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['.bashrc'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['.env'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, + ['.kshrc'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'ksh') + end, + ['.profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, + ['/etc/profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, + APKBUILD = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + PKGBUILD = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['.tcshrc'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + end, + ['tcsh.login'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + end, + ['tcsh.tcshrc'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + end, ['/etc/slp.conf'] = 'slpconf', ['/etc/slp.reg'] = 'slpreg', ['/etc/slp.spi'] = 'slpspi', @@ -1615,6 +1603,9 @@ local filename = { vim.b[b].xf86conf_xfree86_version = 4 end end, + ['XF86Config'] = function(path, bufnr) + return require('vim.filetype.detect').xfree86() + end, ['/etc/xinetd.conf'] = 'xinetd', fglrxrc = 'xml', ['/etc/blkid.tab'] = 'xml', @@ -1627,67 +1618,6 @@ local filename = { ['.zcompdump'] = 'zsh', ['.zshenv'] = 'zsh', ['.zfbfmarks'] = 'zsh', - ['.alias'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['.bashrc'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ['.cshrc'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['.env'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - ['.kshrc'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'ksh') - end, - ['.login'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['.profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - ['.tcshrc'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') - end, - ['/etc/profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - APKBUILD = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - PKGBUILD = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ['bash.bashrc'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - bashrc = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - crontab = 'crontab', - ['csh.cshrc'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['csh.login'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['csh.logout'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['indent.pro'] = function(path, bufnr) - return require('vim.filetype.detect').proto(bufnr, 'indent') - end, - ['tcsh.login'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') - end, - ['tcsh.tcshrc'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') - end, - ['XF86Config'] = function(path, bufnr) - return require('vim.filetype.detect').xfree86(bufnr) - end, -- END FILENAME } @@ -1699,7 +1629,31 @@ local pattern = { ['.*/etc/asound%.conf'] = 'alsaconf', ['.*/etc/apache2/sites%-.*/.*%.com'] = 'apache', ['.*/etc/httpd/.*%.conf'] = 'apache', + ['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'), + ['.*/etc/apache2/conf%..*/.*'] = starsetf('apache'), + ['.*/etc/apache2/mods%-.*/.*'] = starsetf('apache'), + ['.*/etc/apache2/sites%-.*/.*'] = starsetf('apache'), + ['access%.conf.*'] = starsetf('apache'), + ['apache%.conf.*'] = starsetf('apache'), + ['apache2%.conf.*'] = starsetf('apache'), + ['httpd%.conf.*'] = starsetf('apache'), + ['srm%.conf.*'] = starsetf('apache'), + ['.*/etc/httpd/conf%..*/.*'] = starsetf('apache'), + ['.*/etc/httpd/conf%.d/.*%.conf.*'] = starsetf('apache'), + ['.*/etc/httpd/mods%-.*/.*'] = starsetf('apache'), + ['.*/etc/httpd/sites%-.*/.*'] = starsetf('apache'), + ['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'), + ['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'), + ['proftpd%.conf.*'] = starsetf('apachestyle'), + ['.*asterisk/.*%.conf.*'] = starsetf('asterisk'), + ['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'), ['.*/%.aptitude/config'] = 'aptconf', + ['.*%.[aA]'] = function(path, bufnr) + return require('vim.filetype.detect').asm(bufnr) + end, + ['.*%.[sS]'] = function(path, bufnr) + return require('vim.filetype.detect').asm(bufnr) + end, ['[mM]akefile%.am'] = 'automake', ['.*bsd'] = 'bsdl', ['bzr_log%..*'] = 'bzr', @@ -1711,6 +1665,14 @@ local pattern = { ['.*/etc/cdrdao%.conf'] = 'cdrdaoconf', ['.*/etc/default/cdrdao'] = 'cdrdaoconf', ['.*hgrc'] = 'cfg', + ['.*%.[Cc][Ff][Gg]'] = { + function(path, bufnr) + return require('vim.filetype.detect').cfg(bufnr) + end, + -- Decrease the priority to avoid conflicts with more specific patterns + -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. + { priority = -1 }, + }, ['.*%.%.ch'] = 'chill', ['.*%.cmake%.in'] = 'cmake', -- */cmus/rc and */.cmus/rc @@ -1719,7 +1681,24 @@ local pattern = { ['.*/%.?cmus/.*%.theme'] = 'cmusrc', ['.*/%.cmus/autosave'] = 'cmusrc', ['.*/%.cmus/command%-history'] = 'cmusrc', + ['%.cshrc.*'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, + ['%.login.*'] = function(path, bufnr) + return require('vim.filetype.detect').csh(path, bufnr) + end, ['cvs%d+'] = 'cvs', + ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr) + return require('vim.filetype.detect').dat(path, bufnr) + end, + ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr) + require('vim.filetype.detect').changelog(bufnr) + end), + ['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'), + ['Containerfile%..*'] = starsetf('dockerfile'), + ['Dockerfile%..*'] = starsetf('dockerfile'), + ['.*/etc/yum%.repos%.d/.*'] = starsetf('dosini'), + ['drac%..*'] = starsetf('dracula'), ['.*/debian/changelog'] = 'debchangelog', ['.*/debian/control'] = 'debcontrol', ['.*/debian/copyright'] = 'debcopyright', @@ -1736,6 +1715,52 @@ local pattern = { ['.*/dtrace/.*%.d'] = 'dtrace', ['.*esmtprc'] = 'esmtprc', ['.*Eterm/.*%.cfg'] = 'eterm', + ['[a-zA-Z0-9].*Dict'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['[a-zA-Z0-9].*Dict%..*'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['[a-zA-Z].*Properties'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['[a-zA-Z].*Properties%..*'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['.*Transport%..*'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['.*/constant/g'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['.*/0/.*'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['.*/0%.orig/.*'] = function(path, bufnr) + return require('vim.filetype.detect').foam(bufnr) + end, + ['.*/%.fvwm/.*'] = starsetf('fvwm'), + ['.*fvwmrc.*'] = starsetf(function(path, bufnr) + return 'fvwm', function(b) + vim.b[b].fvwm_version = 1 + end + end), + ['.*fvwm95.*%.hook'] = starsetf(function(path, bufnr) + return 'fvwm', function(b) + vim.b[b].fvwm_version = 1 + end + end), + ['.*fvwm2rc.*'] = starsetf(function(path, bufnr) + return require('vim.filetype.detect').fvwm(path) + end), + ['.*/tmp/lltmp.*'] = starsetf('gedcom'), + ['/etc/gitconfig%.d/.*'] = starsetf('gitconfig'), + ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'), + ['tmac%..*'] = starsetf('nroff'), + ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), + ['.*%.git/.*'] = function(path, bufnr) + require('vim.filetype.detect').git(bufnr) + end, ['.*%.git/modules/.*/config'] = 'gitconfig', ['.*%.git/config'] = 'gitconfig', ['.*/etc/gitconfig'] = 'gitconfig', @@ -1766,13 +1791,15 @@ local pattern = { ['.*/etc/gshadow'] = 'group', ['.*/etc/group%.edit'] = 'group', ['.*/var/backups/gshadow%.bak'] = 'group', - ['.*/etc/group-'] = 'group', - ['.*/etc/gshadow-'] = 'group', + ['.*/etc/group%-'] = 'group', + ['.*/etc/gshadow%-'] = 'group', ['.*/var/backups/group%.bak'] = 'group', ['.*/etc/gshadow%.edit'] = 'group', ['.*/boot/grub/grub%.conf'] = 'grub', ['.*/boot/grub/menu%.lst'] = 'grub', ['.*/etc/grub%.conf'] = 'grub', + -- gtkrc* and .gtkrc* + ['%.?gtkrc.*'] = starsetf('gtkrc'), [vim.env.VIMRUNTIME .. '/doc/.*%.txt'] = 'help', ['hg%-editor%-.*%.txt'] = 'hgcommit', ['.*/etc/host%.conf'] = 'hostconf', @@ -1785,8 +1812,15 @@ local pattern = { ['.*/%.sway/config'] = 'i3config', ['.*/%.icewm/menu'] = 'icemenu', ['.*/etc/initng/.*/.*%.i'] = 'initng', + ['JAM.*%..*'] = starsetf('jam'), + ['Prl.*%..*'] = starsetf('jam'), ['.*%.properties_..'] = 'jproperties', ['.*%.properties_.._..'] = 'jproperties', + ['.*%.properties_.._.._.*'] = starsetf('jproperties'), + ['Kconfig%..*'] = starsetf('kconfig'), + ['.*%.[Ss][Uu][Bb]'] = 'krl', + ['lilo%.conf.*'] = starsetf('lilo'), + ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'), ['.*lftp/rc'] = 'lftp', ['.*/%.libao'] = 'libao', ['.*/etc/libao%.conf'] = 'libao', @@ -1796,52 +1830,99 @@ local pattern = { ['.*/LiteStep/.*/.*%.rc'] = 'litestep', ['.*/etc/login%.access'] = 'loginaccess', ['.*/etc/login%.defs'] = 'logindefs', + ['%.letter%.%d+'] = 'mail', + ['%.article%.%d+'] = 'mail', + ['/tmp/SLRN[0-9A-Z.]+'] = 'mail', + ['ae%d+%.txt'] = 'mail', + ['pico%.%d+'] = 'mail', + ['mutt%-.*%-%w+'] = 'mail', + ['muttng%-.*%-%w+'] = 'mail', + ['neomutt%-.*%-%w+'] = 'mail', + ['mutt' .. string.rep('[%w_-]', 6)] = 'mail', + ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail', + ['snd%.%d+'] = 'mail', + ['reportbug%-.*'] = starsetf('mail'), ['.*/etc/mail/aliases'] = 'mailaliases', ['.*/etc/aliases'] = 'mailaliases', ['.*[mM]akefile'] = 'make', + ['[mM]akefile.*'] = starsetf('make'), ['.*/etc/man%.conf'] = 'manconf', + ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr) + return require('vim.filetype.detect').mod(path, bufnr) + end, ['.*/etc/modules%.conf'] = 'modconf', ['.*/etc/conf%.modules'] = 'modconf', ['.*/etc/modules'] = 'modconf', + ['.*/etc/modprobe%..*'] = starsetf('modconf'), + ['.*/etc/modutils/.*'] = starsetf(function(path, bufnr) + if vim.fn.executable(vim.fn.expand(path)) ~= 1 then + return 'modconf' + end + end), ['.*%.[mi][3g]'] = 'modula3', - ['.*/%.mplayer/config'] = 'mplayerconf', + ['Muttrc'] = 'muttrc', + ['Muttngrc'] = 'muttrc', + ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'), + ['.*/%.mplayer/config'] = 'mplayerconf', + ['Muttrc.*'] = starsetf('muttrc'), + ['Muttngrc.*'] = starsetf('muttrc'), + -- muttrc* and .muttrc* + ['%.?muttrc.*'] = starsetf('muttrc'), + -- muttngrc* and .muttngrc* + ['%.?muttngrc.*'] = starsetf('muttrc'), + ['.*/%.mutt/muttrc.*'] = starsetf('muttrc'), + ['.*/%.muttng/muttrc.*'] = starsetf('muttrc'), + ['.*/%.muttng/muttngrc.*'] = starsetf('muttrc'), ['rndc.*%.conf'] = 'named', ['rndc.*%.key'] = 'named', ['named.*%.conf'] = 'named', ['.*/etc/nanorc'] = 'nanorc', ['.*%.NS[ACGLMNPS]'] = 'natural', + ['Neomuttrc.*'] = starsetf('neomuttrc'), + -- neomuttrc* and .neomuttrc* + ['%.?neomuttrc.*'] = starsetf('neomuttrc'), + ['.*/%.neomutt/neomuttrc.*'] = starsetf('neomuttrc'), ['nginx.*%.conf'] = 'nginx', ['.*/etc/nginx/.*'] = 'nginx', ['.*nginx%.conf'] = 'nginx', ['.*/nginx/.*%.conf'] = 'nginx', ['.*/usr/local/nginx/conf/.*'] = 'nginx', + ['.*%.[1-9]'] = function(path, bufnr) + return require('vim.filetype.detect').nroff(bufnr) + end, ['.*%.ml%.cppo'] = 'ocaml', ['.*%.mli%.cppo'] = 'ocaml', ['.*%.opam%.template'] = 'opam', ['.*%.[Oo][Pp][Ll]'] = 'opl', ['.*/etc/pam%.conf'] = 'pamconf', - ['.*/etc/passwd-'] = 'passwd', + ['.*/etc/pam%.d/.*'] = starsetf('pamconf'), + ['.*/etc/passwd%-'] = 'passwd', ['.*/etc/shadow'] = 'passwd', ['.*/etc/shadow%.edit'] = 'passwd', ['.*/var/backups/shadow%.bak'] = 'passwd', ['.*/var/backups/passwd%.bak'] = 'passwd', ['.*/etc/passwd'] = 'passwd', ['.*/etc/passwd%.edit'] = 'passwd', - ['.*/etc/shadow-'] = 'passwd', + ['.*/etc/shadow%-'] = 'passwd', + ['%.?gitolite%.rc'] = 'perl', + ['example%.gitolite%.rc'] = 'perl', ['.*%.php%d'] = 'php', ['.*/%.pinforc'] = 'pinfo', ['.*/etc/pinforc'] = 'pinfo', + ['.*%.[Pp][Rr][Gg]'] = function(path, bufnr) + return require('vim.filetype.detect').prg(bufnr) + end, ['.*/etc/protocols'] = 'protocols', ['.*printcap.*'] = starsetf(function(path, bufnr) - if vim.fn.did_filetype() == 0 then - return 'ptcap', function(b) - vim.b[b].ptcap_type = 'print' - end - end + return require('vim.filetype.detect').printcap('print') end), ['.*baseq[2-3]/.*%.cfg'] = 'quake', ['.*quake[1-3]/.*%.cfg'] = 'quake', ['.*id1/.*%.cfg'] = 'quake', + ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries (Neovim only) + ['.*,v'] = 'rcs', + ['%.reminders.*'] = starsetf('remind'), + ['[rR]akefile.*'] = starsetf('ruby'), ['[rR]antfile'] = 'ruby', ['[rR]akefile'] = 'ruby', ['.*/etc/sensors%.conf'] = 'sensors', @@ -1849,6 +1930,31 @@ local pattern = { ['.*/etc/services'] = 'services', ['.*/etc/serial%.conf'] = 'setserial', ['.*/etc/udev/cdsymlinks%.conf'] = 'sh', + ['%.bash[_%-]aliases'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['%.bash[_%-]logout'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['%.bash[_%-]profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['%.kshrc.*'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'ksh') + end, + ['%.profile.*'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, + ['.*/etc/profile'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr) + end, + ['bash%-fc[%-%.]'] = function(path, bufnr) + return require('vim.filetype.detect').sh(path, bufnr, 'bash') + end, + ['%.tcshrc.*'] = function(path, bufnr) + return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + end, + ['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'), ['.*%._sst%.meta'] = 'sisu', ['.*%.%-sst%.meta'] = 'sisu', ['.*%.sst%.meta'] = 'sisu', @@ -1858,9 +1964,15 @@ local pattern = { ['.*/etc/ssh/ssh_config%.d/.*%.conf'] = 'sshconfig', ['.*/%.ssh/config'] = 'sshconfig', ['.*/etc/ssh/sshd_config%.d/.*%.conf'] = 'sshdconfig', + ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr) + return require('vim.filetype.detect').src(bufnr) + end, ['.*/etc/sudoers'] = 'sudoers', ['svn%-commit.*%.tmp'] = 'svn', ['.*%.swift%.gyb'] = 'swiftgyb', + ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr) + return require('vim.filetype.detect').sys(bufnr) + end, ['.*/etc/sysctl%.conf'] = 'sysctl', ['.*/etc/sysctl%.d/.*%.conf'] = 'sysctl', ['.*/systemd/.*%.automount'] = 'systemd', @@ -1885,11 +1997,7 @@ local pattern = { ['.*/%.config/systemd/user/.*%.d/%.#.*'] = 'systemd', ['.*/%.config/systemd/user/%.#.*'] = 'systemd', ['.*termcap.*'] = starsetf(function(path, bufnr) - if vim.fn.did_filetype() == 0 then - return 'ptcap', function(b) - vim.b[b].ptcap_type = 'term' - end - end + return require('vim.filetype.detect').printcap('term') end), ['.*%.t%.html'] = 'tilde', ['%.?tmux.*%.conf'] = 'tmux', @@ -1907,7 +2015,13 @@ local pattern = { ['.*/%.config/upstart/.*%.conf'] = 'upstart', ['.*/%.init/.*%.conf'] = 'upstart', ['.*/usr/share/upstart/.*%.override'] = 'upstart', + ['.*%.[Ll][Oo][Gg]'] = function(path, bufnr) + return require('vim.filetype.detect').log(path) + end, + ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), ['.*%.ws[fc]'] = 'wsh', + ['.*/Xresources/.*'] = starsetf('xdefaults'), + ['.*/app%-defaults/.*'] = starsetf('xdefaults'), ['.*/etc/xinetd%.conf'] = 'xinetd', ['.*/etc/blkid%.tab'] = 'xml', ['.*/etc/blkid%.tab%.old'] = 'xml', @@ -1917,213 +2031,10 @@ local pattern = { ['.*/etc/xdg/menus/.*%.menu'] = 'xml', ['.*Xmodmap'] = 'xmodmap', ['.*/etc/zprofile'] = 'zsh', - ['%.bash[_-]aliases'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ['%.bash[_-]logout'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ['%.bash[_-]profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ['%.cshrc.*'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['%.gtkrc.*'] = starsetf('gtkrc'), - ['%.kshrc.*'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'ksh') - end, - ['%.login.*'] = function(path, bufnr) - return require('vim.filetype.detect').csh(path, bufnr) - end, - ['Muttrc.*'] = starsetf('muttrc'), - ['Muttngrc.*'] = starsetf('muttrc'), - -- muttrc* and .muttrc* - ['%.?muttrc.*'] = starsetf('muttrc'), - -- muttngrc* and .muttngrc* - ['%.?muttngrc.*'] = starsetf('muttrc'), - ['.*/%.mutt/muttrc.*'] = starsetf('muttrc'), - ['.*/%.muttng/muttrc.*'] = starsetf('muttrc'), - ['.*/%.muttng/muttngrc.*'] = starsetf('muttrc'), - ['Neomuttrc.*'] = starsetf('neomuttrc'), - -- neomuttrc* and .neomuttrc* - ['%.?neomuttrc.*'] = starsetf('neomuttrc'), - ['.*/%.neomutt/neomuttrc.*'] = starsetf('neomuttrc'), - ['%.profile.*'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - ['%.reminders.*'] = starsetf('remind'), - ['%.tcshrc.*'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') - end, - ['%.zcompdump.*'] = starsetf('zsh'), - ['%.zlog.*'] = starsetf('zsh'), - ['%.zsh.*'] = starsetf('zsh'), - ['.*%.[1-9]'] = function(path, bufnr) - return require('vim.filetype.detect').nroff(bufnr) - end, - ['.*%.[aA]'] = function(path, bufnr) - return require('vim.filetype.detect').asm(bufnr) - end, - ['.*%.[sS]'] = function(path, bufnr) - return require('vim.filetype.detect').asm(bufnr) - end, - ['.*%.properties_.._.._.*'] = starsetf('jproperties'), - ['.*%.vhdl_[0-9].*'] = starsetf('vhdl'), - ['.*/%.fvwm/.*'] = starsetf('fvwm'), - ['.*fvwmrc.*'] = starsetf(function(path, bufnr) - return 'fvwm', function(b) - vim.b[b].fvwm_version = 1 - end - end), - ['.*fvwm95.*%.hook'] = starsetf(function(path, bufnr) - return 'fvwm', function(b) - vim.b[b].fvwm_version = 1 - end - end), - ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), - ['.*/Xresources/.*'] = starsetf('xdefaults'), - ['.*/app%-defaults/.*'] = starsetf('xdefaults'), - ['.*/bind/db%..*'] = starsetf('bindzone'), - ['.*/debian/patches/.*'] = function(path, bufnr) - return require('vim.filetype.detect').dep3patch(path, bufnr) - end, - ['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'), - ['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'), - ['.*/etc/apache2/conf%..*/.*'] = starsetf('apache'), - ['.*/etc/apache2/mods%-.*/.*'] = starsetf('apache'), - ['.*/etc/apache2/sites%-.*/.*'] = starsetf('apache'), - ['.*/etc/cron%.d/.*'] = starsetf('crontab'), - ['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'), - ['.*/etc/httpd/conf%..*/.*'] = starsetf('apache'), - ['.*/etc/httpd/conf%.d/.*%.conf.*'] = starsetf('apache'), - ['.*/etc/httpd/mods%-.*/.*'] = starsetf('apache'), - ['.*/etc/httpd/sites%-.*/.*'] = starsetf('apache'), - ['.*/etc/logcheck/.*%.d.*/.*'] = starsetf('logcheck'), - ['.*/etc/modprobe%..*'] = starsetf('modconf'), - ['.*/etc/modutils/.*'] = starsetf(function(path, bufnr) - if vim.fn.executable(vim.fn.expand(path)) ~= 1 then - return 'modconf' - end - end), - ['.*/etc/pam%.d/.*'] = starsetf('pamconf'), - ['.*/etc/profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, getline(bufnr, 1)) - end, - ['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'), - ['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'), - ['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'), - ['.*/etc/xinetd%.d/.*'] = starsetf('xinetd'), - ['.*/etc/yum%.repos%.d/.*'] = starsetf('dosini'), - ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'), - ['.*/named/db%..*'] = starsetf('bindzone'), - ['.*/tmp/lltmp.*'] = starsetf('gedcom'), - ['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'), - ['.*asterisk/.*%.conf.*'] = starsetf('asterisk'), ['.*vimrc.*'] = starsetf('vim'), - ['.*xmodmap.*'] = starsetf('xmodmap'), - ['/etc/gitconfig%.d/.*'] = starsetf('gitconfig'), - ['/etc/hostname%..*'] = starsetf('config'), - ['Containerfile%..*'] = starsetf('dockerfile'), - ['Dockerfile%..*'] = starsetf('dockerfile'), - ['JAM.*%..*'] = starsetf('jam'), - ['Kconfig%..*'] = starsetf('kconfig'), - ['Prl.*%..*'] = starsetf('jam'), ['Xresources.*'] = starsetf('xdefaults'), - ['[mM]akefile.*'] = starsetf('make'), - ['[rR]akefile.*'] = starsetf('ruby'), - ['access%.conf.*'] = starsetf('apache'), - ['apache%.conf.*'] = starsetf('apache'), - ['apache2%.conf.*'] = starsetf('apache'), - ['bash%-fc[-%.]'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') - end, - ['cabal%.project%..*'] = starsetf('cabalproject'), - ['crontab%..*'] = starsetf('crontab'), - ['drac%..*'] = starsetf('dracula'), - ['gtkrc.*'] = starsetf('gtkrc'), - ['httpd%.conf.*'] = starsetf('apache'), - ['lilo%.conf.*'] = starsetf('lilo'), - ['Muttrc'] = 'muttrc', - ['Muttngrc'] = 'muttrc', - ['proftpd%.conf.*'] = starsetf('apachestyle'), - ['reportbug%-.*'] = starsetf('mail'), - ['sgml%.catalog.*'] = starsetf('catalog'), - ['srm%.conf.*'] = starsetf('apache'), - ['tmac%..*'] = starsetf('nroff'), - ['zlog.*'] = starsetf('zsh'), - ['zsh.*'] = starsetf('zsh'), - ['ae%d+%.txt'] = 'mail', - ['snd%.%d+'] = 'mail', - ['%.letter%.%d+'] = 'mail', - ['%.article%.%d+'] = 'mail', - ['pico%.%d+'] = 'mail', - ['mutt%-.*%-%w+'] = 'mail', - ['muttng%-.*%-%w+'] = 'mail', - ['neomutt%-.*%-%w+'] = 'mail', - ['mutt' .. string.rep('[%w_-]', 6)] = 'mail', - ['neomutt' .. string.rep('[%w_-]', 6)] = 'mail', - ['/tmp/SLRN[0-9A-Z.]+'] = 'mail', - ['[a-zA-Z0-9].*Dict'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['[a-zA-Z0-9].*Dict%..*'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['[a-zA-Z].*Properties'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['[a-zA-Z].*Properties%..*'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['.*Transport%..*'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['.*/constant/g'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['.*/0/.*'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['.*/0%.orig/.*'] = function(path, bufnr) - return require('vim.filetype.detect').foam(bufnr) - end, - ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), - ['.*%.git/.*'] = function(path, bufnr) - local firstline = getline(bufnr, 1) - if firstline:find('^' .. string.rep('%x', 40) .. '+ ') or firstline:sub(1, 5) == 'ref: ' then - return 'git' - end - end, - ['.*%.[Cc][Ff][Gg]'] = { - function(path, bufnr) - return require('vim.filetype.detect').cfg(bufnr) - end, - -- Decrease the priority to avoid conflicts with more specific patterns - -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. - { priority = -1 }, - }, - ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr) - return require('vim.filetype.detect').dat(path, bufnr) - end, - ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr) - return require('vim.filetype.detect').mod(path, bufnr) - end, - ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr) - return require('vim.filetype.detect').src(bufnr) - end, - ['.*%.[Ss][Uu][Bb]'] = 'krl', - ['.*%.[Pp][Rr][Gg]'] = function(path, bufnr) - return require('vim.filetype.detect').prg(bufnr) - end, - ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr) - return require('vim.filetype.detect').sys(bufnr) - end, - ['%.?gitolite%.rc'] = 'perl', - ['example%.gitolite%.rc'] = 'perl', - -- Neovim only - ['.*/queries/.*%.scm'] = 'query', -- tree-sitter queries - ['.*,v'] = 'rcs', + ['.*/etc/xinetd%.d/.*'] = starsetf('xinetd'), + ['.*xmodmap.*'] = starsetf('xmodmap'), ['.*/xorg%.conf%.d/.*%.conf'] = function(path, bufnr) return 'xf86config', function(b) vim.b[b].xf86conf_xfree86_version = 4 @@ -2138,37 +2049,11 @@ local pattern = { ['XF86Config.*'] = starsetf(function(path, bufnr) return require('vim.filetype.detect').xfree86(bufnr) end), - ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr) - local line = getline(bufnr, 1):lower() - if line:find('; urgency=') then - return 'debchangelog' - else - return 'changelog' - end - end), - ['.*fvwm2rc.*'] = starsetf(function(path, bufnr) - if vim.fn.fnamemodify(path, ':e') == 'm4' then - return 'fvwm2m4' - else - return 'fvwm', function(b) - vim.b[b].fvwm_version = 2 - end - end - end), - ['.*%.[Ll][Oo][Gg]'] = function(path, bufnr) - -- Innovation Data Processing - -- (refactor of filetype.vim since the patterns are case-insensitive) - path = path:lower() - if M.findany(path, { 'upstream%.log', 'upstream%..*%.log', '.*%.upstream%.log', 'upstream%-.*%.log' }) then - return 'upstreamlog' - elseif M.findany(path, { 'upstreaminstall%.log', 'upstreaminstall%..*%.log', '.*%.upstreaminstall%.log' }) then - return 'upstreaminstalllog' - elseif M.findany(path, { 'usserver%.log', 'usserver%..*%.log', '.*%.usserver%.log' }) then - return 'usserverlog' - elseif M.findany(path, { 'usw2kagt%.log', 'usws2kagt%..*%.log', '.*%.usws2kagt%.log' }) then - return 'usw2kagtlog' - end - end, + ['%.zcompdump.*'] = starsetf('zsh'), + -- .zlog* and zlog* + ['%.?zlog.*'] = starsetf('zsh'), + -- .zsh* and zsh* + ['%.?zsh.*'] = starsetf('zsh'), -- Ignored extension ['.*~'] = function(path, bufnr) local short = path:gsub('~$', '', 1) diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 7e5ed0f4d1..48dd3cb088 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -1,6 +1,9 @@ --- Contains filetype detection functions converted to Lua from Vim's autoload/runtime/dist/ft.vim file. +-- Contains filetype detection functions for use in filetype.lua that are either: +-- * used more than once or +-- * complex (e.g. check more than one line or use conditionals). +-- Simple one-line checks, such as a check for a string in the first line are better inlined in filetype.lua. --- Here are a few guidelines to follow when porting a new function: +-- A few guidelines to follow when porting a new function: -- * Sort the function alphabetically and omit 'ft' or 'check' from the new function name. -- * Use ':find' instead of ':match' / ':sub' if possible. -- * When '=~' is used to match a pattern, there are two possibilities: @@ -45,6 +48,17 @@ function M.asm(bufnr) end end +-- Active Server Pages (with Perl or Visual Basic Script) +function M.asp(bufnr) + if vim.g.filetype_asp then + return vim.g.filetype_asp + elseif table.concat(getlines(bufnr, 1, 3)):lower():find('perlscript') then + return 'aspperl' + else + return 'aspvbs' + end +end + -- Checks the first 5 lines for a asmsyntax=foo override. -- Only whitespace characters can be present immediately before or after this statement. function M.asm_syntax(bufnr) @@ -91,17 +105,8 @@ function M.bindzone(bufnr, default) local lines = table.concat(getlines(bufnr, 1, 4)) if findany(lines, { '^; <<>> DiG [0-9%.]+.* <<>>', '%$ORIGIN', '%$TTL', 'IN%s+SOA' }) then return 'bindzone' - else - return default - end -end - -function M.btm(bufnr) - if vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0 then - return 'dosbatch' - else - return 'btm' end + return default end -- Returns true if file content looks like RAPID @@ -151,6 +156,46 @@ function M.change(bufnr) return 'chill' end +function M.changelog(bufnr) + local line = getlines(bufnr, 1):lower() + if line:find('; urgency=') then + return 'debchangelog' + end + return 'changelog' +end + +function M.class(bufnr) + -- Check if not a Java class (starts with '\xca\xfe\xba\xbe') + if not getlines(bufnr, 1):find('^\202\254\186\190') then + return 'stata' + end +end + +function M.cls(bufnr) + local line = getlines(bufnr, 1) + if line:find('^%%') then + return 'tex' + elseif line:find('^#') and line:lower():find('rexx') then + return 'rexx' + else + return 'st' + end +end + +-- Debian Control +function M.control(bufnr) + if getlines(bufnr, 1):find('^Source:') then + return 'debcontrol' + end +end + +-- Debian Copyright +function M.copyright(bufnr) + if getlines(bufnr, 1):find('^Format:') then + return 'debcopyright' + end +end + function M.csh(path, bufnr) if vim.fn.did_filetype() ~= 0 then -- Filetype was already detected @@ -180,6 +225,14 @@ function M.dat(path, bufnr) end end +function M.decl(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 3)) do + if line:lower():find('^]]) then + return 'edif' + else + return 'clojure' + end +end + -- This function checks for valid cl syntax in the first five lines. -- Look for either an opening comment, '#', or a block start, '{'. -- If not found, assume SGML. @@ -256,14 +318,6 @@ function M.ent(bufnr) return 'dtd' end -function M.euphoria(bufnr) - if vim.g.filetype_euphoria then - return vim.g.filetype_euphoria - else - return 'euphoria3' - end -end - function M.ex(bufnr) if vim.g.filetype_euphoria then return vim.g.filetype_euphoria @@ -303,6 +357,15 @@ function M.frm(bufnr) end end +function M.fvwm(path) + if vim.fn.fnamemodify(path, ':e') == 'm4' then + return 'fvwm2m4' + end + return 'fvwm', function(bufnr) + vim.b[bufnr].fvwm_version = 2 + end +end + -- Distinguish between Forth and F#. function M.fs(bufnr) if vim.g.filetype_fs then @@ -316,6 +379,13 @@ function M.fs(bufnr) end end +function M.git(bufnr) + local line = getlines(bufnr, 1) + if line:find('^' .. string.rep('%x', 40) .. '+ ') or line:sub(1, 5) == 'ref: ' then + return 'git' + end +end + function M.header(bufnr) for _, line in ipairs(getlines(bufnr, 1, 200)) do if findany(line:lower(), { '^@interface', '^@end', '^@class' }) then @@ -346,6 +416,14 @@ function M.html(bufnr) return 'html' end +-- Virata Config Script File or Drupal module +function M.hw(bufnr) + if getlines(bufnr, 1):lower():find('<%?php') then + return 'php' + end + return 'virata' +end + function M.idl(bufnr) for _, line in ipairs(getlines(bufnr, 1, 50)) do if findany(line:lower(), { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then @@ -396,6 +474,28 @@ function M.inp(bufnr) end end +function M.install(path, bufnr) + if getlines(bufnr, 1):lower():find('<%?php') then + return 'php' + end + return M.sh(path, bufnr, 'bash') +end + +-- Innovation Data Processing +-- (refactor of filetype.vim since the patterns are case-insensitive) +function M.log(path) + path = path:lower() + if findany(path, { 'upstream%.log', 'upstream%..*%.log', '.*%.upstream%.log', 'upstream%-.*%.log' }) then + return 'upstreamlog' + elseif findany(path, { 'upstreaminstall%.log', 'upstreaminstall%..*%.log', '.*%.upstreaminstall%.log' }) then + return 'upstreaminstalllog' + elseif findany(path, { 'usserver%.log', 'usserver%..*%.log', '.*%.usserver%.log' }) then + return 'usserverlog' + elseif findany(path, { 'usw2kagt%.log', 'usws2kagt%..*%.log', '.*%.usws2kagt%.log' }) then + return 'usw2kagtlog' + end +end + function M.lpc(bufnr) if vim.g.lpc_syntax_for_c then for _, line in ipairs(getlines(bufnr, 1, 12)) do @@ -467,6 +567,13 @@ function M.m(bufnr) end end +function M.m4(path) + path = path:lower() + if not path:find('html%.m4$') and not path:find('fvwm2rc') then + return 'm4' + end +end + -- Rely on the file to start with a comment. -- MS message text files use ';', Sendmail files use '#' or 'dnl' function M.mc(bufnr) @@ -482,6 +589,13 @@ function M.mc(bufnr) return 'm4' end +function M.me(path) + local filename = vim.fn.fnamemodify(path, ':t'):lower() + if filename ~= 'read.me' and filename ~= 'click.me' then + return 'nroff' + end +end + function M.mm(bufnr) for _, line in ipairs(getlines(bufnr, 1, 20)) do if matchregex(line, [[\c^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)]]) then @@ -533,15 +647,29 @@ function M.mod(path, bufnr) end end +function M.news(bufnr) + if getlines(bufnr, 1):lower():find('; urgency=') then + return 'debchangelog' + end +end + -- This function checks if one of the first five lines start with a dot. In --- that case it is probably an nroff file: 'filetype' is set and true is returned. +-- that case it is probably an nroff file. function M.nroff(bufnr) for _, line in ipairs(getlines(bufnr, 1, 5)) do if line:find('^%.') then - return true + return 'nroff' end end - return false +end + +function M.patch(bufnr) + local firstline = getlines(bufnr, 1) + if string.find(firstline, '^From ' .. string.rep('%x', 40) .. '+ Mon Sep 17 00:00:00 2001$') then + return 'gitsendemail' + else + return 'diff' + end end -- If the file has an extension of 't' and is in a directory 't' or 'xt' then @@ -551,18 +679,17 @@ end function M.perl(path, bufnr) local dirname = vim.fn.expand(path, '%:p:h:t') if vim.fn.expand(dirname, '%:e') == 't' and (dirname == 't' or dirname == 'xt') then - return true + return 'perl' end local first_line = getlines(bufnr, 1) if first_line:find('^#') and first_line:lower():find('perl') then - return true + return 'perl' end for _, line in ipairs(getlines(bufnr, 1, 30)) do if matchregex(line, [[\c^use\s\s*\k]]) then - return true + return 'perl' end end - return false end function M.pl(bufnr) @@ -583,6 +710,17 @@ function M.pl(bufnr) end end +function M.pm(bufnr) + local line = getlines(bufnr, 1) + if line:find('XPM2') then + return 'xpm2' + elseif line:find('XPM') then + return 'xpm' + else + return 'perl' + end +end + function M.pp(bufnr) if vim.g.filetype_pp then return vim.g.filetype_pp @@ -606,6 +744,14 @@ function M.prg(bufnr) end end +function M.printcap(ptcap_type) + if vim.fn.did_filetype() == 0 then + return 'ptcap', function(bufnr) + vim.b[bufnr].ptcap_type = ptcap_type + end + end +end + -- This function checks for an assembly comment in the first ten lines. -- If not found, assume Progress. function M.progress_asm(bufnr) @@ -670,6 +816,19 @@ function M.proto(bufnr, default) end end +-- Software Distributor Product Specification File (POSIX 1387.2-1995) +function M.psf(bufnr) + local line = getlines(bufnr, 1):lower() + if + findany( + line, + { '^%s*distribution%s*$', '^%s*installed_software%s*$', '^%s*root%s*$', '^%s*bundle%s*$', '^%s*product%s*$' } + ) + then + return 'psf' + end +end + function M.r(bufnr) local lines = getlines(bufnr, 1, 50) -- Rebol is easy to recognize, check for that first @@ -705,8 +864,23 @@ function M.redif(bufnr) end end +function M.reg(bufnr) + local line = getlines(bufnr, 1):lower() + if line:find('^regedit[0-9]*%s*$') or line:find('^windows registry editor version %d*%.%d*%s*$') then + return 'registry' + end +end + +-- Diva (with Skill) or InstallShield +function M.rul(bufnr) + if table.concat(getlines(bufnr, 1, 6)):lower():find('installshield') then + return 'ishd' + end + return 'diva' +end + local udev_rules_pattern = '^%s*udev_rules%s*=%s*"([%^"]+)/*".*' -function M.rules(path, bufnr) +function M.rules(path) path = path:lower() if findany(path, { @@ -770,7 +944,20 @@ function M.scd(bufnr) end end --- Also called from filetype.lua +function M.sgml(bufnr) + local lines = table.concat(getlines(bufnr, 1, 5)) + if lines:find('linuxdoc') then + return 'smgllnx' + elseif lines:find(']]) then -- Some .sh scripts contain #!/bin/csh. return M.shell(path, bufnr, 'csh') @@ -832,11 +1020,13 @@ function M.shell(path, bufnr, name) return name end -function M.sql(bufnr) - if vim.g.filetype_sql then - return vim.g.filetype_sql +-- SMIL or SNMP MIB file +function M.smi(bufnr) + local line = getlines(bufnr, 1) + if matchregex(line, [[\c\]]) then + return 'smil' else - return 'sql' + return 'mib' end end @@ -919,6 +1109,43 @@ function M.tf(bufnr) return 'tf' end +function M.ttl(bufnr) + local line = getlines(bufnr, 1):lower() + if line:find('^@?prefix') or line:find('^@?base') then + return 'turtle' + end + return 'teraterm' +end + +function M.txt(bufnr) + -- helpfiles match *.txt, but should have a modeline as last line + if not getlines(bufnr, -1):find('vim:.*ft=help') then + return 'text' + end +end + +-- WEB (*.web is also used for Winbatch: Guess, based on expecting "%" comment +-- lines in a WEB file). +function M.web(bufnr) + for _, line in ipairs(getlines(bufnr, 1, 5)) do + if line:find('^%%') then + return 'web' + end + end + return 'winbatch' +end + +-- XFree86 config +function M.xfree86() + return 'xf86conf', + function(bufnr) + local line = getlines(bufnr, 1) + if matchregex(line, [[\]]) then + vim.b[bufnr].xf86conf_xfree86_version = 3 + end + end +end + function M.xml(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do local is_docbook4 = line:find(']]) then - return 'edif' - else - return 'clojure' - end -end - -function M.smi(bufnr) - local line = getlines(bufnr, 1) - if matchregex(line, [[\c\]]) then - return 'smil' - else - return 'mib' - end -end - -function M.hw(bufnr) - if getlines(bufnr, 1):lower():find('<%?php') then - return 'php' - end - return 'virata' -end - -function M.news(bufnr) - if getlines(bufnr, 1):lower():find('; urgency=') then - return 'debchangelog' - end -end - --- Debian Control -function M.control(bufnr) - if getlines(bufnr, 1):find('^Source:') then - return 'debcontrol' - end -end - --- Debian Copyright -function M.copyright(bufnr) - if getlines(bufnr, 1):find('^Format:') then - return 'debcopyright' - end -end - --- Software Distributor Product Specification File (POSIX 1387.2-1995) -function M.psf(bufnr) - local line = getlines(bufnr, 1):lower() - if - findany( - line, - { '^%s*distribution%s*$', '^%s*installed_software%s*$', '^%s*root%s*$', '^%s*bundle%s*$', '^%s*product%s*$' } - ) - then - return 'psf' - end -end - --- XFree86 config -function M.xfree86(bufnr) - local line = getlines(bufnr, 1) - local on_detect - if matchregex(line, [[\]]) then - on_detect = function(b) - vim.b[b].xf86conf_xfree86_version = 3 - end - end - return 'xf86conf', on_detect -end - -- luacheck: pop -- luacheck: pop -- cgit From 35e89bf9036b755ae14ee87712faf005886f04f0 Mon Sep 17 00:00:00 2001 From: Hazel Weakly Date: Fri, 24 Jun 2022 10:53:44 -0700 Subject: fix(filetype.lua): always return a string in getlines function (#19080) This re-introduces the fix that the filetype.lua refactor inadvertently reverted. The fix ensures that in the case when end_lnum is omitted, a string is always returned. --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 320d6a2a5b..6c4894208f 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -33,7 +33,7 @@ end function M.getlines(bufnr, start_lnum, end_lnum) if not end_lnum then -- Return a single line as a string - return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] + return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or '' end return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) end -- cgit From f3ce06cfa139ca3fb142cf5adf96a2ecc4d8f551 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sun, 26 Jun 2022 10:41:20 -0600 Subject: refactor(filetype)!: allow vim.filetype.match to use different strategies (#18895) This enables vim.filetype.match to match based on a buffer (most accurate) or simply a filename or file contents, which are less accurate but may still be useful for some scenarios. When matching based on a buffer, the buffer's name and contents are both used to do full filetype matching. When using a filename, if the file exists the file is loaded into a buffer and full filetype detection is performed. If the file does not exist then filetype matching is only performed against the filename itself. Content-based matching does the equivalent of scripts.vim, and matches solely based on file contents without any information from the name of the file itself (e.g. for shebangs). BREAKING CHANGE: use `vim.filetype.match({buf = bufnr})` instead of `vim.filetype.match(name, bufnr)` --- runtime/lua/vim/filetype.lua | 88 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 18 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 6c4894208f..3e86159489 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -2047,7 +2047,7 @@ local pattern = { end end, { priority = -math.huge + 1 }), ['XF86Config.*'] = starsetf(function(path, bufnr) - return require('vim.filetype.detect').xfree86(bufnr) + return require('vim.filetype.detect').xfree86() end), ['%.zcompdump.*'] = starsetf('zsh'), -- .zlog* and zlog* @@ -2185,17 +2185,24 @@ end local function dispatch(ft, path, bufnr, ...) local on_detect if type(ft) == 'function' then - ft, on_detect = ft(path, bufnr, ...) + if bufnr then + ft, on_detect = ft(path, bufnr, ...) + else + -- If bufnr is nil (meaning we are matching only against the filename), set it to an invalid + -- value (-1) and catch any errors from the filetype detection function. If the function tries + -- to use the buffer then it will fail, but this enables functions which do not need a buffer + -- to still work. + local ok + ok, ft, on_detect = pcall(ft, path, -1, ...) + if not ok then + return + end + end end if type(ft) == 'string' then return ft, on_detect end - - -- Any non-falsey value (that is, anything other than 'nil' or 'false') will - -- end filetype matching. This is useful for e.g. the dist#ft functions that - -- return 0, but set the buffer's filetype themselves - return ft end ---@private @@ -2214,29 +2221,74 @@ local function match_pattern(name, path, tail, pat) return matches end ---- Find the filetype for the given filename and buffer. +--- Perform filetype detection. +--- +--- The filetype can be detected using one of three methods: +--- 1. Using an existing buffer +--- 2. Using only a file name +--- 3. Using only file contents +--- +--- Of these, option 1 provides the most accurate result as it uses both the buffer's filename and +--- (optionally) the buffer contents. Options 2 and 3 can be used without an existing buffer, but +--- may not always provide a match in cases where the filename (or contents) cannot unambiguously +--- determine the filetype. +--- +--- Each of the three options is specified using a key to the single argument of this function. +--- Example: +--- +---
+---   -- Using a buffer number
+---   vim.filetype.match({ buf = 42 })
 ---
----@param name string File name (can be an absolute or relative path)
----@param bufnr number|nil The buffer to set the filetype for. Defaults to the current buffer.
+---   -- Using a filename
+---   vim.filetype.match({ filename = "main.lua" })
+---
+---   -- Using file contents
+---   vim.filetype.match({ contents = {"#!/usr/bin/env bash"} })
+--- 
+--- +---@param arg table Table specifying which matching strategy to use. It is an error to provide more +--- than one strategy. Accepted keys are: +--- * buf (number): Buffer number to use for matching +--- * filename (string): Filename to use for matching. Note that the file need not +--- actually exist in the filesystem, only the name itself is +--- used. +--- * contents (table): An array of lines representing file contents to use for +--- matching. ---@return string|nil If a match was found, the matched filetype. ---@return function|nil A function that modifies buffer state when called (for example, to set some --- filetype specific buffer variables). The function accepts a buffer number as --- its only argument. -function M.match(name, bufnr) +function M.match(arg) vim.validate({ - name = { name, 's' }, - bufnr = { bufnr, 'n', true }, + arg = { arg, 't' }, }) - -- When fired from the main filetypedetect autocommand the {bufnr} argument is omitted, so we use - -- the current buffer. The {bufnr} argument is provided to allow extensibility in case callers - -- wish to perform filetype detection on buffers other than the current one. - bufnr = bufnr or api.nvim_get_current_buf() + if not (arg.buf or arg.filename or arg.contents) then + error('One of "buf", "filename", or "contents" must be given') + end + + if (arg.buf and arg.filename) or (arg.buf and arg.contents) or (arg.filename and arg.contents) then + error('Only one of "buf", "filename", or "contents" must be given') + end + + local bufnr = arg.buf + local name = bufnr and api.nvim_buf_get_name(bufnr) or arg.filename + local contents = arg.contents - name = normalize_path(name) + if name then + name = normalize_path(name) + end local ft, on_detect + if not (bufnr or name) then + -- Sanity check: this should not happen + assert(contents, 'contents should be non-nil when bufnr and filename are nil') + -- TODO: "scripts.lua" content matching + return + end + -- First check for the simple case where the full path exists as a key local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p')) ft, on_detect = dispatch(filename[path], path, bufnr) -- cgit From 6f3508f8edbc48de1accd931a9d6e66bc99f174a Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Mon, 27 Jun 2022 02:03:43 -0600 Subject: refactor(filetype): allow vim.filetype.match to accept buf and filename (#19114) This is necessary in cases where filetype detection acts recursively. For example, when matching files that end with .bak, the "root" of the filename is matched again against the same buffer (e.g. a buffer named "foo.c.bak" will be matched again with the filename "foo.c", using the same underlying buffer). --- runtime/lua/vim/filetype.lua | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 3e86159489..73605413ee 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -2240,21 +2240,29 @@ end --- -- Using a buffer number --- vim.filetype.match({ buf = 42 }) --- ---- -- Using a filename ---- vim.filetype.match({ filename = "main.lua" }) +--- -- Override the filename of the given buffer +--- vim.filetype.match({ buf = 42, filename = 'foo.c' }) +--- +--- -- Using a filename without a buffer +--- vim.filetype.match({ filename = 'main.lua' }) --- --- -- Using file contents ---- vim.filetype.match({ contents = {"#!/usr/bin/env bash"} }) +--- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} }) --- --- ----@param arg table Table specifying which matching strategy to use. It is an error to provide more ---- than one strategy. Accepted keys are: ---- * buf (number): Buffer number to use for matching ---- * filename (string): Filename to use for matching. Note that the file need not ---- actually exist in the filesystem, only the name itself is ---- used. +---@param arg table Table specifying which matching strategy to use. Accepted keys are: +--- * buf (number): Buffer number to use for matching. Mutually exclusive with +--- {contents} +--- * filename (string): Filename to use for matching. When {buf} is given, +--- defaults to the filename of the given buffer number. The +--- file need not actually exist in the filesystem. When used +--- without {buf} only the name of the file is used for +--- filetype matching. This may result in failure to detect +--- the filetype in cases where the filename alone is not +--- enough to disambiguate the filetype. --- * contents (table): An array of lines representing file contents to use for ---- matching. +--- matching. Can be used with {filename}. Mutually exclusive +--- with {buf}. ---@return string|nil If a match was found, the matched filetype. ---@return function|nil A function that modifies buffer state when called (for example, to set some --- filetype specific buffer variables). The function accepts a buffer number as @@ -2265,26 +2273,30 @@ function M.match(arg) }) if not (arg.buf or arg.filename or arg.contents) then - error('One of "buf", "filename", or "contents" must be given') + error('At least one of "buf", "filename", or "contents" must be given') end - if (arg.buf and arg.filename) or (arg.buf and arg.contents) or (arg.filename and arg.contents) then - error('Only one of "buf", "filename", or "contents" must be given') + if arg.buf and arg.contents then + error('Only one of "buf" or "contents" must be given') end local bufnr = arg.buf - local name = bufnr and api.nvim_buf_get_name(bufnr) or arg.filename + local name = arg.filename local contents = arg.contents + if bufnr and not name then + name = api.nvim_buf_get_name(bufnr) + end + if name then name = normalize_path(name) end local ft, on_detect - if not (bufnr or name) then + if contents then -- Sanity check: this should not happen - assert(contents, 'contents should be non-nil when bufnr and filename are nil') + assert(not bufnr, '"buf" and "contents" are mutually exclusive') -- TODO: "scripts.lua" content matching return end -- cgit From f2fa11708ce6e9d28d1d304dfb05a6476b950042 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Mon, 27 Jun 2022 20:43:37 +0200 Subject: fix(filetype): check for non-nil match in detect.rules (#19129) --- runtime/lua/vim/filetype/detect.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 48dd3cb088..ddef27a0f0 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -906,9 +906,11 @@ function M.rules(path) local dir = vim.fn.expand(path, ':h') for _, line in ipairs(config_lines) do local match = line:match(udev_rules_pattern) - local udev_rules = line:gsub(udev_rules_pattern, match, 1) - if dir == udev_rules then - return 'udevrules' + if match then + local udev_rules = line:gsub(udev_rules_pattern, match, 1) + if dir == udev_rules then + return 'udevrules' + end end end return 'hog' -- cgit From ee6b21e8430ea810ba2e3e9163b941386a2e1d65 Mon Sep 17 00:00:00 2001 From: 0x74696d6d79 <34635512+tzx@users.noreply.github.com> Date: Tue, 28 Jun 2022 05:53:15 -0400 Subject: fix(vim.ui.input): accept nil or empty "opts" #19109 Fix #18143 --- runtime/lua/vim/ui.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 77bca7f6c4..6f1ce3089d 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -59,7 +59,7 @@ end --- ---@param opts table Additional options. See |input()| --- - prompt (string|nil) ---- Text of the prompt. Defaults to `Input: `. +--- Text of the prompt --- - default (string|nil) --- Default reply to the input --- - completion (string|nil) @@ -87,7 +87,7 @@ function M.input(opts, on_confirm) on_confirm = { on_confirm, 'function', false }, }) - opts = opts or {} + opts = (opts and not vim.tbl_isempty(opts)) and opts or vim.empty_dict() local input = vim.fn.input(opts) if #input > 0 then on_confirm(input) -- cgit From ba583f820655d3d7cf4c85854c0359c54d49ae5a Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 29 Jun 2022 16:21:04 +0200 Subject: vim-patch:9.0.0005: hare files are not recognized (#19151) Problem: Hare files are not recognized. Solution: Add a filetype pattern. (Hugo Osvaldo Barrera, closes vim/vim#10630) https://github.com/vim/vim/commit/040674129f3382822eeb7b590380efa5228124a8 --- runtime/lua/vim/filetype.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 73605413ee..c3bdfea6c7 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -435,6 +435,7 @@ local extension = { haml = 'haml', hsm = 'hamster', hbs = 'handlebars', + ha = 'hare', ['hs-boot'] = 'haskell', hsig = 'haskell', hsc = 'haskell', -- cgit From 1eb9624666a8478d66e693c7f00fc633a6b1b8ca Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Wed, 29 Jun 2022 18:43:56 +0200 Subject: vim-patch:9.0.0006: not all Visual Basic files are recognized (#19153) Problem: Not all Visual Basic files are recognized. Solution: Change detection of *.cls files. (Doug Kearns) https://github.com/vim/vim/commit/8b5901e2f9466eb6f38f5b251e871f609f65e252 --- runtime/lua/vim/filetype/detect.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index ddef27a0f0..342f947524 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -83,19 +83,19 @@ function M.bas(bufnr) local fb_keywords = [[\c^\s*\%(extern\|var\|enum\|private\|scope\|union\|byref\|operator\|constructor\|delete\|namespace\|public\|property\|with\|destructor\|using\)\>\%(\s*[:=(]\)\@!]] local fb_preproc = - [[\c^\s*\%(#\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\)]] + [[\c^\s*\%(#\s*\a\+\|option\s\+\%(byval\|dynamic\|escape\|\%(no\)\=gosub\|nokeyword\|private\|static\)\>\|\%(''\|rem\)\s*\$lang\>\|def\%(byte\|longint\|short\|ubyte\|uint\|ulongint\|ushort\)\>\)]] local fb_comment = "^%s*/'" -- OPTION EXPLICIT, without the leading underscore, is common to many dialects local qb64_preproc = [[\c^\s*\%($\a\+\|option\s\+\%(_explicit\|_\=explicitarray\)\>\)]] for _, line in ipairs(getlines(bufnr, 1, 100)) do - if line:find(fb_comment) or matchregex(line, fb_preproc) or matchregex(line, fb_keywords) then + if findany(line:lower(), visual_basic_content) then + return 'vb' + elseif line:find(fb_comment) or matchregex(line, fb_preproc) or matchregex(line, fb_keywords) then return 'freebasic' elseif matchregex(line, qb64_preproc) then return 'qb64' - elseif findany(line:lower(), visual_basic_content) then - return 'vb' end end return 'basic' @@ -172,11 +172,16 @@ function M.class(bufnr) end function M.cls(bufnr) + if vim.g.filetype_cls then + return vim.g.filetype_cls + end local line = getlines(bufnr, 1) if line:find('^%%') then return 'tex' elseif line:find('^#') and line:lower():find('rexx') then return 'rexx' + elseif line == 'VERSION 1.0 CLASS' then + return 'vb' else return 'st' end -- cgit From 6f6286e4f90da25a7d1b6bcc96b79b0ccbaf5c26 Mon Sep 17 00:00:00 2001 From: L3MON4D3 <41961280+L3MON4D3@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:53:49 +0200 Subject: fix(lsp): small bugs in snippet-parser #18998 This fixes the following bugs: `${1:else_text}` -> format with if_text: "else_text" `${1:-else_text}` -> format with if_text: "else_text" `${1:}` in `format` (eg. empty else_text) -> error. `${1:}` (eg. empty placeholder) -> error. Thanks hrsh7th :) --- runtime/lua/vim/lsp/_snippet.lua | 57 +++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/lsp/_snippet.lua b/runtime/lua/vim/lsp/_snippet.lua index 28064f36e9..910deba556 100644 --- a/runtime/lua/vim/lsp/_snippet.lua +++ b/runtime/lua/vim/lsp/_snippet.lua @@ -156,10 +156,10 @@ P.seq = function(...) return function(input, pos) local values = {} local new_pos = pos - for _, parser in ipairs(parsers) do + for i, parser in ipairs(parsers) do local result = parser(input, new_pos) if result.parsed then - table.insert(values, result.value) + values[i] = result.value new_pos = result.pos else return P.unmatch(pos) @@ -272,22 +272,48 @@ S.format = P.any( S.open, S.int, S.colon, - P.any( - P.seq(S.question, P.take_until({ ':' }, { '\\' }), S.colon, P.take_until({ '}' }, { '\\' })), - P.seq(S.plus, P.take_until({ '}' }, { '\\' })), - P.seq(S.minus, P.take_until({ '}' }, { '\\' })) - ), + P.seq(S.question, P.opt(P.take_until({ ':' }, { '\\' })), S.colon, P.opt(P.take_until({ '}' }, { '\\' }))), S.close ), function(values) return setmetatable({ type = Node.Type.FORMAT, capture_index = values[3], - if_text = values[5][2].esc, - else_text = (values[5][4] or {}).esc, + if_text = values[5][2] and values[5][2].esc or '', + else_text = values[5][4] and values[5][4].esc or '', }, Node) end - ) + ), + P.map( + P.seq(S.dollar, S.open, S.int, S.colon, P.seq(S.plus, P.opt(P.take_until({ '}' }, { '\\' }))), S.close), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = values[5][2] and values[5][2].esc or '', + else_text = '', + }, Node) + end + ), + P.map( + P.seq(S.dollar, S.open, S.int, S.colon, S.minus, P.opt(P.take_until({ '}' }, { '\\' })), S.close), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = '', + else_text = values[6] and values[6].esc or '', + }, Node) + end + ), + P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.take_until({ '}' }, { '\\' })), S.close), function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = '', + else_text = values[5] and values[5].esc or '', + }, Node) + end) ) S.transform = P.map( @@ -333,12 +359,19 @@ S.tabstop = P.any( S.placeholder = P.any( P.map( - P.seq(S.dollar, S.open, S.int, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), + P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' })))), S.close), function(values) return setmetatable({ type = Node.Type.PLACEHOLDER, tabstop = values[3], - children = values[5], + -- insert empty text if opt did not match. + children = values[5] or { + setmetatable({ + type = Node.Type.TEXT, + raw = '', + esc = '', + }, Node), + }, }, Node) end ) -- cgit From 3b1423bfa7adc5381af641a6e66fa2ca385ecab4 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 30 Jun 2022 09:54:44 -0600 Subject: fix(filetype): update call sites of vim.filetype.match (#19171) These were not updated in #18895. --- runtime/lua/vim/filetype.lua | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index c3bdfea6c7..72e144b708 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1171,57 +1171,57 @@ local extension = { -- Ignored extensions bak = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, ['dpkg-bak'] = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, ['dpkg-dist'] = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, ['dpkg-old'] = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, ['dpkg-new'] = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, ['in'] = function(path, bufnr) if vim.fs.basename(path) ~= 'configure.in' then local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end end, new = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, old = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, orig = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, pacsave = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, pacnew = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, rpmsave = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, rmpnew = function(path, bufnr) local root = vim.fn.fnamemodify(path, ':r') - return M.match(root, bufnr) + return M.match({ buf = bufnr, filename = root }) end, -- END EXTENSION } @@ -2059,7 +2059,7 @@ local pattern = { ['.*~'] = function(path, bufnr) local short = path:gsub('~$', '', 1) if path ~= short and short ~= '' then - return M.match(vim.fn.fnameescape(short), bufnr) + return M.match({ buf = bufnr, filename = vim.fn.fnameescape(short) }) end end, -- END PATTERN -- cgit From 60604d6a9982319673e5d5e67f0cdc29465cfe54 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Fri, 1 Jul 2022 07:08:44 +0200 Subject: vim-patch:9.0.0012: signature files not detected properly (#19172) Problem: Signature files not detected properly. Solution: Add a function to better detect signature files. (Doug Kearns) https://github.com/vim/vim/commit/cdbfc6dbab1d63aa56af316d6b13e37939e7f7a8 --- runtime/lua/vim/filetype.lua | 4 +++- runtime/lua/vim/filetype/detect.lua | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 72e144b708..8fe631e7ed 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -586,7 +586,6 @@ local extension = { c = function(path, bufnr) return require('vim.filetype.detect').lpc(bufnr) end, - sig = 'lprolog', lsl = 'lsl', lss = 'lss', nse = 'lua', @@ -867,6 +866,9 @@ local extension = { end, sieve = 'sieve', siv = 'sieve', + sig = function(path, bufnr) + return require('vim.filetype.detect').sig(bufnr) + end, sil = 'sil', sim = 'simula', ['s85'] = 'sinda', diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 342f947524..14a4381835 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -922,6 +922,23 @@ function M.rules(path) end end +-- LambdaProlog and Standard ML signature files +function M.sig(bufnr) + if vim.g.filetype_sig then + return vim.g.filetype_sig + end + + local line = nextnonblank(bufnr, 1) + + -- LambdaProlog comment or keyword + if findany(line, { '^%s*/%*', '^%s*%%', '^%s*sig%s+%a' }) then + return 'lprolog' + -- SML comment or keyword + elseif findany(line, { '^%s*%(%*', '^%s*signature%s+%a', '^%s*structure%s+%a' }) then + return 'sml' + end +end + -- This function checks the first 25 lines of file extension "sc" to resolve -- detection between scala and SuperCollider function M.sc(bufnr) -- cgit From acb7a902812a064fced5ef7d389bd94cb45764bb Mon Sep 17 00:00:00 2001 From: Jonas Strittmatter <40792180+smjonas@users.noreply.github.com> Date: Sun, 3 Jul 2022 15:31:56 +0200 Subject: refactor(runtime): port scripts.vim to lua (#18710) --- runtime/lua/vim/filetype.lua | 134 +++++++----- runtime/lua/vim/filetype/detect.lua | 403 +++++++++++++++++++++++++++++++++--- 2 files changed, 458 insertions(+), 79 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 8fe631e7ed..2874ea45e7 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -24,18 +24,26 @@ local function starsetf(ft, opts) end ---@private ---- Get a single line or line-range from the buffer. +--- Get a single line or line range from the buffer. +--- If only start_lnum is specified, return a single line as a string. +--- If both start_lnum and end_lnum are omitted, return all lines from the buffer. --- ---@param bufnr number|nil The buffer to get the lines from ----@param start_lnum number The line number of the first line (inclusive, 1-based) +---@param start_lnum number|nil The line number of the first line (inclusive, 1-based) ---@param end_lnum number|nil The line number of the last line (inclusive, 1-based) ---@return table|string Array of lines, or string when end_lnum is omitted function M.getlines(bufnr, start_lnum, end_lnum) - if not end_lnum then - -- Return a single line as a string + if end_lnum then + -- Return a line range + return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) + end + if start_lnum then + -- Return a single line return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or '' + else + -- Return all lines + return api.nvim_buf_get_lines(bufnr, 0, -1, false) end - return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) end ---@private @@ -600,7 +608,8 @@ local extension = { end, quake = 'm3quake', ['m4'] = function(path, bufnr) - return require('vim.filetype.detect').m4(path) + path = path:lower() + return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4' end, eml = 'mail', mk = 'make', @@ -847,22 +856,22 @@ local extension = { sed = 'sed', sexp = 'sexplib', bash = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ebuild = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, eclass = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, env = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, ksh = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'ksh') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh') end, sh = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, sieve = 'sieve', siv = 'sieve', @@ -1090,7 +1099,7 @@ local extension = { return require('vim.filetype.detect').scd(bufnr) end, tcsh = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh') end, sql = function(path, bufnr) return vim.g.filetype_sql and vim.g.filetype_sql or 'sql' @@ -1510,40 +1519,40 @@ local filename = { ['/etc/serial.conf'] = 'setserial', ['/etc/udev/cdsymlinks.conf'] = 'sh', ['bash.bashrc'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, bashrc = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['.bashrc'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['.env'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, ['.kshrc'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'ksh') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh') end, ['.profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, ['/etc/profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, APKBUILD = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, PKGBUILD = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['.tcshrc'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh') end, ['tcsh.login'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh') end, ['tcsh.tcshrc'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh') end, ['/etc/slp.conf'] = 'slpconf', ['/etc/slp.reg'] = 'slpreg', @@ -1934,28 +1943,28 @@ local pattern = { ['.*/etc/serial%.conf'] = 'setserial', ['.*/etc/udev/cdsymlinks%.conf'] = 'sh', ['%.bash[_%-]aliases'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['%.bash[_%-]logout'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['%.bash[_%-]profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['%.kshrc.*'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'ksh') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh') end, ['%.profile.*'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, ['.*/etc/profile'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr) + return require('vim.filetype.detect').sh(path, M.getlines(bufnr)) end, ['bash%-fc[%-%.]'] = function(path, bufnr) - return require('vim.filetype.detect').sh(path, bufnr, 'bash') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash') end, ['%.tcshrc.*'] = function(path, bufnr) - return require('vim.filetype.detect').shell(path, bufnr, 'tcsh') + return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'tcsh') end, ['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'), ['.*%._sst%.meta'] = 'sisu', @@ -2165,6 +2174,25 @@ end --- }) --- --- +--- To add a fallback match on contents (see |new-filetype-scripts|), use +---
+--- vim.filetype.add {
+---   pattern = {
+---     ['.*'] = {
+---       priority = -math.huge,
+---       function(path, bufnr)
+---         local content = vim.filetype.getlines(bufnr, 1)
+---         if vim.filetype.matchregex(content, { [[^#!.*\\]] }) then
+---           return 'mine'
+---         elseif vim.filetype.matchregex(content, { [[\\]] }) then
+---           return 'drawing'
+---         end
+---       end,
+---     },
+---   },
+--- }
+--- 
+--- ---@param filetypes table A table containing new filetype maps (see example). function M.add(filetypes) for k, v in pairs(filetypes.extension or {}) do @@ -2253,7 +2281,7 @@ end --- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} }) --- --- ----@param arg table Table specifying which matching strategy to use. Accepted keys are: +---@param args table Table specifying which matching strategy to use. Accepted keys are: --- * buf (number): Buffer number to use for matching. Mutually exclusive with --- {contents} --- * filename (string): Filename to use for matching. When {buf} is given, @@ -2270,22 +2298,18 @@ end ---@return function|nil A function that modifies buffer state when called (for example, to set some --- filetype specific buffer variables). The function accepts a buffer number as --- its only argument. -function M.match(arg) +function M.match(args) vim.validate({ - arg = { arg, 't' }, + arg = { args, 't' }, }) - if not (arg.buf or arg.filename or arg.contents) then + if not (args.buf or args.filename or args.contents) then error('At least one of "buf", "filename", or "contents" must be given') end - if arg.buf and arg.contents then - error('Only one of "buf" or "contents" must be given') - end - - local bufnr = arg.buf - local name = arg.filename - local contents = arg.contents + local bufnr = args.buf + local name = args.filename + local contents = args.contents if bufnr and not name then name = api.nvim_buf_get_name(bufnr) @@ -2297,13 +2321,6 @@ function M.match(arg) local ft, on_detect - if contents then - -- Sanity check: this should not happen - assert(not bufnr, '"buf" and "contents" are mutually exclusive') - -- TODO: "scripts.lua" content matching - return - end - -- First check for the simple case where the full path exists as a key local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p')) ft, on_detect = dispatch(filename[path], path, bufnr) @@ -2345,7 +2362,7 @@ function M.match(arg) return ft, on_detect end - -- Finally, check patterns with negative priority + -- Next, check patterns with negative priority for i = j, #pattern_sorted do local v = pattern_sorted[i] local k = next(v) @@ -2359,6 +2376,19 @@ function M.match(arg) end end end + + -- Finally, check file contents + if contents or bufnr then + contents = contents or M.getlines(bufnr) + -- If name is nil, catch any errors from the contents filetype detection function. + -- If the function tries to use the filename that is nil then it will fail, + -- but this enables checks which do not need a filename to still work. + local ok + ok, ft = pcall(require('vim.filetype.detect').match_contents, contents, name) + if ok and ft then + return ft + end + end end return M diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 14a4381835..37922b4ebf 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -206,12 +206,52 @@ function M.csh(path, bufnr) -- Filetype was already detected return end + local contents = getlines(bufnr) if vim.g.filetype_csh then - return M.shell(path, bufnr, vim.g.filetype_csh) + return M.shell(path, contents, vim.g.filetype_csh) elseif string.find(vim.o.shell, 'tcsh') then - return M.shell(path, bufnr, 'tcsh') + return M.shell(path, contents, 'tcsh') else - return M.shell(path, bufnr, 'csh') + return M.shell(path, contents, 'csh') + end +end + +local function cvs_diff(path, contents) + for _, line in ipairs(contents) do + if not line:find('^%? ') then + if matchregex(line, [[^Index:\s\+\f\+$]]) then + -- CVS diff + return 'diff' + elseif + -- Locale input files: Formal Definitions of Cultural Conventions + -- Filename must be like en_US, fr_FR@euro or en_US.UTF-8 + findany(path, { '%a%a_%a%a$', '%a%a_%a%a[%.@]', '%a%a_%a%ai18n$', '%a%a_%a%aPOSIX$', '%a%a_%a%atranslit_' }) + then + -- Only look at the first 100 lines + for line_nr = 1, 100 do + if not contents[line_nr] then + break + elseif + findany(contents[line_nr], { + '^LC_IDENTIFICATION$', + '^LC_CTYPE$', + '^LC_COLLATE$', + '^LC_MONETARY$', + '^LC_NUMERIC$', + '^LC_TIME$', + '^LC_MESSAGES$', + '^LC_PAPER$', + '^LC_TELEPHONE$', + '^LC_MEASUREMENT$', + '^LC_NAME$', + '^LC_ADDRESS$', + }) + then + return 'fdcc' + end + end + end + end end end @@ -270,6 +310,38 @@ function M.dep3patch(path, bufnr) end end +local function diff(contents) + if + contents[1]:find('^%-%-%- ') and contents[2]:find('^%+%+%+ ') + or contents[1]:find('^%* looking for ') and contents[2]:find('^%* comparing to ') + or contents[1]:find('^%*%*%* ') and contents[2]:find('^%-%-%- ') + or contents[1]:find('^=== ') and ((contents[2]:find('^' .. string.rep('=', 66)) and contents[3]:find('^%-%-% ') and contents[4]:find( + '^%+%+%+' + )) or (contents[2]:find('^%-%-%- ') and contents[3]:find('^%+%+%+ '))) + or findany(contents[1], { '^=== removed', '^=== added', '^=== renamed', '^=== modified' }) + then + return 'diff' + end +end + +function M.dns_zone(contents) + if + findany( + contents[1] .. contents[2] .. contents[3] .. contents[4], + { '^; <<>> DiG [0-9%.]+.* <<>>', '%$ORIGIN', '%$TTL', 'IN%s+SOA' } + ) + then + return 'bindzone' + end + -- BAAN + if -- Check for 1 to 80 '*' characters + contents[1]:find('|%*' .. string.rep('%*?', 79)) and contents[2]:find('VRC ') + or contents[2]:find('|%*' .. string.rep('%*?', 79)) and contents[3]:find('VRC ') + then + return 'baan' + end +end + function M.dtrace(bufnr) if vim.fn.did_filetype() ~= 0 then -- Filetype was already detected @@ -483,7 +555,7 @@ function M.install(path, bufnr) if getlines(bufnr, 1):lower():find('<%?php') then return 'php' end - return M.sh(path, bufnr, 'bash') + return M.sh(path, getlines(bufnr), 'bash') end -- Innovation Data Processing @@ -572,10 +644,15 @@ function M.m(bufnr) end end -function M.m4(path) - path = path:lower() - if not path:find('html%.m4$') and not path:find('fvwm2rc') then - return 'm4' +local function m4(contents) + for _, line in ipairs(contents) do + if matchregex(line, [[^\s*dnl\>]]) then + return 'm4' + end + end + if vim.env.TERM == 'amiga' and findany(contents[1]:lower(), { '^;', '^%.bra' }) then + -- AmigaDos scripts + return 'amiga' end end @@ -625,7 +702,7 @@ end local function is_lprolog(bufnr) -- Skip apparent comments and blank lines, what looks like -- LambdaProlog comment may be RAPID header - for _, line in ipairs(getlines(bufnr, 1, -1)) do + for _, line in ipairs(getlines(bufnr)) do -- The second pattern matches a LambdaProlog comment if not findany(line, { '^%s*$', '^%s*%%' }) then -- The pattern must not catch a go.mod file @@ -982,24 +1059,26 @@ function M.sgml(bufnr) end end -function M.sh(path, bufnr, name) - if vim.fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then +function M.sh(path, contents, name) + -- Path may be nil, do not fail in that case + if vim.fn.did_filetype() ~= 0 or (path or ''):find(vim.g.ft_ignore_pat) then -- Filetype was already detected or detection should be skipped return end local on_detect - name = name or getlines(bufnr, 1) + -- Get the name from the first line if not specified + name = name or contents[1] if matchregex(name, [[\]]) then -- Some .sh scripts contain #!/bin/csh. - return M.shell(path, bufnr, 'csh') + return M.shell(path, contents, 'csh') -- Some .sh scripts contain #!/bin/tcsh. elseif matchregex(name, [[\]]) then - return M.shell(path, bufnr, 'tcsh') + return M.shell(path, contents, 'tcsh') -- Some .sh scripts contain #!/bin/zsh. elseif matchregex(name, [[\]]) then - return M.shell(path, bufnr, 'zsh') + return M.shell(path, contents, 'zsh') elseif matchregex(name, [[\]]) then on_detect = function(b) vim.b[b].is_kornshell = 1 @@ -1019,27 +1098,30 @@ function M.sh(path, bufnr, name) vim.b[b].is_bash = nil end end - return M.shell(path, bufnr, 'sh'), on_detect + return M.shell(path, contents, 'sh'), on_detect end -- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl. --- Also called from scripts.vim, thus can't be local to this script. [TODO] -function M.shell(path, bufnr, name) +function M.shell(path, contents, name) if vim.fn.did_filetype() ~= 0 or matchregex(path, vim.g.ft_ignore_pat) then -- Filetype was already detected or detection should be skipped return end + local prev_line = '' - for _, line in ipairs(getlines(bufnr, 2, -1)) do - line = line:lower() - if line:find('%s*exec%s') and not prev_line:find('^%s*#.*\\$') then - -- Found an "exec" line after a comment with continuation - local n = line:gsub('%s*exec%s+([^ ]*/)?', '', 1) - if matchregex(n, [[\c\'] = { 'zsh', { vim_regex = true } }, + ['^\\(tclsh\\|wish\\|expectk\\|itclsh\\|itkwish\\)\\>'] = { 'tcl', { vim_regex = true } }, + ['^expect\\>'] = { 'expect', { vim_regex = true } }, + ['^gnuplot\\>'] = { 'gnuplot', { vim_regex = true } }, + ['make\\>'] = { 'make', { vim_regex = true } }, + ['^pike\\%(\\>\\|[0-9]\\)'] = { 'pike', { vim_regex = true } }, + lua = 'lua', + perl = 'perl', + php = 'php', + python = 'python', + ['^groovy\\>'] = { 'groovy', { vim_regex = true } }, + raku = 'raku', + ruby = 'ruby', + ['node\\(js\\)\\=\\>\\|js\\>'] = { 'javascript', { vim_regex = true } }, + ['rhino\\>'] = { 'javascript', { vim_regex = true } }, + -- BC calculator + ['^bc\\>'] = { 'bc', { vim_regex = true } }, + ['sed\\>'] = { 'sed', { vim_regex = true } }, + ocaml = 'ocaml', + -- Awk scripts; also finds "gawk" + ['awk\\>'] = { 'awk', { vim_regex = true } }, + wml = 'wml', + scheme = 'scheme', + cfengine = 'cfengine', + escript = 'erlang', + haskell = 'haskell', + clojure = 'clojure', + ['scala\\>'] = { 'scala', { vim_regex = true } }, + -- Free Pascal + ['instantfpc\\>'] = { 'pascal', { vim_regex = true } }, + ['fennel\\>'] = { 'fennel', { vim_regex = true } }, + -- MikroTik RouterOS script + ['rsc\\>'] = { 'routeros', { vim_regex = true } }, + ['fish\\>'] = { 'fish', { vim_regex = true } }, + ['gforth\\>'] = { 'forth', { vim_regex = true } }, + ['icon\\>'] = { 'icon', { vim_regex = true } }, +} + +---@private +-- File starts with "#!". +local function match_from_hashbang(contents, path) + local first_line = contents[1] + -- Check for a line like "#!/usr/bin/env {options} bash". Turn it into + -- "#!/usr/bin/bash" to make matching easier. + -- Recognize only a few {options} that are commonly used. + if matchregex(first_line, [[^#!\s*\S*\]]) then + name = vim.fn.substitute(first_line, [[^#!.*\\s\+\(\i\+\).*]], '\\1', '') + elseif matchregex(first_line, [[^#!\s*[^/\\ ]*\>\([^/\\]\|$\)]]) then + name = vim.fn.substitute(first_line, [[^#!\s*\([^/\\ ]*\>\).*]], '\\1', '') + else + name = vim.fn.substitute(first_line, [[^#!\s*\S*[/\\]\(\i\+\).*]], '\\1', '') + end + + -- tcl scripts may have #!/bin/sh in the first line and "exec wish" in the + -- third line. Suggested by Steven Atkinson. + if contents[3] and contents[3]:find('^exec wish') then + name = 'wish' + end + + if matchregex(name, [[^\(bash\d*\|\|ksh\d*\|sh\)\>]]) then + -- Bourne-like shell scripts: bash bash2 ksh ksh93 sh + return require('vim.filetype.detect').sh(path, contents, first_line) + elseif matchregex(name, [[^csh\>]]) then + return require('vim.filetype.detect').shell(path, contents, vim.g.filetype_csh or 'csh') + elseif matchregex(name, [[^tcsh\>]]) then + return require('vim.filetype.detect').shell(path, contents, 'tcsh') + end + + for k, v in pairs(patterns_hashbang) do + local ft = type(v) == 'table' and v[1] or v + local opts = type(v) == 'table' and v[2] or {} + if opts.vim_regex and matchregex(name, k) or name:find(k) then + return ft + end + end +end + +local patterns_text = { + ['^#compdef\\>'] = { 'zsh', { vim_regex = true } }, + ['^#autoload\\>'] = { 'zsh', { vim_regex = true } }, + -- ELM Mail files + ['^From [a-zA-Z][a-zA-Z_0-9%.=%-]*(@[^ ]*)? .* 19%d%d$'] = 'mail', + ['^From [a-zA-Z][a-zA-Z_0-9%.=%-]*(@[^ ]*)? .* 20%d%d$'] = 'mail', + ['^From %- .* 19%d%d$'] = 'mail', + ['^From %- .* 20%d%d$'] = 'mail', + -- Mason + ['^<[%%&].*>'] = 'mason', + -- Vim scripts (must have '" vim' as the first line to trigger this) + ['^" *[vV]im$['] = 'vim', + -- libcxx and libstdc++ standard library headers like ["iostream["] do not have + -- an extension, recognize the Emacs file mode. + ['%-%*%-.*[cC]%+%+.*%-%*%-'] = 'cpp', + ['^\\*\\* LambdaMOO Database, Format Version \\%([1-3]\\>\\)\\@!\\d\\+ \\*\\*$'] = { + 'moo', + { vim_regex = true }, + }, + -- Diff file: + -- - "diff" in first line (context diff) + -- - "Only in " in first line + -- - "--- " in first line and "+++ " in second line (unified diff). + -- - "*** " in first line and "--- " in second line (context diff). + -- - "# It was generated by makepatch " in the second line (makepatch diff). + -- - "Index: " in the first line (CVS file) + -- - "=== ", line of "=", "---", "+++ " (SVK diff) + -- - "=== ", "--- ", "+++ " (bzr diff, common case) + -- - "=== (removed|added|renamed|modified)" (bzr diff, alternative) + -- - "# HG changeset patch" in first line (Mercurial export format) + ['^\\(diff\\>\\|Only in \\|\\d\\+\\(,\\d\\+\\)\\=[cda]\\d\\+\\>\\|# It was generated by makepatch \\|Index:\\s\\+\\f\\+\\r\\=$\\|===== \\f\\+ \\d\\+\\.\\d\\+ vs edited\\|==== //\\f\\+#\\d\\+\\|# HG changeset patch\\)'] = { + 'diff', + { vim_regex = true }, + }, + function(contents) + return diff(contents) + end, + -- PostScript Files (must have %!PS as the first line, like a2ps output) + ['^%%![ \t]*PS'] = 'postscr', + function(contents) + return m4(contents) + end, + -- SiCAD scripts (must have procn or procd as the first line to trigger this) + ['^ *proc[nd] *$'] = { 'sicad', { ignore_case = true } }, + ['^%*%*%*%* Purify'] = 'purifylog', + -- XML + ['<%?%s*xml.*%?>'] = 'xml', + -- XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN") + ['\\'] = { 'html', { vim_regex = true } }, + -- PDF + ['^%%PDF%-'] = 'pdf', + -- XXD output + ['^%x%x%x%x%x%x%x: %x%x ?%x%x ?%x%x ?%x%x '] = 'xxd', + -- RCS/CVS log output + ['^RCS file:'] = { 'rcslog', { start_lnum = 1, end_lnum = 2 } }, + -- CVS commit + ['^CVS:'] = { 'cvs', { start_lnum = 2 } }, + ['^CVS: '] = { 'cvs', { start_lnum = -1 } }, + -- Prescribe + ['^!R!'] = 'prescribe', + -- Send-pr + ['^SEND%-PR:'] = 'sendpr', + -- SNNS files + ['^SNNS network definition file'] = 'snnsnet', + ['^SNNS pattern definition file'] = 'snnspat', + ['^SNNS result file'] = 'snnsres', + ['^%%.-[Vv]irata'] = { 'virata', { start_lnum = 1, end_lnum = 5 } }, + ['[0-9:%.]* *execve%('] = 'strace', + ['^__libc_start_main'] = 'strace', + -- VSE JCL + ['^\\* $$ JOB\\>'] = { 'vsejcl', { vim_regex = true } }, + ['^// *JOB\\>'] = { 'vsejcl', { vim_regex = true } }, + -- TAK and SINDA + ['K & K Associates'] = { 'takout', { start_lnum = 4 } }, + ['TAK 2000'] = { 'takout', { start_lnum = 2 } }, + ['S Y S T E M S I M P R O V E D '] = { 'syndaout', { start_lnum = 3 } }, + ['Run Date: '] = { 'takcmp', { start_lnum = 6 } }, + ['Node File 1'] = { 'sindacmp', { start_lnum = 9 } }, + function(contents) + require('vim.filetype.detect').dns_zone(contents) + end, + -- Valgrind + ['^==%d+== valgrind'] = 'valgrind', + ['^==%d+== Using valgrind'] = { 'valgrind', { start_lnum = 3 } }, + -- Go docs + ['PACKAGE DOCUMENTATION$'] = 'godoc', + -- Renderman Interface Bytestream + ['^##RenderMan'] = 'rib', + -- Scheme scripts + ['exec%s%+%S*scheme'] = { 'scheme', { start_lnum = 1, end_lnum = 2 } }, + -- Git output + ['^\\(commit\\|tree\\|object\\) \\x\\{40,\\}\\>\\|^tag \\S\\+$'] = { 'git', { vim_regex = true } }, + function(lines) + -- Gprof (gnu profiler) + if lines[1] == 'Flat profile:' and lines[2] == '' and lines[3]:find('^Each sample counts as .* seconds%.$') then + return 'gprof' + end + end, + -- Erlang terms + -- (See also: http://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes) + ['%-%*%-.*erlang.*%-%*%-'] = { 'erlang', { ignore_case = true } }, + -- YAML + ['^%%YAML'] = 'yaml', + -- MikroTik RouterOS script + ['^#.*by RouterOS'] = 'routeros', + -- Sed scripts + -- #ncomment is allowed but most likely a false positive so require a space before any trailing comment text + ['^#n%s'] = 'sed', + ['^#n$'] = 'sed', +} + +---@private +-- File does not start with "#!". +local function match_from_text(contents, path) + if contents[1]:find('^:$') then + -- Bourne-like shell scripts: sh ksh bash bash2 + return M.sh(path, contents) + elseif matchregex('\n' .. table.concat(contents, '\n'), [[\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>]]) then + -- Z shell scripts + return 'zsh' + end + + for k, v in pairs(patterns_text) do + if type(v) == 'string' then + -- Check the first line only + if contents[1]:find(k) then + return v + end + elseif type(v) == 'function' then + -- If filetype detection fails, continue with the next pattern + local ok, ft = pcall(v, contents) + if ok and ft then + return ft + end + else + local opts = type(v) == 'table' and v[2] or {} + if opts.start_lnum and opts.end_lnum then + assert(not opts.ignore_case, 'ignore_case=true is ignored when start_lnum is also present, needs refactor') + for i = opts.start_lnum, opts.end_lnum do + if not contents[i] then + break + elseif contents[i]:find(k) then + return v[1] + end + end + else + local line_nr = opts.start_lnum == -1 and #contents or opts.start_lnum or 1 + if contents[line_nr] then + local line = opts.ignore_case and contents[line_nr]:lower() or contents[line_nr] + if opts.vim_regex and matchregex(line, k) or line:find(k) then + return v[1] + end + end + end + end + end + return cvs_diff(path, contents) +end + +M.match_contents = function(contents, path) + local first_line = contents[1] + if first_line:find('^#!') then + return match_from_hashbang(contents, path) + else + return match_from_text(contents, path) + end +end + return M -- cgit From 8b7399782e7054fa76b745f51f742dfc5236902d Mon Sep 17 00:00:00 2001 From: smjonas Date: Wed, 6 Jul 2022 01:16:04 +0200 Subject: vim-patch:9.0.0041: a couple of filetype patterns do not have "*" before "/etc" Problem: A couple of filetype patterns do not have "*" before "/etc". Solution: Add the star. (Jonas Strittmatter, closes vim/vim#10662) https://github.com/vim/vim/commit/704988f0c3598c1b0cc47f3b46f1f1229312f2bc --- runtime/lua/vim/filetype.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 2874ea45e7..377e416f12 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -1257,7 +1257,7 @@ local filename = { ['.*/named/db%..*'] = starsetf('bindzone'), ['cabal%.project%..*'] = starsetf('cabalproject'), ['sgml%.catalog.*'] = starsetf('catalog'), - ['/etc/hostname%..*'] = starsetf('config'), + ['.*/etc/hostname%..*'] = starsetf('config'), ['.*/etc/cron%.d/.*'] = starsetf('crontab'), ['crontab%..*'] = starsetf('crontab'), WORKSPACE = 'bzl', @@ -1766,7 +1766,7 @@ local pattern = { return require('vim.filetype.detect').fvwm(path) end), ['.*/tmp/lltmp.*'] = starsetf('gedcom'), - ['/etc/gitconfig%.d/.*'] = starsetf('gitconfig'), + ['.*/etc/gitconfig%.d/.*'] = starsetf('gitconfig'), ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'), ['tmac%..*'] = starsetf('nroff'), ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), -- cgit From 78300a1587dc43a363744da28f6d5e4ef40ca0bb Mon Sep 17 00:00:00 2001 From: smjonas Date: Wed, 6 Jul 2022 01:26:18 +0200 Subject: vim-patch:9.0.0042: missing change for filetype detection Problem: Missing change for filetype detection. Solution: Include change to detect guile from shebang line. https://github.com/vim/vim/commit/324478037923feef1eb8a771648e38ade9e5e05a --- runtime/lua/vim/filetype/detect.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 37922b4ebf..c6d77dac51 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -1323,6 +1323,7 @@ local patterns_hashbang = { ['fish\\>'] = { 'fish', { vim_regex = true } }, ['gforth\\>'] = { 'forth', { vim_regex = true } }, ['icon\\>'] = { 'icon', { vim_regex = true } }, + guile = 'scheme', } ---@private -- cgit From f3c78a4465942db62cf231b9eedc5107ad46e655 Mon Sep 17 00:00:00 2001 From: smjonas Date: Wed, 6 Jul 2022 16:25:23 +0200 Subject: fix(filetype): fix filetype patterns --- runtime/lua/vim/filetype.lua | 136 +++++++++++++++++++++++++++++------- runtime/lua/vim/filetype/detect.lua | 22 ++++-- 2 files changed, 128 insertions(+), 30 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 377e416f12..de79d65f48 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -17,7 +17,7 @@ local function starsetf(ft, opts) end end, { - -- Starset matches should always have lowest priority + -- Starset matches should have lowest priority by default priority = (opts and opts.priority) or -math.huge, }, } @@ -310,7 +310,7 @@ local extension = { end, ecd = 'ecd', edf = 'edif', - edfi = 'edif', + edif = 'edif', edo = 'edif', edn = function(path, bufnr) return require('vim.filetype.detect').edn(bufnr) @@ -425,7 +425,6 @@ local extension = { gleam = 'gleam', glsl = 'glsl', gpi = 'gnuplot', - gnuplot = 'gnuplot', go = 'go', gp = 'gp', gs = 'grads', @@ -1175,9 +1174,8 @@ local extension = { return require('vim.filetype.detect').sgml(bufnr) end, t = function(path, bufnr) - if not require('vim.filetype.detect').nroff(bufnr) and not require('vim.filetype.detect').perl(path, bufnr) then - return 'tads' - end + local nroff = require('vim.filetype.detect').nroff(bufnr) + return nroff or require('vim.filetype.detect').perl(path, bufnr) or 'tads' end, -- Ignored extensions bak = function(path, bufnr) @@ -1253,13 +1251,6 @@ local filename = { ['.arch-inventory'] = 'arch', ['GNUmakefile.am'] = 'automake', ['named.root'] = 'bindzone', - ['.*/bind/db%..*'] = starsetf('bindzone'), - ['.*/named/db%..*'] = starsetf('bindzone'), - ['cabal%.project%..*'] = starsetf('cabalproject'), - ['sgml%.catalog.*'] = starsetf('catalog'), - ['.*/etc/hostname%..*'] = starsetf('config'), - ['.*/etc/cron%.d/.*'] = starsetf('crontab'), - ['crontab%..*'] = starsetf('crontab'), WORKSPACE = 'bzl', BUILD = 'bzl', ['cabal.project'] = 'cabalproject', @@ -1305,9 +1296,6 @@ local filename = { ['/debian/copyright'] = 'debcopyright', ['/etc/apt/sources.list'] = 'debsources', ['denyhosts.conf'] = 'denyhosts', - ['.*/debian/patches/.*'] = function(path, bufnr) - return require('vim.filetype.detect').dep3patch(path, bufnr) - end, ['dict.conf'] = 'dictconf', ['.dictrc'] = 'dictconf', ['/etc/DIR_COLORS'] = 'dircolors', @@ -1366,6 +1354,7 @@ local filename = { ['.gnashpluginrc'] = 'gnash', gnashpluginrc = 'gnash', gnashrc = 'gnash', + ['.gnuplot'] = 'gnuplot', ['go.work'] = 'gowork', ['.gprc'] = 'gp', ['/.gnupg/gpg.conf'] = 'gpg', @@ -1514,7 +1503,6 @@ local filename = { ['.screenrc'] = 'screen', ['/etc/sensors3.conf'] = 'sensors', ['/etc/sensors.conf'] = 'sensors', - ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), ['/etc/services'] = 'services', ['/etc/serial.conf'] = 'setserial', ['/etc/udev/cdsymlinks.conf'] = 'sh', @@ -1560,13 +1548,15 @@ local filename = { ['.slrnrc'] = 'slrnrc', ['sendmail.cf'] = 'sm', ['squid.conf'] = 'squid', - ['/.ssh/config'] = 'sshconfig', ['ssh_config'] = 'sshconfig', ['sshd_config'] = 'sshdconfig', ['/etc/sudoers'] = 'sudoers', ['sudoers.tmp'] = 'sudoers', ['/etc/sysctl.conf'] = 'sysctl', tags = 'tags', + ['pending.data'] = 'taskdata', + ['completed.data'] = 'taskdata', + ['undo.data'] = 'taskdata', ['.tclshrc'] = 'tcl', ['.wishrc'] = 'tcl', ['tclsh.rc'] = 'tcl', @@ -1667,12 +1657,16 @@ local pattern = { return require('vim.filetype.detect').asm(bufnr) end, ['[mM]akefile%.am'] = 'automake', + ['.*/bind/db%..*'] = starsetf('bindzone'), + ['.*/named/db%..*'] = starsetf('bindzone'), ['.*bsd'] = 'bsdl', ['bzr_log%..*'] = 'bzr', ['.*enlightenment/.*%.cfg'] = 'c', + ['cabal%.project%..*'] = starsetf('cabalproject'), ['.*/%.calendar/.*'] = starsetf('calendar'), ['.*/share/calendar/.*/calendar%..*'] = starsetf('calendar'), ['.*/share/calendar/calendar%..*'] = starsetf('calendar'), + ['sgml%.catalog.*'] = starsetf('catalog'), ['.*/etc/defaults/cdrdao'] = 'cdrdaoconf', ['.*/etc/cdrdao%.conf'] = 'cdrdaoconf', ['.*/etc/default/cdrdao'] = 'cdrdaoconf', @@ -1681,10 +1675,13 @@ local pattern = { function(path, bufnr) return require('vim.filetype.detect').cfg(bufnr) end, - -- Decrease the priority to avoid conflicts with more specific patterns + -- Decrease priority to avoid conflicts with more specific patterns -- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc. { priority = -1 }, }, + ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr) + require('vim.filetype.detect').changelog(bufnr) + end), ['.*%.%.ch'] = 'chill', ['.*%.cmake%.in'] = 'cmake', -- */cmus/rc and */.cmus/rc @@ -1693,6 +1690,9 @@ local pattern = { ['.*/%.?cmus/.*%.theme'] = 'cmusrc', ['.*/%.cmus/autosave'] = 'cmusrc', ['.*/%.cmus/command%-history'] = 'cmusrc', + ['.*/etc/hostname%..*'] = starsetf('config'), + ['crontab%..*'] = starsetf('crontab'), + ['.*/etc/cron%.d/.*'] = starsetf('crontab'), ['%.cshrc.*'] = function(path, bufnr) return require('vim.filetype.detect').csh(path, bufnr) end, @@ -1703,9 +1703,9 @@ local pattern = { ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr) return require('vim.filetype.detect').dat(path, bufnr) end, - ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr) - require('vim.filetype.detect').changelog(bufnr) - end), + ['.*/debian/patches/.*'] = function(path, bufnr) + return require('vim.filetype.detect').dep3patch(path, bufnr) + end, ['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'), ['Containerfile%..*'] = starsetf('dockerfile'), ['Dockerfile%..*'] = starsetf('dockerfile'), @@ -1716,6 +1716,8 @@ local pattern = { ['.*/debian/copyright'] = 'debcopyright', ['.*/etc/apt/sources%.list%.d/.*%.list'] = 'debsources', ['.*/etc/apt/sources%.list'] = 'debsources', + ['.*%.directory'] = 'desktop', + ['.*%.desktop'] = 'desktop', ['dictd.*%.conf'] = 'dictdconf', ['.*/etc/DIR_COLORS'] = 'dircolors', ['.*/etc/dnsmasq%.conf'] = 'dnsmasq', @@ -1770,10 +1772,15 @@ local pattern = { ['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'), ['tmac%..*'] = starsetf('nroff'), ['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'), - ['.*%.git/.*'] = function(path, bufnr) - require('vim.filetype.detect').git(bufnr) - end, + ['.*%.git/.*'] = { + function(path, bufnr) + return require('vim.filetype.detect').git(bufnr) + end, + -- Decrease priority to run after simple pattern checks + { priority = -1 }, + }, ['.*%.git/modules/.*/config'] = 'gitconfig', + ['.*%.git/modules/config'] = 'gitconfig', ['.*%.git/config'] = 'gitconfig', ['.*/etc/gitconfig'] = 'gitconfig', ['.*/%.config/git/config'] = 'gitconfig', @@ -1859,6 +1866,83 @@ local pattern = { ['.*[mM]akefile'] = 'make', ['[mM]akefile.*'] = starsetf('make'), ['.*/etc/man%.conf'] = 'manconf', + ['.*/log/auth'] = 'messages', + ['.*/log/cron'] = 'messages', + ['.*/log/daemon'] = 'messages', + ['.*/log/debug'] = 'messages', + ['.*/log/kern'] = 'messages', + ['.*/log/lpr'] = 'messages', + ['.*/log/mail'] = 'messages', + ['.*/log/messages'] = 'messages', + ['.*/log/news/news'] = 'messages', + ['.*/log/syslog'] = 'messages', + ['.*/log/user'] = 'messages', + ['.*/log/auth%.log'] = 'messages', + ['.*/log/cron%.log'] = 'messages', + ['.*/log/daemon%.log'] = 'messages', + ['.*/log/debug%.log'] = 'messages', + ['.*/log/kern%.log'] = 'messages', + ['.*/log/lpr%.log'] = 'messages', + ['.*/log/mail%.log'] = 'messages', + ['.*/log/messages%.log'] = 'messages', + ['.*/log/news/news%.log'] = 'messages', + ['.*/log/syslog%.log'] = 'messages', + ['.*/log/user%.log'] = 'messages', + ['.*/log/auth%.err'] = 'messages', + ['.*/log/cron%.err'] = 'messages', + ['.*/log/daemon%.err'] = 'messages', + ['.*/log/debug%.err'] = 'messages', + ['.*/log/kern%.err'] = 'messages', + ['.*/log/lpr%.err'] = 'messages', + ['.*/log/mail%.err'] = 'messages', + ['.*/log/messages%.err'] = 'messages', + ['.*/log/news/news%.err'] = 'messages', + ['.*/log/syslog%.err'] = 'messages', + ['.*/log/user%.err'] = 'messages', + ['.*/log/auth%.info'] = 'messages', + ['.*/log/cron%.info'] = 'messages', + ['.*/log/daemon%.info'] = 'messages', + ['.*/log/debug%.info'] = 'messages', + ['.*/log/kern%.info'] = 'messages', + ['.*/log/lpr%.info'] = 'messages', + ['.*/log/mail%.info'] = 'messages', + ['.*/log/messages%.info'] = 'messages', + ['.*/log/news/news%.info'] = 'messages', + ['.*/log/syslog%.info'] = 'messages', + ['.*/log/user%.info'] = 'messages', + ['.*/log/auth%.warn'] = 'messages', + ['.*/log/cron%.warn'] = 'messages', + ['.*/log/daemon%.warn'] = 'messages', + ['.*/log/debug%.warn'] = 'messages', + ['.*/log/kern%.warn'] = 'messages', + ['.*/log/lpr%.warn'] = 'messages', + ['.*/log/mail%.warn'] = 'messages', + ['.*/log/messages%.warn'] = 'messages', + ['.*/log/news/news%.warn'] = 'messages', + ['.*/log/syslog%.warn'] = 'messages', + ['.*/log/user%.warn'] = 'messages', + ['.*/log/auth%.crit'] = 'messages', + ['.*/log/cron%.crit'] = 'messages', + ['.*/log/daemon%.crit'] = 'messages', + ['.*/log/debug%.crit'] = 'messages', + ['.*/log/kern%.crit'] = 'messages', + ['.*/log/lpr%.crit'] = 'messages', + ['.*/log/mail%.crit'] = 'messages', + ['.*/log/messages%.crit'] = 'messages', + ['.*/log/news/news%.crit'] = 'messages', + ['.*/log/syslog%.crit'] = 'messages', + ['.*/log/user%.crit'] = 'messages', + ['.*/log/auth%.notice'] = 'messages', + ['.*/log/cron%.notice'] = 'messages', + ['.*/log/daemon%.notice'] = 'messages', + ['.*/log/debug%.notice'] = 'messages', + ['.*/log/kern%.notice'] = 'messages', + ['.*/log/lpr%.notice'] = 'messages', + ['.*/log/mail%.notice'] = 'messages', + ['.*/log/messages%.notice'] = 'messages', + ['.*/log/news/news%.notice'] = 'messages', + ['.*/log/syslog%.notice'] = 'messages', + ['.*/log/user%.notice'] = 'messages', ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr) return require('vim.filetype.detect').mod(path, bufnr) end, @@ -1937,6 +2021,7 @@ local pattern = { ['[rR]akefile.*'] = starsetf('ruby'), ['[rR]antfile'] = 'ruby', ['[rR]akefile'] = 'ruby', + ['.*/etc/sensors%.d/[^.].*'] = starsetf('sensors'), ['.*/etc/sensors%.conf'] = 'sensors', ['.*/etc/sensors3%.conf'] = 'sensors', ['.*/etc/services'] = 'services', @@ -1975,6 +2060,7 @@ local pattern = { ['.*/etc/slp%.spi'] = 'slpspi', ['.*/etc/ssh/ssh_config%.d/.*%.conf'] = 'sshconfig', ['.*/%.ssh/config'] = 'sshconfig', + ['.*/%.ssh/.*%.conf'] = 'sshconfig', ['.*/etc/ssh/sshd_config%.d/.*%.conf'] = 'sshdconfig', ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr) return require('vim.filetype.detect').src(bufnr) diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index c6d77dac51..fb36a502b0 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -187,6 +187,17 @@ function M.cls(bufnr) end end +function M.conf(path, bufnr) + if vim.fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then + return + end + for _, line in ipairs(getlines(bufnr, 1, 5)) do + if line:find('^#') then + return 'conf' + end + end +end + -- Debian Control function M.control(bufnr) if getlines(bufnr, 1):find('^Source:') then @@ -256,8 +267,9 @@ local function cvs_diff(path, contents) end function M.dat(path, bufnr) + local file_name = vim.fn.fnamemodify(path, ':t'):lower() -- Innovation data processing - if findany(path:lower(), { '^upstream%.dat$', '^upstream%..*%.dat$', '^.*%.upstream%.dat$' }) then + if findany(file_name, { '^upstream%.dat$', '^upstream%..*%.dat$', '^.*%.upstream%.dat$' }) then return 'upstreamdat' end if vim.g.filetype_dat then @@ -458,7 +470,7 @@ end function M.git(bufnr) local line = getlines(bufnr, 1) - if line:find('^' .. string.rep('%x', 40) .. '+ ') or line:sub(1, 5) == 'ref: ' then + if matchregex(line, [[^\x\{40,\}\>\|^ref: ]]) then return 'git' end end @@ -568,7 +580,7 @@ function M.log(path) return 'upstreaminstalllog' elseif findany(path, { 'usserver%.log', 'usserver%..*%.log', '.*%.usserver%.log' }) then return 'usserverlog' - elseif findany(path, { 'usw2kagt%.log', 'usws2kagt%..*%.log', '.*%.usws2kagt%.log' }) then + elseif findany(path, { 'usw2kagt%.log', 'usw2kagt%..*%.log', '.*%.usw2kagt%.log' }) then return 'usw2kagtlog' end end @@ -759,8 +771,8 @@ end -- If the first line starts with '#' and contains 'perl' it's probably a Perl file. -- (Slow test) If a file contains a 'use' statement then it is almost certainly a Perl file. function M.perl(path, bufnr) - local dirname = vim.fn.expand(path, '%:p:h:t') - if vim.fn.expand(dirname, '%:e') == 't' and (dirname == 't' or dirname == 'xt') then + local dir_name = vim.fs.dirname(path) + if vim.fn.expand(path, '%:e') == 't' and (dir_name == 't' or dir_name == 'xt') then return 'perl' end local first_line = getlines(bufnr, 1) -- cgit From f9683f28236599a7082f43304a9685fad8ee8e00 Mon Sep 17 00:00:00 2001 From: smjonas Date: Wed, 6 Jul 2022 16:25:51 +0200 Subject: fix(filetype): remove call to vim.fn.resolve and pass filename to match function For example on MacOS, /etc/hostname.file is symlinked to /private/etc/hostname.file. We only care about the original file path though. --- runtime/lua/vim/filetype.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index de79d65f48..df21fd46a1 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -2408,7 +2408,7 @@ function M.match(args) local ft, on_detect -- First check for the simple case where the full path exists as a key - local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p')) + local path = vim.fn.fnamemodify(name, ':p') ft, on_detect = dispatch(filename[path], path, bufnr) if ft then return ft, on_detect -- cgit From aa4f9c5341f5280f16cce0630ea54b84eef717b3 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 7 Jul 2022 18:27:18 +0200 Subject: refactor(lua): reformat with stylua 0.14.0 (#19264) * reformat Lua runtime to make lint CI pass * reduce max line length to 100 --- runtime/lua/vim/_editor.lua | 13 ++- runtime/lua/vim/_meta.lua | 23 ++++-- runtime/lua/vim/diagnostic.lua | 36 +++++---- runtime/lua/vim/filetype.lua | 8 +- runtime/lua/vim/filetype/detect.lua | 119 +++++++++++++++++++++------- runtime/lua/vim/fs.lua | 3 +- runtime/lua/vim/highlight.lua | 9 ++- runtime/lua/vim/inspect.lua | 14 +++- runtime/lua/vim/lsp.lua | 112 ++++++++++++++++++-------- runtime/lua/vim/lsp/_snippet.lua | 71 +++++++++++++---- runtime/lua/vim/lsp/buf.lua | 35 +++++--- runtime/lua/vim/lsp/diagnostic.lua | 25 +++++- runtime/lua/vim/lsp/handlers.lua | 24 ++++-- runtime/lua/vim/lsp/health.lua | 7 +- runtime/lua/vim/lsp/log.lua | 9 ++- runtime/lua/vim/lsp/protocol.lua | 9 ++- runtime/lua/vim/lsp/rpc.lua | 46 ++++++++--- runtime/lua/vim/lsp/sync.lua | 49 +++++++++--- runtime/lua/vim/lsp/tagfunc.lua | 3 +- runtime/lua/vim/lsp/util.lua | 95 ++++++++++++++++++---- runtime/lua/vim/shared.lua | 17 +++- runtime/lua/vim/treesitter/health.lua | 4 +- runtime/lua/vim/treesitter/highlighter.lua | 3 +- runtime/lua/vim/treesitter/languagetree.lua | 6 +- 24 files changed, 561 insertions(+), 179 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua index f7dcc3a81b..7febad6ef6 100644 --- a/runtime/lua/vim/_editor.lua +++ b/runtime/lua/vim/_editor.lua @@ -739,7 +739,12 @@ function vim._cs_remote(rcid, server_addr, connect_error, args) f_tab = true elseif subcmd == 'silent' then f_silent = true - elseif subcmd == 'wait' or subcmd == 'wait-silent' or subcmd == 'tab-wait' or subcmd == 'tab-wait-silent' then + elseif + subcmd == 'wait' + or subcmd == 'wait-silent' + or subcmd == 'tab-wait' + or subcmd == 'tab-wait-silent' + then return { errmsg = 'E5600: Wait commands not yet implemented in nvim' } elseif subcmd == 'tab-silent' then f_tab = true @@ -795,7 +800,11 @@ function vim.deprecate(name, alternative, version, plugin, backtrace) local message = name .. ' is deprecated' plugin = plugin or 'Nvim' message = alternative and (message .. ', use ' .. alternative .. ' instead.') or message - message = message .. ' See :h deprecated\nThis function will be removed in ' .. plugin .. ' version ' .. version + message = message + .. ' See :h deprecated\nThis function will be removed in ' + .. plugin + .. ' version ' + .. version if vim.notify_once(message, vim.log.levels.WARN) and backtrace ~= false then vim.notify(debug.traceback('', 2):sub(2), vim.log.levels.WARN) end diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua index 715a7e5561..f1652718ee 100644 --- a/runtime/lua/vim/_meta.lua +++ b/runtime/lua/vim/_meta.lua @@ -102,9 +102,13 @@ do -- buffer option accessor if type(k) == 'string' then _setup() if win_options[k] then - error(string.format([['%s' is a window option, not a buffer option. See ":help %s"]], k, k)) + error( + string.format([['%s' is a window option, not a buffer option. See ":help %s"]], k, k) + ) elseif glb_options[k] then - error(string.format([['%s' is a global option, not a buffer option. See ":help %s"]], k, k)) + error( + string.format([['%s' is a global option, not a buffer option. See ":help %s"]], k, k) + ) end end @@ -132,9 +136,13 @@ do -- window option accessor if type(k) == 'string' then _setup() if buf_options[k] then - error(string.format([['%s' is a buffer option, not a window option. See ":help %s"]], k, k)) + error( + string.format([['%s' is a buffer option, not a window option. See ":help %s"]], k, k) + ) elseif glb_options[k] then - error(string.format([['%s' is a global option, not a window option. See ":help %s"]], k, k)) + error( + string.format([['%s' is a global option, not a window option. See ":help %s"]], k, k) + ) end end @@ -252,7 +260,12 @@ local function assert_valid_value(name, value, types) end error( - string.format("Invalid option type '%s' for '%s', should be %s", type_of_value, name, table.concat(types, ' or ')) + string.format( + "Invalid option type '%s' for '%s', should be %s", + type_of_value, + name, + table.concat(types, ' or ') + ) ) end diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua index afc0a4095c..07a3c87da0 100644 --- a/runtime/lua/vim/diagnostic.lua +++ b/runtime/lua/vim/diagnostic.lua @@ -68,7 +68,10 @@ local all_namespaces = {} ---@private local function to_severity(severity) if type(severity) == 'string' then - return assert(M.severity[string.upper(severity)], string.format('Invalid severity: %s', severity)) + return assert( + M.severity[string.upper(severity)], + string.format('Invalid severity: %s', severity) + ) end return severity end @@ -277,7 +280,8 @@ local function set_diagnostic_cache(namespace, bufnr, diagnostics) for _, diagnostic in ipairs(diagnostics) do assert(diagnostic.lnum, 'Diagnostic line number is required') assert(diagnostic.col, 'Diagnostic column is required') - diagnostic.severity = diagnostic.severity and to_severity(diagnostic.severity) or M.severity.ERROR + diagnostic.severity = diagnostic.severity and to_severity(diagnostic.severity) + or M.severity.ERROR diagnostic.end_lnum = diagnostic.end_lnum or diagnostic.lnum diagnostic.end_col = diagnostic.end_col or diagnostic.col diagnostic.namespace = namespace @@ -322,13 +326,8 @@ local function save_extmarks(namespace, bufnr) }) diagnostic_attached_buffers[bufnr] = true end - diagnostic_cache_extmarks[bufnr][namespace] = vim.api.nvim_buf_get_extmarks( - bufnr, - namespace, - 0, - -1, - { details = true } - ) + diagnostic_cache_extmarks[bufnr][namespace] = + vim.api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, { details = true }) end local registered_autocmds = {} @@ -482,7 +481,8 @@ local function next_diagnostic(position, search_forward, bufnr, opts, namespace) bufnr = get_bufnr(bufnr) local wrap = vim.F.if_nil(opts.wrap, true) local line_count = vim.api.nvim_buf_line_count(bufnr) - local diagnostics = get_diagnostics(bufnr, vim.tbl_extend('keep', opts, { namespace = namespace }), true) + local diagnostics = + get_diagnostics(bufnr, vim.tbl_extend('keep', opts, { namespace = namespace }), true) local line_diagnostics = diagnostic_lines(diagnostics) for i = 0, line_count do local offset = i * (search_forward and 1 or -1) @@ -971,7 +971,10 @@ M.handlers.virtual_text = { if opts.virtual_text.format then diagnostics = reformat_diagnostics(opts.virtual_text.format, diagnostics) end - if opts.virtual_text.source and (opts.virtual_text.source ~= 'if_many' or count_sources(bufnr) > 1) then + if + opts.virtual_text.source + and (opts.virtual_text.source ~= 'if_many' or count_sources(bufnr) > 1) + then diagnostics = prefix_source(diagnostics) end if opts.virtual_text.severity then @@ -1279,7 +1282,9 @@ function M.open_float(opts, ...) -- LSP servers can send diagnostics with `end_col` past the length of the line local line_length = #vim.api.nvim_buf_get_lines(bufnr, lnum, lnum + 1, true)[1] diagnostics = vim.tbl_filter(function(d) - return d.lnum == lnum and math.min(d.col, line_length - 1) <= col and (d.end_col >= col or d.end_lnum > lnum) + return d.lnum == lnum + and math.min(d.col, line_length - 1) <= col + and (d.end_col >= col or d.end_lnum > lnum) end, diagnostics) end @@ -1333,9 +1338,10 @@ function M.open_float(opts, ...) diagnostics = prefix_source(diagnostics) end - local prefix_opt = if_nil(opts.prefix, (scope == 'cursor' and #diagnostics <= 1) and '' or function(_, i) - return string.format('%d. ', i) - end) + local prefix_opt = + if_nil(opts.prefix, (scope == 'cursor' and #diagnostics <= 1) and '' or function(_, i) + return string.format('%d. ', i) + end) local prefix, prefix_hl_group if prefix_opt then diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index df21fd46a1..fd47e12f07 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -176,7 +176,8 @@ local extension = { bsdl = 'bsdl', bst = 'bst', btm = function(path, bufnr) - return (vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0) and 'dosbatch' or 'btm' + return (vim.g.dosbatch_syntax_for_btm and vim.g.dosbatch_syntax_for_btm ~= 0) and 'dosbatch' + or 'btm' end, bzl = 'bzl', bazel = 'bzl', @@ -2169,7 +2170,10 @@ local function sort_by_priority(t) local sorted = {} for k, v in pairs(t) do local ft = type(v) == 'table' and v[1] or v - assert(type(ft) == 'string' or type(ft) == 'function', 'Expected string or function for filetype') + assert( + type(ft) == 'string' or type(ft) == 'function', + 'Expected string or function for filetype' + ) local opts = (type(v) == 'table' and type(v[2]) == 'table') and v[2] or {} if not opts.priority then diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index fb36a502b0..8331920406 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -71,7 +71,8 @@ function M.asm_syntax(bufnr) end end -local visual_basic_content = { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform', 'begin vb%.usercontrol' } +local visual_basic_content = + { 'vb_name', 'begin vb%.form', 'begin vb%.mdiform', 'begin vb%.usercontrol' } -- See frm() for Visual Basic form file detection function M.bas(bufnr) @@ -92,7 +93,11 @@ function M.bas(bufnr) for _, line in ipairs(getlines(bufnr, 1, 100)) do if findany(line:lower(), visual_basic_content) then return 'vb' - elseif line:find(fb_comment) or matchregex(line, fb_preproc) or matchregex(line, fb_keywords) then + elseif + line:find(fb_comment) + or matchregex(line, fb_preproc) + or matchregex(line, fb_keywords) + then return 'freebasic' elseif matchregex(line, qb64_preproc) then return 'qb64' @@ -236,7 +241,13 @@ local function cvs_diff(path, contents) elseif -- Locale input files: Formal Definitions of Cultural Conventions -- Filename must be like en_US, fr_FR@euro or en_US.UTF-8 - findany(path, { '%a%a_%a%a$', '%a%a_%a%a[%.@]', '%a%a_%a%ai18n$', '%a%a_%a%aPOSIX$', '%a%a_%a%atranslit_' }) + findany(path, { + '%a%a_%a%a$', + '%a%a_%a%a[%.@]', + '%a%a_%a%ai18n$', + '%a%a_%a%aPOSIX$', + '%a%a_%a%atranslit_', + }) then -- Only look at the first 100 lines for line_nr = 1, 100 do @@ -327,9 +338,11 @@ local function diff(contents) contents[1]:find('^%-%-%- ') and contents[2]:find('^%+%+%+ ') or contents[1]:find('^%* looking for ') and contents[2]:find('^%* comparing to ') or contents[1]:find('^%*%*%* ') and contents[2]:find('^%-%-%- ') - or contents[1]:find('^=== ') and ((contents[2]:find('^' .. string.rep('=', 66)) and contents[3]:find('^%-%-% ') and contents[4]:find( - '^%+%+%+' - )) or (contents[2]:find('^%-%-%- ') and contents[3]:find('^%+%+%+ '))) + or contents[1]:find('^=== ') and ((contents[2]:find('^' .. string.rep('=', 66)) and contents[3]:find( + '^%-%-% ' + ) and contents[4]:find('^%+%+%+')) or (contents[2]:find('^%-%-%- ') and contents[3]:find( + '^%+%+%+ ' + ))) or findany(contents[1], { '^=== removed', '^=== added', '^=== renamed', '^=== modified' }) then return 'diff' @@ -523,7 +536,8 @@ function M.idl(bufnr) end local pascal_comments = { '^%s*{', '^%s*%(%*', '^%s*//' } -local pascal_keywords = [[\c^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>]] +local pascal_keywords = + [[\c^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>]] function M.inc(bufnr) if vim.g.filetype_inc then @@ -574,9 +588,19 @@ end -- (refactor of filetype.vim since the patterns are case-insensitive) function M.log(path) path = path:lower() - if findany(path, { 'upstream%.log', 'upstream%..*%.log', '.*%.upstream%.log', 'upstream%-.*%.log' }) then + if + findany( + path, + { 'upstream%.log', 'upstream%..*%.log', '.*%.upstream%.log', 'upstream%-.*%.log' } + ) + then return 'upstreamlog' - elseif findany(path, { 'upstreaminstall%.log', 'upstreaminstall%..*%.log', '.*%.upstreaminstall%.log' }) then + elseif + findany( + path, + { 'upstreaminstall%.log', 'upstreaminstall%..*%.log', '.*%.upstreaminstall%.log' } + ) + then return 'upstreaminstalllog' elseif findany(path, { 'usserver%.log', 'usserver%..*%.log', '.*%.usserver%.log' }) then return 'usserverlog' @@ -616,7 +640,8 @@ function M.m(bufnr) -- Excluding end(for|function|if|switch|while) common to Murphi local octave_block_terminators = [[\]] - local objc_preprocessor = [[\c^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>]] + local objc_preprocessor = + [[\c^\s*#\s*\%(import\|include\|define\|if\|ifn\=def\|undef\|line\|error\|pragma\)\>]] -- Whether we've seen a multiline comment leader local saw_comment = false @@ -627,7 +652,11 @@ function M.m(bufnr) -- anything more definitive. saw_comment = true end - if line:find('^%s*//') or matchregex(line, [[\c^\s*@import\>]]) or matchregex(line, objc_preprocessor) then + if + line:find('^%s*//') + or matchregex(line, [[\c^\s*@import\>]]) + or matchregex(line, objc_preprocessor) + then return 'objc' end if @@ -869,7 +898,10 @@ function M.progress_cweb(bufnr) if vim.g.filetype_w then return vim.g.filetype_w else - if getlines(bufnr, 1):lower():find('^&analyze') or getlines(bufnr, 3):lower():find('^&global%-define') then + if + getlines(bufnr, 1):lower():find('^&analyze') + or getlines(bufnr, 3):lower():find('^&global%-define') + then return 'progress' else return 'cweb' @@ -914,10 +946,13 @@ end function M.psf(bufnr) local line = getlines(bufnr, 1):lower() if - findany( - line, - { '^%s*distribution%s*$', '^%s*installed_software%s*$', '^%s*root%s*$', '^%s*bundle%s*$', '^%s*product%s*$' } - ) + findany(line, { + '^%s*distribution%s*$', + '^%s*installed_software%s*$', + '^%s*root%s*$', + '^%s*bundle%s*$', + '^%s*product%s*$', + }) then return 'psf' end @@ -960,7 +995,9 @@ end function M.reg(bufnr) local line = getlines(bufnr, 1):lower() - if line:find('^regedit[0-9]*%s*$') or line:find('^windows registry editor version %d*%.%d*%s*$') then + if + line:find('^regedit[0-9]*%s*$') or line:find('^windows registry editor version %d*%.%d*%s*$') + then return 'registry' end end @@ -1033,10 +1070,15 @@ end function M.sc(bufnr) for _, line in ipairs(getlines(bufnr, 1, 25)) do if - findany( - line, - { '[A-Za-z0-9]*%s:%s[A-Za-z0-9]', 'var%s<', 'classvar%s<', '%^this.*', '|%w*|', '%+%s%w*%s{', '%*ar%s' } - ) + findany(line, { + '[A-Za-z0-9]*%s:%s[A-Za-z0-9]', + 'var%s<', + 'classvar%s<', + '%^this.*', + '|%w*|', + '%+%s%w*%s{', + '%*ar%s', + }) then return 'supercollider' end @@ -1062,10 +1104,11 @@ function M.sgml(bufnr) if lines:find('linuxdoc') then return 'smgllnx' elseif lines:find('\\|^tag \\S\\+$'] = { 'git', { vim_regex = true } }, + ['^\\(commit\\|tree\\|object\\) \\x\\{40,\\}\\>\\|^tag \\S\\+$'] = { + 'git', + { vim_regex = true }, + }, function(lines) -- Gprof (gnu profiler) - if lines[1] == 'Flat profile:' and lines[2] == '' and lines[3]:find('^Each sample counts as .* seconds%.$') then + if + lines[1] == 'Flat profile:' + and lines[2] == '' + and lines[3]:find('^Each sample counts as .* seconds%.$') + then return 'gprof' end end, @@ -1515,7 +1566,12 @@ local function match_from_text(contents, path) if contents[1]:find('^:$') then -- Bourne-like shell scripts: sh ksh bash bash2 return M.sh(path, contents) - elseif matchregex('\n' .. table.concat(contents, '\n'), [[\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>]]) then + elseif + matchregex( + '\n' .. table.concat(contents, '\n'), + [[\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>]] + ) + then -- Z shell scripts return 'zsh' end @@ -1535,7 +1591,10 @@ local function match_from_text(contents, path) else local opts = type(v) == 'table' and v[2] or {} if opts.start_lnum and opts.end_lnum then - assert(not opts.ignore_case, 'ignore_case=true is ignored when start_lnum is also present, needs refactor') + assert( + not opts.ignore_case, + 'ignore_case=true is ignored when start_lnum is also present, needs refactor' + ) for i = opts.start_lnum, opts.end_lnum do if not contents[i] then break diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua index 6f9c48ca24..ce845eda15 100644 --- a/runtime/lua/vim/fs.lua +++ b/runtime/lua/vim/fs.lua @@ -61,7 +61,8 @@ end function M.dir(path) return function(fs) return vim.loop.fs_scandir_next(fs) - end, vim.loop.fs_scandir(M.normalize(path)) + end, + vim.loop.fs_scandir(M.normalize(path)) end --- Find files or directories in the given path. diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 36e3c2ad20..e72d45f11c 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -16,7 +16,14 @@ function M.create(higroup, hi_info, default) for k, v in pairs(hi_info) do table.insert(options, string.format('%s=%s', k, v)) end - vim.cmd(string.format([[highlight %s %s %s]], default and 'default' or '', higroup, table.concat(options, ' '))) + vim.cmd( + string.format( + [[highlight %s %s %s]], + default and 'default' or '', + higroup, + table.concat(options, ' ') + ) + ) end ---@private diff --git a/runtime/lua/vim/inspect.lua b/runtime/lua/vim/inspect.lua index c19e55fb37..0a53fb203b 100644 --- a/runtime/lua/vim/inspect.lua +++ b/runtime/lua/vim/inspect.lua @@ -80,7 +80,13 @@ for i = 0, 31 do end local function escape(str) - return (gsub(gsub(gsub(str, '\\', '\\\\'), '(%c)%f[0-9]', longControlCharEscapes), '%c', shortControlCharEscapes)) + return ( + gsub( + gsub(gsub(str, '\\', '\\\\'), '(%c)%f[0-9]', longControlCharEscapes), + '%c', + shortControlCharEscapes + ) + ) end local function isIdentifier(str) @@ -181,11 +187,13 @@ local function processRecursive(process, item, path, visited) for k, v in rawpairs(processed) do processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) if processedKey ~= nil then - processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) + processedCopy[processedKey] = + processRecursive(process, v, makePath(path, processedKey), visited) end end - local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) + local mt = + processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) if type(mt) ~= 'table' then mt = nil end diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 8bf736a2ca..75c3b63da7 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -200,7 +200,12 @@ local function validate_encoding(encoding) encoding = { encoding, 's' }, }) return valid_encodings[encoding:lower()] - or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding)) + or error( + string.format( + "Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", + encoding + ) + ) end ---@internal @@ -211,13 +216,15 @@ end ---@returns (string) the command ---@returns (list of strings) its arguments function lsp._cmd_parts(input) - vim.validate({ cmd = { - input, - function() - return vim.tbl_islist(input) - end, - 'list', - } }) + vim.validate({ + cmd = { + input, + function() + return vim.tbl_islist(input) + end, + 'list', + }, + }) local cmd = input[1] local cmd_args = {} @@ -274,7 +281,11 @@ local function validate_client_config(config) get_language_id = { config.get_language_id, 'f', true }, }) assert( - (not config.flags or not config.flags.debounce_text_changes or type(config.flags.debounce_text_changes) == 'number'), + ( + not config.flags + or not config.flags.debounce_text_changes + or type(config.flags.debounce_text_changes) == 'number' + ), 'flags.debounce_text_changes must be a number with the debounce time in milliseconds' ) @@ -474,7 +485,8 @@ do local uri = vim.uri_from_bufnr(bufnr) return function(client) if - vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') == protocol.TextDocumentSyncKind.None + vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'change') + == protocol.TextDocumentSyncKind.None then return end @@ -493,7 +505,8 @@ do if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then return end - local changes = state.use_incremental_sync and buf_state.pending_changes or { full_changes() } + local changes = state.use_incremental_sync and buf_state.pending_changes + or { full_changes() } client.notify('textDocument/didChange', { textDocument = { uri = uri, @@ -852,7 +865,8 @@ end --- the client has been initialized. function lsp.start_client(config) local cleaned_config = validate_client_config(config) - local cmd, cmd_args, offset_encoding = cleaned_config.cmd, cleaned_config.cmd_args, cleaned_config.offset_encoding + local cmd, cmd_args, offset_encoding = + cleaned_config.cmd, cleaned_config.cmd_args, cleaned_config.offset_encoding config.flags = config.flags or {} config.settings = config.settings or {} @@ -921,7 +935,8 @@ function lsp.start_client(config) ---@see |vim.lsp.rpc.client_errors| for possible errors. Use ---`vim.lsp.rpc.client_errors[code]` to get a human-friendly name. function dispatch.on_error(code, err) - local _ = log.error() and log.error(log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) + local _ = log.error() + and log.error(log_prefix, 'on_error', { code = lsp.client_errors[code], err = err }) err_message(log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err)) if config.on_error then local status, usererr = pcall(config.on_error, code, err) @@ -964,7 +979,8 @@ function lsp.start_client(config) changetracking.reset(client_id) if code ~= 0 or (signal ~= 0 and signal ~= 15) then - local msg = string.format('Client %s quit with exit code %s and signal %s', client_id, code, signal) + local msg = + string.format('Client %s quit with exit code %s and signal %s', client_id, code, signal) vim.schedule(function() vim.notify(msg, vim.log.levels.WARN) end) @@ -1082,7 +1098,8 @@ function lsp.start_client(config) -- These are the cleaned up capabilities we use for dynamically deciding -- when to send certain events to clients. - client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities") + client.server_capabilities = + assert(result.capabilities, "initialize result doesn't contain capabilities") client.server_capabilities = protocol.resolve_capabilities(client.server_capabilities) -- Deprecation wrapper: this will be removed in 0.8 @@ -1128,7 +1145,11 @@ function lsp.start_client(config) end end local _ = log.info() - and log.info(log_prefix, 'server_capabilities', { server_capabilities = client.server_capabilities }) + and log.info( + log_prefix, + 'server_capabilities', + { server_capabilities = client.server_capabilities } + ) -- Only assign after initialized. active_clients[client_id] = client @@ -1168,9 +1189,14 @@ function lsp.start_client(config) -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state changetracking.flush(client, bufnr) bufnr = resolve_bufnr(bufnr) - local _ = log.debug() and log.debug(log_prefix, 'client.request', client_id, method, params, handler, bufnr) + local _ = log.debug() + and log.debug(log_prefix, 'client.request', client_id, method, params, handler, bufnr) local success, request_id = rpc.request(method, params, function(err, result) - handler(err, result, { method = method, client_id = client_id, bufnr = bufnr, params = params }) + handler( + err, + result, + { method = method, client_id = client_id, bufnr = bufnr, params = params } + ) end, function(request_id) client.requests[request_id] = nil nvim_command('doautocmd User LspRequest') @@ -1322,15 +1348,17 @@ end --- Notify all attached clients that a buffer has changed. local text_document_did_change_handler do - text_document_did_change_handler = function(_, bufnr, changedtick, firstline, lastline, new_lastline) - -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached - if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then - return true + text_document_did_change_handler = + function(_, bufnr, changedtick, firstline, lastline, new_lastline) + -- Detach (nvim_buf_attach) via returning True to on_lines if no clients are attached + if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then + return true + end + util.buf_versions[bufnr] = changedtick + local compute_change_and_notify = + changetracking.prepare(bufnr, firstline, lastline, new_lastline) + for_each_buffer_client(bufnr, compute_change_and_notify) end - util.buf_versions[bufnr] = changedtick - local compute_change_and_notify = changetracking.prepare(bufnr, firstline, lastline, new_lastline) - for_each_buffer_client(bufnr, compute_change_and_notify) - end end -- Buffer lifecycle handler for textDocument/didSave @@ -1369,7 +1397,8 @@ function lsp.buf_attach_client(bufnr, client_id) }) bufnr = resolve_bufnr(bufnr) if not vim.api.nvim_buf_is_loaded(bufnr) then - local _ = log.warn() and log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr)) + local _ = log.warn() + and log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr)) return false end local buffer_client_ids = all_buffer_active_clients[bufnr] @@ -1447,7 +1476,13 @@ function lsp.buf_detach_client(bufnr, client_id) local client = lsp.get_client_by_id(client_id) if not client or not client.attached_buffers[bufnr] then - vim.notify(string.format('Buffer (id: %d) is not attached to client (id: %d). Cannot detach.', client_id, bufnr)) + vim.notify( + string.format( + 'Buffer (id: %d) is not attached to client (id: %d). Cannot detach.', + client_id, + bufnr + ) + ) return end @@ -1548,10 +1583,14 @@ function lsp.get_active_clients(filter) local clients = {} - local t = filter.bufnr and (all_buffer_active_clients[resolve_bufnr(filter.bufnr)] or {}) or active_clients + local t = filter.bufnr and (all_buffer_active_clients[resolve_bufnr(filter.bufnr)] or {}) + or active_clients for client_id in pairs(t) do local client = active_clients[client_id] - if (filter.id == nil or client.id == filter.id) and (filter.name == nil or client.name == filter.name) then + if + (filter.id == nil or client.id == filter.id) + and (filter.name == nil or client.name == filter.name) + then clients[#clients + 1] = client end end @@ -1643,7 +1682,9 @@ function lsp.buf_request(bufnr, method, params, handler) end) -- if has client but no clients support the given method, notify the user - if not tbl_isempty(all_buffer_active_clients[resolve_bufnr(bufnr)] or {}) and not method_supported then + if + not tbl_isempty(all_buffer_active_clients[resolve_bufnr(bufnr)] or {}) and not method_supported + then vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR) vim.api.nvim_command('redraw') return {}, function() end @@ -1888,12 +1929,17 @@ function lsp.formatexpr(opts) }, } params.options = util.make_formatting_params().options - local client_results = vim.lsp.buf_request_sync(0, 'textDocument/rangeFormatting', params, timeout_ms) + local client_results = + vim.lsp.buf_request_sync(0, 'textDocument/rangeFormatting', params, timeout_ms) -- Apply the text edits from one and only one of the clients. for client_id, response in pairs(client_results) do if response.result then - vim.lsp.util.apply_text_edits(response.result, 0, vim.lsp.get_client_by_id(client_id).offset_encoding) + vim.lsp.util.apply_text_edits( + response.result, + 0, + vim.lsp.get_client_by_id(client_id).offset_encoding + ) return 0 end end diff --git a/runtime/lua/vim/lsp/_snippet.lua b/runtime/lua/vim/lsp/_snippet.lua index 910deba556..3488639fb4 100644 --- a/runtime/lua/vim/lsp/_snippet.lua +++ b/runtime/lua/vim/lsp/_snippet.lua @@ -255,7 +255,13 @@ S.format = P.any( S.int, S.colon, S.slash, - P.any(P.token('upcase'), P.token('downcase'), P.token('capitalize'), P.token('camelcase'), P.token('pascalcase')), + P.any( + P.token('upcase'), + P.token('downcase'), + P.token('capitalize'), + P.token('camelcase'), + P.token('pascalcase') + ), S.close ), function(values) @@ -272,7 +278,12 @@ S.format = P.any( S.open, S.int, S.colon, - P.seq(S.question, P.opt(P.take_until({ ':' }, { '\\' })), S.colon, P.opt(P.take_until({ '}' }, { '\\' }))), + P.seq( + S.question, + P.opt(P.take_until({ ':' }, { '\\' })), + S.colon, + P.opt(P.take_until({ '}' }, { '\\' })) + ), S.close ), function(values) @@ -285,7 +296,14 @@ S.format = P.any( end ), P.map( - P.seq(S.dollar, S.open, S.int, S.colon, P.seq(S.plus, P.opt(P.take_until({ '}' }, { '\\' }))), S.close), + P.seq( + S.dollar, + S.open, + S.int, + S.colon, + P.seq(S.plus, P.opt(P.take_until({ '}' }, { '\\' }))), + S.close + ), function(values) return setmetatable({ type = Node.Type.FORMAT, @@ -296,7 +314,15 @@ S.format = P.any( end ), P.map( - P.seq(S.dollar, S.open, S.int, S.colon, S.minus, P.opt(P.take_until({ '}' }, { '\\' })), S.close), + P.seq( + S.dollar, + S.open, + S.int, + S.colon, + S.minus, + P.opt(P.take_until({ '}' }, { '\\' })), + S.close + ), function(values) return setmetatable({ type = Node.Type.FORMAT, @@ -306,14 +332,17 @@ S.format = P.any( }, Node) end ), - P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.take_until({ '}' }, { '\\' })), S.close), function(values) - return setmetatable({ - type = Node.Type.FORMAT, - capture_index = values[3], - if_text = '', - else_text = values[5] and values[5].esc or '', - }, Node) - end) + P.map( + P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.take_until({ '}' }, { '\\' })), S.close), + function(values) + return setmetatable({ + type = Node.Type.FORMAT, + capture_index = values[3], + if_text = '', + else_text = values[5] and values[5].esc or '', + }, Node) + end + ) ) S.transform = P.map( @@ -359,7 +388,14 @@ S.tabstop = P.any( S.placeholder = P.any( P.map( - P.seq(S.dollar, S.open, S.int, S.colon, P.opt(P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' })))), S.close), + P.seq( + S.dollar, + S.open, + S.int, + S.colon, + P.opt(P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' })))), + S.close + ), function(values) return setmetatable({ type = Node.Type.PLACEHOLDER, @@ -419,7 +455,14 @@ S.variable = P.any( }, Node) end), P.map( - P.seq(S.dollar, S.open, S.var, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), + P.seq( + S.dollar, + S.open, + S.var, + S.colon, + P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), + S.close + ), function(values) return setmetatable({ type = Node.Type.VARIABLE, diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 97c30bc46a..981aebada1 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -228,7 +228,8 @@ function M.format(options) end local params = util.make_formatting_params(options.formatting_options) client.request('textDocument/formatting', params, function(...) - local handler = client.handlers['textDocument/formatting'] or vim.lsp.handlers['textDocument/formatting'] + local handler = client.handlers['textDocument/formatting'] + or vim.lsp.handlers['textDocument/formatting'] handler(...) do_format(next(clients, idx)) end, bufnr) @@ -284,7 +285,10 @@ end ---@param timeout_ms (number) Request timeout ---@see |vim.lsp.buf.formatting_seq_sync| function M.formatting_sync(options, timeout_ms) - vim.notify_once('vim.lsp.buf.formatting_sync is deprecated. Use vim.lsp.buf.format instead', vim.log.levels.WARN) + vim.notify_once( + 'vim.lsp.buf.formatting_sync is deprecated. Use vim.lsp.buf.format instead', + vim.log.levels.WARN + ) local params = util.make_formatting_params(options) local bufnr = vim.api.nvim_get_current_buf() select_client('textDocument/formatting', function(client) @@ -318,7 +322,10 @@ end ---in the following order: first all clients that are not in the `order` list, then ---the remaining clients in the order as they occur in the `order` list. function M.formatting_seq_sync(options, timeout_ms, order) - vim.notify_once('vim.lsp.buf.formatting_seq_sync is deprecated. Use vim.lsp.buf.format instead', vim.log.levels.WARN) + vim.notify_once( + 'vim.lsp.buf.formatting_seq_sync is deprecated. Use vim.lsp.buf.format instead', + vim.log.levels.WARN + ) local clients = vim.tbl_values(vim.lsp.buf_get_clients()) local bufnr = vim.api.nvim_get_current_buf() @@ -346,7 +353,10 @@ function M.formatting_seq_sync(options, timeout_ms, order) if result and result.result then util.apply_text_edits(result.result, bufnr, client.offset_encoding) elseif err then - vim.notify(string.format('vim.lsp.buf.formatting_seq_sync: (%s) %s', client.name, err), vim.log.levels.WARN) + vim.notify( + string.format('vim.lsp.buf.formatting_seq_sync: (%s) %s', client.name, err), + vim.log.levels.WARN + ) end end end @@ -429,7 +439,8 @@ function M.rename(new_name, options) local function rename(name) local params = util.make_position_params(win, client.offset_encoding) params.newName = name - local handler = client.handlers['textDocument/rename'] or vim.lsp.handlers['textDocument/rename'] + local handler = client.handlers['textDocument/rename'] + or vim.lsp.handlers['textDocument/rename'] client.request('textDocument/rename', params, function(...) handler(...) try_use_client(next(clients, idx)) @@ -443,7 +454,8 @@ function M.rename(new_name, options) if next(clients, idx) then try_use_client(next(clients, idx)) else - local msg = err and ('Error on prepareRename: ' .. (err.message or '')) or 'Nothing to rename' + local msg = err and ('Error on prepareRename: ' .. (err.message or '')) + or 'Nothing to rename' vim.notify(msg, vim.log.levels.INFO) end return @@ -475,7 +487,10 @@ function M.rename(new_name, options) end) end, bufnr) else - assert(client.supports_method('textDocument/rename'), 'Client must support textDocument/rename') + assert( + client.supports_method('textDocument/rename'), + 'Client must support textDocument/rename' + ) if new_name then rename(new_name) return @@ -587,7 +602,8 @@ end --- Add the folder at path to the workspace folders. If {path} is --- not provided, the user will be prompted for a path using |input()|. function M.add_workspace_folder(workspace_folder) - workspace_folder = workspace_folder or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h'), 'dir') + workspace_folder = workspace_folder + or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h'), 'dir') vim.api.nvim_command('redraw') if not (workspace_folder and #workspace_folder > 0) then return @@ -623,7 +639,8 @@ end --- {path} is not provided, the user will be prompted for --- a path using |input()|. function M.remove_workspace_folder(workspace_folder) - workspace_folder = workspace_folder or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h')) + workspace_folder = workspace_folder + or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h')) vim.api.nvim_command('redraw') if not (workspace_folder and #workspace_folder > 0) then return diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 126be2a0ad..0851c080bc 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -302,7 +302,9 @@ function M.get(bufnr, client_id, predicate) end local namespace = M.get_namespace(client_id) - return diagnostic_vim_to_lsp(vim.tbl_filter(predicate, vim.diagnostic.get(bufnr, { namespace = namespace }))) + return diagnostic_vim_to_lsp( + vim.tbl_filter(predicate, vim.diagnostic.get(bufnr, { namespace = namespace })) + ) end --- Get the diagnostics by line @@ -483,7 +485,12 @@ function M.set_signs(diagnostics, bufnr, client_id, _, opts) opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end - vim.diagnostic._set_signs(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts) + vim.diagnostic._set_signs( + namespace, + bufnr, + diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), + opts + ) end --- Set underline for given diagnostics @@ -503,7 +510,12 @@ function M.set_underline(diagnostics, bufnr, client_id, _, opts) if opts and not opts.severity and opts.severity_limit then opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end - return vim.diagnostic._set_underline(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts) + return vim.diagnostic._set_underline( + namespace, + bufnr, + diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), + opts + ) end --- Set virtual text given diagnostics @@ -525,7 +537,12 @@ function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts) if opts and not opts.severity and opts.severity_limit then opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) } end - return vim.diagnostic._set_virtual_text(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts) + return vim.diagnostic._set_virtual_text( + namespace, + bufnr, + diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), + opts + ) end --- Default function to get text chunks to display using |nvim_buf_set_extmark()|. diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index 935f4b64f8..8a64e64396 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -125,7 +125,8 @@ M['workspace/applyEdit'] = function(_, workspace_edit, ctx) if workspace_edit.label then print('Workspace edit', workspace_edit.label) end - local status, result = pcall(util.apply_workspace_edit, workspace_edit.edit, client.offset_encoding) + local status, result = + pcall(util.apply_workspace_edit, workspace_edit.edit, client.offset_encoding) return { applied = status, failureReason = result, @@ -137,7 +138,11 @@ M['workspace/configuration'] = function(_, result, ctx) local client_id = ctx.client_id local client = vim.lsp.get_client_by_id(client_id) if not client then - err_message('LSP[', client_id, '] client has shut down after sending a workspace/configuration request') + err_message( + 'LSP[', + client_id, + '] client has shut down after sending a workspace/configuration request' + ) return end if not result.items then @@ -239,10 +244,14 @@ local function response_to_list(map_result, entity, title_fn) end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol -M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols', function(ctx) - local fname = vim.fn.fnamemodify(vim.uri_to_fname(ctx.params.textDocument.uri), ':.') - return string.format('Symbols in %s', fname) -end) +M['textDocument/documentSymbol'] = response_to_list( + util.symbols_to_items, + 'document symbols', + function(ctx) + local fname = vim.fn.fnamemodify(vim.uri_to_fname(ctx.params.textDocument.uri), ':.') + return string.format('Symbols in %s', fname) + end +) --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols', function(ctx) @@ -391,7 +400,8 @@ function M.signature_help(_, result, ctx, config) return end local client = vim.lsp.get_client_by_id(ctx.client_id) - local triggers = vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters') + local triggers = + vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters') local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype') local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers) lines = util.trim_empty_lines(lines) diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua index bf8fe0932e..ba730e3d6d 100644 --- a/runtime/lua/vim/lsp/health.lua +++ b/runtime/lua/vim/lsp/health.lua @@ -11,7 +11,12 @@ function M.check() report_info(string.format('LSP log level : %s', log_level_string)) if current_log_level < log.levels.WARN then - report_warn(string.format('Log level %s will cause degraded performance and high disk usage', log_level_string)) + report_warn( + string.format( + 'Log level %s will cause degraded performance and high disk usage', + log_level_string + ) + ) end local log_path = vim.lsp.get_log_path() diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 29cb27d373..6c6ba0f206 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -59,7 +59,11 @@ do local log_info = vim.loop.fs_stat(logfilename) if log_info and log_info.size > 1e9 then - local warn_msg = string.format('LSP client log is large (%d MB): %s', log_info.size / (1000 * 1000), logfilename) + local warn_msg = string.format( + 'LSP client log is large (%d MB): %s', + log_info.size / (1000 * 1000), + logfilename + ) vim.notify(warn_msg) end @@ -129,7 +133,8 @@ vim.tbl_add_reverse_lookup(log.levels) ---@param level (string or number) One of `vim.lsp.log.levels` function log.set_level(level) if type(level) == 'string' then - current_log_level = assert(log.levels[level:upper()], string.format('Invalid log level: %q', level)) + current_log_level = + assert(log.levels[level:upper()], string.format('Invalid log level: %q', level)) else assert(type(level) == 'number', 'level must be a number or string') assert(log.levels[level], string.format('Invalid log level: %d', level)) diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 6ecf7891c7..6ecb9959d5 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -880,7 +880,8 @@ function protocol._resolve_capabilities_compat(server_capabilities) general_properties.document_symbol = server_capabilities.documentSymbolProvider or false general_properties.workspace_symbol = server_capabilities.workspaceSymbolProvider or false general_properties.document_formatting = server_capabilities.documentFormattingProvider or false - general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider or false + general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider + or false general_properties.call_hierarchy = server_capabilities.callHierarchyProvider or false general_properties.execute_command = server_capabilities.executeCommandProvider ~= nil @@ -897,7 +898,8 @@ function protocol._resolve_capabilities_compat(server_capabilities) general_properties.code_lens_resolve = false elseif type(server_capabilities.codeLensProvider) == 'table' then general_properties.code_lens = true - general_properties.code_lens_resolve = server_capabilities.codeLensProvider.resolveProvider or false + general_properties.code_lens_resolve = server_capabilities.codeLensProvider.resolveProvider + or false else error('The server sent invalid codeLensProvider') end @@ -974,7 +976,8 @@ function protocol._resolve_capabilities_compat(server_capabilities) signature_help_properties = { signature_help = true, -- The characters that trigger signature help automatically. - signature_help_trigger_characters = server_capabilities.signatureHelpProvider.triggerCharacters or {}, + signature_help_trigger_characters = server_capabilities.signatureHelpProvider.triggerCharacters + or {}, } else error('The server sent invalid signatureHelpProvider') diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index ad2498fb6f..cf74dd2b47 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -115,7 +115,8 @@ local function request_parser_loop() local body_length = #body_chunks[1] -- Keep waiting for data until we have enough. while body_length < content_length do - local chunk = coroutine.yield() or error('Expected more data for the body. The server may have died.') -- TODO hmm. + local chunk = coroutine.yield() + or error('Expected more data for the body. The server may have died.') -- TODO hmm. table.insert(body_chunks, chunk) body_length = body_length + #chunk end @@ -129,10 +130,16 @@ local function request_parser_loop() local body = table.concat(body_chunks) -- Yield our data. buffer = rest - .. (coroutine.yield(headers, body) or error('Expected more data for the body. The server may have died.')) -- TODO hmm. + .. ( + coroutine.yield(headers, body) + or error('Expected more data for the body. The server may have died.') + ) -- TODO hmm. else -- Get more data since we don't have enough. - buffer = buffer .. (coroutine.yield() or error('Expected more data for the header. The server may have died.')) -- TODO hmm. + buffer = buffer + .. ( + coroutine.yield() or error('Expected more data for the header. The server may have died.') + ) -- TODO hmm. end end end @@ -262,7 +269,8 @@ end --- - {handle} A handle for low-level interaction with the LSP server process --- |vim.loop|. local function start(cmd, cmd_args, dispatchers, extra_spawn_params) - local _ = log.info() and log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) + local _ = log.info() + and log.info('Starting RPC client', { cmd = cmd, args = cmd_args, extra = extra_spawn_params }) validate({ cmd = { cmd, 's' }, cmd_args = { cmd_args, 't' }, @@ -336,7 +344,8 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) if handle == nil then local msg = string.format('Spawning language server with cmd: `%s` failed', cmd) if string.match(pid, 'ENOENT') then - msg = msg .. '. The language server is either not installed, missing from PATH, or not executable.' + msg = msg + .. '. The language server is either not installed, missing from PATH, or not executable.' else msg = msg .. string.format(' with error message: %s', pid) end @@ -476,7 +485,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) decoded.params ) local _ = log.debug() - and log.debug('server_request: callback result', { status = status, result = result, err = err }) + and log.debug( + 'server_request: callback result', + { status = status, result = result, err = err } + ) if status then if not (result or err) then -- TODO this can be a problem if `null` is sent for result. needs vim.NIL @@ -488,7 +500,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) ) end if err then - assert(type(err) == 'table', 'err must be a table. Use rpc_response_error to help format errors.') + assert( + type(err) == 'table', + 'err must be a table. Use rpc_response_error to help format errors.' + ) local code_name = assert( protocol.ErrorCodes[err.code], 'Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.' @@ -549,14 +564,25 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) __tostring = format_rpc_error, }) end - try_call(client_errors.SERVER_RESULT_CALLBACK_ERROR, callback, decoded.error, decoded.result) + try_call( + client_errors.SERVER_RESULT_CALLBACK_ERROR, + callback, + decoded.error, + decoded.result + ) else on_error(client_errors.NO_RESULT_CALLBACK_FOUND, decoded) - local _ = log.error() and log.error('No callback found for server response id ' .. result_id) + local _ = log.error() + and log.error('No callback found for server response id ' .. result_id) end elseif type(decoded.method) == 'string' then -- Notification - try_call(client_errors.NOTIFICATION_HANDLER_ERROR, dispatchers.notification, decoded.method, decoded.params) + try_call( + client_errors.NOTIFICATION_HANDLER_ERROR, + dispatchers.notification, + decoded.method, + decoded.params + ) else -- Invalid server message on_error(client_errors.INVALID_SERVER_MESSAGE, decoded) diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua index 73b4e0025a..0d65e86b55 100644 --- a/runtime/lua/vim/lsp/sync.lua +++ b/runtime/lua/vim/lsp/sync.lua @@ -130,7 +130,14 @@ end ---@param new_lastline integer new_lastline from on_lines, adjusted to 1-index ---@param offset_encoding string utf-8|utf-16|utf-32|nil (fallback to utf-8) ---@returns table line_idx, byte_idx, and char_idx of first change position -local function compute_start_range(prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding) +local function compute_start_range( + prev_lines, + curr_lines, + firstline, + lastline, + new_lastline, + offset_encoding +) local char_idx local byte_idx -- If firstline == lastline, no existing text is changed. All edit operations @@ -249,13 +256,19 @@ local function compute_end_range( local max_length if start_line_idx == prev_line_idx then -- Search until beginning of difference - max_length = min(prev_line_length - start_range.byte_idx, curr_line_length - start_range.byte_idx) + 1 + max_length = min( + prev_line_length - start_range.byte_idx, + curr_line_length - start_range.byte_idx + ) + 1 else max_length = min(prev_line_length, curr_line_length) + 1 end for idx = 0, max_length do byte_offset = idx - if str_byte(prev_line, prev_line_length - byte_offset) ~= str_byte(curr_line, curr_line_length - byte_offset) then + if + str_byte(prev_line, prev_line_length - byte_offset) + ~= str_byte(curr_line, curr_line_length - byte_offset) + then break end end @@ -268,8 +281,10 @@ local function compute_end_range( if prev_end_byte_idx == 0 then prev_end_byte_idx = 1 end - local prev_byte_idx, prev_char_idx = align_end_position(prev_line, prev_end_byte_idx, offset_encoding) - local prev_end_range = { line_idx = prev_line_idx, byte_idx = prev_byte_idx, char_idx = prev_char_idx } + local prev_byte_idx, prev_char_idx = + align_end_position(prev_line, prev_end_byte_idx, offset_encoding) + local prev_end_range = + { line_idx = prev_line_idx, byte_idx = prev_byte_idx, char_idx = prev_char_idx } local curr_end_range -- Deletion event, new_range cannot be before start @@ -281,8 +296,10 @@ local function compute_end_range( if curr_end_byte_idx == 0 then curr_end_byte_idx = 1 end - local curr_byte_idx, curr_char_idx = align_end_position(curr_line, curr_end_byte_idx, offset_encoding) - curr_end_range = { line_idx = curr_line_idx, byte_idx = curr_byte_idx, char_idx = curr_char_idx } + local curr_byte_idx, curr_char_idx = + align_end_position(curr_line, curr_end_byte_idx, offset_encoding) + curr_end_range = + { line_idx = curr_line_idx, byte_idx = curr_byte_idx, char_idx = curr_char_idx } end return prev_end_range, curr_end_range @@ -341,7 +358,10 @@ local function compute_range_length(lines, start_range, end_range, offset_encodi local start_line = lines[start_range.line_idx] local range_length if start_line and #start_line > 0 then - range_length = compute_line_length(start_line, offset_encoding) - start_range.char_idx + 1 + line_ending_length + range_length = compute_line_length(start_line, offset_encoding) + - start_range.char_idx + + 1 + + line_ending_length else -- Length of newline character range_length = line_ending_length @@ -373,7 +393,15 @@ end ---@param new_lastline number line to begin search in new_lines for last difference ---@param offset_encoding string encoding requested by language server ---@returns table TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocumentContentChangeEvent -function M.compute_diff(prev_lines, curr_lines, firstline, lastline, new_lastline, offset_encoding, line_ending) +function M.compute_diff( + prev_lines, + curr_lines, + firstline, + lastline, + new_lastline, + offset_encoding, + line_ending +) -- Find the start of changes between the previous and current buffer. Common between both. -- Sent to the server as the start of the changed range. -- Used to grab the changed text from the latest buffer. @@ -403,7 +431,8 @@ function M.compute_diff(prev_lines, curr_lines, firstline, lastline, new_lastlin local text = extract_text(curr_lines, start_range, curr_end_range, line_ending) -- Compute the range of the replaced text. Deprecated but still required for certain language servers - local range_length = compute_range_length(prev_lines, start_range, prev_end_range, offset_encoding, line_ending) + local range_length = + compute_range_length(prev_lines, start_range, prev_end_range, offset_encoding, line_ending) -- convert to 0 based indexing local result = { diff --git a/runtime/lua/vim/lsp/tagfunc.lua b/runtime/lua/vim/lsp/tagfunc.lua index 5c55e8559f..f0ae6a6c49 100644 --- a/runtime/lua/vim/lsp/tagfunc.lua +++ b/runtime/lua/vim/lsp/tagfunc.lua @@ -44,7 +44,8 @@ end ---@private local function query_workspace_symbols(pattern) - local results_by_client, err = lsp.buf_request_sync(0, 'workspace/symbol', { query = pattern }, 1000) + local results_by_client, err = + lsp.buf_request_sync(0, 'workspace/symbol', { query = pattern }, 1000) if err then return {} end diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b041385c9c..b10f0e82f2 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -44,12 +44,22 @@ local function get_border_size(opts) shadow = { 1, 1 }, } if border_size[border] == nil then - error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) + error( + string.format( + 'invalid floating preview border: %s. :help vim.api.nvim_open_win()', + vim.inspect(border) + ) + ) end height, width = unpack(border_size[border]) else if 8 % #border ~= 0 then - error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) + error( + string.format( + 'invalid floating preview border: %s. :help vim.api.nvim_open_win()', + vim.inspect(border) + ) + ) end ---@private local function border_width(id) @@ -61,7 +71,12 @@ local function get_border_size(opts) -- border specified as a list of border characters return vim.fn.strdisplaywidth(border[id]) end - error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) + error( + string.format( + 'invalid floating preview border: %s. :help vim.api.nvim_open_win()', + vim.inspect(border) + ) + ) end ---@private local function border_height(id) @@ -73,7 +88,12 @@ local function get_border_size(opts) -- border specified as a list of border characters return #border[id] > 0 and 1 or 0 end - error(string.format('invalid floating preview border: %s. :help vim.api.nvim_open_win()', vim.inspect(border))) + error( + string.format( + 'invalid floating preview border: %s. :help vim.api.nvim_open_win()', + vim.inspect(border) + ) + ) end height = height + border_height(2) -- top height = height + border_height(6) -- bottom @@ -531,7 +551,10 @@ function M.apply_text_document_edit(text_document_edit, index, offset_encoding) local text_document = text_document_edit.textDocument local bufnr = vim.uri_to_bufnr(text_document.uri) if offset_encoding == nil then - vim.notify_once('apply_text_document_edit must be called with valid offset encoding', vim.log.levels.WARN) + vim.notify_once( + 'apply_text_document_edit must be called with valid offset encoding', + vim.log.levels.WARN + ) end -- For lists of text document edits, @@ -765,7 +788,10 @@ end --see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) if offset_encoding == nil then - vim.notify_once('apply_workspace_edit must be called with valid offset encoding', vim.log.levels.WARN) + vim.notify_once( + 'apply_workspace_edit must be called with valid offset encoding', + vim.log.levels.WARN + ) end if workspace_edit.documentChanges then for idx, change in ipairs(workspace_edit.documentChanges) do @@ -1022,7 +1048,10 @@ function M.jump_to_location(location, offset_encoding, reuse_win) return end if offset_encoding == nil then - vim.notify_once('jump_to_location must be called with valid offset encoding', vim.log.levels.WARN) + vim.notify_once( + 'jump_to_location must be called with valid offset encoding', + vim.log.levels.WARN + ) end local bufnr = vim.uri_to_bufnr(uri) -- Save position in jumplist @@ -1226,14 +1255,21 @@ function M.stylize_markdown(bufnr, contents, opts) -- strip any empty lines or separators prior to this separator in actual markdown if line:match('^---+$') then while - markdown_lines[#stripped] and (stripped[#stripped]:match('^%s*$') or stripped[#stripped]:match('^---+$')) + markdown_lines[#stripped] + and (stripped[#stripped]:match('^%s*$') or stripped[#stripped]:match('^---+$')) do markdown_lines[#stripped] = false table.remove(stripped, #stripped) end end -- add the line if its not an empty line following a separator - if not (line:match('^%s*$') and markdown_lines[#stripped] and stripped[#stripped]:match('^---+$')) then + if + not ( + line:match('^%s*$') + and markdown_lines[#stripped] + and stripped[#stripped]:match('^---+$') + ) + then table.insert(stripped, line) markdown_lines[#stripped] = true end @@ -1265,7 +1301,11 @@ function M.stylize_markdown(bufnr, contents, opts) local function apply_syntax_to_region(ft, start, finish) if ft == '' then vim.cmd( - string.format('syntax region markdownCode start=+\\%%%dl+ end=+\\%%%dl+ keepend extend', start, finish + 1) + string.format( + 'syntax region markdownCode start=+\\%%%dl+ end=+\\%%%dl+ keepend extend', + start, + finish + 1 + ) ) return end @@ -1283,7 +1323,13 @@ function M.stylize_markdown(bufnr, contents, opts) langs[lang] = true end vim.cmd( - string.format('syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend', name, start, finish + 1, lang) + string.format( + 'syntax region %s start=+\\%%%dl+ end=+\\%%%dl+ contains=%s keepend', + name, + start, + finish + 1, + lang + ) ) end @@ -1587,15 +1633,21 @@ do --[[ References ]] offset_encoding = { offset_encoding, 'string', false }, }) for _, reference in ipairs(references) do - local start_line, start_char = reference['range']['start']['line'], reference['range']['start']['character'] - local end_line, end_char = reference['range']['end']['line'], reference['range']['end']['character'] + local start_line, start_char = + reference['range']['start']['line'], reference['range']['start']['character'] + local end_line, end_char = + reference['range']['end']['line'], reference['range']['end']['character'] local start_idx = get_line_byte_from_position( bufnr, { line = start_line, character = start_char }, offset_encoding ) - local end_idx = get_line_byte_from_position(bufnr, { line = start_line, character = end_char }, offset_encoding) + local end_idx = get_line_byte_from_position( + bufnr, + { line = start_line, character = end_char }, + offset_encoding + ) local document_highlight_kind = { [protocol.DocumentHighlightKind.Text] = 'LspReferenceText', @@ -1630,7 +1682,10 @@ end) ---@returns (table) list of items function M.locations_to_items(locations, offset_encoding) if offset_encoding == nil then - vim.notify_once('locations_to_items must be called with valid offset encoding', vim.log.levels.WARN) + vim.notify_once( + 'locations_to_items must be called with valid offset encoding', + vim.log.levels.WARN + ) end local items = {} @@ -1857,7 +1912,10 @@ function M._get_offset_encoding(bufnr) for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do if client.offset_encoding == nil then vim.notify_once( - string.format('Client (id: %s) offset_encoding is nil. Do not unset offset_encoding.', client.id), + string.format( + 'Client (id: %s) offset_encoding is nil. Do not unset offset_encoding.', + client.id + ), vim.log.levels.ERROR ) end @@ -1994,7 +2052,10 @@ end function M.character_offset(buf, row, col, offset_encoding) local line = get_line(buf, row) if offset_encoding == nil then - vim.notify_once('character_offset must be called with valid offset encoding', vim.log.levels.WARN) + vim.notify_once( + 'character_offset must be called with valid offset encoding', + vim.log.levels.WARN + ) end -- If the col is past the EOL, use the line length. if col > #line then diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 9bbe356f03..d6c3e25b3b 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -254,7 +254,11 @@ local function tbl_extend(behavior, deep_extend, ...) end if select('#', ...) < 2 then - error('wrong number of arguments (given ' .. tostring(1 + select('#', ...)) .. ', expected at least 3)') + error( + 'wrong number of arguments (given ' + .. tostring(1 + select('#', ...)) + .. ', expected at least 3)' + ) end local ret = {} @@ -650,7 +654,8 @@ do -- Check user-provided validation function local valid, optional_message = types(val) if not valid then - local error_message = string.format('%s: expected %s, got %s', param_name, (spec[3] or '?'), tostring(val)) + local error_message = + string.format('%s: expected %s, got %s', param_name, (spec[3] or '?'), tostring(val)) if optional_message ~= nil then error_message = error_message .. string.format('. Info: %s', optional_message) end @@ -672,7 +677,13 @@ do end end if not success then - return false, string.format('%s: expected %s, got %s', param_name, table.concat(types, '|'), type(val)) + return false, + string.format( + '%s: expected %s, got %s', + param_name, + table.concat(types, '|'), + type(val) + ) end else return false, string.format('invalid type name: %s', tostring(types)) diff --git a/runtime/lua/vim/treesitter/health.lua b/runtime/lua/vim/treesitter/health.lua index aa9db6b71b..3bd59ca282 100644 --- a/runtime/lua/vim/treesitter/health.lua +++ b/runtime/lua/vim/treesitter/health.lua @@ -26,7 +26,9 @@ function M.check() report_error(string.format('Impossible to load parser for %s: %s', parsername, ret)) elseif ret then local lang = ts.language.inspect_language(parsername) - report_ok(string.format('Loaded parser for %s: ABI version %d', parsername, lang._abi_version)) + report_ok( + string.format('Loaded parser for %s: ABI version %d', parsername, lang._abi_version) + ) else report_error(string.format('Unable to load parser for %s', parsername)) end diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d3da300e96..92352db70e 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -280,7 +280,8 @@ local function on_line_impl(self, buf, line) end if state.iter == nil or state.next_row < line then - state.iter = highlighter_query:query():iter_captures(root_node, self.bufnr, line, root_end_row + 1) + state.iter = + highlighter_query:query():iter_captures(root_node, self.bufnr, line, root_end_row + 1) end while line >= state.next_row do diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 767573e345..4d3b0631a2 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -32,10 +32,8 @@ function LanguageTree.new(source, lang, opts) _regions = {}, _trees = {}, _opts = opts, - _injection_query = injections[lang] and query.parse_query(lang, injections[lang]) or query.get_query( - lang, - 'injections' - ), + _injection_query = injections[lang] and query.parse_query(lang, injections[lang]) + or query.get_query(lang, 'injections'), _valid = false, _parser = vim._create_ts_parser(lang), _callbacks = { -- cgit From 72877bb17d70362f91a60b31bf0244dbf8ed58ae Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Thu, 7 Jul 2022 18:53:47 +0200 Subject: feat(runtime)!: enable filetype.lua by default (#19216) * revert to filetype.vim by setting `g:do_legacy_filetype` * skip either filetype.lua or filetype.vim via `g:did_load_filetypes` (Running both is no longer required and therefore no longer supported.) --- runtime/lua/vim/filetype.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'runtime/lua/vim') diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index fd47e12f07..8e86812347 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -2227,8 +2227,7 @@ end --- --- See $VIMRUNTIME/lua/vim/filetype.lua for more examples. --- ---- Note that Lua filetype detection is only enabled when |g:do_filetype_lua| is ---- set to 1. +--- Note that Lua filetype detection is disabled when |g:do_legacy_filetype| is set. --- --- Example: ---
-- 
cgit 


From 6b1a8f23d7da60aa2fe53cd66760176d2f589690 Mon Sep 17 00:00:00 2001
From: Raphael 
Date: Sun, 10 Jul 2022 00:40:32 +0800
Subject: refactor(lua): replace vim.cmd use with API calls (#19283)

Signed-off-by: Raphael 
---
 runtime/lua/vim/diagnostic.lua             | 72 +++++++++++++-------------
 runtime/lua/vim/highlight.lua              |  2 +
 runtime/lua/vim/lsp/util.lua               | 82 ++++++++++++------------------
 runtime/lua/vim/treesitter/highlighter.lua |  2 +-
 4 files changed, 71 insertions(+), 87 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 07a3c87da0..40991673f3 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -338,6 +338,32 @@ local function make_augroup_key(namespace, bufnr)
   return string.format('DiagnosticInsertLeave:%s:%s', bufnr, ns.name)
 end
 
+---@private
+local function execute_scheduled_display(namespace, bufnr)
+  local args = bufs_waiting_to_update[bufnr][namespace]
+  if not args then
+    return
+  end
+
+  -- Clear the args so we don't display unnecessarily.
+  bufs_waiting_to_update[bufnr][namespace] = nil
+
+  M.show(namespace, bufnr, nil, args)
+end
+
+--- @deprecated
+--- Callback scheduled when leaving Insert mode.
+---
+--- called from the Vimscript autocommand.
+---
+--- See @ref schedule_display()
+---
+---@private
+function M._execute_scheduled_display(namespace, bufnr)
+  vim.deprecate('vim.diagnostic._execute_scheduled_display', nil, '0.9')
+  execute_scheduled_display(namespace, bufnr)
+end
+
 --- Table of autocmd events to fire the update for displaying new diagnostic information
 local insert_leave_auto_cmds = { 'InsertLeave', 'CursorHoldI' }
 
@@ -346,18 +372,15 @@ local function schedule_display(namespace, bufnr, args)
   bufs_waiting_to_update[bufnr][namespace] = args
 
   local key = make_augroup_key(namespace, bufnr)
+  local group = vim.api.nvim_create_augroup(key, { clear = true })
   if not registered_autocmds[key] then
-    vim.cmd(string.format(
-      [[augroup %s
-      au!
-      autocmd %s  lua vim.diagnostic._execute_scheduled_display(%s, %s)
-    augroup END]],
-      key,
-      table.concat(insert_leave_auto_cmds, ','),
-      bufnr,
-      namespace,
-      bufnr
-    ))
+    vim.api.nvim_create_autocmd(insert_leave_auto_cmds, {
+      group = group,
+      buffer = bufnr,
+      callback = function()
+        execute_scheduled_display(namespace, bufnr)
+      end,
+    })
     registered_autocmds[key] = true
   end
 end
@@ -367,12 +390,7 @@ local function clear_scheduled_display(namespace, bufnr)
   local key = make_augroup_key(namespace, bufnr)
 
   if registered_autocmds[key] then
-    vim.cmd(string.format(
-      [[augroup %s
-      au!
-    augroup END]],
-      key
-    ))
+    vim.api.nvim_del_augroup_by_name(key)
     registered_autocmds[key] = nil
   end
 end
@@ -1048,26 +1066,6 @@ function M._get_virt_text_chunks(line_diags, opts)
   end
 end
 
---- Callback scheduled when leaving Insert mode.
----
---- This function must be exported publicly so that it is available to be
---- called from the Vimscript autocommand.
----
---- See @ref schedule_display()
----
----@private
-function M._execute_scheduled_display(namespace, bufnr)
-  local args = bufs_waiting_to_update[bufnr][namespace]
-  if not args then
-    return
-  end
-
-  -- Clear the args so we don't display unnecessarily.
-  bufs_waiting_to_update[bufnr][namespace] = nil
-
-  M.show(namespace, bufnr, nil, args)
-end
-
 --- Hide currently displayed diagnostics.
 ---
 --- This only clears the decorations displayed in the buffer. Diagnostics can
diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua
index e72d45f11c..ddd504a0e0 100644
--- a/runtime/lua/vim/highlight.lua
+++ b/runtime/lua/vim/highlight.lua
@@ -11,6 +11,7 @@ M.priorities = {
 
 ---@private
 function M.create(higroup, hi_info, default)
+  vim.deprecate('vim.highlight.create', 'vim.api.nvim_set_hl', '0.9')
   local options = {}
   -- TODO: Add validation
   for k, v in pairs(hi_info) do
@@ -28,6 +29,7 @@ end
 
 ---@private
 function M.link(higroup, link_to, force)
+  vim.deprecate('vim.highlight.link', 'vim.api.nvim_set_hl', '0.9')
   vim.cmd(string.format([[highlight%s link %s %s]], force and '!' or ' default', higroup, link_to))
 end
 
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index b10f0e82f2..c061cbd216 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1354,50 +1354,12 @@ function M.stylize_markdown(bufnr, contents, opts)
   return stripped
 end
 
----@private
---- Creates autocommands to close a preview window when events happen.
----
----@param events table list of events
----@param winnr number window id of preview window
----@param bufnrs table list of buffers where the preview window will remain visible
----@see |autocmd-events|
-local function close_preview_autocmd(events, winnr, bufnrs)
-  local augroup = 'preview_window_' .. winnr
-
-  -- close the preview window when entered a buffer that is not
-  -- the floating window buffer or the buffer that spawned it
-  vim.cmd(string.format(
-    [[
-    augroup %s
-      autocmd!
-      autocmd BufEnter * lua vim.lsp.util._close_preview_window(%d, {%s})
-    augroup end
-  ]],
-    augroup,
-    winnr,
-    table.concat(bufnrs, ',')
-  ))
-
-  if #events > 0 then
-    vim.cmd(string.format(
-      [[
-      augroup %s
-        autocmd %s  lua vim.lsp.util._close_preview_window(%d)
-      augroup end
-    ]],
-      augroup,
-      table.concat(events, ','),
-      winnr
-    ))
-  end
-end
-
 ---@private
 --- Closes the preview window
 ---
 ---@param winnr number window id of preview window
 ---@param bufnrs table|nil optional list of ignored buffers
-function M._close_preview_window(winnr, bufnrs)
+local function close_preview_window(winnr, bufnrs)
   vim.schedule(function()
     -- exit if we are in one of ignored buffers
     if bufnrs and vim.tbl_contains(bufnrs, api.nvim_get_current_buf()) then
@@ -1405,20 +1367,42 @@ function M._close_preview_window(winnr, bufnrs)
     end
 
     local augroup = 'preview_window_' .. winnr
-    vim.cmd(string.format(
-      [[
-      augroup %s
-        autocmd!
-      augroup end
-      augroup! %s
-    ]],
-      augroup,
-      augroup
-    ))
+    api.nvim_del_augroup_by_name(augroup)
     pcall(vim.api.nvim_win_close, winnr, true)
   end)
 end
 
+---@private
+--- Creates autocommands to close a preview window when events happen.
+---
+---@param events table list of events
+---@param winnr number window id of preview window
+---@param bufnrs table list of buffers where the preview window will remain visible
+---@see |autocmd-events|
+local function close_preview_autocmd(events, winnr, bufnrs)
+  local augroup = api.nvim_create_augroup('preview_window_' .. winnr, {
+    clear = true,
+  })
+
+  -- close the preview window when entered a buffer that is not
+  -- the floating window buffer or the buffer that spawned it
+  api.nvim_create_autocmd('BufEnter', {
+    group = augroup,
+    callback = function()
+      close_preview_window(winnr, bufnrs)
+    end,
+  })
+
+  if #events > 0 then
+    api.nvim_create_autocmd(events, {
+      buffer = bufnrs[2],
+      callback = function()
+        close_preview_window(winnr)
+      end,
+    })
+  end
+end
+
 ---@internal
 --- Computes size of float needed to show contents (with optional wrapping)
 ---
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 92352db70e..e27a5fa9c3 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -16,7 +16,7 @@ local _default_highlights = {}
 local _link_default_highlight_once = function(from, to)
   if not _default_highlights[from] then
     _default_highlights[from] = true
-    vim.cmd(string.format('highlight default link %s %s', from, to))
+    a.nvim_set_hl(0, from, { link = to, default = true })
   end
 
   return from
-- 
cgit 


From 782f7261363f7242cf7472e64434604915fa3075 Mon Sep 17 00:00:00 2001
From: Gregory Anders <8965202+gpanders@users.noreply.github.com>
Date: Sat, 9 Jul 2022 10:42:49 -0600
Subject: refactor: remove functions marked for deprecation in 0.8 (#19299)

---
 runtime/lua/vim/lsp/diagnostic.lua | 481 -------------------------------------
 runtime/lua/vim/lsp/util.lua       |  29 ---
 2 files changed, 510 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 0851c080bc..1f9d084e2b 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -21,17 +21,6 @@ local function get_client_id(client_id)
   return client_id
 end
 
----@private
-local function get_bufnr(bufnr)
-  if not bufnr then
-    return vim.api.nvim_get_current_buf()
-  elseif bufnr == 0 then
-    return vim.api.nvim_get_current_buf()
-  end
-
-  return bufnr
-end
-
 ---@private
 local function severity_lsp_to_vim(severity)
   if type(severity) == 'string' then
@@ -238,75 +227,6 @@ function M.reset(client_id, buffer_client_map)
   end)
 end
 
--- Deprecated Functions {{{
-
---- Save diagnostics to the current buffer.
----
----@deprecated Prefer |vim.diagnostic.set()|
----
---- Handles saving diagnostics from multiple clients in the same buffer.
----@param diagnostics Diagnostic[]
----@param bufnr number
----@param client_id number
----@private
-function M.save(diagnostics, bufnr, client_id)
-  vim.deprecate('vim.lsp.diagnostic.save', 'vim.diagnostic.set', '0.8')
-  local namespace = M.get_namespace(client_id)
-  vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id))
-end
--- }}}
-
---- Get all diagnostics for clients
----
----@deprecated Prefer |vim.diagnostic.get()|
----
----@param client_id number Restrict included diagnostics to the client
----                        If nil, diagnostics of all clients are included.
----@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[])
-function M.get_all(client_id)
-  vim.deprecate('vim.lsp.diagnostic.get_all', 'vim.diagnostic.get', '0.8')
-  local result = {}
-  local namespace
-  if client_id then
-    namespace = M.get_namespace(client_id)
-  end
-  for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
-    local diagnostics = diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, { namespace = namespace }))
-    result[bufnr] = diagnostics
-  end
-  return result
-end
-
---- Return associated diagnostics for bufnr
----
----@deprecated Prefer |vim.diagnostic.get()|
----
----@param bufnr number
----@param client_id number|nil If nil, then return all of the diagnostics.
----                            Else, return just the diagnostics associated with the client_id.
----@param predicate function|nil Optional function for filtering diagnostics
-function M.get(bufnr, client_id, predicate)
-  vim.deprecate('vim.lsp.diagnostic.get', 'vim.diagnostic.get', '0.8')
-  predicate = predicate or function()
-    return true
-  end
-  if client_id == nil then
-    local all_diagnostics = {}
-    vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _)
-      local iter_diagnostics = vim.tbl_filter(predicate, M.get(bufnr, iter_client_id))
-      for _, diagnostic in ipairs(iter_diagnostics) do
-        table.insert(all_diagnostics, diagnostic)
-      end
-    end)
-    return all_diagnostics
-  end
-
-  local namespace = M.get_namespace(client_id)
-  return diagnostic_vim_to_lsp(
-    vim.tbl_filter(predicate, vim.diagnostic.get(bufnr, { namespace = namespace }))
-  )
-end
-
 --- Get the diagnostics by line
 ---
 --- Marked private as this is used internally by the LSP subsystem, but
@@ -344,405 +264,4 @@ function M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
   return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, opts))
 end
 
---- Get the counts for a particular severity
----
----@deprecated Prefer |vim.diagnostic.get_count()|
----
----@param bufnr number The buffer number
----@param severity DiagnosticSeverity
----@param client_id number the client id
-function M.get_count(bufnr, severity, client_id)
-  vim.deprecate('vim.lsp.diagnostic.get_count', 'vim.diagnostic.get', '0.8')
-  severity = severity_lsp_to_vim(severity)
-  local opts = { severity = severity }
-  if client_id ~= nil then
-    opts.namespace = M.get_namespace(client_id)
-  end
-
-  return #vim.diagnostic.get(bufnr, opts)
-end
-
---- Get the previous diagnostic closest to the cursor_position
----
----@deprecated Prefer |vim.diagnostic.get_prev()|
----
----@param opts table See |vim.lsp.diagnostic.goto_next()|
----@return table Previous diagnostic
-function M.get_prev(opts)
-  vim.deprecate('vim.lsp.diagnostic.get_prev', 'vim.diagnostic.get_prev', '0.8')
-  if opts then
-    if opts.severity then
-      opts.severity = severity_lsp_to_vim(opts.severity)
-    elseif opts.severity_limit then
-      opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-    end
-  end
-  return diagnostic_vim_to_lsp({ vim.diagnostic.get_prev(opts) })[1]
-end
-
---- Return the pos, {row, col}, for the prev diagnostic in the current buffer.
----
----@deprecated Prefer |vim.diagnostic.get_prev_pos()|
----
----@param opts table See |vim.lsp.diagnostic.goto_next()|
----@return table Previous diagnostic position
-function M.get_prev_pos(opts)
-  vim.deprecate('vim.lsp.diagnostic.get_prev_pos', 'vim.diagnostic.get_prev_pos', '0.8')
-  if opts then
-    if opts.severity then
-      opts.severity = severity_lsp_to_vim(opts.severity)
-    elseif opts.severity_limit then
-      opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-    end
-  end
-  return vim.diagnostic.get_prev_pos(opts)
-end
-
---- Move to the previous diagnostic
----
----@deprecated Prefer |vim.diagnostic.goto_prev()|
----
----@param opts table See |vim.lsp.diagnostic.goto_next()|
-function M.goto_prev(opts)
-  vim.deprecate('vim.lsp.diagnostic.goto_prev', 'vim.diagnostic.goto_prev', '0.8')
-  if opts then
-    if opts.severity then
-      opts.severity = severity_lsp_to_vim(opts.severity)
-    elseif opts.severity_limit then
-      opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-    end
-  end
-  return vim.diagnostic.goto_prev(opts)
-end
-
---- Get the next diagnostic closest to the cursor_position
----
----@deprecated Prefer |vim.diagnostic.get_next()|
----
----@param opts table See |vim.lsp.diagnostic.goto_next()|
----@return table Next diagnostic
-function M.get_next(opts)
-  vim.deprecate('vim.lsp.diagnostic.get_next', 'vim.diagnostic.get_next', '0.8')
-  if opts then
-    if opts.severity then
-      opts.severity = severity_lsp_to_vim(opts.severity)
-    elseif opts.severity_limit then
-      opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-    end
-  end
-  return diagnostic_vim_to_lsp({ vim.diagnostic.get_next(opts) })[1]
-end
-
---- Return the pos, {row, col}, for the next diagnostic in the current buffer.
----
----@deprecated Prefer |vim.diagnostic.get_next_pos()|
----
----@param opts table See |vim.lsp.diagnostic.goto_next()|
----@return table Next diagnostic position
-function M.get_next_pos(opts)
-  vim.deprecate('vim.lsp.diagnostic.get_next_pos', 'vim.diagnostic.get_next_pos', '0.8')
-  if opts then
-    if opts.severity then
-      opts.severity = severity_lsp_to_vim(opts.severity)
-    elseif opts.severity_limit then
-      opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-    end
-  end
-  return vim.diagnostic.get_next_pos(opts)
-end
-
---- Move to the next diagnostic
----
----@deprecated Prefer |vim.diagnostic.goto_next()|
-function M.goto_next(opts)
-  vim.deprecate('vim.lsp.diagnostic.goto_next', 'vim.diagnostic.goto_next', '0.8')
-  if opts then
-    if opts.severity then
-      opts.severity = severity_lsp_to_vim(opts.severity)
-    elseif opts.severity_limit then
-      opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-    end
-  end
-  return vim.diagnostic.goto_next(opts)
-end
-
---- Set signs for given diagnostics
----
----@deprecated Prefer |vim.diagnostic._set_signs()|
----
----@param diagnostics Diagnostic[]
----@param bufnr number The buffer number
----@param client_id number the client id
----@param sign_ns number|nil
----@param opts table Configuration for signs. Keys:
----             - priority: Set the priority of the signs.
----             - severity_limit (DiagnosticSeverity):
----                 - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
-function M.set_signs(diagnostics, bufnr, client_id, _, opts)
-  vim.deprecate('vim.lsp.diagnostic.set_signs', nil, '0.8')
-  local namespace = M.get_namespace(client_id)
-  if opts and not opts.severity and opts.severity_limit then
-    opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-  end
-
-  vim.diagnostic._set_signs(
-    namespace,
-    bufnr,
-    diagnostic_lsp_to_vim(diagnostics, bufnr, client_id),
-    opts
-  )
-end
-
---- Set underline for given diagnostics
----
----@deprecated Prefer |vim.diagnostic._set_underline()|
----
----@param diagnostics Diagnostic[]
----@param bufnr number: The buffer number
----@param client_id number: The client id
----@param diagnostic_ns number|nil: The namespace
----@param opts table: Configuration table:
----             - severity_limit (DiagnosticSeverity):
----                 - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
-function M.set_underline(diagnostics, bufnr, client_id, _, opts)
-  vim.deprecate('vim.lsp.diagnostic.set_underline', nil, '0.8')
-  local namespace = M.get_namespace(client_id)
-  if opts and not opts.severity and opts.severity_limit then
-    opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-  end
-  return vim.diagnostic._set_underline(
-    namespace,
-    bufnr,
-    diagnostic_lsp_to_vim(diagnostics, bufnr, client_id),
-    opts
-  )
-end
-
---- Set virtual text given diagnostics
----
----@deprecated Prefer |vim.diagnostic._set_virtual_text()|
----
----@param diagnostics Diagnostic[]
----@param bufnr number
----@param client_id number
----@param diagnostic_ns number
----@param opts table Options on how to display virtual text. Keys:
----             - prefix (string): Prefix to display before virtual text on line
----             - spacing (number): Number of spaces to insert before virtual text
----             - severity_limit (DiagnosticSeverity):
----                 - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
-function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts)
-  vim.deprecate('vim.lsp.diagnostic.set_virtual_text', nil, '0.8')
-  local namespace = M.get_namespace(client_id)
-  if opts and not opts.severity and opts.severity_limit then
-    opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-  end
-  return vim.diagnostic._set_virtual_text(
-    namespace,
-    bufnr,
-    diagnostic_lsp_to_vim(diagnostics, bufnr, client_id),
-    opts
-  )
-end
-
---- Default function to get text chunks to display using |nvim_buf_set_extmark()|.
----
----@deprecated Prefer |vim.diagnostic.get_virt_text_chunks()|
----
----@param bufnr number The buffer to display the virtual text in
----@param line number The line number to display the virtual text on
----@param line_diags Diagnostic[] The diagnostics associated with the line
----@param opts table See {opts} from |vim.lsp.diagnostic.set_virtual_text()|
----@return an array of [text, hl_group] arrays. This can be passed directly to
----        the {virt_text} option of |nvim_buf_set_extmark()|.
-function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts)
-  vim.deprecate('vim.lsp.diagnostic.get_virtual_text_chunks_for_line', nil, '0.8')
-  return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts)
-end
-
---- Open a floating window with the diagnostics from {position}
----
----@deprecated Prefer |vim.diagnostic.show_position_diagnostics()|
----
----@param opts table|nil Configuration keys
----         - severity: (DiagnosticSeverity, default nil)
----             - Only return diagnostics with this severity. Overrides severity_limit
----         - severity_limit: (DiagnosticSeverity, default nil)
----             - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
----         - all opts for |show_diagnostics()| can be used here
----@param buf_nr number|nil The buffer number
----@param position table|nil The (0,0)-indexed position
----@return table {popup_bufnr, win_id}
-function M.show_position_diagnostics(opts, buf_nr, position)
-  vim.deprecate('vim.lsp.diagnostic.show_position_diagnostics', 'vim.diagnostic.open_float', '0.8')
-  opts = opts or {}
-  opts.scope = 'cursor'
-  opts.pos = position
-  if opts.severity then
-    opts.severity = severity_lsp_to_vim(opts.severity)
-  elseif opts.severity_limit then
-    opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-  end
-  return vim.diagnostic.open_float(buf_nr, opts)
-end
-
---- Open a floating window with the diagnostics from {line_nr}
----
----@deprecated Prefer |vim.diagnostic.open_float()|
----
----@param opts table Configuration table
----     - all opts for |vim.lsp.diagnostic.get_line_diagnostics()| and
----          |show_diagnostics()| can be used here
----@param buf_nr number|nil The buffer number
----@param line_nr number|nil The line number
----@param client_id number|nil the client id
----@return table {popup_bufnr, win_id}
-function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id)
-  vim.deprecate('vim.lsp.diagnostic.show_line_diagnostics', 'vim.diagnostic.open_float', '0.8')
-  opts = opts or {}
-  opts.scope = 'line'
-  opts.pos = line_nr
-  if client_id then
-    opts.namespace = M.get_namespace(client_id)
-  end
-  return vim.diagnostic.open_float(buf_nr, opts)
-end
-
---- Redraw diagnostics for the given buffer and client
----
----@deprecated Prefer |vim.diagnostic.show()|
----
---- This calls the "textDocument/publishDiagnostics" handler manually using
---- the cached diagnostics already received from the server. This can be useful
---- for redrawing diagnostics after making changes in diagnostics
---- configuration. |lsp-handler-configuration|
----
----@param bufnr (optional, number): Buffer handle, defaults to current
----@param client_id (optional, number): Redraw diagnostics for the given
----       client. The default is to redraw diagnostics for all attached
----       clients.
-function M.redraw(bufnr, client_id)
-  vim.deprecate('vim.lsp.diagnostic.redraw', 'vim.diagnostic.show', '0.8')
-  bufnr = get_bufnr(bufnr)
-  if not client_id then
-    return vim.lsp.for_each_buffer_client(bufnr, function(client)
-      M.redraw(bufnr, client.id)
-    end)
-  end
-
-  local namespace = M.get_namespace(client_id)
-  return vim.diagnostic.show(namespace, bufnr)
-end
-
---- Sets the quickfix list
----
----@deprecated Prefer |vim.diagnostic.setqflist()|
----
----@param opts table|nil Configuration table. Keys:
----         - {open}: (boolean, default true)
----             - Open quickfix list after set
----         - {client_id}: (number)
----             - If nil, will consider all clients attached to buffer.
----         - {severity}: (DiagnosticSeverity)
----             - Exclusive severity to consider. Overrides {severity_limit}
----         - {severity_limit}: (DiagnosticSeverity)
----             - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
----         - {workspace}: (boolean, default true)
----             - Set the list with workspace diagnostics
-function M.set_qflist(opts)
-  vim.deprecate('vim.lsp.diagnostic.set_qflist', 'vim.diagnostic.setqflist', '0.8')
-  opts = opts or {}
-  if opts.severity then
-    opts.severity = severity_lsp_to_vim(opts.severity)
-  elseif opts.severity_limit then
-    opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-  end
-  if opts.client_id then
-    opts.client_id = nil
-    opts.namespace = M.get_namespace(opts.client_id)
-  end
-  local workspace = vim.F.if_nil(opts.workspace, true)
-  opts.bufnr = not workspace and 0
-  return vim.diagnostic.setqflist(opts)
-end
-
---- Sets the location list
----
----@deprecated Prefer |vim.diagnostic.setloclist()|
----
----@param opts table|nil Configuration table. Keys:
----         - {open}: (boolean, default true)
----             - Open loclist after set
----         - {client_id}: (number)
----             - If nil, will consider all clients attached to buffer.
----         - {severity}: (DiagnosticSeverity)
----             - Exclusive severity to consider. Overrides {severity_limit}
----         - {severity_limit}: (DiagnosticSeverity)
----             - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
----         - {workspace}: (boolean, default false)
----             - Set the list with workspace diagnostics
-function M.set_loclist(opts)
-  vim.deprecate('vim.lsp.diagnostic.set_loclist', 'vim.diagnostic.setloclist', '0.8')
-  opts = opts or {}
-  if opts.severity then
-    opts.severity = severity_lsp_to_vim(opts.severity)
-  elseif opts.severity_limit then
-    opts.severity = { min = severity_lsp_to_vim(opts.severity_limit) }
-  end
-  if opts.client_id then
-    opts.client_id = nil
-    opts.namespace = M.get_namespace(opts.client_id)
-  end
-  local workspace = vim.F.if_nil(opts.workspace, false)
-  opts.bufnr = not workspace and 0
-  return vim.diagnostic.setloclist(opts)
-end
-
---- Disable diagnostics for the given buffer and client
----
----@deprecated Prefer |vim.diagnostic.disable()|
----
----@param bufnr (optional, number): Buffer handle, defaults to current
----@param client_id (optional, number): Disable diagnostics for the given
----       client. The default is to disable diagnostics for all attached
----       clients.
--- Note that when diagnostics are disabled for a buffer, the server will still
--- send diagnostic information and the client will still process it. The
--- diagnostics are simply not displayed to the user.
-function M.disable(bufnr, client_id)
-  vim.deprecate('vim.lsp.diagnostic.disable', 'vim.diagnostic.disable', '0.8')
-  if not client_id then
-    return vim.lsp.for_each_buffer_client(bufnr, function(client)
-      M.disable(bufnr, client.id)
-    end)
-  end
-
-  bufnr = get_bufnr(bufnr)
-  local namespace = M.get_namespace(client_id)
-  return vim.diagnostic.disable(bufnr, namespace)
-end
-
---- Enable diagnostics for the given buffer and client
----
----@deprecated Prefer |vim.diagnostic.enable()|
----
----@param bufnr (optional, number): Buffer handle, defaults to current
----@param client_id (optional, number): Enable diagnostics for the given
----       client. The default is to enable diagnostics for all attached
----       clients.
-function M.enable(bufnr, client_id)
-  vim.deprecate('vim.lsp.diagnostic.enable', 'vim.diagnostic.enable', '0.8')
-  if not client_id then
-    return vim.lsp.for_each_buffer_client(bufnr, function(client)
-      M.enable(bufnr, client.id)
-    end)
-  end
-
-  bufnr = get_bufnr(bufnr)
-  local namespace = M.get_namespace(client_id)
-  return vim.diagnostic.enable(bufnr, namespace)
-end
-
--- }}}
-
 return M
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index c061cbd216..73476c0795 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1722,35 +1722,6 @@ function M.locations_to_items(locations, offset_encoding)
   return items
 end
 
---- Fills target window's location list with given list of items.
---- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
---- Defaults to current window.
----
----@deprecated Use |setloclist()|
----
----@param items (table) list of items
-function M.set_loclist(items, win_id)
-  vim.deprecate('vim.lsp.util.set_loclist', 'setloclist', '0.8')
-  vim.fn.setloclist(win_id or 0, {}, ' ', {
-    title = 'Language Server',
-    items = items,
-  })
-end
-
---- Fills quickfix list with given list of items.
---- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
----
----@deprecated Use |setqflist()|
----
----@param items (table) list of items
-function M.set_qflist(items)
-  vim.deprecate('vim.lsp.util.set_qflist', 'setqflist', '0.8')
-  vim.fn.setqflist({}, ' ', {
-    title = 'Language Server',
-    items = items,
-  })
-end
-
 -- According to LSP spec, if the client set "symbolKind.valueSet",
 -- the client must handle it properly even if it receives a value outside the specification.
 -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
-- 
cgit 


From d606c39a9cadcf2d627e93b1bdf18bea359d1c63 Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sun, 10 Jul 2022 01:14:07 +0200
Subject: vim-patch:9.0.0049: csv and tsv files are not recognized (#19300)

Problem:    Csv and tsv files are not recognized.
Solution:   Add patterns fo csv and tsv files. (Leandro Lourenci,
            closes vim/vim#10680)
https://github.com/vim/vim/commit/99af91e5820c78a196c9272cd8ce5aa5be7bf374
---
 runtime/lua/vim/filetype.lua | 2 ++
 1 file changed, 2 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 8e86812347..9ba036ca92 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -259,6 +259,7 @@ local extension = {
   fdr = 'csp',
   csp = 'csp',
   css = 'css',
+  csv = 'csv',
   con = 'cterm',
   feature = 'cucumber',
   cuh = 'cuda',
@@ -974,6 +975,7 @@ local extension = {
   tsscl = 'tsscl',
   tssgm = 'tssgm',
   tssop = 'tssop',
+  tsv = 'tsv',
   tutor = 'tutor',
   twig = 'twig',
   ts = function(path, bufnr)
-- 
cgit 


From 2966cfe21f8e19f684caf8e9253f40dad107f5ba Mon Sep 17 00:00:00 2001
From: Christian Clason 
Date: Sun, 10 Jul 2022 11:19:26 +0200
Subject: fix(lsp): pcall nvim_del_augroup_by_name (#19302)

fixup for #19283
---
 runtime/lua/vim/lsp/util.lua | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 73476c0795..6f2b95514a 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1367,8 +1367,8 @@ local function close_preview_window(winnr, bufnrs)
     end
 
     local augroup = 'preview_window_' .. winnr
-    api.nvim_del_augroup_by_name(augroup)
-    pcall(vim.api.nvim_win_close, winnr, true)
+    pcall(api.nvim_del_augroup_by_name, augroup)
+    pcall(api.nvim_win_close, winnr, true)
   end)
 end
 
-- 
cgit 


From 95c65a6b221fe6e1cf91e8322e7d7571dc511a71 Mon Sep 17 00:00:00 2001
From: Mathias Fußenegger 
Date: Sun, 10 Jul 2022 17:26:43 +0200
Subject: feat(lsp): defaults: tagfunc, omnifunc (#19003)

set `tagfunc` to `vim.lsp.tagfunc` and `omnifunc` to `vim.lsp.omnifunc` if empty when attaching a server
---
 runtime/lua/vim/lsp.lua | 31 ++++++++++++++++++++++++++++++-
 1 file changed, 30 insertions(+), 1 deletion(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 75c3b63da7..e11f127f47 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -562,7 +562,7 @@ end
 ---@private
 --- Default handler for the 'textDocument/didOpen' LSP notification.
 ---
----@param bufnr (Number) Number of the buffer, or 0 for current
+---@param bufnr number Number of the buffer, or 0 for current
 ---@param client Client object
 local function text_document_did_open_handler(bufnr, client)
   changetracking.init(client, bufnr)
@@ -947,6 +947,28 @@ function lsp.start_client(config)
     end
   end
 
+  ---@private
+  local function set_defaults(client, bufnr)
+    if client.server_capabilities.definitionProvider and vim.bo[bufnr].tagfunc == '' then
+      vim.bo[bufnr].tagfunc = 'v:lua.vim.lsp.tagfunc'
+    end
+    if client.server_capabilities.completionProvider and vim.bo[bufnr].omnifunc == '' then
+      vim.bo[bufnr].omnifunc = 'v:lua.vim.lsp.omnifunc'
+    end
+  end
+
+  ---@private
+  --- Reset defaults set by `set_defaults`.
+  --- Must only be called if the last client attached to a buffer exits.
+  local function unset_defaults(bufnr)
+    if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then
+      vim.bo[bufnr].tagfunc = nil
+    end
+    if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then
+      vim.bo[bufnr].omnifunc = nil
+    end
+  end
+
   ---@private
   --- Invoked on client exit.
   ---
@@ -972,6 +994,11 @@ function lsp.start_client(config)
 
         client_ids[client_id] = nil
       end
+      if vim.tbl_isempty(client_ids) then
+        vim.schedule(function()
+          unset_defaults(bufnr)
+        end)
+      end
     end
 
     active_clients[client_id] = nil
@@ -1325,6 +1352,8 @@ function lsp.start_client(config)
   function client._on_attach(bufnr)
     text_document_did_open_handler(bufnr, client)
 
+    set_defaults(client, bufnr)
+
     nvim_exec_autocmds('LspAttach', {
       buffer = bufnr,
       modeline = false,
-- 
cgit 


From ac10c0f4184a04c82b8e039c546ab32f4a629e30 Mon Sep 17 00:00:00 2001
From: Rishikesh Vaishnav 
Date: Mon, 11 Jul 2022 03:48:02 -0700
Subject: fix(lsp): abort pending changes after flush when debouncing (#19314)

Issuing a server request triggers `changetracking.flush` so as to
make sure we're not operating on a stale state. This immediately
triggers notification of any pending changes (as a result of debouncing)
to the server. However, this happens in addition to the notification
that is waiting on the debounce delay. Because we `nil`
`buf_state.pending_change` when it is called, the fix is to
also check that this is non-`nil` when it is called and exit if it is,
as this being `nil` would mean that it originates from a pending change
that has already been flushed out.
---
 runtime/lua/vim/lsp.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index e11f127f47..554b5f0bfa 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -500,6 +500,9 @@ do
         table.insert(buf_state.pending_changes, incremental_changes(client, buf_state))
       end
       buf_state.pending_change = function()
+        if buf_state.pending_change == nil then
+          return
+        end
         buf_state.pending_change = nil
         buf_state.last_flush = uv.hrtime()
         if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then
-- 
cgit 


From 034d28c705ccb93dea27613cbf91ba3f9c1caaa7 Mon Sep 17 00:00:00 2001
From: Nicolas Hillegeer 
Date: Tue, 12 Jul 2022 03:37:01 +0200
Subject: fix(lsp): don't attach a client in lsp.start() if there is none
 (#19328)

vim.lsp.start_client() may fail (for example if the `cmd` is not
executable). It produces a nice error notification in this case. Passing
the `nil` value returned from an erroneous `vim.lsp.start_client()` call
into `vim.lsp.buf_attach_client()` causes a meaty param validate
exception message. Avoid this.
---
 runtime/lua/vim/lsp.lua | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 554b5f0bfa..29b077e3c0 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -746,6 +746,9 @@ function lsp.start(config, opts)
     end
   end
   local client_id = lsp.start_client(config)
+  if client_id == nil then
+    return nil -- lsp.start_client will have printed an error
+  end
   lsp.buf_attach_client(bufnr, client_id)
   return client_id
 end
-- 
cgit 


From 0f1b17788eb584f41d59c12c968f5e1886655334 Mon Sep 17 00:00:00 2001
From: Nicolas Hillegeer 
Date: Tue, 12 Jul 2022 09:44:11 +0200
Subject: fix(lsp): account for initializing servers in vim.lsp.start (#19329)

Fixes #19326
---
 runtime/lua/vim/lsp.lua | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 29b077e3c0..0e72aae188 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -739,10 +739,12 @@ function lsp.start(config, opts)
     end
   config.name = config.name or (config.cmd[1] and vim.fs.basename(config.cmd[1])) or nil
   local bufnr = api.nvim_get_current_buf()
-  for _, client in pairs(lsp.get_active_clients()) do
-    if reuse_client(client, config) then
-      lsp.buf_attach_client(bufnr, client.id)
-      return client.id
+  for _, clients in ipairs({ uninitialized_clients, lsp.get_active_clients() }) do
+    for _, client in pairs(clients) do
+      if reuse_client(client, config) then
+        lsp.buf_attach_client(bufnr, client.id)
+        return client.id
+      end
     end
   end
   local client_id = lsp.start_client(config)
-- 
cgit 


From ddaef0618dbe4f55ed5eed50440ff6d06e48f02a Mon Sep 17 00:00:00 2001
From: Stephan Seitz 
Date: Thu, 14 Jul 2022 12:18:03 +0200
Subject: fix(treesitter): don't error when node argument of predicate is nil
 (#19355)

When the node mentioned in a predicate is not required for the query
then predicates putting restrictions on that node shouldn't run.

Fixes https://github.com/nvim-treesitter/nvim-treesitter/issues/2600
---
 runtime/lua/vim/treesitter/query.lua | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 0cc2b6d2a4..103e85abfd 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -221,6 +221,9 @@ end
 local predicate_handlers = {
   ['eq?'] = function(match, _, source, predicate)
     local node = match[predicate[2]]
+    if not node then
+      return true
+    end
     local node_text = M.get_node_text(node, source)
 
     local str
@@ -241,6 +244,9 @@ local predicate_handlers = {
 
   ['lua-match?'] = function(match, _, source, predicate)
     local node = match[predicate[2]]
+    if not node then
+      return true
+    end
     local regex = predicate[3]
     return string.find(M.get_node_text(node, source), regex)
   end,
@@ -265,6 +271,9 @@ local predicate_handlers = {
 
     return function(match, _, source, pred)
       local node = match[pred[2]]
+      if not node then
+        return true
+      end
       local regex = compiled_vim_regexes[pred[3]]
       return regex:match_str(M.get_node_text(node, source))
     end
@@ -272,6 +281,9 @@ local predicate_handlers = {
 
   ['contains?'] = function(match, _, source, predicate)
     local node = match[predicate[2]]
+    if not node then
+      return true
+    end
     local node_text = M.get_node_text(node, source)
 
     for i = 3, #predicate do
@@ -285,6 +297,9 @@ local predicate_handlers = {
 
   ['any-of?'] = function(match, _, source, predicate)
     local node = match[predicate[2]]
+    if not node then
+      return true
+    end
     local node_text = M.get_node_text(node, source)
 
     -- Since 'predicate' will not be used by callers of this function, use it
-- 
cgit 


From 8a5c7e91f21b9f49c5443105e694056a65bf761e Mon Sep 17 00:00:00 2001
From: ii14 
Date: Sun, 10 Jul 2022 01:57:35 +0200
Subject: refactor(lsp): make the use of local aliases more consistent

---
 runtime/lua/vim/lsp.lua          |  40 +++++-----
 runtime/lua/vim/lsp/buf.lua      |  36 ++++-----
 runtime/lua/vim/lsp/codelens.lua |  26 +++---
 runtime/lua/vim/lsp/handlers.lua |  28 +++----
 runtime/lua/vim/lsp/rpc.lua      |   2 +-
 runtime/lua/vim/lsp/tagfunc.lua  |   4 +-
 runtime/lua/vim/lsp/util.lua     | 168 +++++++++++++++++++--------------------
 7 files changed, 152 insertions(+), 152 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 0e72aae188..f6870cbd94 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -4,15 +4,15 @@ local lsp_rpc = require('vim.lsp.rpc')
 local protocol = require('vim.lsp.protocol')
 local util = require('vim.lsp.util')
 local sync = require('vim.lsp.sync')
-local api = vim.api
 
 local vim = vim
+local a = vim.api
 local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option, nvim_exec_autocmds =
-  vim.api.nvim_err_writeln,
-  vim.api.nvim_buf_get_lines,
-  vim.api.nvim_command,
-  vim.api.nvim_buf_get_option,
-  vim.api.nvim_exec_autocmds
+  a.nvim_err_writeln,
+  a.nvim_buf_get_lines,
+  a.nvim_command,
+  a.nvim_buf_get_option,
+  a.nvim_exec_autocmds
 local uv = vim.loop
 local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend
 local validate = vim.validate
@@ -79,7 +79,7 @@ end
 local function resolve_bufnr(bufnr)
   validate({ bufnr = { bufnr, 'n', true } })
   if bufnr == nil or bufnr == 0 then
-    return vim.api.nvim_get_current_buf()
+    return a.nvim_get_current_buf()
   end
   return bufnr
 end
@@ -216,7 +216,7 @@ end
 ---@returns (string) the command
 ---@returns (list of strings) its arguments
 function lsp._cmd_parts(input)
-  vim.validate({
+  validate({
     cmd = {
       input,
       function()
@@ -230,7 +230,7 @@ function lsp._cmd_parts(input)
   local cmd_args = {}
   -- Don't mutate our input.
   for i, v in ipairs(input) do
-    vim.validate({ ['cmd argument'] = { v, 's' } })
+    validate({ ['cmd argument'] = { v, 's' } })
     if i > 1 then
       table.insert(cmd_args, v)
     end
@@ -505,7 +505,7 @@ do
         end
         buf_state.pending_change = nil
         buf_state.last_flush = uv.hrtime()
-        if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then
+        if client.is_stopped() or not a.nvim_buf_is_valid(bufnr) then
           return
         end
         local changes = state.use_incremental_sync and buf_state.pending_changes
@@ -522,7 +522,7 @@ do
       if debounce == 0 then
         buf_state.pending_change()
       else
-        local timer = vim.loop.new_timer()
+        local timer = uv.new_timer()
         buf_state.timer = timer
         -- Must use schedule_wrap because `full_changes()` calls nvim_buf_get_lines
         timer:start(debounce, 0, vim.schedule_wrap(buf_state.pending_change))
@@ -572,7 +572,7 @@ local function text_document_did_open_handler(bufnr, client)
   if not vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then
     return
   end
-  if not vim.api.nvim_buf_is_loaded(bufnr) then
+  if not a.nvim_buf_is_loaded(bufnr) then
     return
   end
   local filetype = nvim_buf_get_option(bufnr, 'filetype')
@@ -592,7 +592,7 @@ local function text_document_did_open_handler(bufnr, client)
   vim.schedule(function()
     -- Protect against a race where the buffer disappears
     -- between `did_open_handler` and the scheduled function firing.
-    if vim.api.nvim_buf_is_valid(bufnr) then
+    if a.nvim_buf_is_valid(bufnr) then
       local namespace = vim.lsp.diagnostic.get_namespace(client.id)
       vim.diagnostic.show(namespace, bufnr)
     end
@@ -738,7 +738,7 @@ function lsp.start(config, opts)
       return client.config.root_dir == conf.root_dir and client.name == conf.name
     end
   config.name = config.name or (config.cmd[1] and vim.fs.basename(config.cmd[1])) or nil
-  local bufnr = api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
   for _, clients in ipairs({ uninitialized_clients, lsp.get_active_clients() }) do
     for _, client in pairs(clients) do
       if reuse_client(client, config) then
@@ -1433,7 +1433,7 @@ function lsp.buf_attach_client(bufnr, client_id)
     client_id = { client_id, 'n' },
   })
   bufnr = resolve_bufnr(bufnr)
-  if not vim.api.nvim_buf_is_loaded(bufnr) then
+  if not a.nvim_buf_is_loaded(bufnr) then
     local _ = log.warn()
       and log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
     return false
@@ -1451,9 +1451,9 @@ function lsp.buf_attach_client(bufnr, client_id)
         au BufWritePost  lua vim.lsp._text_document_did_save_handler(0)
       augroup END
     ]=]
-    vim.api.nvim_exec(string.format(buf_did_save_autocommand, client_id, bufnr, bufnr), false)
+    a.nvim_exec(string.format(buf_did_save_autocommand, client_id, bufnr, bufnr), false)
     -- First time, so attach and set up stuff.
-    vim.api.nvim_buf_attach(bufnr, false, {
+    a.nvim_buf_attach(bufnr, false, {
       on_lines = text_document_did_change_handler,
       on_reload = function()
         local params = { textDocument = { uri = uri } }
@@ -1723,7 +1723,7 @@ function lsp.buf_request(bufnr, method, params, handler)
     not tbl_isempty(all_buffer_active_clients[resolve_bufnr(bufnr)] or {}) and not method_supported
   then
     vim.notify(lsp._unsupported_method(method), vim.log.levels.ERROR)
-    vim.api.nvim_command('redraw')
+    nvim_command('redraw')
     return {}, function() end
   end
 
@@ -1888,8 +1888,8 @@ function lsp.omnifunc(findstart, base)
   -- Then, perform standard completion request
   local _ = log.info() and log.info('base ', base)
 
-  local pos = vim.api.nvim_win_get_cursor(0)
-  local line = vim.api.nvim_get_current_line()
+  local pos = a.nvim_win_get_cursor(0)
+  local line = a.nvim_get_current_line()
   local line_to_cursor = line:sub(1, pos[2])
   local _ = log.trace() and log.trace('omnifunc.line', pos, line)
 
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 981aebada1..50e77cb7ca 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -1,6 +1,6 @@
 local vim = vim
+local a = vim.api
 local validate = vim.validate
-local vfn = vim.fn
 local util = require('vim.lsp.util')
 
 local M = {}
@@ -201,7 +201,7 @@ end
 
 function M.format(options)
   options = options or {}
-  local bufnr = options.bufnr or vim.api.nvim_get_current_buf()
+  local bufnr = options.bufnr or a.nvim_get_current_buf()
   local clients = vim.lsp.get_active_clients({
     id = options.id,
     bufnr = bufnr,
@@ -262,7 +262,7 @@ function M.formatting(options)
     vim.log.levels.WARN
   )
   local params = util.make_formatting_params(options)
-  local bufnr = vim.api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
   select_client('textDocument/formatting', function(client)
     if client == nil then
       return
@@ -290,7 +290,7 @@ function M.formatting_sync(options, timeout_ms)
     vim.log.levels.WARN
   )
   local params = util.make_formatting_params(options)
-  local bufnr = vim.api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
   select_client('textDocument/formatting', function(client)
     if client == nil then
       return
@@ -327,7 +327,7 @@ function M.formatting_seq_sync(options, timeout_ms, order)
     vim.log.levels.WARN
   )
   local clients = vim.tbl_values(vim.lsp.buf_get_clients())
-  local bufnr = vim.api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
 
   -- sort the clients according to `order`
   for _, client_name in pairs(order or {}) do
@@ -348,7 +348,7 @@ function M.formatting_seq_sync(options, timeout_ms, order)
         'textDocument/formatting',
         params,
         timeout_ms,
-        vim.api.nvim_get_current_buf()
+        a.nvim_get_current_buf()
       )
       if result and result.result then
         util.apply_text_edits(result.result, bufnr, client.offset_encoding)
@@ -394,7 +394,7 @@ end
 ---         this field.
 function M.rename(new_name, options)
   options = options or {}
-  local bufnr = options.bufnr or vim.api.nvim_get_current_buf()
+  local bufnr = options.bufnr or a.nvim_get_current_buf()
   local clients = vim.lsp.get_active_clients({
     bufnr = bufnr,
     name = options.name,
@@ -412,14 +412,14 @@ function M.rename(new_name, options)
     vim.notify('[LSP] Rename, no matching language servers with rename capability.')
   end
 
-  local win = vim.api.nvim_get_current_win()
+  local win = a.nvim_get_current_win()
 
   -- Compute early to account for cursor movements after going async
-  local cword = vfn.expand('')
+  local cword = vim.fn.expand('')
 
   ---@private
   local function get_text_at_range(range, offset_encoding)
-    return vim.api.nvim_buf_get_text(
+    return a.nvim_buf_get_text(
       bufnr,
       range.start.line,
       util._get_line_byte_from_position(bufnr, range.start, offset_encoding),
@@ -603,8 +603,8 @@ end
 --- not provided, the user will be prompted for a path using |input()|.
 function M.add_workspace_folder(workspace_folder)
   workspace_folder = workspace_folder
-    or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h'), 'dir')
-  vim.api.nvim_command('redraw')
+    or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'), 'dir')
+  a.nvim_command('redraw')
   if not (workspace_folder and #workspace_folder > 0) then
     return
   end
@@ -640,8 +640,8 @@ end
 --- a path using |input()|.
 function M.remove_workspace_folder(workspace_folder)
   workspace_folder = workspace_folder
-    or npcall(vfn.input, 'Workspace Folder: ', vfn.expand('%:p:h'))
-  vim.api.nvim_command('redraw')
+    or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'))
+  a.nvim_command('redraw')
   if not (workspace_folder and #workspace_folder > 0) then
     return
   end
@@ -669,7 +669,7 @@ end
 ---
 ---@param query (string, optional)
 function M.workspace_symbol(query)
-  query = query or npcall(vfn.input, 'Query: ')
+  query = query or npcall(vim.fn.input, 'Query: ')
   if query == nil then
     return
   end
@@ -838,7 +838,7 @@ end
 --- with all aggregated results
 ---@private
 local function code_action_request(params, options)
-  local bufnr = vim.api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
   local method = 'textDocument/codeAction'
   vim.lsp.buf_request_all(bufnr, method, params, function(results)
     local ctx = { bufnr = bufnr, method = method, params = params }
@@ -875,7 +875,7 @@ function M.code_action(options)
   end
   local context = options.context or {}
   if not context.diagnostics then
-    local bufnr = vim.api.nvim_get_current_buf()
+    local bufnr = a.nvim_get_current_buf()
     context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
   end
   local params = util.make_range_params()
@@ -902,7 +902,7 @@ function M.range_code_action(context, start_pos, end_pos)
   validate({ context = { context, 't', true } })
   context = context or {}
   if not context.diagnostics then
-    local bufnr = vim.api.nvim_get_current_buf()
+    local bufnr = a.nvim_get_current_buf()
     context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
   end
   local params = util.make_given_range_params(start_pos, end_pos)
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index 4fa02c8db2..0e48bd85f8 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -1,6 +1,6 @@
 local util = require('vim.lsp.util')
 local log = require('vim.lsp.log')
-local api = vim.api
+local a = vim.api
 local M = {}
 
 --- bufnr → true|nil
@@ -10,14 +10,14 @@ local active_refreshes = {}
 --- bufnr -> client_id -> lenses
 local lens_cache_by_buf = setmetatable({}, {
   __index = function(t, b)
-    local key = b > 0 and b or api.nvim_get_current_buf()
+    local key = b > 0 and b or a.nvim_get_current_buf()
     return rawget(t, key)
   end,
 })
 
 local namespaces = setmetatable({}, {
   __index = function(t, key)
-    local value = api.nvim_create_namespace('vim_lsp_codelens:' .. key)
+    local value = a.nvim_create_namespace('vim_lsp_codelens:' .. key)
     rawset(t, key, value)
     return value
   end,
@@ -29,7 +29,7 @@ M.__namespaces = namespaces
 ---@private
 local function execute_lens(lens, bufnr, client_id)
   local line = lens.range.start.line
-  api.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1)
+  a.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1)
 
   local client = vim.lsp.get_client_by_id(client_id)
   assert(client, 'Client is required to execute lens, client_id=' .. client_id)
@@ -78,8 +78,8 @@ end
 --- Run the code lens in the current line
 ---
 function M.run()
-  local line = api.nvim_win_get_cursor(0)[1]
-  local bufnr = api.nvim_get_current_buf()
+  local line = a.nvim_win_get_cursor(0)[1]
+  local bufnr = a.nvim_get_current_buf()
   local options = {}
   local lenses_by_client = lens_cache_by_buf[bufnr] or {}
   for client, lenses in pairs(lenses_by_client) do
@@ -127,10 +127,10 @@ function M.display(lenses, bufnr, client_id)
     table.insert(line_lenses, lens)
   end
   local ns = namespaces[client_id]
-  local num_lines = api.nvim_buf_line_count(bufnr)
+  local num_lines = a.nvim_buf_line_count(bufnr)
   for i = 0, num_lines do
     local line_lenses = lenses_by_lnum[i] or {}
-    api.nvim_buf_clear_namespace(bufnr, ns, i, i + 1)
+    a.nvim_buf_clear_namespace(bufnr, ns, i, i + 1)
     local chunks = {}
     local num_line_lenses = #line_lenses
     table.sort(line_lenses, function(a, b)
@@ -144,7 +144,7 @@ function M.display(lenses, bufnr, client_id)
       end
     end
     if #chunks > 0 then
-      api.nvim_buf_set_extmark(bufnr, ns, i, 0, {
+      a.nvim_buf_set_extmark(bufnr, ns, i, 0, {
         virt_text = chunks,
         hl_mode = 'combine',
       })
@@ -163,12 +163,12 @@ function M.save(lenses, bufnr, client_id)
     lenses_by_client = {}
     lens_cache_by_buf[bufnr] = lenses_by_client
     local ns = namespaces[client_id]
-    api.nvim_buf_attach(bufnr, false, {
+    a.nvim_buf_attach(bufnr, false, {
       on_detach = function(b)
         lens_cache_by_buf[b] = nil
       end,
       on_lines = function(_, b, _, first_lnum, last_lnum)
-        api.nvim_buf_clear_namespace(b, ns, first_lnum, last_lnum)
+        a.nvim_buf_clear_namespace(b, ns, first_lnum, last_lnum)
       end,
     })
   end
@@ -203,7 +203,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback)
           -- Eager display to have some sort of incremental feedback
           -- Once all lenses got resolved there will be a full redraw for all lenses
           -- So that multiple lens per line are properly displayed
-          api.nvim_buf_set_extmark(
+          a.nvim_buf_set_extmark(
             bufnr,
             ns,
             lens.range.start.line,
@@ -249,7 +249,7 @@ function M.refresh()
   local params = {
     textDocument = util.make_text_document_params(),
   }
-  local bufnr = api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
   if active_refreshes[bufnr] then
     return
   end
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 8a64e64396..3c43676850 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -2,7 +2,7 @@ local log = require('vim.lsp.log')
 local protocol = require('vim.lsp.protocol')
 local util = require('vim.lsp.util')
 local vim = vim
-local api = vim.api
+local a = vim.api
 
 local M = {}
 
@@ -13,7 +13,7 @@ local M = {}
 ---@param ... (table of strings) Will be concatenated before being written
 local function err_message(...)
   vim.notify(table.concat(vim.tbl_flatten({ ... })), vim.log.levels.ERROR)
-  api.nvim_command('redraw')
+  a.nvim_command('redraw')
 end
 
 --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
@@ -61,7 +61,7 @@ local function progress_handler(_, result, ctx, _)
     client.messages.progress[token].done = true
   end
 
-  vim.api.nvim_command('doautocmd  User LspProgressUpdate')
+  a.nvim_command('doautocmd  User LspProgressUpdate')
 end
 
 --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
@@ -195,14 +195,14 @@ M['textDocument/references'] = function(_, result, ctx, config)
         items = util.locations_to_items(result, client.offset_encoding),
         context = ctx,
       })
-      api.nvim_command('lopen')
+      a.nvim_command('lopen')
     else
       vim.fn.setqflist({}, ' ', {
         title = 'References',
         items = util.locations_to_items(result, client.offset_encoding),
         context = ctx,
       })
-      api.nvim_command('botright copen')
+      a.nvim_command('botright copen')
     end
   end
 end
@@ -230,14 +230,14 @@ local function response_to_list(map_result, entity, title_fn)
           items = map_result(result, ctx.bufnr),
           context = ctx,
         })
-        api.nvim_command('lopen')
+        a.nvim_command('lopen')
       else
         vim.fn.setqflist({}, ' ', {
           title = title_fn(ctx),
           items = map_result(result, ctx.bufnr),
           context = ctx,
         })
-        api.nvim_command('botright copen')
+        a.nvim_command('botright copen')
       end
     end
   end
@@ -290,8 +290,8 @@ M['textDocument/completion'] = function(_, result, _, _)
   if vim.tbl_isempty(result or {}) then
     return
   end
-  local row, col = unpack(api.nvim_win_get_cursor(0))
-  local line = assert(api.nvim_buf_get_lines(0, row - 1, row, false)[1])
+  local row, col = unpack(a.nvim_win_get_cursor(0))
+  local line = assert(a.nvim_buf_get_lines(0, row - 1, row, false)[1])
   local line_to_cursor = line:sub(col + 1)
   local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
   local prefix = line_to_cursor:sub(textMatch + 1)
@@ -358,7 +358,7 @@ local function location_handler(_, result, ctx, config)
         title = 'LSP locations',
         items = util.locations_to_items(result, client.offset_encoding),
       })
-      api.nvim_command('botright copen')
+      a.nvim_command('botright copen')
     end
   else
     util.jump_to_location(result, client.offset_encoding, config.reuse_win)
@@ -402,7 +402,7 @@ function M.signature_help(_, result, ctx, config)
   local client = vim.lsp.get_client_by_id(ctx.client_id)
   local triggers =
     vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters')
-  local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype')
+  local ft = a.nvim_buf_get_option(ctx.bufnr, 'filetype')
   local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers)
   lines = util.trim_empty_lines(lines)
   if vim.tbl_isempty(lines) then
@@ -413,7 +413,7 @@ function M.signature_help(_, result, ctx, config)
   end
   local fbuf, fwin = util.open_floating_preview(lines, 'markdown', config)
   if hl then
-    api.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', 0, unpack(hl))
+    a.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', 0, unpack(hl))
   end
   return fbuf, fwin
 end
@@ -459,7 +459,7 @@ local make_call_hierarchy_handler = function(direction)
       end
     end
     vim.fn.setqflist({}, ' ', { title = 'LSP call hierarchy', items = items })
-    api.nvim_command('botright copen')
+    a.nvim_command('botright copen')
   end
 end
 
@@ -505,7 +505,7 @@ M['window/showMessage'] = function(_, result, ctx, _)
     err_message('LSP[', client_name, '] ', message)
   else
     local message_type_name = protocol.MessageType[message_type]
-    api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
+    a.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
   end
   return result
 end
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index cf74dd2b47..913eee19a2 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -11,7 +11,7 @@ local is_win = uv.os_uname().version:find('Windows')
 ---@param filename (string) path to check
 ---@returns (bool)
 local function is_dir(filename)
-  local stat = vim.loop.fs_stat(filename)
+  local stat = uv.fs_stat(filename)
   return stat and stat.type == 'directory' or false
 end
 
diff --git a/runtime/lua/vim/lsp/tagfunc.lua b/runtime/lua/vim/lsp/tagfunc.lua
index f0ae6a6c49..49029f8599 100644
--- a/runtime/lua/vim/lsp/tagfunc.lua
+++ b/runtime/lua/vim/lsp/tagfunc.lua
@@ -1,5 +1,5 @@
 local lsp = vim.lsp
-local util = vim.lsp.util
+local util = lsp.util
 
 ---@private
 local function mk_tag_item(name, range, uri, offset_encoding)
@@ -15,7 +15,7 @@ end
 
 ---@private
 local function query_definition(pattern)
-  local params = lsp.util.make_position_params()
+  local params = util.make_position_params()
   local results_by_client, err = lsp.buf_request_sync(0, 'textDocument/definition', params, 1000)
   if err then
     return {}
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 6f2b95514a..5e3f95cf94 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -2,7 +2,7 @@ local protocol = require('vim.lsp.protocol')
 local snippet = require('vim.lsp._snippet')
 local vim = vim
 local validate = vim.validate
-local api = vim.api
+local a = vim.api
 local list_extend = vim.list_extend
 local highlight = require('vim.highlight')
 local uv = vim.loop
@@ -238,14 +238,14 @@ local function get_lines(bufnr, rows)
 
   -- This is needed for bufload and bufloaded
   if bufnr == 0 then
-    bufnr = vim.api.nvim_get_current_buf()
+    bufnr = a.nvim_get_current_buf()
   end
 
   ---@private
   local function buf_lines()
     local lines = {}
     for _, row in pairs(rows) do
-      lines[row] = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
+      lines[row] = (a.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
     end
     return lines
   end
@@ -264,7 +264,7 @@ local function get_lines(bufnr, rows)
     return buf_lines()
   end
 
-  local filename = api.nvim_buf_get_name(bufnr)
+  local filename = a.nvim_buf_get_name(bufnr)
 
   -- get the data from the file
   local fd = uv.fs_open(filename, 'r', 438)
@@ -389,10 +389,10 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
   if not next(text_edits) then
     return
   end
-  if not api.nvim_buf_is_loaded(bufnr) then
+  if not a.nvim_buf_is_loaded(bufnr) then
     vim.fn.bufload(bufnr)
   end
-  api.nvim_buf_set_option(bufnr, 'buflisted', true)
+  a.nvim_buf_set_option(bufnr, 'buflisted', true)
 
   -- Fix reversed range and indexing each text_edits
   local index = 0
@@ -427,7 +427,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
 
   -- Some LSP servers are depending on the VSCode behavior.
   -- The VSCode will re-locate the cursor position after applying TextEdit so we also do it.
-  local is_current_buf = vim.api.nvim_get_current_buf() == bufnr
+  local is_current_buf = a.nvim_get_current_buf() == bufnr
   local cursor = (function()
     if not is_current_buf then
       return {
@@ -435,7 +435,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
         col = -1,
       }
     end
-    local cursor = vim.api.nvim_win_get_cursor(0)
+    local cursor = a.nvim_win_get_cursor(0)
     return {
       row = cursor[1] - 1,
       col = cursor[2],
@@ -455,11 +455,11 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
       start_col = get_line_byte_from_position(bufnr, text_edit.range.start, offset_encoding),
       end_row = text_edit.range['end'].line,
       end_col = get_line_byte_from_position(bufnr, text_edit.range['end'], offset_encoding),
-      text = vim.split(text_edit.newText, '\n', true),
+      text = split(text_edit.newText, '\n', true),
     }
 
     -- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here.
-    local max = vim.api.nvim_buf_line_count(bufnr)
+    local max = a.nvim_buf_line_count(bufnr)
     if max <= e.start_row or max <= e.end_row then
       local len = #(get_line(bufnr, max - 1) or '')
       if max <= e.start_row then
@@ -473,7 +473,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
       end
       has_eol_text_edit = true
     end
-    vim.api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
+    a.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
 
     -- Fix cursor position.
     local row_count = (e.end_row - e.start_row) + 1
@@ -490,7 +490,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
     end
   end
 
-  local max = vim.api.nvim_buf_line_count(bufnr)
+  local max = a.nvim_buf_line_count(bufnr)
 
   -- Apply fixed cursor position.
   if is_cursor_fixed then
@@ -498,7 +498,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
     is_valid_cursor = is_valid_cursor and cursor.row < max
     is_valid_cursor = is_valid_cursor and cursor.col <= #(get_line(bufnr, max - 1) or '')
     if is_valid_cursor then
-      vim.api.nvim_win_set_cursor(0, { cursor.row + 1, cursor.col })
+      a.nvim_win_set_cursor(0, { cursor.row + 1, cursor.col })
     end
   end
 
@@ -506,12 +506,12 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
   local fix_eol = has_eol_text_edit
   fix_eol = fix_eol
     and (
-      api.nvim_buf_get_option(bufnr, 'eol')
-      or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option(bufnr, 'binary'))
+      a.nvim_buf_get_option(bufnr, 'eol')
+      or (a.nvim_buf_get_option(bufnr, 'fixeol') and not a.nvim_buf_get_option(bufnr, 'binary'))
     )
   fix_eol = fix_eol and get_line(bufnr, max - 1) == ''
   if fix_eol then
-    vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {})
+    a.nvim_buf_set_lines(bufnr, -2, -1, false, {})
   end
 end
 
@@ -710,8 +710,8 @@ end
 ---@private
 --- Like vim.fn.bufwinid except it works across tabpages.
 local function bufwinid(bufnr)
-  for _, win in ipairs(api.nvim_list_wins()) do
-    if api.nvim_win_get_buf(win) == bufnr then
+  for _, win in ipairs(a.nvim_list_wins()) do
+    if a.nvim_win_get_buf(win) == bufnr then
       return win
     end
   end
@@ -724,7 +724,7 @@ end
 --         ignoreIfExists? bool
 function M.rename(old_fname, new_fname, opts)
   opts = opts or {}
-  local target_exists = vim.loop.fs_stat(new_fname) ~= nil
+  local target_exists = uv.fs_stat(new_fname) ~= nil
   if target_exists and not opts.overwrite or opts.ignoreIfExists then
     vim.notify('Rename target already exists. Skipping rename.')
     return
@@ -733,7 +733,7 @@ function M.rename(old_fname, new_fname, opts)
   vim.fn.bufload(oldbuf)
 
   -- The there may be pending changes in the buffer
-  api.nvim_buf_call(oldbuf, function()
+  a.nvim_buf_call(oldbuf, function()
     vim.cmd('w!')
   end)
 
@@ -743,9 +743,9 @@ function M.rename(old_fname, new_fname, opts)
   local newbuf = vim.fn.bufadd(new_fname)
   local win = bufwinid(oldbuf)
   if win then
-    api.nvim_win_set_buf(win, newbuf)
+    a.nvim_win_set_buf(win, newbuf)
   end
-  api.nvim_buf_delete(oldbuf, { force = true })
+  a.nvim_buf_delete(oldbuf, { force = true })
 end
 
 ---@private
@@ -764,7 +764,7 @@ end
 local function delete_file(change)
   local opts = change.options or {}
   local fname = vim.uri_to_fname(change.uri)
-  local stat = vim.loop.fs_stat(fname)
+  local stat = uv.fs_stat(fname)
   if opts.ignoreIfNotExists and not stat then
     return
   end
@@ -778,7 +778,7 @@ local function delete_file(change)
   local bufnr = vim.fn.bufadd(fname)
   local result = tonumber(vim.fn.delete(fname, flags))
   assert(result == 0, 'Could not delete file: ' .. fname .. ', stat: ' .. vim.inspect(stat))
-  api.nvim_buf_delete(bufnr, { force = true })
+  a.nvim_buf_delete(bufnr, { force = true })
 end
 
 --- Applies a `WorkspaceEdit`.
@@ -906,7 +906,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers
     -- wrap inside a code block so stylize_markdown can render it properly
     label = ('```%s\n%s\n```'):format(ft, label)
   end
-  vim.list_extend(contents, vim.split(label, '\n', true))
+  list_extend(contents, split(label, '\n', true))
   if signature.documentation then
     M.convert_input_to_markdown_lines(signature.documentation, contents)
   end
@@ -1013,7 +1013,7 @@ function M.make_floating_popup_options(width, height, opts)
     row = 0
   end
 
-  if vim.fn.wincol() + width + (opts.offset_x or 0) <= api.nvim_get_option('columns') then
+  if vim.fn.wincol() + width + (opts.offset_x or 0) <= a.nvim_get_option('columns') then
     anchor = anchor .. 'W'
     col = 0
   else
@@ -1065,15 +1065,15 @@ function M.jump_to_location(location, offset_encoding, reuse_win)
   --- Jump to new location (adjusting for UTF-16 encoding of characters)
   local win = reuse_win and bufwinid(bufnr)
   if win then
-    api.nvim_set_current_win(win)
+    a.nvim_set_current_win(win)
   else
-    api.nvim_buf_set_option(bufnr, 'buflisted', true)
-    api.nvim_set_current_buf(bufnr)
+    a.nvim_buf_set_option(bufnr, 'buflisted', true)
+    a.nvim_set_current_buf(bufnr)
   end
   local range = location.range or location.targetSelectionRange
   local row = range.start.line
   local col = get_line_byte_from_position(bufnr, range.start, offset_encoding)
-  api.nvim_win_set_cursor(0, { row + 1, col })
+  a.nvim_win_set_cursor(0, { row + 1, col })
   -- Open folds under the cursor
   vim.cmd('normal! zv')
   return true
@@ -1094,17 +1094,17 @@ function M.preview_location(location, opts)
     return
   end
   local bufnr = vim.uri_to_bufnr(uri)
-  if not api.nvim_buf_is_loaded(bufnr) then
+  if not a.nvim_buf_is_loaded(bufnr) then
     vim.fn.bufload(bufnr)
   end
   local range = location.targetRange or location.range
-  local contents = api.nvim_buf_get_lines(bufnr, range.start.line, range['end'].line + 1, false)
-  local syntax = api.nvim_buf_get_option(bufnr, 'syntax')
+  local contents = a.nvim_buf_get_lines(bufnr, range.start.line, range['end'].line + 1, false)
+  local syntax = a.nvim_buf_get_option(bufnr, 'syntax')
   if syntax == '' then
     -- When no syntax is set, we use filetype as fallback. This might not result
     -- in a valid syntax definition. See also ft detection in stylize_markdown.
     -- An empty syntax is more common now with TreeSitter, since TS disables syntax.
-    syntax = api.nvim_buf_get_option(bufnr, 'filetype')
+    syntax = a.nvim_buf_get_option(bufnr, 'filetype')
   end
   opts = opts or {}
   opts.focus_id = 'location'
@@ -1113,8 +1113,8 @@ end
 
 ---@private
 local function find_window_by_var(name, value)
-  for _, win in ipairs(api.nvim_list_wins()) do
-    if npcall(api.nvim_win_get_var, win, name) == value then
+  for _, win in ipairs(a.nvim_list_wins()) do
+    if npcall(a.nvim_win_get_var, win, name) == value then
       return win
     end
   end
@@ -1279,7 +1279,7 @@ function M.stylize_markdown(bufnr, contents, opts)
   end
 
   -- Compute size of float needed to show (wrapped) lines
-  opts.wrap_at = opts.wrap_at or (vim.wo['wrap'] and api.nvim_win_get_width(0))
+  opts.wrap_at = opts.wrap_at or (vim.wo['wrap'] and a.nvim_win_get_width(0))
   local width = M._make_floating_popup_size(stripped, opts)
 
   local sep_line = string.rep('─', math.min(width, opts.wrap_at or width))
@@ -1290,7 +1290,7 @@ function M.stylize_markdown(bufnr, contents, opts)
     end
   end
 
-  vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
+  a.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
 
   local idx = 1
   ---@private
@@ -1315,7 +1315,7 @@ function M.stylize_markdown(bufnr, contents, opts)
     local lang = '@' .. ft:upper()
     if not langs[lang] then
       -- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set
-      pcall(vim.api.nvim_buf_del_var, bufnr, 'current_syntax')
+      pcall(a.nvim_buf_del_var, bufnr, 'current_syntax')
       -- TODO(ashkan): better validation before this.
       if not pcall(vim.cmd, string.format('syntax include %s syntax/%s.vim', lang, ft)) then
         return
@@ -1334,7 +1334,7 @@ function M.stylize_markdown(bufnr, contents, opts)
   end
 
   -- needs to run in the buffer for the regions to work
-  api.nvim_buf_call(bufnr, function()
+  a.nvim_buf_call(bufnr, function()
     -- we need to apply lsp_markdown regions speperately, since otherwise
     -- markdown regions can "bleed" through the other syntax regions
     -- and mess up the formatting
@@ -1362,13 +1362,13 @@ end
 local function close_preview_window(winnr, bufnrs)
   vim.schedule(function()
     -- exit if we are in one of ignored buffers
-    if bufnrs and vim.tbl_contains(bufnrs, api.nvim_get_current_buf()) then
+    if bufnrs and vim.tbl_contains(bufnrs, a.nvim_get_current_buf()) then
       return
     end
 
     local augroup = 'preview_window_' .. winnr
-    pcall(api.nvim_del_augroup_by_name, augroup)
-    pcall(api.nvim_win_close, winnr, true)
+    pcall(a.nvim_del_augroup_by_name, augroup)
+    pcall(a.nvim_win_close, winnr, true)
   end)
 end
 
@@ -1380,13 +1380,13 @@ end
 ---@param bufnrs table list of buffers where the preview window will remain visible
 ---@see |autocmd-events|
 local function close_preview_autocmd(events, winnr, bufnrs)
-  local augroup = api.nvim_create_augroup('preview_window_' .. winnr, {
+  local augroup = a.nvim_create_augroup('preview_window_' .. winnr, {
     clear = true,
   })
 
   -- close the preview window when entered a buffer that is not
   -- the floating window buffer or the buffer that spawned it
-  api.nvim_create_autocmd('BufEnter', {
+  a.nvim_create_autocmd('BufEnter', {
     group = augroup,
     callback = function()
       close_preview_window(winnr, bufnrs)
@@ -1394,7 +1394,7 @@ local function close_preview_autocmd(events, winnr, bufnrs)
   })
 
   if #events > 0 then
-    api.nvim_create_autocmd(events, {
+    a.nvim_create_autocmd(events, {
       buffer = bufnrs[2],
       callback = function()
         close_preview_window(winnr)
@@ -1438,7 +1438,7 @@ function M._make_floating_popup_size(contents, opts)
   end
 
   local border_width = get_border_size(opts).width
-  local screen_width = api.nvim_win_get_width(0)
+  local screen_width = a.nvim_win_get_width(0)
   width = math.min(width, screen_width)
 
   -- make sure borders are always inside the screen
@@ -1511,35 +1511,35 @@ function M.open_floating_preview(contents, syntax, opts)
   opts.focus = opts.focus ~= false
   opts.close_events = opts.close_events or { 'CursorMoved', 'CursorMovedI', 'InsertCharPre' }
 
-  local bufnr = api.nvim_get_current_buf()
+  local bufnr = a.nvim_get_current_buf()
 
   -- check if this popup is focusable and we need to focus
   if opts.focus_id and opts.focusable ~= false and opts.focus then
     -- Go back to previous window if we are in a focusable one
-    local current_winnr = api.nvim_get_current_win()
-    if npcall(api.nvim_win_get_var, current_winnr, opts.focus_id) then
-      api.nvim_command('wincmd p')
+    local current_winnr = a.nvim_get_current_win()
+    if npcall(a.nvim_win_get_var, current_winnr, opts.focus_id) then
+      a.nvim_command('wincmd p')
       return bufnr, current_winnr
     end
     do
       local win = find_window_by_var(opts.focus_id, bufnr)
-      if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
+      if win and a.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
         -- focus and return the existing buf, win
-        api.nvim_set_current_win(win)
-        api.nvim_command('stopinsert')
-        return api.nvim_win_get_buf(win), win
+        a.nvim_set_current_win(win)
+        a.nvim_command('stopinsert')
+        return a.nvim_win_get_buf(win), win
       end
     end
   end
 
   -- check if another floating preview already exists for this buffer
   -- and close it if needed
-  local existing_float = npcall(api.nvim_buf_get_var, bufnr, 'lsp_floating_preview')
-  if existing_float and api.nvim_win_is_valid(existing_float) then
-    api.nvim_win_close(existing_float, true)
+  local existing_float = npcall(a.nvim_buf_get_var, bufnr, 'lsp_floating_preview')
+  if existing_float and a.nvim_win_is_valid(existing_float) then
+    a.nvim_win_close(existing_float, true)
   end
 
-  local floating_bufnr = api.nvim_create_buf(false, true)
+  local floating_bufnr = a.nvim_create_buf(false, true)
   local do_stylize = syntax == 'markdown' and opts.stylize_markdown
 
   -- Clean up input: trim empty lines from the end, pad
@@ -1550,33 +1550,33 @@ function M.open_floating_preview(contents, syntax, opts)
     contents = M.stylize_markdown(floating_bufnr, contents, opts)
   else
     if syntax then
-      api.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
+      a.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
     end
-    api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
+    a.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
   end
 
   -- Compute size of float needed to show (wrapped) lines
   if opts.wrap then
-    opts.wrap_at = opts.wrap_at or api.nvim_win_get_width(0)
+    opts.wrap_at = opts.wrap_at or a.nvim_win_get_width(0)
   else
     opts.wrap_at = nil
   end
   local width, height = M._make_floating_popup_size(contents, opts)
 
   local float_option = M.make_floating_popup_options(width, height, opts)
-  local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
+  local floating_winnr = a.nvim_open_win(floating_bufnr, false, float_option)
   if do_stylize then
-    api.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
-    api.nvim_win_set_option(floating_winnr, 'concealcursor', 'n')
+    a.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
+    a.nvim_win_set_option(floating_winnr, 'concealcursor', 'n')
   end
   -- disable folding
-  api.nvim_win_set_option(floating_winnr, 'foldenable', false)
+  a.nvim_win_set_option(floating_winnr, 'foldenable', false)
   -- soft wrapping
-  api.nvim_win_set_option(floating_winnr, 'wrap', opts.wrap)
+  a.nvim_win_set_option(floating_winnr, 'wrap', opts.wrap)
 
-  api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
-  api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
-  api.nvim_buf_set_keymap(
+  a.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
+  a.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
+  a.nvim_buf_set_keymap(
     floating_bufnr,
     'n',
     'q',
@@ -1587,22 +1587,22 @@ function M.open_floating_preview(contents, syntax, opts)
 
   -- save focus_id
   if opts.focus_id then
-    api.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
+    a.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
   end
-  api.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr)
+  a.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr)
 
   return floating_bufnr, floating_winnr
 end
 
 do --[[ References ]]
-  local reference_ns = api.nvim_create_namespace('vim_lsp_references')
+  local reference_ns = a.nvim_create_namespace('vim_lsp_references')
 
   --- Removes document highlights from a buffer.
   ---
   ---@param bufnr number Buffer id
   function M.buf_clear_references(bufnr)
     validate({ bufnr = { bufnr, 'n', true } })
-    api.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
+    a.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
   end
 
   --- Shows a list of document highlights for a certain buffer.
@@ -1750,7 +1750,7 @@ function M.symbols_to_items(symbols, bufnr)
         local kind = M._get_symbol_kind_name(symbol.kind)
         table.insert(_items, {
           -- bufnr = _bufnr,
-          filename = vim.api.nvim_buf_get_name(_bufnr),
+          filename = a.nvim_buf_get_name(_bufnr),
           lnum = symbol.selectionRange.start.line + 1,
           col = symbol.selectionRange.start.character + 1,
           kind = kind,
@@ -1788,7 +1788,7 @@ function M.trim_empty_lines(lines)
       break
     end
   end
-  return vim.list_extend({}, lines, start, finish)
+  return list_extend({}, lines, start, finish)
 end
 
 --- Accepts markdown lines and tries to reduce them to a filetype if they
@@ -1824,11 +1824,11 @@ end
 ---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
 local function make_position_param(window, offset_encoding)
   window = window or 0
-  local buf = vim.api.nvim_win_get_buf(window)
-  local row, col = unpack(api.nvim_win_get_cursor(window))
+  local buf = a.nvim_win_get_buf(window)
+  local row, col = unpack(a.nvim_win_get_cursor(window))
   offset_encoding = offset_encoding or M._get_offset_encoding(buf)
   row = row - 1
-  local line = api.nvim_buf_get_lines(buf, row, row + 1, true)[1]
+  local line = a.nvim_buf_get_lines(buf, row, row + 1, true)[1]
   if not line then
     return { line = 0, character = 0 }
   end
@@ -1846,7 +1846,7 @@ end
 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
 function M.make_position_params(window, offset_encoding)
   window = window or 0
-  local buf = vim.api.nvim_win_get_buf(window)
+  local buf = a.nvim_win_get_buf(window)
   offset_encoding = offset_encoding or M._get_offset_encoding(buf)
   return {
     textDocument = M.make_text_document_params(buf),
@@ -1898,7 +1898,7 @@ end
 ---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
 ---`current_position`, end = `current_position` } }
 function M.make_range_params(window, offset_encoding)
-  local buf = vim.api.nvim_win_get_buf(window or 0)
+  local buf = a.nvim_win_get_buf(window or 0)
   offset_encoding = offset_encoding or M._get_offset_encoding(buf)
   local position = make_position_param(window, offset_encoding)
   return {
@@ -1924,10 +1924,10 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
     end_pos = { end_pos, 't', true },
     offset_encoding = { offset_encoding, 's', true },
   })
-  bufnr = bufnr or vim.api.nvim_get_current_buf()
+  bufnr = bufnr or a.nvim_get_current_buf()
   offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
-  local A = list_extend({}, start_pos or api.nvim_buf_get_mark(bufnr, '<'))
-  local B = list_extend({}, end_pos or api.nvim_buf_get_mark(bufnr, '>'))
+  local A = list_extend({}, start_pos or a.nvim_buf_get_mark(bufnr, '<'))
+  local B = list_extend({}, end_pos or a.nvim_buf_get_mark(bufnr, '>'))
   -- convert to 0-index
   A[1] = A[1] - 1
   B[1] = B[1] - 1
-- 
cgit 


From 8bccefcb87ec1beb91fc42e4646201917d85baf7 Mon Sep 17 00:00:00 2001
From: ii14 
Date: Fri, 15 Jul 2022 17:55:00 +0200
Subject: refactor: use npcall from vim.F

---
 runtime/lua/vim/lsp/buf.lua | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 50e77cb7ca..07f552239f 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -2,30 +2,10 @@ local vim = vim
 local a = vim.api
 local validate = vim.validate
 local util = require('vim.lsp.util')
+local npcall = vim.F.npcall
 
 local M = {}
 
----@private
---- Returns nil if {status} is false or nil, otherwise returns the rest of the
---- arguments.
-local function ok_or_nil(status, ...)
-  if not status then
-    return
-  end
-  return ...
-end
-
----@private
---- Swallows errors.
----
----@param fn Function to run
----@param ... Function arguments
----@returns Result of `fn(...)` if there are no errors, otherwise nil.
---- Returns nil if errors occur during {fn}, otherwise returns
-local function npcall(fn, ...)
-  return ok_or_nil(pcall(fn, ...))
-end
-
 ---@private
 --- Sends an async request to all active clients attached to the current
 --- buffer.
-- 
cgit 


From f59c96903a61702c69a5bf23a7adb09fff435331 Mon Sep 17 00:00:00 2001
From: ii14 
Date: Fri, 15 Jul 2022 18:26:47 +0200
Subject: refactor: use `local api = vim.api`

---
 runtime/lua/vim/lsp.lua          |  32 ++++----
 runtime/lua/vim/lsp/buf.lua      |  28 +++----
 runtime/lua/vim/lsp/codelens.lua |  26 +++----
 runtime/lua/vim/lsp/handlers.lua |  28 +++----
 runtime/lua/vim/lsp/util.lua     | 158 +++++++++++++++++++--------------------
 5 files changed, 136 insertions(+), 136 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index f6870cbd94..7c95ecef92 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -6,13 +6,13 @@ local util = require('vim.lsp.util')
 local sync = require('vim.lsp.sync')
 
 local vim = vim
-local a = vim.api
+local api = vim.api
 local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option, nvim_exec_autocmds =
-  a.nvim_err_writeln,
-  a.nvim_buf_get_lines,
-  a.nvim_command,
-  a.nvim_buf_get_option,
-  a.nvim_exec_autocmds
+  api.nvim_err_writeln,
+  api.nvim_buf_get_lines,
+  api.nvim_command,
+  api.nvim_buf_get_option,
+  api.nvim_exec_autocmds
 local uv = vim.loop
 local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend
 local validate = vim.validate
@@ -79,7 +79,7 @@ end
 local function resolve_bufnr(bufnr)
   validate({ bufnr = { bufnr, 'n', true } })
   if bufnr == nil or bufnr == 0 then
-    return a.nvim_get_current_buf()
+    return api.nvim_get_current_buf()
   end
   return bufnr
 end
@@ -505,7 +505,7 @@ do
         end
         buf_state.pending_change = nil
         buf_state.last_flush = uv.hrtime()
-        if client.is_stopped() or not a.nvim_buf_is_valid(bufnr) then
+        if client.is_stopped() or not api.nvim_buf_is_valid(bufnr) then
           return
         end
         local changes = state.use_incremental_sync and buf_state.pending_changes
@@ -572,7 +572,7 @@ local function text_document_did_open_handler(bufnr, client)
   if not vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then
     return
   end
-  if not a.nvim_buf_is_loaded(bufnr) then
+  if not api.nvim_buf_is_loaded(bufnr) then
     return
   end
   local filetype = nvim_buf_get_option(bufnr, 'filetype')
@@ -592,7 +592,7 @@ local function text_document_did_open_handler(bufnr, client)
   vim.schedule(function()
     -- Protect against a race where the buffer disappears
     -- between `did_open_handler` and the scheduled function firing.
-    if a.nvim_buf_is_valid(bufnr) then
+    if api.nvim_buf_is_valid(bufnr) then
       local namespace = vim.lsp.diagnostic.get_namespace(client.id)
       vim.diagnostic.show(namespace, bufnr)
     end
@@ -738,7 +738,7 @@ function lsp.start(config, opts)
       return client.config.root_dir == conf.root_dir and client.name == conf.name
     end
   config.name = config.name or (config.cmd[1] and vim.fs.basename(config.cmd[1])) or nil
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
   for _, clients in ipairs({ uninitialized_clients, lsp.get_active_clients() }) do
     for _, client in pairs(clients) do
       if reuse_client(client, config) then
@@ -1433,7 +1433,7 @@ function lsp.buf_attach_client(bufnr, client_id)
     client_id = { client_id, 'n' },
   })
   bufnr = resolve_bufnr(bufnr)
-  if not a.nvim_buf_is_loaded(bufnr) then
+  if not api.nvim_buf_is_loaded(bufnr) then
     local _ = log.warn()
       and log.warn(string.format('buf_attach_client called on unloaded buffer (id: %d): ', bufnr))
     return false
@@ -1451,9 +1451,9 @@ function lsp.buf_attach_client(bufnr, client_id)
         au BufWritePost  lua vim.lsp._text_document_did_save_handler(0)
       augroup END
     ]=]
-    a.nvim_exec(string.format(buf_did_save_autocommand, client_id, bufnr, bufnr), false)
+    api.nvim_exec(string.format(buf_did_save_autocommand, client_id, bufnr, bufnr), false)
     -- First time, so attach and set up stuff.
-    a.nvim_buf_attach(bufnr, false, {
+    api.nvim_buf_attach(bufnr, false, {
       on_lines = text_document_did_change_handler,
       on_reload = function()
         local params = { textDocument = { uri = uri } }
@@ -1888,8 +1888,8 @@ function lsp.omnifunc(findstart, base)
   -- Then, perform standard completion request
   local _ = log.info() and log.info('base ', base)
 
-  local pos = a.nvim_win_get_cursor(0)
-  local line = a.nvim_get_current_line()
+  local pos = api.nvim_win_get_cursor(0)
+  local line = api.nvim_get_current_line()
   local line_to_cursor = line:sub(1, pos[2])
   local _ = log.trace() and log.trace('omnifunc.line', pos, line)
 
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 07f552239f..50a51e897c 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -1,5 +1,5 @@
 local vim = vim
-local a = vim.api
+local api = vim.api
 local validate = vim.validate
 local util = require('vim.lsp.util')
 local npcall = vim.F.npcall
@@ -181,7 +181,7 @@ end
 
 function M.format(options)
   options = options or {}
-  local bufnr = options.bufnr or a.nvim_get_current_buf()
+  local bufnr = options.bufnr or api.nvim_get_current_buf()
   local clients = vim.lsp.get_active_clients({
     id = options.id,
     bufnr = bufnr,
@@ -242,7 +242,7 @@ function M.formatting(options)
     vim.log.levels.WARN
   )
   local params = util.make_formatting_params(options)
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
   select_client('textDocument/formatting', function(client)
     if client == nil then
       return
@@ -270,7 +270,7 @@ function M.formatting_sync(options, timeout_ms)
     vim.log.levels.WARN
   )
   local params = util.make_formatting_params(options)
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
   select_client('textDocument/formatting', function(client)
     if client == nil then
       return
@@ -307,7 +307,7 @@ function M.formatting_seq_sync(options, timeout_ms, order)
     vim.log.levels.WARN
   )
   local clients = vim.tbl_values(vim.lsp.buf_get_clients())
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
 
   -- sort the clients according to `order`
   for _, client_name in pairs(order or {}) do
@@ -328,7 +328,7 @@ function M.formatting_seq_sync(options, timeout_ms, order)
         'textDocument/formatting',
         params,
         timeout_ms,
-        a.nvim_get_current_buf()
+        api.nvim_get_current_buf()
       )
       if result and result.result then
         util.apply_text_edits(result.result, bufnr, client.offset_encoding)
@@ -374,7 +374,7 @@ end
 ---         this field.
 function M.rename(new_name, options)
   options = options or {}
-  local bufnr = options.bufnr or a.nvim_get_current_buf()
+  local bufnr = options.bufnr or api.nvim_get_current_buf()
   local clients = vim.lsp.get_active_clients({
     bufnr = bufnr,
     name = options.name,
@@ -392,14 +392,14 @@ function M.rename(new_name, options)
     vim.notify('[LSP] Rename, no matching language servers with rename capability.')
   end
 
-  local win = a.nvim_get_current_win()
+  local win = api.nvim_get_current_win()
 
   -- Compute early to account for cursor movements after going async
   local cword = vim.fn.expand('')
 
   ---@private
   local function get_text_at_range(range, offset_encoding)
-    return a.nvim_buf_get_text(
+    return api.nvim_buf_get_text(
       bufnr,
       range.start.line,
       util._get_line_byte_from_position(bufnr, range.start, offset_encoding),
@@ -584,7 +584,7 @@ end
 function M.add_workspace_folder(workspace_folder)
   workspace_folder = workspace_folder
     or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'), 'dir')
-  a.nvim_command('redraw')
+  api.nvim_command('redraw')
   if not (workspace_folder and #workspace_folder > 0) then
     return
   end
@@ -621,7 +621,7 @@ end
 function M.remove_workspace_folder(workspace_folder)
   workspace_folder = workspace_folder
     or npcall(vim.fn.input, 'Workspace Folder: ', vim.fn.expand('%:p:h'))
-  a.nvim_command('redraw')
+  api.nvim_command('redraw')
   if not (workspace_folder and #workspace_folder > 0) then
     return
   end
@@ -818,7 +818,7 @@ end
 --- with all aggregated results
 ---@private
 local function code_action_request(params, options)
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
   local method = 'textDocument/codeAction'
   vim.lsp.buf_request_all(bufnr, method, params, function(results)
     local ctx = { bufnr = bufnr, method = method, params = params }
@@ -855,7 +855,7 @@ function M.code_action(options)
   end
   local context = options.context or {}
   if not context.diagnostics then
-    local bufnr = a.nvim_get_current_buf()
+    local bufnr = api.nvim_get_current_buf()
     context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
   end
   local params = util.make_range_params()
@@ -882,7 +882,7 @@ function M.range_code_action(context, start_pos, end_pos)
   validate({ context = { context, 't', true } })
   context = context or {}
   if not context.diagnostics then
-    local bufnr = a.nvim_get_current_buf()
+    local bufnr = api.nvim_get_current_buf()
     context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics(bufnr)
   end
   local params = util.make_given_range_params(start_pos, end_pos)
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index 0e48bd85f8..4fa02c8db2 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -1,6 +1,6 @@
 local util = require('vim.lsp.util')
 local log = require('vim.lsp.log')
-local a = vim.api
+local api = vim.api
 local M = {}
 
 --- bufnr → true|nil
@@ -10,14 +10,14 @@ local active_refreshes = {}
 --- bufnr -> client_id -> lenses
 local lens_cache_by_buf = setmetatable({}, {
   __index = function(t, b)
-    local key = b > 0 and b or a.nvim_get_current_buf()
+    local key = b > 0 and b or api.nvim_get_current_buf()
     return rawget(t, key)
   end,
 })
 
 local namespaces = setmetatable({}, {
   __index = function(t, key)
-    local value = a.nvim_create_namespace('vim_lsp_codelens:' .. key)
+    local value = api.nvim_create_namespace('vim_lsp_codelens:' .. key)
     rawset(t, key, value)
     return value
   end,
@@ -29,7 +29,7 @@ M.__namespaces = namespaces
 ---@private
 local function execute_lens(lens, bufnr, client_id)
   local line = lens.range.start.line
-  a.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1)
+  api.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1)
 
   local client = vim.lsp.get_client_by_id(client_id)
   assert(client, 'Client is required to execute lens, client_id=' .. client_id)
@@ -78,8 +78,8 @@ end
 --- Run the code lens in the current line
 ---
 function M.run()
-  local line = a.nvim_win_get_cursor(0)[1]
-  local bufnr = a.nvim_get_current_buf()
+  local line = api.nvim_win_get_cursor(0)[1]
+  local bufnr = api.nvim_get_current_buf()
   local options = {}
   local lenses_by_client = lens_cache_by_buf[bufnr] or {}
   for client, lenses in pairs(lenses_by_client) do
@@ -127,10 +127,10 @@ function M.display(lenses, bufnr, client_id)
     table.insert(line_lenses, lens)
   end
   local ns = namespaces[client_id]
-  local num_lines = a.nvim_buf_line_count(bufnr)
+  local num_lines = api.nvim_buf_line_count(bufnr)
   for i = 0, num_lines do
     local line_lenses = lenses_by_lnum[i] or {}
-    a.nvim_buf_clear_namespace(bufnr, ns, i, i + 1)
+    api.nvim_buf_clear_namespace(bufnr, ns, i, i + 1)
     local chunks = {}
     local num_line_lenses = #line_lenses
     table.sort(line_lenses, function(a, b)
@@ -144,7 +144,7 @@ function M.display(lenses, bufnr, client_id)
       end
     end
     if #chunks > 0 then
-      a.nvim_buf_set_extmark(bufnr, ns, i, 0, {
+      api.nvim_buf_set_extmark(bufnr, ns, i, 0, {
         virt_text = chunks,
         hl_mode = 'combine',
       })
@@ -163,12 +163,12 @@ function M.save(lenses, bufnr, client_id)
     lenses_by_client = {}
     lens_cache_by_buf[bufnr] = lenses_by_client
     local ns = namespaces[client_id]
-    a.nvim_buf_attach(bufnr, false, {
+    api.nvim_buf_attach(bufnr, false, {
       on_detach = function(b)
         lens_cache_by_buf[b] = nil
       end,
       on_lines = function(_, b, _, first_lnum, last_lnum)
-        a.nvim_buf_clear_namespace(b, ns, first_lnum, last_lnum)
+        api.nvim_buf_clear_namespace(b, ns, first_lnum, last_lnum)
       end,
     })
   end
@@ -203,7 +203,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback)
           -- Eager display to have some sort of incremental feedback
           -- Once all lenses got resolved there will be a full redraw for all lenses
           -- So that multiple lens per line are properly displayed
-          a.nvim_buf_set_extmark(
+          api.nvim_buf_set_extmark(
             bufnr,
             ns,
             lens.range.start.line,
@@ -249,7 +249,7 @@ function M.refresh()
   local params = {
     textDocument = util.make_text_document_params(),
   }
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
   if active_refreshes[bufnr] then
     return
   end
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 3c43676850..68e1f59aaf 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -2,7 +2,7 @@ local log = require('vim.lsp.log')
 local protocol = require('vim.lsp.protocol')
 local util = require('vim.lsp.util')
 local vim = vim
-local a = vim.api
+local api = vim.api
 
 local M = {}
 
@@ -13,7 +13,7 @@ local M = {}
 ---@param ... (table of strings) Will be concatenated before being written
 local function err_message(...)
   vim.notify(table.concat(vim.tbl_flatten({ ... })), vim.log.levels.ERROR)
-  a.nvim_command('redraw')
+  api.nvim_command('redraw')
 end
 
 --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
@@ -61,7 +61,7 @@ local function progress_handler(_, result, ctx, _)
     client.messages.progress[token].done = true
   end
 
-  a.nvim_command('doautocmd  User LspProgressUpdate')
+  api.nvim_command('doautocmd  User LspProgressUpdate')
 end
 
 --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
@@ -195,14 +195,14 @@ M['textDocument/references'] = function(_, result, ctx, config)
         items = util.locations_to_items(result, client.offset_encoding),
         context = ctx,
       })
-      a.nvim_command('lopen')
+      api.nvim_command('lopen')
     else
       vim.fn.setqflist({}, ' ', {
         title = 'References',
         items = util.locations_to_items(result, client.offset_encoding),
         context = ctx,
       })
-      a.nvim_command('botright copen')
+      api.nvim_command('botright copen')
     end
   end
 end
@@ -230,14 +230,14 @@ local function response_to_list(map_result, entity, title_fn)
           items = map_result(result, ctx.bufnr),
           context = ctx,
         })
-        a.nvim_command('lopen')
+        api.nvim_command('lopen')
       else
         vim.fn.setqflist({}, ' ', {
           title = title_fn(ctx),
           items = map_result(result, ctx.bufnr),
           context = ctx,
         })
-        a.nvim_command('botright copen')
+        api.nvim_command('botright copen')
       end
     end
   end
@@ -290,8 +290,8 @@ M['textDocument/completion'] = function(_, result, _, _)
   if vim.tbl_isempty(result or {}) then
     return
   end
-  local row, col = unpack(a.nvim_win_get_cursor(0))
-  local line = assert(a.nvim_buf_get_lines(0, row - 1, row, false)[1])
+  local row, col = unpack(api.nvim_win_get_cursor(0))
+  local line = assert(api.nvim_buf_get_lines(0, row - 1, row, false)[1])
   local line_to_cursor = line:sub(col + 1)
   local textMatch = vim.fn.match(line_to_cursor, '\\k*$')
   local prefix = line_to_cursor:sub(textMatch + 1)
@@ -358,7 +358,7 @@ local function location_handler(_, result, ctx, config)
         title = 'LSP locations',
         items = util.locations_to_items(result, client.offset_encoding),
       })
-      a.nvim_command('botright copen')
+      api.nvim_command('botright copen')
     end
   else
     util.jump_to_location(result, client.offset_encoding, config.reuse_win)
@@ -402,7 +402,7 @@ function M.signature_help(_, result, ctx, config)
   local client = vim.lsp.get_client_by_id(ctx.client_id)
   local triggers =
     vim.tbl_get(client.server_capabilities, 'signatureHelpProvider', 'triggerCharacters')
-  local ft = a.nvim_buf_get_option(ctx.bufnr, 'filetype')
+  local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype')
   local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers)
   lines = util.trim_empty_lines(lines)
   if vim.tbl_isempty(lines) then
@@ -413,7 +413,7 @@ function M.signature_help(_, result, ctx, config)
   end
   local fbuf, fwin = util.open_floating_preview(lines, 'markdown', config)
   if hl then
-    a.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', 0, unpack(hl))
+    api.nvim_buf_add_highlight(fbuf, -1, 'LspSignatureActiveParameter', 0, unpack(hl))
   end
   return fbuf, fwin
 end
@@ -459,7 +459,7 @@ local make_call_hierarchy_handler = function(direction)
       end
     end
     vim.fn.setqflist({}, ' ', { title = 'LSP call hierarchy', items = items })
-    a.nvim_command('botright copen')
+    api.nvim_command('botright copen')
   end
 end
 
@@ -505,7 +505,7 @@ M['window/showMessage'] = function(_, result, ctx, _)
     err_message('LSP[', client_name, '] ', message)
   else
     local message_type_name = protocol.MessageType[message_type]
-    a.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
+    api.nvim_out_write(string.format('LSP[%s][%s] %s\n', client_name, message_type_name, message))
   end
   return result
 end
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 5e3f95cf94..89b2301aa7 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -2,7 +2,7 @@ local protocol = require('vim.lsp.protocol')
 local snippet = require('vim.lsp._snippet')
 local vim = vim
 local validate = vim.validate
-local a = vim.api
+local api = vim.api
 local list_extend = vim.list_extend
 local highlight = require('vim.highlight')
 local uv = vim.loop
@@ -238,14 +238,14 @@ local function get_lines(bufnr, rows)
 
   -- This is needed for bufload and bufloaded
   if bufnr == 0 then
-    bufnr = a.nvim_get_current_buf()
+    bufnr = api.nvim_get_current_buf()
   end
 
   ---@private
   local function buf_lines()
     local lines = {}
     for _, row in pairs(rows) do
-      lines[row] = (a.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
+      lines[row] = (api.nvim_buf_get_lines(bufnr, row, row + 1, false) or { '' })[1]
     end
     return lines
   end
@@ -264,7 +264,7 @@ local function get_lines(bufnr, rows)
     return buf_lines()
   end
 
-  local filename = a.nvim_buf_get_name(bufnr)
+  local filename = api.nvim_buf_get_name(bufnr)
 
   -- get the data from the file
   local fd = uv.fs_open(filename, 'r', 438)
@@ -389,10 +389,10 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
   if not next(text_edits) then
     return
   end
-  if not a.nvim_buf_is_loaded(bufnr) then
+  if not api.nvim_buf_is_loaded(bufnr) then
     vim.fn.bufload(bufnr)
   end
-  a.nvim_buf_set_option(bufnr, 'buflisted', true)
+  api.nvim_buf_set_option(bufnr, 'buflisted', true)
 
   -- Fix reversed range and indexing each text_edits
   local index = 0
@@ -427,7 +427,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
 
   -- Some LSP servers are depending on the VSCode behavior.
   -- The VSCode will re-locate the cursor position after applying TextEdit so we also do it.
-  local is_current_buf = a.nvim_get_current_buf() == bufnr
+  local is_current_buf = api.nvim_get_current_buf() == bufnr
   local cursor = (function()
     if not is_current_buf then
       return {
@@ -435,7 +435,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
         col = -1,
       }
     end
-    local cursor = a.nvim_win_get_cursor(0)
+    local cursor = api.nvim_win_get_cursor(0)
     return {
       row = cursor[1] - 1,
       col = cursor[2],
@@ -459,7 +459,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
     }
 
     -- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here.
-    local max = a.nvim_buf_line_count(bufnr)
+    local max = api.nvim_buf_line_count(bufnr)
     if max <= e.start_row or max <= e.end_row then
       local len = #(get_line(bufnr, max - 1) or '')
       if max <= e.start_row then
@@ -473,7 +473,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
       end
       has_eol_text_edit = true
     end
-    a.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
+    api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
 
     -- Fix cursor position.
     local row_count = (e.end_row - e.start_row) + 1
@@ -490,7 +490,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
     end
   end
 
-  local max = a.nvim_buf_line_count(bufnr)
+  local max = api.nvim_buf_line_count(bufnr)
 
   -- Apply fixed cursor position.
   if is_cursor_fixed then
@@ -498,7 +498,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
     is_valid_cursor = is_valid_cursor and cursor.row < max
     is_valid_cursor = is_valid_cursor and cursor.col <= #(get_line(bufnr, max - 1) or '')
     if is_valid_cursor then
-      a.nvim_win_set_cursor(0, { cursor.row + 1, cursor.col })
+      api.nvim_win_set_cursor(0, { cursor.row + 1, cursor.col })
     end
   end
 
@@ -506,12 +506,12 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding)
   local fix_eol = has_eol_text_edit
   fix_eol = fix_eol
     and (
-      a.nvim_buf_get_option(bufnr, 'eol')
-      or (a.nvim_buf_get_option(bufnr, 'fixeol') and not a.nvim_buf_get_option(bufnr, 'binary'))
+      api.nvim_buf_get_option(bufnr, 'eol')
+      or (api.nvim_buf_get_option(bufnr, 'fixeol') and not api.nvim_buf_get_option(bufnr, 'binary'))
     )
   fix_eol = fix_eol and get_line(bufnr, max - 1) == ''
   if fix_eol then
-    a.nvim_buf_set_lines(bufnr, -2, -1, false, {})
+    api.nvim_buf_set_lines(bufnr, -2, -1, false, {})
   end
 end
 
@@ -710,8 +710,8 @@ end
 ---@private
 --- Like vim.fn.bufwinid except it works across tabpages.
 local function bufwinid(bufnr)
-  for _, win in ipairs(a.nvim_list_wins()) do
-    if a.nvim_win_get_buf(win) == bufnr then
+  for _, win in ipairs(api.nvim_list_wins()) do
+    if api.nvim_win_get_buf(win) == bufnr then
       return win
     end
   end
@@ -733,7 +733,7 @@ function M.rename(old_fname, new_fname, opts)
   vim.fn.bufload(oldbuf)
 
   -- The there may be pending changes in the buffer
-  a.nvim_buf_call(oldbuf, function()
+  api.nvim_buf_call(oldbuf, function()
     vim.cmd('w!')
   end)
 
@@ -743,9 +743,9 @@ function M.rename(old_fname, new_fname, opts)
   local newbuf = vim.fn.bufadd(new_fname)
   local win = bufwinid(oldbuf)
   if win then
-    a.nvim_win_set_buf(win, newbuf)
+    api.nvim_win_set_buf(win, newbuf)
   end
-  a.nvim_buf_delete(oldbuf, { force = true })
+  api.nvim_buf_delete(oldbuf, { force = true })
 end
 
 ---@private
@@ -778,7 +778,7 @@ local function delete_file(change)
   local bufnr = vim.fn.bufadd(fname)
   local result = tonumber(vim.fn.delete(fname, flags))
   assert(result == 0, 'Could not delete file: ' .. fname .. ', stat: ' .. vim.inspect(stat))
-  a.nvim_buf_delete(bufnr, { force = true })
+  api.nvim_buf_delete(bufnr, { force = true })
 end
 
 --- Applies a `WorkspaceEdit`.
@@ -1013,7 +1013,7 @@ function M.make_floating_popup_options(width, height, opts)
     row = 0
   end
 
-  if vim.fn.wincol() + width + (opts.offset_x or 0) <= a.nvim_get_option('columns') then
+  if vim.fn.wincol() + width + (opts.offset_x or 0) <= api.nvim_get_option('columns') then
     anchor = anchor .. 'W'
     col = 0
   else
@@ -1065,15 +1065,15 @@ function M.jump_to_location(location, offset_encoding, reuse_win)
   --- Jump to new location (adjusting for UTF-16 encoding of characters)
   local win = reuse_win and bufwinid(bufnr)
   if win then
-    a.nvim_set_current_win(win)
+    api.nvim_set_current_win(win)
   else
-    a.nvim_buf_set_option(bufnr, 'buflisted', true)
-    a.nvim_set_current_buf(bufnr)
+    api.nvim_buf_set_option(bufnr, 'buflisted', true)
+    api.nvim_set_current_buf(bufnr)
   end
   local range = location.range or location.targetSelectionRange
   local row = range.start.line
   local col = get_line_byte_from_position(bufnr, range.start, offset_encoding)
-  a.nvim_win_set_cursor(0, { row + 1, col })
+  api.nvim_win_set_cursor(0, { row + 1, col })
   -- Open folds under the cursor
   vim.cmd('normal! zv')
   return true
@@ -1094,17 +1094,17 @@ function M.preview_location(location, opts)
     return
   end
   local bufnr = vim.uri_to_bufnr(uri)
-  if not a.nvim_buf_is_loaded(bufnr) then
+  if not api.nvim_buf_is_loaded(bufnr) then
     vim.fn.bufload(bufnr)
   end
   local range = location.targetRange or location.range
-  local contents = a.nvim_buf_get_lines(bufnr, range.start.line, range['end'].line + 1, false)
-  local syntax = a.nvim_buf_get_option(bufnr, 'syntax')
+  local contents = api.nvim_buf_get_lines(bufnr, range.start.line, range['end'].line + 1, false)
+  local syntax = api.nvim_buf_get_option(bufnr, 'syntax')
   if syntax == '' then
     -- When no syntax is set, we use filetype as fallback. This might not result
     -- in a valid syntax definition. See also ft detection in stylize_markdown.
     -- An empty syntax is more common now with TreeSitter, since TS disables syntax.
-    syntax = a.nvim_buf_get_option(bufnr, 'filetype')
+    syntax = api.nvim_buf_get_option(bufnr, 'filetype')
   end
   opts = opts or {}
   opts.focus_id = 'location'
@@ -1113,8 +1113,8 @@ end
 
 ---@private
 local function find_window_by_var(name, value)
-  for _, win in ipairs(a.nvim_list_wins()) do
-    if npcall(a.nvim_win_get_var, win, name) == value then
+  for _, win in ipairs(api.nvim_list_wins()) do
+    if npcall(api.nvim_win_get_var, win, name) == value then
       return win
     end
   end
@@ -1279,7 +1279,7 @@ function M.stylize_markdown(bufnr, contents, opts)
   end
 
   -- Compute size of float needed to show (wrapped) lines
-  opts.wrap_at = opts.wrap_at or (vim.wo['wrap'] and a.nvim_win_get_width(0))
+  opts.wrap_at = opts.wrap_at or (vim.wo['wrap'] and api.nvim_win_get_width(0))
   local width = M._make_floating_popup_size(stripped, opts)
 
   local sep_line = string.rep('─', math.min(width, opts.wrap_at or width))
@@ -1290,7 +1290,7 @@ function M.stylize_markdown(bufnr, contents, opts)
     end
   end
 
-  a.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
+  api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
 
   local idx = 1
   ---@private
@@ -1315,7 +1315,7 @@ function M.stylize_markdown(bufnr, contents, opts)
     local lang = '@' .. ft:upper()
     if not langs[lang] then
       -- HACK: reset current_syntax, since some syntax files like markdown won't load if it is already set
-      pcall(a.nvim_buf_del_var, bufnr, 'current_syntax')
+      pcall(api.nvim_buf_del_var, bufnr, 'current_syntax')
       -- TODO(ashkan): better validation before this.
       if not pcall(vim.cmd, string.format('syntax include %s syntax/%s.vim', lang, ft)) then
         return
@@ -1334,7 +1334,7 @@ function M.stylize_markdown(bufnr, contents, opts)
   end
 
   -- needs to run in the buffer for the regions to work
-  a.nvim_buf_call(bufnr, function()
+  api.nvim_buf_call(bufnr, function()
     -- we need to apply lsp_markdown regions speperately, since otherwise
     -- markdown regions can "bleed" through the other syntax regions
     -- and mess up the formatting
@@ -1362,13 +1362,13 @@ end
 local function close_preview_window(winnr, bufnrs)
   vim.schedule(function()
     -- exit if we are in one of ignored buffers
-    if bufnrs and vim.tbl_contains(bufnrs, a.nvim_get_current_buf()) then
+    if bufnrs and vim.tbl_contains(bufnrs, api.nvim_get_current_buf()) then
       return
     end
 
     local augroup = 'preview_window_' .. winnr
-    pcall(a.nvim_del_augroup_by_name, augroup)
-    pcall(a.nvim_win_close, winnr, true)
+    pcall(api.nvim_del_augroup_by_name, augroup)
+    pcall(api.nvim_win_close, winnr, true)
   end)
 end
 
@@ -1380,13 +1380,13 @@ end
 ---@param bufnrs table list of buffers where the preview window will remain visible
 ---@see |autocmd-events|
 local function close_preview_autocmd(events, winnr, bufnrs)
-  local augroup = a.nvim_create_augroup('preview_window_' .. winnr, {
+  local augroup = api.nvim_create_augroup('preview_window_' .. winnr, {
     clear = true,
   })
 
   -- close the preview window when entered a buffer that is not
   -- the floating window buffer or the buffer that spawned it
-  a.nvim_create_autocmd('BufEnter', {
+  api.nvim_create_autocmd('BufEnter', {
     group = augroup,
     callback = function()
       close_preview_window(winnr, bufnrs)
@@ -1394,7 +1394,7 @@ local function close_preview_autocmd(events, winnr, bufnrs)
   })
 
   if #events > 0 then
-    a.nvim_create_autocmd(events, {
+    api.nvim_create_autocmd(events, {
       buffer = bufnrs[2],
       callback = function()
         close_preview_window(winnr)
@@ -1438,7 +1438,7 @@ function M._make_floating_popup_size(contents, opts)
   end
 
   local border_width = get_border_size(opts).width
-  local screen_width = a.nvim_win_get_width(0)
+  local screen_width = api.nvim_win_get_width(0)
   width = math.min(width, screen_width)
 
   -- make sure borders are always inside the screen
@@ -1511,35 +1511,35 @@ function M.open_floating_preview(contents, syntax, opts)
   opts.focus = opts.focus ~= false
   opts.close_events = opts.close_events or { 'CursorMoved', 'CursorMovedI', 'InsertCharPre' }
 
-  local bufnr = a.nvim_get_current_buf()
+  local bufnr = api.nvim_get_current_buf()
 
   -- check if this popup is focusable and we need to focus
   if opts.focus_id and opts.focusable ~= false and opts.focus then
     -- Go back to previous window if we are in a focusable one
-    local current_winnr = a.nvim_get_current_win()
-    if npcall(a.nvim_win_get_var, current_winnr, opts.focus_id) then
-      a.nvim_command('wincmd p')
+    local current_winnr = api.nvim_get_current_win()
+    if npcall(api.nvim_win_get_var, current_winnr, opts.focus_id) then
+      api.nvim_command('wincmd p')
       return bufnr, current_winnr
     end
     do
       local win = find_window_by_var(opts.focus_id, bufnr)
-      if win and a.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
+      if win and api.nvim_win_is_valid(win) and vim.fn.pumvisible() == 0 then
         -- focus and return the existing buf, win
-        a.nvim_set_current_win(win)
-        a.nvim_command('stopinsert')
-        return a.nvim_win_get_buf(win), win
+        api.nvim_set_current_win(win)
+        api.nvim_command('stopinsert')
+        return api.nvim_win_get_buf(win), win
       end
     end
   end
 
   -- check if another floating preview already exists for this buffer
   -- and close it if needed
-  local existing_float = npcall(a.nvim_buf_get_var, bufnr, 'lsp_floating_preview')
-  if existing_float and a.nvim_win_is_valid(existing_float) then
-    a.nvim_win_close(existing_float, true)
+  local existing_float = npcall(api.nvim_buf_get_var, bufnr, 'lsp_floating_preview')
+  if existing_float and api.nvim_win_is_valid(existing_float) then
+    api.nvim_win_close(existing_float, true)
   end
 
-  local floating_bufnr = a.nvim_create_buf(false, true)
+  local floating_bufnr = api.nvim_create_buf(false, true)
   local do_stylize = syntax == 'markdown' and opts.stylize_markdown
 
   -- Clean up input: trim empty lines from the end, pad
@@ -1550,33 +1550,33 @@ function M.open_floating_preview(contents, syntax, opts)
     contents = M.stylize_markdown(floating_bufnr, contents, opts)
   else
     if syntax then
-      a.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
+      api.nvim_buf_set_option(floating_bufnr, 'syntax', syntax)
     end
-    a.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
+    api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
   end
 
   -- Compute size of float needed to show (wrapped) lines
   if opts.wrap then
-    opts.wrap_at = opts.wrap_at or a.nvim_win_get_width(0)
+    opts.wrap_at = opts.wrap_at or api.nvim_win_get_width(0)
   else
     opts.wrap_at = nil
   end
   local width, height = M._make_floating_popup_size(contents, opts)
 
   local float_option = M.make_floating_popup_options(width, height, opts)
-  local floating_winnr = a.nvim_open_win(floating_bufnr, false, float_option)
+  local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
   if do_stylize then
-    a.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
-    a.nvim_win_set_option(floating_winnr, 'concealcursor', 'n')
+    api.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
+    api.nvim_win_set_option(floating_winnr, 'concealcursor', 'n')
   end
   -- disable folding
-  a.nvim_win_set_option(floating_winnr, 'foldenable', false)
+  api.nvim_win_set_option(floating_winnr, 'foldenable', false)
   -- soft wrapping
-  a.nvim_win_set_option(floating_winnr, 'wrap', opts.wrap)
+  api.nvim_win_set_option(floating_winnr, 'wrap', opts.wrap)
 
-  a.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
-  a.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
-  a.nvim_buf_set_keymap(
+  api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
+  api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe')
+  api.nvim_buf_set_keymap(
     floating_bufnr,
     'n',
     'q',
@@ -1587,22 +1587,22 @@ function M.open_floating_preview(contents, syntax, opts)
 
   -- save focus_id
   if opts.focus_id then
-    a.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
+    api.nvim_win_set_var(floating_winnr, opts.focus_id, bufnr)
   end
-  a.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr)
+  api.nvim_buf_set_var(bufnr, 'lsp_floating_preview', floating_winnr)
 
   return floating_bufnr, floating_winnr
 end
 
 do --[[ References ]]
-  local reference_ns = a.nvim_create_namespace('vim_lsp_references')
+  local reference_ns = api.nvim_create_namespace('vim_lsp_references')
 
   --- Removes document highlights from a buffer.
   ---
   ---@param bufnr number Buffer id
   function M.buf_clear_references(bufnr)
     validate({ bufnr = { bufnr, 'n', true } })
-    a.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
+    api.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
   end
 
   --- Shows a list of document highlights for a certain buffer.
@@ -1750,7 +1750,7 @@ function M.symbols_to_items(symbols, bufnr)
         local kind = M._get_symbol_kind_name(symbol.kind)
         table.insert(_items, {
           -- bufnr = _bufnr,
-          filename = a.nvim_buf_get_name(_bufnr),
+          filename = api.nvim_buf_get_name(_bufnr),
           lnum = symbol.selectionRange.start.line + 1,
           col = symbol.selectionRange.start.character + 1,
           kind = kind,
@@ -1824,11 +1824,11 @@ end
 ---@param offset_encoding string utf-8|utf-16|utf-32|nil defaults to `offset_encoding` of first client of buffer of `window`
 local function make_position_param(window, offset_encoding)
   window = window or 0
-  local buf = a.nvim_win_get_buf(window)
-  local row, col = unpack(a.nvim_win_get_cursor(window))
+  local buf = api.nvim_win_get_buf(window)
+  local row, col = unpack(api.nvim_win_get_cursor(window))
   offset_encoding = offset_encoding or M._get_offset_encoding(buf)
   row = row - 1
-  local line = a.nvim_buf_get_lines(buf, row, row + 1, true)[1]
+  local line = api.nvim_buf_get_lines(buf, row, row + 1, true)[1]
   if not line then
     return { line = 0, character = 0 }
   end
@@ -1846,7 +1846,7 @@ end
 ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
 function M.make_position_params(window, offset_encoding)
   window = window or 0
-  local buf = a.nvim_win_get_buf(window)
+  local buf = api.nvim_win_get_buf(window)
   offset_encoding = offset_encoding or M._get_offset_encoding(buf)
   return {
     textDocument = M.make_text_document_params(buf),
@@ -1898,7 +1898,7 @@ end
 ---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
 ---`current_position`, end = `current_position` } }
 function M.make_range_params(window, offset_encoding)
-  local buf = a.nvim_win_get_buf(window or 0)
+  local buf = api.nvim_win_get_buf(window or 0)
   offset_encoding = offset_encoding or M._get_offset_encoding(buf)
   local position = make_position_param(window, offset_encoding)
   return {
@@ -1924,10 +1924,10 @@ function M.make_given_range_params(start_pos, end_pos, bufnr, offset_encoding)
     end_pos = { end_pos, 't', true },
     offset_encoding = { offset_encoding, 's', true },
   })
-  bufnr = bufnr or a.nvim_get_current_buf()
+  bufnr = bufnr or api.nvim_get_current_buf()
   offset_encoding = offset_encoding or M._get_offset_encoding(bufnr)
-  local A = list_extend({}, start_pos or a.nvim_buf_get_mark(bufnr, '<'))
-  local B = list_extend({}, end_pos or a.nvim_buf_get_mark(bufnr, '>'))
+  local A = list_extend({}, start_pos or api.nvim_buf_get_mark(bufnr, '<'))
+  local B = list_extend({}, end_pos or api.nvim_buf_get_mark(bufnr, '>'))
   -- convert to 0-index
   A[1] = A[1] - 1
   B[1] = B[1] - 1
-- 
cgit 


From eb9b93b5e025386ec9431c9d35a4a073d6946d1d Mon Sep 17 00:00:00 2001
From: matveyt <35012635+matveyt@users.noreply.github.com>
Date: Sun, 17 Jul 2022 14:14:04 +0300
Subject: feat(defaults): mouse=nvi  #19290

Problem:
Since right-click can now show a popup menu, we can provide messaging to
guide users who expect 'mouse' to be disabled by default. So 'mouse' can
now be enabled by default.

Solution:
Do it.
Closes #15521
---
 runtime/lua/vim/_editor.lua | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 7febad6ef6..c4cc151bca 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -810,6 +810,44 @@ function vim.deprecate(name, alternative, version, plugin, backtrace)
   end
 end
 
+--- Create builtin mappings (incl. menus).
+--- Called once on startup.
+function vim._init_default_mappings()
+  -- mappings
+
+  --@private
+  local function map(mode, lhs, rhs)
+    vim.api.nvim_set_keymap(mode, lhs, rhs, { noremap = true, desc = 'Nvim builtin' })
+  end
+
+  map('n', 'Y', 'y$')
+  -- Use normal!  to prevent inserting raw  when using i_. #17473
+  map('n', '', 'nohlsearchdiffupdatenormal! ')
+  map('i', '', 'u')
+  map('i', '', 'u')
+  map('x', '*', 'y/\\V"')
+  map('x', '#', 'y?\\V"')
+  -- Use : instead of  so that ranges are supported. #19365
+  map('n', '&', ':&&')
+
+  -- menus
+
+  -- TODO VimScript, no l10n
+  vim.cmd([[
+    aunmenu *
+    vnoremenu PopUp.Cut                     "+x
+    vnoremenu PopUp.Copy                    "+y
+    anoremenu PopUp.Paste                   "+gP
+    vnoremenu PopUp.Paste                   "+P
+    vnoremenu PopUp.Delete                  "_x
+    nnoremenu PopUp.Select\ All             ggVG
+    vnoremenu PopUp.Select\ All             gg0oG$
+    inoremenu PopUp.Select\ All             VG
+    anoremenu PopUp.-1-                     
+    anoremenu PopUp.How-to\ disable\ mouse  help disable-mouse
+  ]])
+end
+
 require('vim._meta')
 
 return vim
-- 
cgit 


From 5ccdf6a88d5790382ad3da6bb908c606765754e0 Mon Sep 17 00:00:00 2001
From: Gregory Anders <8965202+gpanders@users.noreply.github.com>
Date: Sun, 17 Jul 2022 06:33:51 -0600
Subject: vim-patch:9.0.0055 (#19392)

vim-patch:9.0.0055: bitbake files are not detected

Problem:    Bitbake files are not detected.
Solution:   Add bitbake filetype detection by file name and contents. (Gregory
            Anders, closes vim/vim#10697)
https://github.com/vim/vim/commit/fa49eb482729a5fe7da9c9a5ed8d14f68afa55c7
---
 runtime/lua/vim/filetype.lua        | 6 ++++++
 runtime/lua/vim/filetype/detect.lua | 4 +++-
 2 files changed, 9 insertions(+), 1 deletion(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 9ba036ca92..70c8cd15eb 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -172,6 +172,9 @@ local extension = {
     return require('vim.filetype.detect').bindzone(bufnr, '')
   end,
   bicep = 'bicep',
+  bb = 'bitbake',
+  bbappend = 'bitbake',
+  bbclass = 'bitbake',
   bl = 'blank',
   bsdl = 'bsdl',
   bst = 'bst',
@@ -1662,6 +1665,9 @@ local pattern = {
   ['[mM]akefile%.am'] = 'automake',
   ['.*/bind/db%..*'] = starsetf('bindzone'),
   ['.*/named/db%..*'] = starsetf('bindzone'),
+  ['.*/build/conf/.*%.conf'] = 'bitbake',
+  ['.*/meta/conf/.*%.conf'] = 'bitbake',
+  ['.*/meta%-.*/conf/.*%.conf'] = 'bitbake',
   ['.*bsd'] = 'bsdl',
   ['bzr_log%..*'] = 'bzr',
   ['.*enlightenment/.*%.cfg'] = 'c',
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 8331920406..8c10517687 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -62,7 +62,7 @@ end
 -- Checks the first 5 lines for a asmsyntax=foo override.
 -- Only whitespace characters can be present immediately before or after this statement.
 function M.asm_syntax(bufnr)
-  local lines = table.concat(getlines(bufnr, 1, 5), ' '):lower()
+  local lines = ' ' .. table.concat(getlines(bufnr, 1, 5), ' '):lower() .. ' '
   local match = lines:match('%sasmsyntax=([a-zA-Z0-9]+)%s')
   if match then
     return match
@@ -554,6 +554,8 @@ function M.inc(bufnr)
     -- headers so assume POV-Ray
   elseif findany(lines, { '^%s{', '^%s%(%*' }) or matchregex(lines, pascal_keywords) then
     return 'pascal'
+  elseif findany(lines, { '^%s*inherit ', '^%s*require ', '^%s*%w+%s+= ' }) then
+    return 'bitbake'
   else
     local syntax = M.asm_syntax(bufnr)
     if not syntax or syntax == '' then
-- 
cgit 


From ff35d7a4b9a9bcbd664a9dae1471d55be014f0af Mon Sep 17 00:00:00 2001
From: Raphael 
Date: Mon, 18 Jul 2022 01:11:05 +0800
Subject: fix(lsp): move augroup define to if statement (#19406)

---
 runtime/lua/vim/diagnostic.lua | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 40991673f3..ae20b5c517 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -372,14 +372,15 @@ local function schedule_display(namespace, bufnr, args)
   bufs_waiting_to_update[bufnr][namespace] = args
 
   local key = make_augroup_key(namespace, bufnr)
-  local group = vim.api.nvim_create_augroup(key, { clear = true })
   if not registered_autocmds[key] then
+    local group = vim.api.nvim_create_augroup(key, { clear = true })
     vim.api.nvim_create_autocmd(insert_leave_auto_cmds, {
       group = group,
       buffer = bufnr,
       callback = function()
         execute_scheduled_display(namespace, bufnr)
       end,
+      desc = 'vim.diagnostic: display diagnostics',
     })
     registered_autocmds[key] = true
   end
-- 
cgit 


From 13abe20b5f855779456c84b9583ed614223a69c8 Mon Sep 17 00:00:00 2001
From: ii14 <59243201+ii14@users.noreply.github.com>
Date: Sun, 17 Jul 2022 19:13:33 +0200
Subject: refactor(lsp): use autocmd api (#19407)

* refactor(lsp): use autocmd api

* refactor(lsp): inline BufWritePost and VimLeavePre callbacks
---
 runtime/lua/vim/lsp.lua          | 112 ++++++++++++++++++++-------------------
 runtime/lua/vim/lsp/handlers.lua |   2 +-
 2 files changed, 59 insertions(+), 55 deletions(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 7c95ecef92..61586ca44f 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1234,12 +1234,12 @@ function lsp.start_client(config)
       )
     end, function(request_id)
       client.requests[request_id] = nil
-      nvim_command('doautocmd  User LspRequest')
+      nvim_exec_autocmds('User', { pattern = 'LspRequest', modeline = false })
     end)
 
     if success then
       client.requests[request_id] = { type = 'pending', bufnr = bufnr, method = method }
-      nvim_command('doautocmd  User LspRequest')
+      nvim_exec_autocmds('User', { pattern = 'LspRequest', modeline = false })
     end
 
     return success, request_id
@@ -1308,7 +1308,7 @@ function lsp.start_client(config)
     local request = client.requests[id]
     if request and request.type == 'pending' then
       request.type = 'cancel'
-      nvim_command('doautocmd  User LspRequest')
+      nvim_exec_autocmds('User', { pattern = 'LspRequest', modeline = false })
     end
     return rpc.notify('$/cancelRequest', { id = id })
   end
@@ -1398,8 +1398,9 @@ do
     end
 end
 
--- Buffer lifecycle handler for textDocument/didSave
-function lsp._text_document_did_save_handler(bufnr)
+---@private
+---Buffer lifecycle handler for textDocument/didSave
+local function text_document_did_save_handler(bufnr)
   bufnr = resolve_bufnr(bufnr)
   local uri = vim.uri_from_bufnr(bufnr)
   local text = once(buf_get_full_text)
@@ -1445,13 +1446,15 @@ function lsp.buf_attach_client(bufnr, client_id)
     all_buffer_active_clients[bufnr] = buffer_client_ids
 
     local uri = vim.uri_from_bufnr(bufnr)
-    local buf_did_save_autocommand = [=[
-      augroup lsp_c_%d_b_%d_did_save
-        au!
-        au BufWritePost  lua vim.lsp._text_document_did_save_handler(0)
-      augroup END
-    ]=]
-    api.nvim_exec(string.format(buf_did_save_autocommand, client_id, bufnr, bufnr), false)
+    local augroup = ('lsp_c_%d_b_%d_did_save'):format(client_id, bufnr)
+    api.nvim_create_autocmd('BufWritePost', {
+      group = api.nvim_create_augroup(augroup, { clear = true }),
+      buffer = bufnr,
+      desc = 'vim.lsp: textDocument/didSave handler',
+      callback = function(ctx)
+        text_document_did_save_handler(ctx.buf)
+      end,
+    })
     -- First time, so attach and set up stuff.
     api.nvim_buf_attach(bufnr, false, {
       on_lines = text_document_did_change_handler,
@@ -1634,60 +1637,61 @@ function lsp.get_active_clients(filter)
   return clients
 end
 
-function lsp._vim_exit_handler()
-  log.info('exit_handler', active_clients)
-  for _, client in pairs(uninitialized_clients) do
-    client.stop(true)
-  end
-  -- TODO handle v:dying differently?
-  if tbl_isempty(active_clients) then
-    return
-  end
-  for _, client in pairs(active_clients) do
-    client.stop()
-  end
+api.nvim_create_autocmd('VimLeavePre', {
+  desc = 'vim.lsp: exit handler',
+  callback = function()
+    log.info('exit_handler', active_clients)
+    for _, client in pairs(uninitialized_clients) do
+      client.stop(true)
+    end
+    -- TODO handle v:dying differently?
+    if tbl_isempty(active_clients) then
+      return
+    end
+    for _, client in pairs(active_clients) do
+      client.stop()
+    end
 
-  local timeouts = {}
-  local max_timeout = 0
-  local send_kill = false
+    local timeouts = {}
+    local max_timeout = 0
+    local send_kill = false
 
-  for client_id, client in pairs(active_clients) do
-    local timeout = if_nil(client.config.flags.exit_timeout, 500)
-    if timeout then
-      send_kill = true
-      timeouts[client_id] = timeout
-      max_timeout = math.max(timeout, max_timeout)
+    for client_id, client in pairs(active_clients) do
+      local timeout = if_nil(client.config.flags.exit_timeout, 500)
+      if timeout then
+        send_kill = true
+        timeouts[client_id] = timeout
+        max_timeout = math.max(timeout, max_timeout)
+      end
     end
-  end
 
-  local poll_time = 50
+    local poll_time = 50
 
-  ---@private
-  local function check_clients_closed()
-    for client_id, timeout in pairs(timeouts) do
-      timeouts[client_id] = timeout - poll_time
-    end
+    ---@private
+    local function check_clients_closed()
+      for client_id, timeout in pairs(timeouts) do
+        timeouts[client_id] = timeout - poll_time
+      end
 
-    for client_id, _ in pairs(active_clients) do
-      if timeouts[client_id] ~= nil and timeouts[client_id] > 0 then
-        return false
+      for client_id, _ in pairs(active_clients) do
+        if timeouts[client_id] ~= nil and timeouts[client_id] > 0 then
+          return false
+        end
       end
+      return true
     end
-    return true
-  end
 
-  if send_kill then
-    if not vim.wait(max_timeout, check_clients_closed, poll_time) then
-      for client_id, client in pairs(active_clients) do
-        if timeouts[client_id] ~= nil then
-          client.stop(true)
+    if send_kill then
+      if not vim.wait(max_timeout, check_clients_closed, poll_time) then
+        for client_id, client in pairs(active_clients) do
+          if timeouts[client_id] ~= nil then
+            client.stop(true)
+          end
         end
       end
     end
-  end
-end
-
-nvim_command('autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()')
+  end,
+})
 
 --- Sends an async request for all active clients attached to the
 --- buffer.
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 68e1f59aaf..3b869d8f5c 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -61,7 +61,7 @@ local function progress_handler(_, result, ctx, _)
     client.messages.progress[token].done = true
   end
 
-  api.nvim_command('doautocmd  User LspProgressUpdate')
+  api.nvim_exec_autocmds('User', { pattern = 'LspProgressUpdate', modeline = false })
 end
 
 --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
-- 
cgit 


From 9169fb8f07238efd9fd0d0781c64c04abd1fa1ce Mon Sep 17 00:00:00 2001
From: ii14 <59243201+ii14@users.noreply.github.com>
Date: Mon, 18 Jul 2022 00:40:18 +0200
Subject: fix(lua): double entries in :lua completion #19410

`:lua vim.ls` would list `lsp` twice.
---
 runtime/lua/vim/_editor.lua | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index c4cc151bca..442d7b07d8 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -614,7 +614,7 @@ function vim._expand_pat(pat, env)
   local function insert_keys(obj)
     for k, _ in pairs(obj) do
       if type(k) == 'string' and string.sub(k, 1, string.len(match_part)) == match_part then
-        table.insert(keys, k)
+        keys[k] = true
       end
     end
   end
@@ -630,6 +630,7 @@ function vim._expand_pat(pat, env)
     insert_keys(vim._submodules)
   end
 
+  keys = vim.tbl_keys(keys)
   table.sort(keys)
 
   return keys, #prefix_match_pat
-- 
cgit 


From 776913e32ea4526847b1fffe2959d2b1f7d67451 Mon Sep 17 00:00:00 2001
From: Raphael 
Date: Mon, 18 Jul 2022 07:11:41 +0800
Subject: fix: add group in autocmd api #19412

regression from PR #19283: custom close autocommands for the preview window were
not cleaned up after the window was closed.
---
 runtime/lua/vim/lsp/util.lua | 1 +
 1 file changed, 1 insertion(+)

(limited to 'runtime/lua/vim')

diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 89b2301aa7..70f5010256 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1395,6 +1395,7 @@ local function close_preview_autocmd(events, winnr, bufnrs)
 
   if #events > 0 then
     api.nvim_create_autocmd(events, {
+      group = augroup,
       buffer = bufnrs[2],
       callback = function()
         close_preview_window(winnr)
-- 
cgit