diff options
118 files changed, 6640 insertions, 4811 deletions
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 2d06b1e685..4be49fd153 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -23,6 +23,11 @@ environment: CMAKE_EXTRA_FLAGS: -DCI_BUILD=ON -DMIN_LOG_LEVEL=3 tasks: +- should-run: | + if ! git -C neovim diff --name-only HEAD^! | grep -E -v "^(.github|runtime/doc/.*)" >/dev/null; then + echo "Skipping build because only ignored files were changed" + complete-build + fi - build-deps: | cd neovim gmake deps diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml index 0aaa003820..6263c436ae 100644 --- a/.builds/openbsd.yml +++ b/.builds/openbsd.yml @@ -23,6 +23,11 @@ environment: CMAKE_EXTRA_FLAGS: -DCI_BUILD=ON -DMIN_LOG_LEVEL=3 tasks: +- should-run: | + if ! git -C neovim diff --name-only HEAD^! | grep -E -v "^(.github|runtime/doc/.*)" >/dev/null; then + echo "Skipping build because only ignored files were changed" + complete-build + fi - build-deps: | export AUTOCONF_VERSION=2.71 export AUTOMAKE_VERSION=1.16 diff --git a/.editorconfig b/.editorconfig index 5a5fba37ac..2aa956b1fc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,14 +6,10 @@ indent_size = 2 tab_width = 8 end_of_line = lf insert_final_newline = true -charset = utf-8 [*.{c,h,in,lua}] max_line_length = 100 -[*.{vim,po}] -charset = unset - [{Makefile,**/Makefile,runtime/doc/*.txt}] indent_style = tab indent_size = 8 diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index fce35b54ee..c3078cfd35 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -47,6 +47,7 @@ a68faed02dc8e37b8f10da14dc02e33e6ed93947 ee031eb5256bb83e0d6add2bae6fd943a4186ffe 69e11b58b4db0952f11a5ff85aa7150b5f5b8db8 271bb32855853b011fceaf0ad2f829bce66b2a19 +aefdc6783cb77f09786542c90901a9e7120bea42 # typos d238b8f6003d34cae7f65ff7585b48a2cd9449fb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1aa0906ffc..87c270afbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,6 +87,13 @@ jobs: run: ./ci/run_lint.sh clint-full - if: "!cancelled()" + name: stylua + uses: JohnnyMorganz/stylua-action@1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --check runtime/ + + - if: "!cancelled()" name: lualint run: ./ci/run_lint.sh lualint diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000000..255bfd939d --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,6 @@ +column_width = 120 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferSingle" +call_parentheses = "Always" diff --git a/.styluaignore b/.styluaignore new file mode 100644 index 0000000000..c1871de90a --- /dev/null +++ b/.styluaignore @@ -0,0 +1,3 @@ +/scripts +/src +/test diff --git a/CMakeLists.txt b/CMakeLists.txt index 01df172ed4..409face71c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -614,7 +614,6 @@ endif() find_program(LUACHECK_PRG luacheck) find_program(FLAKE8_PRG flake8) -find_program(GPERF_PRG gperf) include(InstallHelpers) @@ -146,9 +146,16 @@ functionaltest: | nvim functionaltest-lua: | nvim +$(BUILD_TOOL) -C build functionaltest-lua +stylua: + stylua --check runtime/ + lualint: | build/.ran-cmake deps $(BUILD_TOOL) -C build lualint +_opt_stylua: + @command -v stylua && { $(MAKE) stylua; exit $$?; } \ + || echo "SKIP: stylua (stylua not found)" + shlint: @shellcheck --version | head -n 2 shellcheck scripts/vim-patch.sh @@ -214,7 +221,7 @@ appimage: appimage-%: bash scripts/genappimage.sh $* -lint: check-single-includes clint lualint _opt_pylint _opt_shlint _opt_commitlint +lint: check-single-includes clint _opt_stylua lualint _opt_pylint _opt_shlint _opt_commitlint # Generic pattern rules, allowing for `make build/bin/nvim` etc. # Does not work with "Unix Makefiles". @@ -226,4 +233,4 @@ $(DEPS_BUILD_DIR)/%: phony_force $(BUILD_TOOL) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@) endif -.PHONY: test lualint pylint shlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix commitlint +.PHONY: test stylua lualint pylint shlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix commitlint diff --git a/man/nvim.1 b/man/nvim.1 index 43dfc21dc7..9f35014ee8 100644 --- a/man/nvim.1 +++ b/man/nvim.1 @@ -188,7 +188,7 @@ loading plugins is also skipped. Use .Ar shada instead of the default -.Pa ~/.local/share/nvim/shada/main.shada . +.Pa ~/.local/state/nvim/shada/main.shada . If .Ar shada is @@ -326,7 +326,7 @@ Print version information and exit. .Sh ENVIRONMENT .Bl -tag -width Fl .It Ev NVIM_LOG_FILE -Low-level log file, usually found at ~/.cache/nvim/log. +Low-level log file, usually found at ~/.local/state/nvim/log. :help $NVIM_LOG_FILE .It Ev VIM Used to locate user files, such as init.vim. @@ -340,12 +340,20 @@ Path to the user-local configuration directory, see Defaults to .Pa ~/.config . :help xdg -.It Ev XDG_DATA_HOME +.It Ev XDG_STATE_HOME Like .Ev XDG_CONFIG_HOME , but used to store data not generally edited by the user, namely swap, backup, and ShaDa files. Defaults to +.Pa ~/.local/state . +:help xdg +.It Ev XDG_DATA_HOME +Like +.Ev XDG_CONFIG_HOME , +but used to store data not generally edited by the user, +things like runtime files. +Defaults to .Pa ~/.local/share . :help xdg .It Ev VIMINIT diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 50fe60a0fc..36325fb0ba 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -426,6 +426,14 @@ Two ways to create a floating window: To close it use |nvim_win_close()| or a command such as |:close|. +To check whether a window is floating, check whether the `relative` option in +its config is non-empty: > + + if vim.api.nvim_win_get_config(window_id).relative ~= '' then + -- window with this window_id is floating + end +> + Buffer text can be highlighted by typical mechanisms (syntax highlighting, |api-highlights|). The |hl-NormalFloat| group highlights normal text; 'winhighlight' can be used as usual to override groups locally. Floats inherit @@ -1711,17 +1719,49 @@ nvim_call_function({fn}, {args}) *nvim_call_function()* Return: ~ Result of the function call -nvim_command({command}) *nvim_command()* - Executes an ex-command. +nvim_cmd({*cmd}, {*opts}) *nvim_cmd()* + Executes an Ex command. - On execution error: fails with VimL error, does not update - v:errmsg. + Unlike |nvim_command()| this command takes a structured + Dictionary instead of a String. This allows for easier + construction and manipulation of an Ex command. This also + allows for things such as having spaces inside a command + argument, expanding filenames in a command that otherwise + doesn't expand filenames, etc. Parameters: ~ - {command} Ex-command string + {cmd} Command to execute. Must be a Dictionary that can + contain the same values as the return value of + |nvim_parse_cmd()| except "addr", "nargs" and + "nextcmd" which are ignored if provided. All + values except for "cmd" are optional. + {opts} Optional parameters. + • output: (boolean, default false) Whether to + return command output. + + Return: ~ + Command output (non-error, non-shell |:!|) if `output` is + true, else empty string. See also: ~ |nvim_exec()| + |nvim_command()| + +nvim_command({command}) *nvim_command()* + Executes an Ex command. + + On execution error: fails with VimL error, does not update + v:errmsg. + + Prefer using |nvim_cmd()| or |nvim_exec()| over this. To + evaluate multiple lines of Vim script or an Ex command + directly, use |nvim_exec()|. To construct an Ex command using + a structured format and then execute it, use |nvim_cmd()|. To + modify an Ex command before evaluating it, use + |nvim_parse_cmd()| in conjunction with |nvim_cmd()|. + + Parameters: ~ + {command} Ex command string nvim_eval({expr}) *nvim_eval()* Evaluates a VimL |expression|. Dictionaries and Lists are @@ -1737,7 +1777,7 @@ nvim_eval({expr}) *nvim_eval()* Evaluation result or expanded object nvim_exec({src}, {output}) *nvim_exec()* - Executes Vimscript (multiline block of Ex-commands), like + Executes Vimscript (multiline block of Ex commands), like anonymous |:source|. Unlike |nvim_command()| this function supports heredocs, @@ -1758,6 +1798,7 @@ nvim_exec({src}, {output}) *nvim_exec()* See also: ~ |execute()| |nvim_command()| + |nvim_cmd()| nvim_parse_cmd({str}, {opts}) *nvim_parse_cmd()* Parse command line. @@ -2197,7 +2238,7 @@ nvim_buf_get_lines({buffer}, {start}, {end}, {strict_indexing}) Parameters: ~ {buffer} Buffer handle, or 0 for current buffer {start} First line index - {end} Last line index (exclusive) + {end} Last line index, exclusive {strict_indexing} Whether out-of-bounds should be an error. @@ -2268,16 +2309,18 @@ nvim_buf_get_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, This differs from |nvim_buf_get_lines()| in that it allows retrieving only portions of a line. - Indexing is zero-based. Column indices are end-exclusive. + Indexing is zero-based. Row indices are end-inclusive, and + column indices are end-exclusive. Prefer |nvim_buf_get_lines()| when retrieving entire lines. Parameters: ~ {buffer} Buffer handle, or 0 for current buffer {start_row} First line index - {start_col} Starting byte offset of first line - {end_row} Last line index - {end_col} Ending byte offset of last line (exclusive) + {start_col} Starting column (byte offset) on first line + {end_row} Last line index, inclusive + {end_col} Ending column (byte offset) on last line, + exclusive {opts} Optional parameters. Currently unused. Return: ~ @@ -2357,7 +2400,7 @@ nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, {replacement}) Parameters: ~ {buffer} Buffer handle, or 0 for current buffer {start} First line index - {end} Last line index (exclusive) + {end} Last line index, exclusive {strict_indexing} Whether out-of-bounds should be an error. {replacement} Array of lines to use as replacement @@ -2407,25 +2450,27 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col}, {replacement}) Sets (replaces) a range in the buffer - This is recommended over nvim_buf_set_lines when only + This is recommended over |nvim_buf_set_lines()| when only modifying parts of a line, as extmarks will be preserved on non-modified parts of the touched lines. - Indexing is zero-based and end-exclusive. + Indexing is zero-based. Row indices are end-inclusive, and + column indices are end-exclusive. - To insert text at a given index, set `start` and `end` ranges - to the same index. To delete a range, set `replacement` to an - array containing an empty string, or simply an empty array. + To insert text at a given `(row, column)` location, use + `start_row = end_row = row` and `start_col = end_col = col`. + To delete the text in a range, use `replacement = {}`. - Prefer nvim_buf_set_lines when adding or deleting entire lines - only. + Prefer |nvim_buf_set_lines()| if you are only adding or + deleting entire lines. Parameters: ~ {buffer} Buffer handle, or 0 for current buffer {start_row} First line index - {start_col} First column - {end_row} Last line index - {end_col} Last column + {start_col} Starting column (byte offset) on first line + {end_row} Last line index, inclusive + {end_col} Ending column (byte offset) on last line, + exclusive {replacement} Array of lines to use as replacement nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()* diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index b9954dc99c..d197a2c62c 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -2800,7 +2800,7 @@ getcmdcompltype() *getcmdcompltype()* Return the type of the current command-line completion. Only works when the command line is being edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. - See |command-completion| for the return string. + See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()| and |getcmdline()|. Returns an empty string when completion is not defined. @@ -4976,10 +4976,9 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()* The optional {dict} argument always supports the following items: - matchseq When this item is present and {str} contains - multiple words separated by white space, then - returns only matches that contain the words in - the given sequence. + matchseq When this item is present return only matches + that contain the characters in {str} in the + given sequence. If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: @@ -7466,14 +7465,17 @@ stdpath({what}) *stdpath()* *E6100* directories. {what} Type Description ~ - cache String Cache directory. Arbitrary temporary + cache String Cache directory: arbitrary temporary storage for plugins, etc. - config String User configuration directory. The - |init.vim| is stored here. - config_dirs List Additional configuration directories. + config String User configuration directory. |init.vim| + is stored here. + config_dirs List Other configuration directories. data String User data directory. The |shada-file| is stored here. - data_dirs List Additional data directories. + data_dirs List Other data directories. + log String Logs directory (for use by plugins too). + state String Session state directory: storage for file + drafts, undo history, shada, etc. Example: > :echo stdpath("config") diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt index 32936a7ee6..2446506dec 100644 --- a/runtime/doc/diagnostic.txt +++ b/runtime/doc/diagnostic.txt @@ -336,8 +336,8 @@ config({opts}, {namespace}) *vim.diagnostic.config()* that returns any of the above. Parameters: ~ - {opts} table|nil When omitted or "nil", retrieve the - current configuration. Otherwise, a + {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: @@ -401,7 +401,7 @@ config({opts}, {namespace}) *vim.diagnostic.config()* displayed before lower severities (e.g. ERROR is displayed before WARN). Options: • reverse: (boolean) Reverse sort order - {namespace} number|nil Update the options for the given + {namespace} (number|nil) Update the options for the given namespace. When omitted, update the global diagnostic options. @@ -409,28 +409,28 @@ disable({bufnr}, {namespace}) *vim.diagnostic.disable()* Disable diagnostics in the given buffer. Parameters: ~ - {bufnr} number|nil Buffer number, or 0 for current + {bufnr} (number|nil) Buffer number, or 0 for current buffer. When omitted, disable diagnostics in all buffers. - {namespace} number|nil Only disable diagnostics for the + {namespace} (number|nil) Only disable diagnostics for the given namespace. enable({bufnr}, {namespace}) *vim.diagnostic.enable()* Enable diagnostics in the given buffer. Parameters: ~ - {bufnr} number|nil Buffer number, or 0 for current + {bufnr} (number|nil) Buffer number, or 0 for current buffer. When omitted, enable diagnostics in all buffers. - {namespace} number|nil Only enable diagnostics for the + {namespace} (number|nil) Only enable diagnostics for the given namespace. fromqflist({list}) *vim.diagnostic.fromqflist()* Convert a list of quickfix items to a list of diagnostics. Parameters: ~ - {list} table A list of quickfix items from |getqflist()| - or |getloclist()|. + {list} (table) A list of quickfix items from + |getqflist()| or |getloclist()|. Return: ~ array of diagnostics |diagnostic-structure| @@ -439,9 +439,10 @@ get({bufnr}, {opts}) *vim.diagnostic.get()* Get current diagnostics. Parameters: ~ - {bufnr} number|nil Buffer number to get diagnostics from. - Use 0 for current buffer or nil for all buffers. - {opts} table|nil A table with the following keys: + {bufnr} (number|nil) Buffer number to get diagnostics + from. Use 0 for current buffer or nil for all + buffers. + {opts} (table|nil) A table with the following keys: • namespace: (number) Limit diagnostics to the given namespace. • lnum: (number) Limit diagnostics to the given @@ -449,67 +450,68 @@ get({bufnr}, {opts}) *vim.diagnostic.get()* • severity: See |diagnostic-severity|. Return: ~ - table A list of diagnostic items |diagnostic-structure|. + (table) A list of diagnostic items |diagnostic-structure|. get_namespace({namespace}) *vim.diagnostic.get_namespace()* Get namespace metadata. Parameters: ~ - {namespace} number Diagnostic namespace + {namespace} (number) Diagnostic namespace Return: ~ - table Namespace metadata + (table) Namespace metadata get_namespaces() *vim.diagnostic.get_namespaces()* Get current diagnostic namespaces. Return: ~ - table A list of active diagnostic namespaces + (table) A list of active diagnostic namespaces |vim.diagnostic|. get_next({opts}) *vim.diagnostic.get_next()* Get the next diagnostic closest to the cursor position. Parameters: ~ - {opts} table See |vim.diagnostic.goto_next()| + {opts} (table) See |vim.diagnostic.goto_next()| Return: ~ - table Next diagnostic + (table) Next diagnostic get_next_pos({opts}) *vim.diagnostic.get_next_pos()* Return the position of the next diagnostic in the current buffer. Parameters: ~ - {opts} table See |vim.diagnostic.goto_next()| + {opts} (table) See |vim.diagnostic.goto_next()| Return: ~ - table Next diagnostic position as a (row, col) tuple. + (table) Next diagnostic position as a (row, col) tuple. get_prev({opts}) *vim.diagnostic.get_prev()* Get the previous diagnostic closest to the cursor position. Parameters: ~ - {opts} table See |vim.diagnostic.goto_next()| + {opts} (table) See |vim.diagnostic.goto_next()| Return: ~ - table Previous diagnostic + (table) Previous diagnostic get_prev_pos({opts}) *vim.diagnostic.get_prev_pos()* Return the position of the previous diagnostic in the current buffer. Parameters: ~ - {opts} table See |vim.diagnostic.goto_next()| + {opts} (table) See |vim.diagnostic.goto_next()| Return: ~ - table Previous diagnostic position as a (row, col) tuple. + (table) Previous diagnostic position as a (row, col) + tuple. goto_next({opts}) *vim.diagnostic.goto_next()* Move to the next diagnostic. Parameters: ~ - {opts} table|nil Configuration table with the following + {opts} (table|nil) Configuration table with the following keys: • namespace: (number) Only consider diagnostics from the given namespace. @@ -533,7 +535,7 @@ goto_prev({opts}) *vim.diagnostic.goto_prev()* Move to the previous diagnostic in the current buffer. Parameters: ~ - {opts} table See |vim.diagnostic.goto_next()| + {opts} (table) See |vim.diagnostic.goto_next()| hide({namespace}, {bufnr}) *vim.diagnostic.hide()* Hide currently displayed diagnostics. @@ -547,10 +549,10 @@ hide({namespace}, {bufnr}) *vim.diagnostic.hide()* |vim.diagnostic.disable()|. Parameters: ~ - {namespace} number|nil Diagnostic namespace. When + {namespace} (number|nil) Diagnostic namespace. When omitted, hide diagnostics from all namespaces. - {bufnr} number|nil Buffer number, or 0 for current + {bufnr} (number|nil) Buffer number, or 0 for current buffer. When omitted, hide diagnostics in all buffers. @@ -573,16 +575,16 @@ match({str}, {pat}, {groups}, {severity_map}, {defaults}) < Parameters: ~ - {str} string String to parse diagnostics from. - {pat} string Lua pattern with capture groups. - {groups} table List of fields in a + {str} (string) String to parse diagnostics from. + {pat} (string) Lua pattern with capture groups. + {groups} (table) List of fields in a |diagnostic-structure| to associate with captures from {pat}. - {severity_map} table A table mapping the severity field + {severity_map} (table) A table mapping the severity field from {groups} with an item from |vim.diagnostic.severity|. - {defaults} table|nil Table of default values for any - fields not listed in {groups}. When + {defaults} (table|nil) Table of default values for + any fields not listed in {groups}. When omitted, numeric values default to 0 and "severity" defaults to ERROR. @@ -594,7 +596,7 @@ open_float({opts}, {...}) *vim.diagnostic.open_float()* Show diagnostics in a floating window. Parameters: ~ - {opts} table|nil Configuration table with the same keys + {opts} (table|nil) Configuration table with the same keys as |vim.lsp.util.open_floating_preview()| in addition to the following: • bufnr: (number) Buffer number to show @@ -665,10 +667,10 @@ reset({namespace}, {bufnr}) *vim.diagnostic.reset()* |vim.diagnostic.hide()|. Parameters: ~ - {namespace} number|nil Diagnostic namespace. When + {namespace} (number|nil) Diagnostic namespace. When omitted, remove diagnostics from all namespaces. - {bufnr} number|nil Remove diagnostics for the given + {bufnr} (number|nil) Remove diagnostics for the given buffer. When omitted, diagnostics are removed for all buffers. @@ -676,18 +678,18 @@ set({namespace}, {bufnr}, {diagnostics}, {opts}) *vim.diagnostic.set()* Set diagnostics for the given namespace and buffer. Parameters: ~ - {namespace} number The diagnostic namespace - {bufnr} number Buffer number - {diagnostics} table A list of diagnostic items + {namespace} (number) The diagnostic namespace + {bufnr} (number) Buffer number + {diagnostics} (table) A list of diagnostic items |diagnostic-structure| - {opts} table|nil Display options to pass to + {opts} (table|nil) Display options to pass to |vim.diagnostic.show()| setloclist({opts}) *vim.diagnostic.setloclist()* Add buffer diagnostics to the location list. Parameters: ~ - {opts} table|nil Configuration table with the following + {opts} (table|nil) Configuration table with the following keys: • namespace: (number) Only add diagnostics from the given namespace. @@ -703,7 +705,7 @@ setqflist({opts}) *vim.diagnostic.setqflist()* Add all diagnostics to the quickfix list. Parameters: ~ - {opts} table|nil Configuration table with the following + {opts} (table|nil) Configuration table with the following keys: • namespace: (number) Only add diagnostics from the given namespace. @@ -718,20 +720,20 @@ show({namespace}, {bufnr}, {diagnostics}, {opts}) Display diagnostics for the given namespace and buffer. Parameters: ~ - {namespace} number|nil Diagnostic namespace. When + {namespace} (number|nil) Diagnostic namespace. When omitted, show diagnostics from all namespaces. - {bufnr} number|nil Buffer number, or 0 for current - buffer. When omitted, show diagnostics in - all buffers. - {diagnostics} table|nil The diagnostics to display. When - omitted, use the saved diagnostics for the - given namespace and buffer. This can be + {bufnr} (number|nil) Buffer number, or 0 for + current buffer. When omitted, show + diagnostics in all buffers. + {diagnostics} (table|nil) The diagnostics to display. + When omitted, use the saved diagnostics for + the given namespace and buffer. This can be used to display a list of diagnostics without saving them or to display only a subset of diagnostics. May not be used when {namespace} or {bufnr} is nil. - {opts} table|nil Display options. See + {opts} (table|nil) Display options. See |vim.diagnostic.config()|. toqflist({diagnostics}) *vim.diagnostic.toqflist()* @@ -739,7 +741,7 @@ toqflist({diagnostics}) *vim.diagnostic.toqflist()* can be passed to |setqflist()| or |setloclist()|. Parameters: ~ - {diagnostics} table List of diagnostics + {diagnostics} (table) List of diagnostics |diagnostic-structure|. Return: ~ diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 647feb6755..569c570624 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -495,8 +495,8 @@ buf_detach_client({bufnr}, {client_id}) *vim.lsp.buf_detach_client()* notification. Parameters: ~ - {bufnr} number Buffer handle, or 0 for current - {client_id} number Client id + {bufnr} (number) Buffer handle, or 0 for current + {client_id} (number) Client id buf_get_clients({bufnr}) *vim.lsp.buf_get_clients()* Gets a map of client_id:client pairs for the given buffer, @@ -668,11 +668,11 @@ for_each_buffer_client({bufnr}, {fn}) Invokes a function for each LSP client attached to a buffer. Parameters: ~ - {bufnr} number Buffer number - {fn} function Function to run on each client attached - to buffer {bufnr}. The function takes the client, - client ID, and buffer number as arguments. - Example: > + {bufnr} (number) Buffer number + {fn} (function) Function to run on each client + attached to buffer {bufnr}. The function takes + the client, client ID, and buffer number as + arguments. Example: > vim.lsp.for_each_buffer_client(0, function(client, client_id, bufnr) print(vim.inspect(client)) @@ -690,7 +690,7 @@ formatexpr({opts}) *vim.lsp.formatexpr()* 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})')`. Parameters: ~ - {opts} table options for customizing the formatting + {opts} (table) options for customizing the formatting expression which takes the following optional keys: • timeout_ms (default 500ms). The timeout period @@ -707,7 +707,7 @@ get_buffers_by_client_id({client_id}) Returns list of buffers attached to client_id. Parameters: ~ - {client_id} number client id + {client_id} (number) client id Return: ~ list of buffer ids @@ -717,7 +717,7 @@ get_client_by_id({client_id}) *vim.lsp.get_client_by_id()* client may not yet be fully initialized. Parameters: ~ - {client_id} number client id + {client_id} (number) client id Return: ~ |vim.lsp.client| object, or nil @@ -820,7 +820,7 @@ start_client({config}) *vim.lsp.start_client()* language server if requested via `workspace/configuration`. Keys are case-sensitive. - {commands} table Table that maps string of + {commands} (table) Table that maps string of clientside commands to user-defined functions. Commands passed to start_client take precedence over the @@ -908,10 +908,10 @@ start_client({config}) *vim.lsp.start_client()* kill -15. If set to false, nvim exits immediately after sending the 'shutdown' request to the server. - {root_dir} string Directory where the LSP server - will base its workspaceFolders, - rootUri, and rootPath on - initialization. + {root_dir} (string) Directory where the LSP + server will base its + workspaceFolders, rootUri, and + rootPath on initialization. Return: ~ Client id. |vim.lsp.get_client_by_id()| Note: client may @@ -935,7 +935,7 @@ stop_client({client_id}, {force}) *vim.lsp.stop_client()* Parameters: ~ {client_id} client id or |vim.lsp.client| object, or list thereof - {force} boolean (optional) shutdown forcefully + {force} (boolean) (optional) shutdown forcefully tagfunc({...}) *vim.lsp.tagfunc()* Provides an interface between the built-in client and @@ -980,7 +980,7 @@ code_action({options}) *vim.lsp.buf.code_action()* position. Parameters: ~ - {options} table|nil Optional table which holds the + {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 @@ -1048,7 +1048,7 @@ execute_command({command_params}) *vim.lsp.buf.execute_command()* Executes an LSP server command. Parameters: ~ - {command_params} table A valid `ExecuteCommandParams` + {command_params} (table) A valid `ExecuteCommandParams` object See also: ~ @@ -1146,7 +1146,7 @@ formatting_sync({options}, {timeout_ms}) < Parameters: ~ - {options} table|nil with valid `FormattingOptions` + {options} (table|nil) with valid `FormattingOptions` entries {timeout_ms} (number) Request timeout @@ -1180,7 +1180,7 @@ range_code_action({context}, {start_pos}, {end_pos}) Performs |vim.lsp.buf.code_action()| for a given range. Parameters: ~ - {context} table|nil `CodeActionContext` of the LSP specification: + {context} (table|nil) `CodeActionContext` of the LSP specification: • diagnostics: (table|nil) LSP`Diagnostic[]` . Inferred from the current position if not provided. • only: (table|nil) List of LSP @@ -1227,10 +1227,10 @@ rename({new_name}, {options}) *vim.lsp.buf.rename()* Renames all references to the symbol under the cursor. Parameters: ~ - {new_name} string|nil If not provided, the user will be + {new_name} (string|nil) If not provided, the user will be prompted for a new name using |vim.ui.input()|. - {options} table|nil additional options + {options} (table|nil) additional options • filter (function|nil): Predicate to filter clients used for rename. Receives the attached clients as argument and must return @@ -1275,7 +1275,7 @@ get_namespace({client_id}) *vim.lsp.diagnostic.get_namespace()* |vim.diagnostic|. Parameters: ~ - {client_id} number The id of the LSP client + {client_id} (number) The id of the LSP client *vim.lsp.diagnostic.on_publish_diagnostics()* on_publish_diagnostics({_}, {result}, {ctx}, {config}) @@ -1305,7 +1305,7 @@ on_publish_diagnostics({_}, {result}, {ctx}, {config}) < Parameters: ~ - {config} table Configuration table (see + {config} (table) Configuration table (see |vim.diagnostic.config()|). @@ -1316,20 +1316,20 @@ display({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.display()* Display the lenses using virtual text Parameters: ~ - {lenses} table of lenses to display (`CodeLens[] | + {lenses} (table) of lenses to display (`CodeLens[] | null`) - {bufnr} number - {client_id} number + {bufnr} (number) + {client_id} (number) get({bufnr}) *vim.lsp.codelens.get()* Return all lenses for the given buffer Parameters: ~ - {bufnr} number Buffer number. 0 can be used for the + {bufnr} (number) Buffer number. 0 can be used for the current buffer. Return: ~ - table (`CodeLens[]`) + (table) (`CodeLens[]`) *vim.lsp.codelens.on_codelens()* on_codelens({err}, {result}, {ctx}, {_}) @@ -1351,10 +1351,10 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()* Store lenses for a specific buffer and client Parameters: ~ - {lenses} table of lenses to store (`CodeLens[] | + {lenses} (table) of lenses to store (`CodeLens[] | null`) - {bufnr} number - {client_id} number + {bufnr} (number) + {client_id} (number) ============================================================================== @@ -1372,7 +1372,7 @@ hover({_}, {result}, {ctx}, {config}) *vim.lsp.handlers.hover()* < Parameters: ~ - {config} table Configuration table. + {config} (table) Configuration table. • border: (default=nil) • Add borders to the floating window • See |nvim_open_win()| @@ -1392,7 +1392,7 @@ signature_help({_}, {result}, {ctx}, {config}) < Parameters: ~ - {config} table Configuration table. + {config} (table) Configuration table. • border: (default=nil) • Add borders to the floating window • See |vim.api.nvim_open_win()| @@ -1420,9 +1420,9 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding}) Applies a list of text edits to a buffer. Parameters: ~ - {text_edits} table list of `TextEdit` objects - {bufnr} number Buffer id - {offset_encoding} string utf-8|utf-16|utf-32 + {text_edits} (table) list of `TextEdit` objects + {bufnr} (number) Buffer id + {offset_encoding} (string) utf-8|utf-16|utf-32 See also: ~ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit @@ -1432,24 +1432,24 @@ apply_workspace_edit({workspace_edit}, {offset_encoding}) Applies a `WorkspaceEdit`. Parameters: ~ - {workspace_edit} table `WorkspaceEdit` - {offset_encoding} string utf-8|utf-16|utf-32 (required) + {workspace_edit} (table) `WorkspaceEdit` + {offset_encoding} (string) utf-8|utf-16|utf-32 (required) buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()* Removes document highlights from a buffer. Parameters: ~ - {bufnr} number Buffer id + {bufnr} (number) Buffer id *vim.lsp.util.buf_highlight_references()* buf_highlight_references({bufnr}, {references}, {offset_encoding}) Shows a list of document highlights for a certain buffer. Parameters: ~ - {bufnr} number Buffer id - {references} table List of `DocumentHighlight` + {bufnr} (number) Buffer id + {references} (table) List of `DocumentHighlight` objects to highlight - {offset_encoding} string One of "utf-8", "utf-16", + {offset_encoding} (string) One of "utf-8", "utf-16", "utf-32". See also: ~ @@ -1464,9 +1464,9 @@ character_offset({buf}, {row}, {col}, {offset_encoding}) {buf} buffer id (0 for current) {row} 0-indexed line {col} 0-indexed byte offset in line - {offset_encoding} string utf-8|utf-16|utf-32|nil defaults - to `offset_encoding` of first client of - `buf` + {offset_encoding} (string) utf-8|utf-16|utf-32|nil + defaults to `offset_encoding` of first + client of `buf` Return: ~ (number, number) `offset_encoding` index of the character @@ -1543,8 +1543,8 @@ jump_to_location({location}, {offset_encoding}) Jumps to a location. Parameters: ~ - {location} table (`Location`|`LocationLink`) - {offset_encoding} string utf-8|utf-16|utf-32 (required) + {location} (table) (`Location`|`LocationLink`) + {offset_encoding} (string) utf-8|utf-16|utf-32 (required) Return: ~ `true` if the jump succeeded @@ -1559,9 +1559,9 @@ locations_to_items({locations}, {offset_encoding}) |setqflist()| or |setloclist()|. Parameters: ~ - {locations} table list of `Location`s or + {locations} (table) list of `Location`s or `LocationLink`s - {offset_encoding} string offset_encoding for locations + {offset_encoding} (string) offset_encoding for locations utf-8|utf-16|utf-32 Return: ~ @@ -1606,7 +1606,7 @@ make_formatting_params({options}) buffer and cursor position. Parameters: ~ - {options} table|nil with valid `FormattingOptions` + {options} (table|nil) with valid `FormattingOptions` entries Return: ~ @@ -1629,9 +1629,9 @@ make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding}) end of the last visual selection. {bufnr} (optional, number): buffer handle or 0 for current, defaults to current - {offset_encoding} string utf-8|utf-16|utf-32|nil defaults - to `offset_encoding` of first client of - `bufnr` + {offset_encoding} (string) utf-8|utf-16|utf-32|nil + defaults to `offset_encoding` of first + client of `bufnr` Return: ~ { textDocument = { uri = `current_file_uri` }, range = { @@ -1645,9 +1645,9 @@ make_position_params({window}, {offset_encoding}) Parameters: ~ {window} (optional, number): window handle or 0 for current, defaults to current - {offset_encoding} string utf-8|utf-16|utf-32|nil defaults - to `offset_encoding` of first client of - buffer of `window` + {offset_encoding} (string) utf-8|utf-16|utf-32|nil + defaults to `offset_encoding` of first + client of buffer of `window` Return: ~ `TextDocumentPositionParams` object @@ -1666,9 +1666,9 @@ make_range_params({window}, {offset_encoding}) Parameters: ~ {window} (optional, number): window handle or 0 for current, defaults to current - {offset_encoding} string utf-8|utf-16|utf-32|nil defaults - to `offset_encoding` of first client of - buffer of `window` + {offset_encoding} (string) utf-8|utf-16|utf-32|nil + defaults to `offset_encoding` of first + client of buffer of `window` Return: ~ { textDocument = { uri = `current_file_uri` }, range = { @@ -1702,9 +1702,9 @@ open_floating_preview({contents}, {syntax}, {opts}) Shows contents in a floating window. Parameters: ~ - {contents} table of lines to show in window - {syntax} string of syntax to set for opened buffer - {opts} table with optional fields (additional keys + {contents} (table) of lines to show in window + {syntax} (string) of syntax to set for opened buffer + {opts} (table) with optional fields (additional keys are passed on to |vim.api.nvim_open_win()|) • height: (number) height of floating window • width: (number) width of floating window @@ -1739,10 +1739,10 @@ parse_snippet({input}) *vim.lsp.util.parse_snippet()* Parses snippets in a completion entry. Parameters: ~ - {input} string unparsed snippet + {input} (string) unparsed snippet Return: ~ - string parsed snippet + (string) parsed snippet preview_location({location}, {opts}) *vim.lsp.util.preview_location()* Previews a location in a floating window @@ -1795,7 +1795,7 @@ stylize_markdown({bufnr}, {contents}, {opts}) `open_floating_preview` instead Parameters: ~ - {contents} table of lines to show in window + {contents} (table) of lines to show in window {opts} dictionary with optional fields • height of floating window • width of floating window @@ -1873,14 +1873,15 @@ get_level() *vim.lsp.log.get_level()* Gets the current log level. Return: ~ - string current log level + (string) current log level set_format_func({handle}) *vim.lsp.log.set_format_func()* Sets formatting function used to format logs Parameters: ~ - {handle} function function to apply to logging arguments, - pass vim.inspect for multi-line formatting + {handle} (function) function to apply to logging + arguments, pass vim.inspect for multi-line + formatting set_level({level}) *vim.lsp.log.set_level()* Sets the current log level. @@ -1892,7 +1893,7 @@ should_log({level}) *vim.lsp.log.should_log()* Checks whether the level is sufficient for logging. Parameters: ~ - {level} number log level + {level} (number) log level Return: ~ (bool) true if would log, false if not @@ -1998,19 +1999,19 @@ compute_diff({prev_lines}, {curr_lines}, {firstline}, {lastline}, curr lines Parameters: ~ - {prev_lines} table list of lines - {curr_lines} table list of lines - {firstline} number line to begin search for first + {prev_lines} (table) list of lines + {curr_lines} (table) list of lines + {firstline} (number) line to begin search for first difference - {lastline} number line to begin search in + {lastline} (number) line to begin search in old_lines for last difference - {new_lastline} number line to begin search in + {new_lastline} (number) line to begin search in new_lines for last difference - {offset_encoding} string encoding requested by language + {offset_encoding} (string) encoding requested by language server Return: ~ - table TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocumentContentChangeEvent + (table) TextDocumentContentChangeEvent see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#textDocumentContentChangeEvent ============================================================================== @@ -2027,10 +2028,10 @@ resolve_capabilities({server_capabilities}) capabilities. Parameters: ~ - {server_capabilities} table Table of capabilities + {server_capabilities} (table) Table of capabilities supported by the server Return: ~ - table Normalized table of capabilities + (table) Normalized table of capabilities vim:tw=78:ts=8:ft=help:norl: diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 534a40ff4f..150a3d18e9 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -4,52 +4,52 @@ NVIM REFERENCE MANUAL -Lua engine *lua* *Lua* +Lua engine *lua* *Lua* - Type |gO| to see the table of contents. + Type |gO| to see the table of contents. ============================================================================== -INTRODUCTION *lua-intro* +INTRODUCTION *lua-intro* -The Lua 5.1 language is builtin and always available. Try this command to get +The Lua 5.1 language is builtin and always available. Try this command to get an idea of what lurks beneath: > :lua print(vim.inspect(package.loaded)) - -Nvim includes a "standard library" |lua-stdlib| for Lua. It complements the +< +Nvim includes a "standard library" |lua-stdlib| for Lua. It complements the "editor stdlib" (|builtin-functions| and Ex commands) and the |API|, all of which can be used from Lua code. A good overview of using Lua in neovim is given by https://github.com/nanotee/nvim-lua-guide. The |:source| and |:runtime| commands can run Lua scripts as well as Vim -scripts. Lua modules can be loaded with `require('name')`, which +scripts. Lua modules can be loaded with `require('name')`, which conventionally returns a table but can return any value. See |lua-require| for details on how Nvim finds and loads Lua modules. See |lua-require-example| for an example of how to write and use a module. ============================================================================== -IMPORTING LUA MODULES *lua-require* +IMPORTING LUA MODULES *lua-require* Modules are searched for under the directories specified in 'runtimepath', in -the order they appear. Any `.` in the module name is treated as a directory -separator when searching. For a module `foo.bar`, each directory is searched -for `lua/foo/bar.lua`, then `lua/foo/bar/init.lua`. If no files are found, +the order they appear. Any `.` in the module name is treated as a directory +separator when searching. For a module `foo.bar`, each directory is searched +for `lua/foo/bar.lua`, then `lua/foo/bar/init.lua`. If no files are found, the directories are searched again for a shared library with a name matching -`lua/foo/bar.?`, where `?` is a list of suffixes (such as `so` or `dll`) -derived from the initial value of `package.cpath`. If still no files are -found, Nvim falls back to Lua's default search mechanism. The first script -found is run and `require()` returns the value returned by the script if any, -else `true`. - -The return value is cached after the first call to `require()` for each -module, with subsequent calls returning the cached value without searching for -or executing any script. For further details on `require()`, see the Lua +`lua/foo/bar.?`, where `?` is a list of suffixes (such as `so` or `dll`) derived from +the initial value of `package.cpath`. If still no files are found, Nvim falls +back to Lua's default search mechanism. The first script found is run and +`require()` returns the value returned by the script if any, else `true`. + +The return value is cached after the first call to `require()` for each module, +with subsequent calls returning the cached value without searching for, or +executing any script. For further details on `require()`, see the Lua documentation at https://www.lua.org/manual/5.1/manual.html#pdf-require. For example, if 'runtimepath' is `foo,bar` and `package.cpath` was `./?.so;./?.dll` at startup, `require('mod')` searches these paths in order and loads the first module found: + foo/lua/mod.lua foo/lua/mod/init.lua bar/lua/mod.lua @@ -59,35 +59,34 @@ and loads the first module found: bar/lua/mod.so bar/lua/mod.dll - *lua-package-path* -Nvim automatically adjusts `package.path` and `package.cpath` according to -effective 'runtimepath' value. Adjustment happens whenever 'runtimepath' is -changed. `package.path` is adjusted by simply appending `/lua/?.lua` and +Nvim automatically adjusts `package.path` and `package.cpath` according to the +effective 'runtimepath' value. Adjustment happens whenever 'runtimepath' is +changed. `package.path` is adjusted by simply appending `/lua/?.lua` and `/lua/?/init.lua` to each directory from 'runtimepath' (`/` is actually the first character of `package.config`). Similarly to `package.path`, modified directories from 'runtimepath' are also -added to `package.cpath`. In this case, instead of appending `/lua/?.lua` and +added to `package.cpath`. In this case, instead of appending `/lua/?.lua` and `/lua/?/init.lua` to each runtimepath, all unique `?`-containing suffixes of -the existing `package.cpath` are used. Example: +the existing `package.cpath` are used. Example: 1. Given that - 'runtimepath' contains `/foo/bar,/xxx;yyy/baz,/abc`; - - initial (defined at compile-time or derived from - `$LUA_CPATH`/`$LUA_INIT`) `package.cpath` contains + - initial (defined at compile-time or derived from + `$LUA_CPATH`/`$LUA_INIT`) `package.cpath` contains `./?.so;/def/ghi/a?d/j/g.elf;/def/?.so`. -2. It finds `?`-containing suffixes `/?.so`, `/a?d/j/g.elf` and `/?.so`, in - order: parts of the path starting from the first path component containing +2. It finds `?`-containing suffixes `/?.so`, `/a?d/j/g.elf` and `/?.so`, in + order: parts of the path starting from the first path component containing question mark and preceding path separator. -3. The suffix of `/def/?.so`, namely `/?.so` is not unique, as it’s the same - as the suffix of the first path from `package.path` (i.e. `./?.so`). Which +3. The suffix of `/def/?.so`, namely `/?.so` is not unique, as it’s the same + as the suffix of the first path from `package.path` (i.e. `./?.so`). Which leaves `/?.so` and `/a?d/j/g.elf`, in this order. -4. 'runtimepath' has three paths: `/foo/bar`, `/xxx;yyy/baz` and `/abc`. The - second one contains semicolon which is a paths separator so it is out, +4. 'runtimepath' has three paths: `/foo/bar`, `/xxx;yyy/baz` and `/abc`. The + second one contains a semicolon which is a paths separator so it is out, leaving only `/foo/bar` and `/abc`, in order. -5. The cartesian product of paths from 4. and suffixes from 3. is taken, - giving four variants. In each variant `/lua` path segment is inserted - between path and suffix, leaving +5. The cartesian product of paths from 4. and suffixes from 3. is taken, + giving four variants. In each variant, a `/lua` path segment is inserted + between path and suffix, leaving: - `/foo/bar/lua/?.so` - `/foo/bar/lua/a?d/j/g.elf` @@ -107,28 +106,28 @@ Note: - To track 'runtimepath' updates, paths added at previous update are remembered and removed at the next update, while all paths derived from the - new 'runtimepath' are prepended as described above. This allows removing + new 'runtimepath' are prepended as described above. This allows removing paths when path is removed from 'runtimepath', adding paths when they are added and reordering `package.path`/`package.cpath` content if 'runtimepath' was reordered. - Although adjustments happen automatically, Nvim does not track current - values of `package.path` or `package.cpath`. If you happen to delete some + values of `package.path` or `package.cpath`. If you happen to delete some paths from there you can set 'runtimepath' to trigger an update: > let &runtimepath = &runtimepath - Skipping paths from 'runtimepath' which contain semicolons applies both to - `package.path` and `package.cpath`. Given that there are some badly written - plugins using shell which will not work with paths containing semicolons it - is better to not have them in 'runtimepath' at all. + `package.path` and `package.cpath`. Given that there are some badly written + plugins using shell, which will not work with paths containing semicolons, + it is better to not have them in 'runtimepath' at all. ============================================================================== -Lua Syntax Information *lua-syntax-help* +Lua Syntax Information *lua-syntax-help* While Lua has a simple syntax, there are a few things to understand, particularly when looking at the documentation above. - *lua-syntax-call-function* + *lua-syntax-call-function* Lua functions can be called in multiple ways. Consider the function: > @@ -136,8 +135,7 @@ Lua functions can be called in multiple ways. Consider the function: > print("A is: ", a) print("B is: ", b) end - - +< The first way to call this function is: > example_func(1, 2) @@ -154,7 +152,6 @@ not supplied are automatically set to `nil`. For example: > -- A is: 1 -- B is: nil < - Additionally, if any extra parameters are passed, they are discarded completely. @@ -172,18 +169,16 @@ single dictionary, for example: > func_with_opts { foo = true, filename = "hello.world" } < - In this style, each "parameter" is passed via keyword. It is still valid to call the function in the standard style: > func_with_opts({ foo = true, filename = "hello.world" }) < - But often in the documentation, you will see the former rather than the latter style due to its brevity. ============================================================================== -Lua Patterns *lua-patterns* +Lua Patterns *lua-patterns* For performance reasons, Lua does not support regular expressions natively. Instead, the Lua `string` standard library allows manipulations using a @@ -207,13 +202,13 @@ For more complex matching, Vim regular expressions can be used from Lua through |vim.regex()|. ------------------------------------------------------------------------------ -LUA PLUGIN EXAMPLE *lua-require-example* +LUA PLUGIN EXAMPLE *lua-require-example* -The following example plugin adds a command `:MakeCharBlob` which transforms -current buffer into a long `unsigned char` array. Lua contains transformation -function in a module `lua/charblob.lua` which is imported in -`autoload/charblob.vim` (`require("charblob")`). Example plugin is supposed -to be put into any directory from 'runtimepath', e.g. `~/.config/nvim` (in +The following example plugin adds a command `:MakeCharBlob` which transforms +current buffer into a long `unsigned char` array. Lua contains transformation +function in a module `lua/charblob.lua` which is imported in +`autoload/charblob.vim` (`require("charblob")`). Example plugin is supposed +to be put into any directory from 'runtimepath', e.g. `~/.config/nvim` (in this case `lua/charblob.lua` means `~/.config/nvim/lua/charblob.lua`). autoload/charblob.vim: > @@ -223,7 +218,7 @@ autoload/charblob.vim: > \ 'require("charblob").encode(unpack(_A))', \ [getline(1, '$'), &textwidth, ' '])) endfunction - +< plugin/charblob.vim: > if exists('g:charblob_loaded') @@ -232,7 +227,7 @@ plugin/charblob.vim: > let g:charblob_loaded = 1 command MakeCharBlob :call charblob#encode_buffer() - +< lua/charblob.lua: > local function charblob_bytes_iter(lines) @@ -282,9 +277,9 @@ lua/charblob.lua: > bytes_iter = charblob_bytes_iter, encode = charblob_encode, } - +< ============================================================================== -COMMANDS *lua-commands* +COMMANDS *lua-commands* These commands execute a Lua chunk from either the command line (:lua, :luado) or a file (:luafile) on the given line [range]. As always in Lua, each chunk @@ -295,10 +290,10 @@ command calls. The |lua-stdlib| modules, user modules, and anything else on The Lua print() function redirects its output to the Nvim message area, with arguments separated by " " (space) instead of "\t" (tab). - *:lua* + *:lua* :[range]lua {chunk} Executes Lua chunk {chunk}. - if {chunk} starts with "=" the rest of the chunk is + If {chunk} starts with "=" the rest of the chunk is evaluated as an expression and printed. `:lua =expr` is equivalent to `:lua print(vim.inspect(expr))` Examples: > @@ -308,7 +303,7 @@ arguments separated by " " (space) instead of "\t" (tab). < To see the LuaJIT version: > :lua =jit.version < - *:lua-heredoc* + *:lua-heredoc* :[range]lua << [endmarker] {script} {endmarker} @@ -328,11 +323,11 @@ arguments separated by " " (space) instead of "\t" (tab). linenr, #curline)) EOF endfunction - -< Note that the `local` variables will disappear when +< + Note that the `local` variables will disappear when the block finishes. But not globals. - *:luado* + *:luado* :[range]luado {body} Executes Lua chunk "function(line, linenr) {body} end" for each buffer line in [range], where `line` is the current line text (without <EOL>), and `linenr` is the @@ -349,8 +344,7 @@ arguments separated by " " (space) instead of "\t" (tab). :lua bp = lpeg.P{ "(" * ((1 - lpeg.S"()") + lpeg.V(1))^0 * ")" } :luado if bp:match(line) then return "-->\t" .. line end < - - *:luafile* + *:luafile* :[range]luafile {file} Execute Lua script in {file}. The whole argument is used as the filename (like @@ -363,19 +357,19 @@ arguments separated by " " (space) instead of "\t" (tab). < ============================================================================== -luaeval() *lua-eval* *luaeval()* +luaeval() *lua-eval* *luaeval()* The (dual) equivalent of "vim.eval" for passing Lua values to Nvim is -"luaeval". "luaeval" takes an expression string and an optional argument used -for _A inside expression and returns the result of the expression. It is -semantically equivalent in Lua to: -> +"luaeval". "luaeval" takes an expression string and an optional argument used +for _A inside expression and returns the result of the expression. It is +semantically equivalent in Lua to: > + local chunkheader = "local _A = select(1, ...) return " function luaeval (expstr, arg) local chunk = assert(loadstring(chunkheader .. expstr, "luaeval")) return chunk(arg) -- return typval end - +< Lua nils, numbers, strings, tables and booleans are converted to their respective Vimscript types. If a Lua string contains a NUL byte, it will be converted to a |Blob|. Conversion of other Lua types is an error. @@ -387,22 +381,22 @@ Example: > 42 :echo luaeval('string.match(_A, "[a-z]+")', 'XYXfoo123') foo - +< Lua tables are used as both dictionaries and lists, so it is impossible to determine whether empty table is meant to be empty list or empty dictionary. Additionally Lua does not have integer numbers. To distinguish between these cases there is the following agreement: 0. Empty table is empty list. -1. Table with N incrementally growing integral numbers, starting from 1 and +1. Table with N incrementally growing integral numbers, starting from 1 and ending with N is considered to be a list. -2. Table with string keys, none of which contains NUL byte, is considered to +2. Table with string keys, none of which contains NUL byte, is considered to be a dictionary. -3. Table with string keys, at least one of which contains NUL byte, is also - considered to be a dictionary, but this time it is converted to +3. Table with string keys, at least one of which contains NUL byte, is also + considered to be a dictionary, but this time it is converted to a |msgpack-special-map|. - *lua-special-tbl* -4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point + *lua-special-tbl* +4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point value: - `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to a floating-point 1.0. Note that by default integral Lua numbers are @@ -425,14 +419,14 @@ Examples: > : return luaeval('(_A.y-_A.x)*math.random()+_A.x', {'x':a:x,'y':a:y}) : endfunction :echo Rand(1,10) - -Note: second argument to `luaeval` is converted ("marshalled") from Vimscript +< +Note: Second argument to `luaeval` is converted ("marshalled") from Vimscript to Lua, so changes to Lua containers do not affect values in Vimscript. Return value is also always converted. When converting, |msgpack-special-dict|s are treated specially. ============================================================================== -Vimscript v:lua interface *v:lua-call* +Vimscript v:lua interface *v:lua-call* From Vimscript the special `v:lua` prefix can be used to call Lua functions which are global or accessible from global tables. The expression > @@ -447,7 +441,7 @@ is equivalent to the Lua chunk > In addition, functions of packages can be accessed like > v:lua.require'mypack'.func(arg1, arg2) v:lua.require'mypack.submod'.func(arg1, arg2) -Note: only single quote form without parens is allowed. Using +Note: Only single quote form without parens is allowed. Using `require"mypack"` or `require('mypack')` as prefixes do NOT work (the latter is still valid as a function call of itself, in case require returns a useful value). @@ -455,7 +449,7 @@ value). The `v:lua` prefix may be used to call Lua functions as |method|s. For example: > arg1->v:lua.somemod.func(arg2) - +< You can use `v:lua` in "func" options like 'tagfunc', 'omnifunc', etc. For example consider the following Lua omnifunc handler: > @@ -468,7 +462,7 @@ For example consider the following Lua omnifunc handler: > end vim.api.nvim_buf_set_option(0, 'omnifunc', 'v:lua.mymod.omnifunc') -Note: the module ("mymod" in the above example) must either be a Lua global, +Note: The module ("mymod" in the above example) must either be a Lua global, or use the require syntax as specified above to access it from a package. Note: `v:lua` without a call is not allowed in a Vimscript expression: @@ -478,13 +472,12 @@ Note: `v:lua` without a call is not allowed in a Vimscript expression: call SomeFunc(v:lua.mycallback) " Error let g:foo = v:lua " Error let g:foo = v:['lua'] " Error - - +< ============================================================================== -Lua standard modules *lua-stdlib* +Lua standard modules *lua-stdlib* The Nvim Lua "standard library" (stdlib) is the `vim` module, which exposes -various functions and sub-modules. It is always loaded, thus require("vim") +various functions and sub-modules. It is always loaded, thus `require("vim")` is unnecessary. You can peek at the module properties: > @@ -515,34 +508,35 @@ Note that underscore-prefixed functions (e.g. "_os_proc_children") are internal/private and must not be used by plugins. ------------------------------------------------------------------------------ -VIM.LOOP *lua-loop* *vim.loop* +VIM.LOOP *lua-loop* *vim.loop* -`vim.loop` exposes all features of the Nvim event-loop. This is a low-level +`vim.loop` exposes all features of the Nvim event-loop. This is a low-level API that provides functionality for networking, filesystem, and process -management. Try this command to see available functions: > +management. Try this command to see available functions: > :lua print(vim.inspect(vim.loop)) - +< Reference: https://github.com/luvit/luv/blob/master/docs.md Examples: https://github.com/luvit/luv/tree/master/examples - *E5560* *lua-loop-callbacks* + *E5560* *lua-loop-callbacks* It is an error to directly invoke `vim.api` functions (except |api-fast|) in -`vim.loop` callbacks. For example, this is an error: > +`vim.loop` callbacks. For example, this is an error: > local timer = vim.loop.new_timer() timer:start(1000, 0, function() vim.api.nvim_command('echomsg "test"') end) - +< To avoid the error use |vim.schedule_wrap()| to defer the callback: > local timer = vim.loop.new_timer() timer:start(1000, 0, vim.schedule_wrap(function() vim.api.nvim_command('echomsg "test"') end)) - -(For one-shot timers, see |vim.defer_fn()|, which automatically adds the wrapping.) +< +(For one-shot timers, see |vim.defer_fn()|, which automatically adds the +wrapping.) Example: repeating timer 1. Save this code to a file. @@ -560,9 +554,8 @@ Example: repeating timer i = i + 1 end) print('sleeping'); - - -Example: File-change detection *watch-file* +< +Example: File-change detection *watch-file* 1. Save this code to a file. 2. Execute it with ":luafile %". 3. Use ":Watch %" to watch any file. @@ -586,9 +579,8 @@ Example: File-change detection *watch-file* end vim.api.nvim_command( "command! -nargs=1 Watch call luaeval('watch_file(_A)', expand('<args>'))") - - -Example: TCP echo-server *tcp-server* +< +Example: TCP echo-server *tcp-server* 1. Save this code to a file. 2. Execute it with ":luafile %". 3. Note the port number. @@ -616,9 +608,8 @@ Example: TCP echo-server *tcp-server* end) end) print('TCP echo-server listening on port: '..server:getsockname().port) - - -Multithreading *lua-loop-threading* +< +Multithreading *lua-loop-threading* Plugins can perform work in separate (os-level) threads using the threading APIs in luv, for instance `vim.loop.new_thread`. Note that every thread @@ -638,7 +629,7 @@ A subset of the `vim.*` API is available in threads. This includes: - `vim.is_thread()` returns true from a non-main thread. ------------------------------------------------------------------------------ -VIM.HIGHLIGHT *lua-highlight* +VIM.HIGHLIGHT *lua-highlight* Nvim includes a function for highlighting a selection on yank (see for example https://github.com/machakann/vim-highlightedyank). To enable it, add @@ -654,8 +645,7 @@ If you want to exclude visual selections from highlighting on yank, use > au TextYankPost * silent! lua vim.highlight.on_yank {on_visual=false} < - -vim.highlight.on_yank({opts}) *vim.highlight.on_yank()* +vim.highlight.on_yank({opts}) *vim.highlight.on_yank()* Highlights the yanked text. The fields of the optional dict {opts} control the highlight: - {higroup} highlight group for yanked region (default |hl-IncSearch|) @@ -678,12 +668,12 @@ vim.highlight.range({bufnr}, {ns}, {hlgroup}, {start}, {finish}, {opts}) {opts} optional parameters: • `regtype`: type of range (characterwise, linewise, or blockwise, see |setreg|), default `'v'` - • `inclusive`: range includes end position, default - `false` + • `inclusive`: range includes end position, + default `false` • `priority`: priority of highlight, default `vim.highlight.user` (see below) -vim.highlight.priorities *vim.highlight.priorities* +vim.highlight.priorities *vim.highlight.priorities* Table with default priorities used for highlighting: • `syntax`: `50`, used for standard syntax highlighting @@ -693,19 +683,19 @@ vim.highlight.priorities *vim.highlight.priorities* document symbols or `on_yank` autocommands ------------------------------------------------------------------------------ -VIM.REGEX *lua-regex* +VIM.REGEX *lua-regex* Vim regexes can be used directly from lua. Currently they only allow matching within a single line. -vim.regex({re}) *vim.regex()* +vim.regex({re}) *vim.regex()* Parse the Vim regex {re} and return a regex object. Regexes are "magic" and case-insensitive by default, regardless of 'magic' and - 'ignorecase'. The can be controlled with flags, see |/magic|. + 'ignorecase'. They can be controlled with flags, see |/magic|. Methods on the regex object: -regex:match_str({str}) *regex:match_str()* +regex:match_str({str}) *regex:match_str()* Match the string against the regex. If the string should match the regex precisely, surround the regex with `^` and `$`. If the was a match, the byte indices for the beginning and end of @@ -713,7 +703,7 @@ regex:match_str({str}) *regex:match_str()* As any integer is truth-y, `regex:match()` can be directly used as a condition in an if-statement. -regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()* +regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()* Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and {end} are supplied, match only this byte index range. Otherwise see |regex:match_str()|. If {start} is used, then the returned byte @@ -728,18 +718,19 @@ vim.diff({a}, {b}, {opts}) *vim.diff()* 1-based. Examples: > - vim.diff('a\n', 'b\nc\n') - --> - @@ -1 +1,2 @@ - -a - +b - +c - - vim.diff('a\n', 'b\nc\n', {result_type = 'indices'}) - --> - { - {1, 1, 1, 2} - } + + vim.diff('a\n', 'b\nc\n') + --> + @@ -1 +1,2 @@ + -a + +b + +c + + vim.diff('a\n', 'b\nc\n', {result_type = 'indices'}) + --> + { + {1, 1, 1, 2} + } < Parameters: ~ {a} First string to compare @@ -757,7 +748,7 @@ vim.diff({a}, {b}, {opts}) *vim.diff()* • `result_type` (string): Form of the returned diff: • "unified": (default) String in unified format. • "indices": Array of hunk locations. - Note this option is ignored if `on_hunk` is + Note: This option is ignored if `on_hunk` is used. • `algorithm` (string): Diff algorithm to use. Values: @@ -792,31 +783,31 @@ VIM.MPACK *lua-mpack* The *vim.mpack* module provides encoding and decoding of Lua objects to and from msgpack-encoded strings. Supports |vim.NIL| and |vim.empty_dict()|. -vim.mpack.encode({obj}) *vim.mpack.encode* +vim.mpack.encode({obj}) *vim.mpack.encode* Encodes (or "packs") Lua object {obj} as msgpack in a Lua string. -vim.mpack.decode({str}) *vim.mpack.decode* +vim.mpack.decode({str}) *vim.mpack.decode* Decodes (or "unpacks") the msgpack-encoded {str} to a Lua object. ------------------------------------------------------------------------------ -VIM.SPELL *lua-spell* +VIM.SPELL *lua-spell* -vim.spell.check({str}) *vim.spell.check()* +vim.spell.check({str}) *vim.spell.check()* Check {str} for spelling errors. Similar to the Vimscript function |spellbadword()|. Note: The behaviour of this function is dependent on: 'spelllang', - 'spellfile', 'spellcapcheck' and 'spelloptions' which can all be local - to the buffer. Consider calling this with |nvim_buf_call()|. + 'spellfile', 'spellcapcheck' and 'spelloptions' which can all be + local to the buffer. Consider calling this with |nvim_buf_call()|. Example: > + vim.spell.check("the quik brown fox") --> { {'quik', 'bad', 4} } < - Parameters: ~ {str} String to spell check. @@ -831,24 +822,24 @@ vim.spell.check({str}) *vim.spell.check()* - The position in {str} where the word begins. ------------------------------------------------------------------------------ -VIM *lua-builtin* +VIM *lua-builtin* -vim.api.{func}({...}) *vim.api* +vim.api.{func}({...}) *vim.api* Invokes Nvim |API| function {func} with arguments {...}. Example: call the "nvim_get_current_line()" API function: > print(tostring(vim.api.nvim_get_current_line())) -vim.version() *vim.version* +vim.version() *vim.version* Gets the version of the current Nvim build. -vim.in_fast_event() *vim.in_fast_event()* +vim.in_fast_event() *vim.in_fast_event()* Returns true if the code is executing as part of a "fast" event handler, where most of the API is disabled. These are low-level events (e.g. |lua-loop-callbacks|) which can be invoked whenever Nvim polls - for input. When this is `false` most API functions are callable (but + for input. When this is `false` most API functions are callable (but may be subject to other restrictions such as |textlock|). -vim.NIL *vim.NIL* +vim.NIL *vim.NIL* Special value representing NIL in |RPC| and |v:null| in Vimscript conversion, and similar cases. Lua `nil` cannot be used as part of a Lua table representing a Dictionary or Array, because it is @@ -860,10 +851,10 @@ vim.empty_dict() *vim.empty_dict()* Vimscript or API types. Nvim by default converts an empty table `{}` without this metatable to an list/array. - Note: if numeric keys are present in the table, Nvim ignores the + Note: If numeric keys are present in the table, Nvim ignores the metatable marker and converts the dict to a list/array anyway. -vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()* +vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()* Sends {event} to {channel} via |RPC| and returns immediately. If {channel} is 0, the event is broadcast to all channels. @@ -876,12 +867,12 @@ vim.rpcrequest({channel}, {method}[, {args}...]) *vim.rpcrequest()* Note: NIL values as part of the return value is represented as |vim.NIL| special value -vim.stricmp({a}, {b}) *vim.stricmp()* - Compares strings case-insensitively. Returns 0, 1 or -1 if strings +vim.stricmp({a}, {b}) *vim.stricmp()* + Compares strings case-insensitively. Returns 0, 1 or -1 if strings are equal, {a} is greater than {b} or {a} is lesser than {b}, respectively. -vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()* +vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()* Convert byte index to UTF-32 and UTF-16 indices. If {index} is not supplied, the length of the string is used. All indices are zero-based. Returns two values: the UTF-32 and UTF-16 indices respectively. @@ -891,21 +882,21 @@ vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()* point each. An {index} in the middle of a UTF-8 sequence is rounded upwards to the end of that sequence. -vim.str_byteindex({str}, {index}[, {use_utf16}]) *vim.str_byteindex()* +vim.str_byteindex({str}, {index}[, {use_utf16}]) *vim.str_byteindex()* Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not supplied, it defaults to false (use UTF-32). Returns the byte index. - Invalid UTF-8 and NUL is treated like by |vim.str_byteindex()|. An {index} - in the middle of a UTF-16 sequence is rounded upwards to the end of that - sequence. + Invalid UTF-8 and NUL is treated like by |vim.str_byteindex()|. + An {index} in the middle of a UTF-16 sequence is rounded upwards to + the end of that sequence. -vim.schedule({callback}) *vim.schedule()* +vim.schedule({callback}) *vim.schedule()* Schedules {callback} to be invoked soon by the main event-loop. Useful to avoid |textlock| or other temporary restrictions. -vim.defer_fn({fn}, {timeout}) *vim.defer_fn* - Defers calling {fn} until {timeout} ms passes. Use to do a one-shot timer +vim.defer_fn({fn}, {timeout}) *vim.defer_fn* + 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 @@ -969,15 +960,15 @@ vim.wait({time} [, {callback}, {interval}, {fast_only}]) *vim.wait()* end < -vim.type_idx *vim.type_idx* - Type index for use in |lua-special-tbl|. Specifying one of the values +vim.type_idx *vim.type_idx* + Type index for use in |lua-special-tbl|. Specifying one of the values from |vim.types| allows typing the empty table (it is unclear whether empty Lua table represents empty list or empty array) and forcing - integral numbers to be |Float|. See |lua-special-tbl| for more + integral numbers to be |Float|. See |lua-special-tbl| for more details. -vim.val_idx *vim.val_idx* - Value index for tables representing |Float|s. A table representing +vim.val_idx *vim.val_idx* + Value index for tables representing |Float|s. A table representing floating-point value 1.0 looks like this: > { [vim.type_idx] = vim.types.float, @@ -985,17 +976,17 @@ vim.val_idx *vim.val_idx* } < See also |vim.type_idx| and |lua-special-tbl|. -vim.types *vim.types* - Table with possible values for |vim.type_idx|. Contains two sets of +vim.types *vim.types* + Table with possible values for |vim.type_idx|. Contains two sets of key-value pairs: first maps possible values for |vim.type_idx| to human-readable strings, second maps human-readable type names to - values for |vim.type_idx|. Currently contains pairs for `float`, + values for |vim.type_idx|. Currently contains pairs for `float`, `array` and `dictionary` types. - Note: one must expect that values corresponding to `vim.types.float`, + Note: One must expect that values corresponding to `vim.types.float`, `vim.types.array` and `vim.types.dictionary` fall under only two following assumptions: - 1. Value may serve both as a key and as a value in a table. Given the + 1. Value may serve both as a key and as a value in a table. Given the properties of Lua tables this basically means “value is not `nil`â€. 2. For each value in `vim.types` table `vim.types[vim.types[value]]` is the same as `value`. @@ -1015,33 +1006,22 @@ Log levels are one of the values defined in `vim.log.levels`: vim.log.levels.OFF ------------------------------------------------------------------------------ -LUA-VIMSCRIPT BRIDGE *lua-vimscript* +LUA-VIMSCRIPT BRIDGE *lua-vimscript* Nvim Lua provides an interface to Vimscript variables and functions, and editor commands and options. See also https://github.com/nanotee/nvim-lua-guide. -vim.call({func}, {...}) *vim.call()* +vim.call({func}, {...}) *vim.call()* Invokes |vim-function| or |user-function| {func} with arguments {...}. See also |vim.fn|. Equivalent to: > vim.fn[func]({...}) -vim.cmd({cmd}) *vim.cmd()* - Executes multiple lines of Vimscript at once. It is an alias to - |nvim_exec()|, where `output` is set to false. Thus it works identical - to |:source|. - See also |ex-cmd-index|. - Example: > - vim.cmd('echo 42') - vim.cmd([[ - augroup My_group - autocmd! - autocmd FileType c setlocal cindent - augroup END - ]]) - -vim.fn.{func}({...}) *vim.fn* +vim.cmd({command}) + See |vim.cmd()|. + +vim.fn.{func}({...}) *vim.fn* Invokes |vim-function| or |user-function| {func} with arguments {...}. To call autoload functions, use the syntax: > vim.fn['some#function']({...}) @@ -1058,7 +1038,7 @@ vim.fn.{func}({...}) *vim.fn* enumerates functions that were called at least once. - *lua-vim-variables* + *lua-vim-variables* The Vim editor global dictionaries |g:| |w:| |b:| |t:| |v:| can be accessed from Lua conveniently and idiomatically by referencing the `vim.*` Lua tables described below. In this way you can easily read and modify global Vimscript @@ -1070,31 +1050,31 @@ Example: > print(vim.g.foo) -- Get and print the g:foo Vimscript variable. vim.g.foo = nil -- Delete (:unlet) the Vimscript variable. vim.b[2].foo = 6 -- Set b:foo for buffer 2 - -vim.g *vim.g* +< +vim.g *vim.g* Global (|g:|) editor variables. Key with no value returns `nil`. -vim.b *vim.b* +vim.b *vim.b* Buffer-scoped (|b:|) variables for the current buffer. Invalid or unset key returns `nil`. Can be indexed with an integer to access variables for a specific buffer. -vim.w *vim.w* +vim.w *vim.w* Window-scoped (|w:|) variables for the current window. Invalid or unset key returns `nil`. Can be indexed with an integer to access variables for a specific window. -vim.t *vim.t* +vim.t *vim.t* Tabpage-scoped (|t:|) variables for the current tabpage. Invalid or unset key returns `nil`. Can be indexed with an integer to access variables for a specific tabpage. -vim.v *vim.v* +vim.v *vim.v* |v:| variables. Invalid or unset key returns `nil`. -vim.env *vim.env* +vim.env *vim.env* Environment variables defined in the editor session. See |expand-env| and |:let-environment| for the Vimscript behavior. Invalid or unset key returns `nil`. @@ -1144,7 +1124,6 @@ from within Lua. -- or using the `:append(...)` method vim.opt.wildignore:append { "*.pyc", "node_modules" } < - To replicate the behavior of |:set^=|, use: > -- vim.opt supports prepending options via the "^" operator @@ -1265,14 +1244,13 @@ vim.o :set set set vim.bo/vim.wo :setlocal - set vim.go :setglobal set - -vim.o *vim.o* +vim.o *vim.o* Get or set editor options, like |:set|. Invalid key is an error. Example: > vim.o.cmdheight = 4 print(vim.o.columns) - - -vim.go *vim.go* +< +vim.go *vim.go* Get or set an |option|. Invalid key is an error. This is a wrapper around |nvim_set_option()| and |nvim_get_option()|. @@ -1284,8 +1262,7 @@ vim.go *vim.go* Example: > vim.go.cmdheight = 4 < - -vim.bo *vim.bo* +vim.bo *vim.bo* Get or set buffer-scoped |local-options|. Invalid key is an error. This is a wrapper around |nvim_buf_set_option()| and @@ -1294,8 +1271,8 @@ vim.bo *vim.bo* Example: > vim.bo.buflisted = true print(vim.bo.comments) - -vim.wo *vim.wo* +< +vim.wo *vim.wo* Get or set window-scoped |local-options|. Invalid key is an error. This is a wrapper around |nvim_win_set_option()| and @@ -1304,11 +1281,38 @@ vim.wo *vim.wo* Example: > vim.wo.cursorcolumn = true print(vim.wo.foldmarker) - - +< ============================================================================== Lua module: vim *lua-vim* +cmd({command}) *vim.cmd()* + 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"' } }) +< + + Parameters: ~ + {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 also: ~ + |ex-cmd-index| + *vim.connection_failure_errmsg()* connection_failure_errmsg({consequence}) TODO: Documentation @@ -1332,7 +1336,8 @@ deprecate({name}, {alternative}, {version}, {plugin}) *vim.deprecate()* Parameters: ~ {name} string Deprecated function. - {alternative} string|nil Preferred alternative function. + {alternative} (string|nil) Preferred alternative + function. {version} string Version in which the deprecated function will be removed. {plugin} string|nil Plugin name that the function @@ -1353,11 +1358,12 @@ notify({msg}, {level}, {opts}) *vim.notify()* notification provider). By default, writes to |:messages|. Parameters: ~ - {msg} string Content of the notification to show to the - user. - {level} number|nil One of the values from + {msg} (string) Content of the notification to show to + the user. + {level} (number|nil) One of the values from |vim.log.levels|. - {opts} table|nil Optional parameters. Unused by default. + {opts} (table|nil) Optional parameters. Unused by + default. notify_once({msg}, {level}, {opts}) *vim.notify_once()* Display a notification only one time. @@ -1366,11 +1372,12 @@ notify_once({msg}, {level}, {opts}) *vim.notify_once()* message will not display a notification. Parameters: ~ - {msg} string Content of the notification to show to the - user. - {level} number|nil One of the values from + {msg} (string) Content of the notification to show to + the user. + {level} (number|nil) One of the values from |vim.log.levels|. - {opts} table|nil Optional parameters. Unused by default. + {opts} (table|nil) Optional parameters. Unused by + default. on_key({fn}, {ns_id}) *vim.on_key()* Adds Lua function {fn} with namespace id {ns_id} as a listener @@ -1396,8 +1403,8 @@ on_key({fn}, {ns_id}) *vim.on_key()* 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. + (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. @@ -1451,12 +1458,12 @@ region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive}) *vim.region()* marked by two points Parameters: ~ - {bufnr} number of buffer + {bufnr} (number) of buffer {pos1} (line, column) tuple marking beginning of region {pos2} (line, column) tuple marking end of region {regtype} type of selection (:help setreg) - {inclusive} boolean indicating whether the selection is + {inclusive} (boolean) indicating whether the selection is end-inclusive Return: ~ @@ -1476,14 +1483,14 @@ schedule_wrap({cb}) *vim.schedule_wrap()* deep_equal({a}, {b}) *vim.deep_equal()* Deep compare values for equality - Tables are compared recursively unless they both provide the `eq` methamethod. All other types are compared using the equality `==` operator. + Tables are compared recursively unless they both provide the `eq` metamethod. All other types are compared using the equality `==` operator. Parameters: ~ - {a} first value - {b} second value + {a} any First value + {b} any Second value Return: ~ - `true` if values are equals, else `false`. + (boolean) `true` if values are equals, else `false` deepcopy({orig}) *vim.deepcopy()* Returns a deep copy of the given object. Non-table objects are @@ -1494,32 +1501,32 @@ deepcopy({orig}) *vim.deepcopy()* and will throw an error. Parameters: ~ - {orig} table Table to copy + {orig} (table) Table to copy Return: ~ - New table of copied keys and (nested) values. + (table) Table of copied keys and (nested) values. endswith({s}, {suffix}) *vim.endswith()* Tests if `s` ends with `suffix`. Parameters: ~ - {s} (string) a string - {suffix} (string) a suffix + {s} (string) String + {suffix} (string) Suffix to match Return: ~ - (boolean) true if `suffix` is a suffix of s + (boolean) `true` if `suffix` is a suffix of `s` gsplit({s}, {sep}, {plain}) *vim.gsplit()* Splits a string at each instance of a separator. Parameters: ~ - {s} String to split - {sep} Separator string or pattern - {plain} If `true` use `sep` literally (passed to - String.find) + {s} (string) String to split + {sep} (string) Separator or pattern + {plain} (boolean) If `true` use `sep` literally (passed + to string.find) Return: ~ - Iterator over the split components + (function) Iterator over the split components See also: ~ |vim.split()| @@ -1530,10 +1537,10 @@ is_callable({f}) *vim.is_callable()* Returns true if object `f` can be called as a function. Parameters: ~ - {f} Any object + {f} any Any object Return: ~ - true if `f` is callable, else false + (boolean) `true` if `f` is callable, else `false` list_extend({dst}, {src}, {start}, {finish}) *vim.list_extend()* Extends a list-like table with the values of another list-like @@ -1542,13 +1549,14 @@ list_extend({dst}, {src}, {start}, {finish}) *vim.list_extend()* NOTE: This mutates dst! Parameters: ~ - {dst} list which will be modified and appended to. - {src} list from which values will be inserted. - {start} Start index on src. defaults to 1 - {finish} Final index on src. defaults to #src + {dst} (table) List which will be modified and appended + to + {src} (table) List from which values will be inserted + {start} (number) Start index on src. Defaults to 1 + {finish} (number) Final index on src. Defaults to `#src` Return: ~ - dst + (table) dst See also: ~ |vim.tbl_extend()| @@ -1558,21 +1566,22 @@ list_slice({list}, {start}, {finish}) *vim.list_slice()* to end (inclusive) Parameters: ~ - {list} table table - {start} integer Start range of slice - {finish} integer End range of slice + {list} (table) Table + {start} (number) Start range of slice + {finish} (number) End range of slice Return: ~ - Copy of table sliced from start to finish (inclusive) + (table) Copy of table sliced from start to finish + (inclusive) pesc({s}) *vim.pesc()* Escapes magic chars in a Lua pattern. Parameters: ~ - {s} String to escape + {s} (string) String to escape Return: ~ - %-escaped pattern string + (string) %-escaped pattern string See also: ~ https://github.com/rxi/lume @@ -1589,16 +1598,16 @@ split({s}, {sep}, {kwargs}) *vim.split()* < Parameters: ~ - {s} String to split - {sep} Separator string or pattern - {kwargs} Keyword arguments: + {s} (string) String to split + {sep} (string) Separator or pattern + {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 Return: ~ - List-like table of the split components. + (table) List of split components See also: ~ |vim.gsplit()| @@ -1607,28 +1616,34 @@ startswith({s}, {prefix}) *vim.startswith()* Tests if `s` starts with `prefix`. Parameters: ~ - {s} (string) a string - {prefix} (string) a prefix + {s} (string) String + {prefix} (string) Prefix to match Return: ~ - (boolean) true if `prefix` is a prefix of s + (boolean) `true` if `prefix` is a prefix of `s` tbl_add_reverse_lookup({o}) *vim.tbl_add_reverse_lookup()* Add the reverse lookup values to an existing table. For - example: `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }` + example: `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = + 1 }` + + Note that this modifies the input. Parameters: ~ - {o} table The table to add the reverse to. + {o} (table) Table to add the reverse to + + Return: ~ + (table) o tbl_contains({t}, {value}) *vim.tbl_contains()* Checks if a list-like (vector) table contains `value`. Parameters: ~ - {t} Table to check - {value} Value to compare + {t} (table) Table to check + {value} any Value to compare Return: ~ - true if `t` contains `value` + (boolean) `true` if `t` contains `value` tbl_count({t}) *vim.tbl_count()* Counts the number of non-nil values in table `t`. @@ -1639,10 +1654,10 @@ tbl_count({t}) *vim.tbl_count()* < Parameters: ~ - {t} Table + {t} (table) Table Return: ~ - Number that is the number of the value in table + (number) Number of non-nil values in table See also: ~ https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua @@ -1651,12 +1666,15 @@ tbl_deep_extend({behavior}, {...}) *vim.tbl_deep_extend()* Merges recursively two or more map-like tables. Parameters: ~ - {behavior} Decides what to do if a key is found in more - than one map: + {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 - {...} Two or more map-like tables. + {...} (table) Two or more map-like tables + + Return: ~ + (table) Merged table See also: ~ |tbl_extend()| @@ -1665,12 +1683,15 @@ tbl_extend({behavior}, {...}) *vim.tbl_extend()* Merges two or more map-like tables. Parameters: ~ - {behavior} Decides what to do if a key is found in more - than one map: + {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 - {...} Two or more map-like tables. + {...} (table) Two or more map-like tables + + Return: ~ + (table) Merged table See also: ~ |extend()| @@ -1679,43 +1700,51 @@ tbl_filter({func}, {t}) *vim.tbl_filter()* Filter a table using a predicate function Parameters: ~ - {func} function or callable table - {t} table + {func} function|table Function or callable table + {t} (table) Table + + Return: ~ + (table) Table of filtered values tbl_flatten({t}) *vim.tbl_flatten()* Creates a copy of a list-like table such that any nested tables are "unrolled" and appended to the result. Parameters: ~ - {t} List-like table + {t} (table) List-like table Return: ~ - Flattened copy of the given list-like table. + (table) Flattened copy of the given list-like table See also: ~ From https://github.com/premake/premake-core/blob/master/src/base/table.lua tbl_get({o}, {...}) *vim.tbl_get()* Index into a table (first argument) via string keys passed as - subsequent arguments. Return `nil` if the key does not exist. Examples: > + 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 < Parameters: ~ - {o} Table to index - {...} Optional strings (0 or more, variadic) via which to - index the table + {o} (table) Table to index + {...} (string) Optional strings (0 or more, variadic) via + which to index the table Return: ~ - nested value indexed by key if it exists, else nil + any Nested value indexed by key (if it exists), else nil tbl_isempty({t}) *vim.tbl_isempty()* Checks if a table is empty. Parameters: ~ - {t} Table to check + {t} (table) Table to check + + Return: ~ + (boolean) `true` if `t` is empty See also: ~ https://github.com/premake/premake-core/blob/master/src/base/table.lua @@ -1729,20 +1758,20 @@ tbl_islist({t}) *vim.tbl_islist()* |vim.fn|. Parameters: ~ - {t} Table + {t} (table) Table Return: ~ - `true` if array-like table, else `false`. + (boolean) `true` if array-like table, else `false` tbl_keys({t}) *vim.tbl_keys()* Return a list of all keys used in a table. However, the order of the return table of keys is not guaranteed. Parameters: ~ - {t} Table + {t} (table) Table Return: ~ - list of keys + (table) List of keys See also: ~ From https://github.com/premake/premake-core/blob/master/src/base/table.lua @@ -1751,28 +1780,32 @@ tbl_map({func}, {t}) *vim.tbl_map()* Apply a function to all values of a table. Parameters: ~ - {func} function or callable table - {t} table + {func} function|table Function or callable table + {t} (table) Table + + Return: ~ + (table) Table of transformed values tbl_values({t}) *vim.tbl_values()* Return a list of all values used in a table. However, the order of the return table of values is not guaranteed. Parameters: ~ - {t} Table + {t} (table) Table Return: ~ - list of values + (table) List of values trim({s}) *vim.trim()* Trim whitespace (Lua pattern "%s") from both sides of a string. Parameters: ~ - {s} String to trim + {s} (string) String to trim Return: ~ - String with whitespace removed from its beginning and end + (string) String with whitespace removed from its beginning + and end See also: ~ https://www.lua.org/pil/20.2.html @@ -1814,7 +1847,7 @@ validate({opt}) *vim.validate()* < Parameters: ~ - {opt} table of parameter names to validations. Each key + {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) @@ -1844,38 +1877,38 @@ uri_from_bufnr({bufnr}) *vim.uri_from_bufnr()* Get a URI from a bufnr Parameters: ~ - {bufnr} number + {bufnr} (number) Return: ~ - string URI + (string) URI uri_from_fname({path}) *vim.uri_from_fname()* Get a URI from a file path. Parameters: ~ - {path} string Path to file + {path} (string) Path to file Return: ~ - string URI + (string) URI uri_to_bufnr({uri}) *vim.uri_to_bufnr()* Get the buffer for a uri. Creates a new unloaded buffer if no buffer for the uri already exists. Parameters: ~ - {uri} string + {uri} (string) Return: ~ - number bufnr + (number) bufnr uri_to_fname({uri}) *vim.uri_to_fname()* Get a filename from a URI Parameters: ~ - {uri} string + {uri} (string) Return: ~ - string filename or unchanged URI for non-file URIs + (string) filename or unchanged URI for non-file URIs ============================================================================== @@ -1892,7 +1925,7 @@ input({opts}, {on_confirm}) *vim.ui.input()* < Parameters: ~ - {opts} table Additional options. See |input()| + {opts} (table) Additional options. See |input()| • prompt (string|nil) Text of the prompt. Defaults to `Input:`. • default (string|nil) Default reply to the @@ -1905,10 +1938,10 @@ input({opts}, {on_confirm}) *vim.ui.input()* |:command-completion| • highlight (function) Function that will be used for highlighting user inputs. - {on_confirm} function ((input|nil) -> ()) Called once the - user confirms or abort the input. `input` is - what the user typed. `nil` if the user - aborted the dialog. + {on_confirm} (function) ((input|nil) -> ()) Called once + the user confirms or abort the input. + `input` is what the user typed. `nil` if the + user aborted the dialog. select({items}, {opts}, {on_choice}) *vim.ui.select()* Prompts the user to pick a single item from a collection of @@ -1931,8 +1964,8 @@ select({items}, {opts}, {on_choice}) *vim.ui.select()* < Parameters: ~ - {items} table Arbitrary items - {opts} table Additional options + {items} (table) Arbitrary items + {opts} (table) Additional options • prompt (string|nil) Text of the prompt. Defaults to `Select one of:` • format_item (function item -> text) @@ -1944,7 +1977,7 @@ select({items}, {opts}, {on_choice}) *vim.ui.select()* use this to infer the structure or semantics of `items`, or the context in which select() was called. - {on_choice} function ((item|nil, idx|nil) -> ()) Called + {on_choice} (function) ((item|nil, idx|nil) -> ()) Called once the user made a choice. `idx` is the 1-based index of `item` within `items`. `nil` if the user aborted the dialog. @@ -2013,16 +2046,16 @@ add({filetypes}) *vim.filetype.add()* < Parameters: ~ - {filetypes} table A table containing new filetype maps + {filetypes} (table) A table containing new filetype maps (see example). match({name}, {bufnr}) *vim.filetype.match()* Set the filetype for the given buffer from a file name. Parameters: ~ - {name} string File name (can be an absolute or relative - path) - {bufnr} number|nil The buffer to set the filetype for. + {name} (string) File name (can be an absolute or + relative path) + {bufnr} (number|nil) The buffer to set the filetype for. Defaults to the current buffer. @@ -2038,7 +2071,7 @@ del({modes}, {lhs}, {opts}) *vim.keymap.del()* < Parameters: ~ - {opts} table A table of optional arguments: + {opts} (table) A table of optional arguments: • buffer: (number or boolean) Remove a mapping from the given buffer. When "true" or 0, use the current buffer. @@ -2082,12 +2115,12 @@ set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()* {mode} string|table Same mode short names as |nvim_set_keymap()|. Can also be list of modes to create mapping on multiple modes. - {lhs} string Left-hand side |{lhs}| of the mapping. + {lhs} (string) Left-hand side |{lhs}| of the mapping. {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` is equivalent to an empty string. - {opts} table A table of |:map-arguments| such as + {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: diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 6e100e5854..056e6c3b56 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -105,7 +105,7 @@ modes. command applies. Use the <buffer> argument to remove buffer-local mappings |:map-<buffer>| - Warning: This also removes the default mappings. + Warning: This also removes the |default-mappings|. :map |mapmode-nvo| :nm[ap] |mapmode-n| diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 1109056d47..4d6f589714 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -841,7 +841,7 @@ A jump table for the options with a short description can be found at |Q_op|. again not rename the file. *'backupdir'* *'bdir'* -'backupdir' 'bdir' string (default ".,$XDG_DATA_HOME/nvim/backup//") +'backupdir' 'bdir' string (default ".,$XDG_STATE_HOME/nvim/backup//") global List of directories for the backup file, separated with commas. - The backup file will be created in the first directory in the list @@ -2063,7 +2063,7 @@ A jump table for the options with a short description can be found at |Q_op|. {char2}. See |digraphs|. *'directory'* *'dir'* -'directory' 'dir' string (default "$XDG_DATA_HOME/nvim/swap//") +'directory' 'dir' string (default "$XDG_STATE_HOME/nvim/swap//") global List of directory names for the swap file, separated with commas. @@ -3502,7 +3502,7 @@ A jump table for the options with a short description can be found at |Q_op|. option. For '@' only characters up to 255 are used. Careful: If you change this option, it might break expanding environment variables. E.g., when '/' is included and Vim tries to - expand "$HOME/.local/share/nvim/shada/main.shada". Maybe you should + expand "$HOME/.local/state/nvim/shada/main.shada". Maybe you should change 'iskeyword' instead. *'iskeyword'* *'isk'* @@ -4942,9 +4942,12 @@ A jump table for the options with a short description can be found at |Q_op|. but are not part of the Nvim distribution. XDG_DATA_DIRS defaults to /usr/local/share/:/usr/share/, so system administrators are expected to install site plugins to /usr/share/nvim/site. - 5. $VIMRUNTIME, for files distributed with Neovim. + 5. Applications state home directory, for files that contain your + session state (eg. backupdir, viewdir, undodir, etc). + Given by `stdpath("state")`. |$XDG_STATE_HOME| + 6. $VIMRUNTIME, for files distributed with Neovim. *after-directory* - 6, 7, 8, 9. In after/ subdirectories of 1, 2, 3 and 4, with reverse + 7, 8, 9, 10. In after/ subdirectories of 1, 2, 3 and 4, with reverse ordering. This is for preferences to overrule or add to the distributed defaults or system-wide settings (rarely needed). @@ -6623,7 +6626,7 @@ A jump table for the options with a short description can be found at |Q_op|. 'ttyfast' 'tf' Removed. |vim-differences| *'undodir'* *'udir'* *E5003* -'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo//") +'undodir' 'udir' string (default "$XDG_STATE_HOME/nvim/undo//") global List of directory names for undo files, separated with commas. See 'backupdir' for details of the format. @@ -6786,7 +6789,7 @@ A jump table for the options with a short description can be found at |Q_op|. displayed when 'verbosefile' is set. *'viewdir'* *'vdir'* -'viewdir' 'vdir' string (default: "$XDG_DATA_HOME/nvim/view//") +'viewdir' 'vdir' string (default: "$XDG_STATE_HOME/nvim/view//") global Name of the directory where to store files for |:mkview|. This option cannot be set from a |modeline| or in the |sandbox|, for diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 1d3fa6c2ca..f542f33451 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -367,7 +367,7 @@ argument. *--headless* --headless Start without UI, and do not wait for `nvim_ui_attach`. The builtin TUI is not used, so stdio works as an arbitrary - communication channel. |channel-stdio| + communication channel. |channel-stdio| Also useful for scripting (tests) to see messages that would not be printed by |-es|. @@ -584,7 +584,7 @@ setting can affect the entire editor in ways that are not initially obvious. To find the cause of a problem in your config, you must "bisect" it: 1. Remove or disable half of your |config|. 2. Restart Nvim. -3. If the problem still occurs, goto 1. +3. If the problem still occurs, goto 1. 4. If the problem is gone, restore half of the removed lines. 5. Continue narrowing your config in this way, until you find the setting or plugin causing the issue. @@ -701,7 +701,7 @@ vimrc file. These commands will write ":map" and ":set" commands to a file, in such a way that when these commands are executed, the current key mappings and options will be set to the same values. The options 'columns', 'endofline', -'fileformat', 'lines', 'modified', and 'scroll' are not included, because +'fileformat', 'lines', 'modified', and 'scroll' are not included, because these are terminal or file dependent. Note that the options 'binary', 'paste' and 'readonly' are included, this might not always be what you want. @@ -718,7 +718,7 @@ with ":map" and ":set" commands and write the modified file. First read the default vimrc in with a command like ":source ~piet/.vimrc.Cprogs", change the settings and then save them in the current directory with ":mkvimrc!". If you want to make this file your default |config|, move it to -$XDG_CONFIG_HOME/nvim. You could also use autocommands |autocommand| and/or +$XDG_CONFIG_HOME/nvim. You could also use autocommands |autocommand| and/or modelines |modeline|. *vimrc-option-example* @@ -886,7 +886,7 @@ Shada ("shared data") file *shada* *shada-file* If you exit Vim and later start it again, you would normally lose a lot of information. The ShaDa file can be used to remember that information, which -enables you to continue where you left off. Its name is the abbreviation of +enables you to continue where you left off. Its name is the abbreviation of SHAred DAta because it is used for sharing data between Neovim sessions. This is introduced in section |21.3| of the user manual. @@ -917,9 +917,9 @@ The |v:oldfiles| variable is filled. The marks are not read in at startup option upon startup. *shada-write* -When Vim exits and 'shada' is non-empty, the info is stored in the ShaDa file -(it's actually merged with the existing one, if one exists |shada-merging|). -The 'shada' option is a string containing information about what info should +When Vim exits and 'shada' is non-empty, the info is stored in the ShaDa file +(it's actually merged with the existing one, if one exists |shada-merging|). +The 'shada' option is a string containing information about what info should be stored, and contains limits on how much should be stored (see 'shada'). Notes for Unix: @@ -977,75 +977,75 @@ remembered. MERGING *shada-merging* -When writing ShaDa files with |:wshada| without bang or at regular exit -information in the existing ShaDa file is merged with information from current -Neovim instance. For this purpose ShaDa files store timestamps associated +When writing ShaDa files with |:wshada| without bang or at regular exit +information in the existing ShaDa file is merged with information from current +Neovim instance. For this purpose ShaDa files store timestamps associated with ShaDa entries. Specifically the following is being done: -1. History lines are merged, ordered by timestamp. Maximum amount of items in - ShaDa file is defined by 'shada' option (|shada-/|, |shada-:|, |shada-@|, - etc: one suboption for each character that represents history name +1. History lines are merged, ordered by timestamp. Maximum amount of items in + ShaDa file is defined by 'shada' option (|shada-/|, |shada-:|, |shada-@|, + etc: one suboption for each character that represents history name (|:history|)). -2. Local marks and changes for files that were not opened by Neovim are copied - to new ShaDa file. Marks for files that were opened by Neovim are merged, +2. Local marks and changes for files that were not opened by Neovim are copied + to new ShaDa file. Marks for files that were opened by Neovim are merged, changes to files opened by Neovim are ignored. |shada-'| -3. Jump list is merged: jumps are ordered by timestamp, identical jumps +3. Jump list is merged: jumps are ordered by timestamp, identical jumps (identical position AND timestamp) are squashed. -4. Search patterns and substitute strings are not merged: search pattern or - substitute string which has greatest timestamp will be the only one copied +4. Search patterns and substitute strings are not merged: search pattern or + substitute string which has greatest timestamp will be the only one copied to ShaDa file. -5. For each register entity with greatest timestamp is the only saved. +5. For each register entity with greatest timestamp is the only saved. |shada-<| -6. All saved variables are saved from current Neovim instance. Additionally - existing variable values are copied, meaning that the only way to remove - variable from a ShaDa file is either removing it by hand or disabling +6. All saved variables are saved from current Neovim instance. Additionally + existing variable values are copied, meaning that the only way to remove + variable from a ShaDa file is either removing it by hand or disabling writing variables completely. |shada-!| 7. For each global mark entity with greatest timestamp is the only saved. -8. Buffer list and header are the only entries which are not merged in any - fashion: the only header and buffer list present are the ones from the +8. Buffer list and header are the only entries which are not merged in any + fashion: the only header and buffer list present are the ones from the Neovim instance which was last writing the file. |shada-%| COMPATIBILITY *shada-compatibility* ShaDa files are forward and backward compatible. This means that -1. Entries which have unknown type (i.e. that hold unidentified data) are +1. Entries which have unknown type (i.e. that hold unidentified data) are ignored when reading and blindly copied when writing. -2. Register entries with unknown register name are ignored when reading and - blindly copied when writing. Limitation: only registers that use name with +2. Register entries with unknown register name are ignored when reading and + blindly copied when writing. Limitation: only registers that use name with code in interval [1, 255] are supported. |registers| -3. Register entries with unknown register type are ignored when reading and +3. Register entries with unknown register type are ignored when reading and merged as usual when writing. |getregtype()| -4. Local and global mark entries with unknown mark names are ignored when - reading. When writing global mark entries are blindly copied and local mark - entries are also blindly copied, but only if file they are attached to fits - in the |shada-'| limit. Unknown local mark entry's timestamp is also taken - into account when calculating which files exactly should fit into this - limit. Limitation: only marks that use name with code in interval [1, 255] +4. Local and global mark entries with unknown mark names are ignored when + reading. When writing global mark entries are blindly copied and local mark + entries are also blindly copied, but only if file they are attached to fits + in the |shada-'| limit. Unknown local mark entry's timestamp is also taken + into account when calculating which files exactly should fit into this + limit. Limitation: only marks that use name with code in interval [1, 255] are supported. |mark-motions| -5. History entries with unknown history type are ignored when reading and - blindly copied when writing. Limitation: there can be only up to 256 +5. History entries with unknown history type are ignored when reading and + blindly copied when writing. Limitation: there can be only up to 256 history types. |history| -6. Unknown keys found in register, local mark, global mark, change, jump and - search pattern entries are saved internally and dumped when writing. +6. Unknown keys found in register, local mark, global mark, change, jump and + search pattern entries are saved internally and dumped when writing. Entries created during Neovim session never have such additions. -7. Additional elements found in replacement string and history entries are - saved internally and dumped. Entries created during Neovim session never +7. Additional elements found in replacement string and history entries are + saved internally and dumped. Entries created during Neovim session never have such additions. -8. Additional elements found in variable entries are simply ignored when - reading. When writing new variables they will be preserved during merging, - but that's all. Variable values dumped from current Neovim session never - have additional elements, even if variables themselves were obtained by +8. Additional elements found in variable entries are simply ignored when + reading. When writing new variables they will be preserved during merging, + but that's all. Variable values dumped from current Neovim session never + have additional elements, even if variables themselves were obtained by reading ShaDa files. -"Blindly" here means that there will be no attempts to somehow merge them, +"Blindly" here means that there will be no attempts to somehow merge them, even if other entries (with known name/type/etc) are merged. |shada-merging| SHADA FILE NAME *shada-file-name* - Default name of the |shada| file is: - Unix: "$XDG_DATA_HOME/nvim/shada/main.shada" - Windows: "$XDG_DATA_HOME/nvim-data/shada/main.shada" + Unix: "$XDG_STATE_HOME/nvim/shada/main.shada" + Windows: "$XDG_STATE_HOME/nvim-data/shada/main.shada" See also |base-directories|. - To choose a different file name you can use: - The "n" flag in the 'shada' option. @@ -1067,55 +1067,55 @@ however that this means everything will be overwritten with information from the first Vim, including the command line history, etc. The ShaDa file itself can be edited by hand too, although we suggest you -start with an existing one to get the format right. You need to understand -MessagePack (or, more likely, find software that is able to use it) format to -do this. This can be useful in order to create a second file, say -"~/.my.shada" which could contain certain settings that you always want when -you first start Neovim. For example, you can preload registers with -particular data, or put certain commands in the command line history. A line +start with an existing one to get the format right. You need to understand +MessagePack (or, more likely, find software that is able to use it) format to +do this. This can be useful in order to create a second file, say +"~/.my.shada" which could contain certain settings that you always want when +you first start Neovim. For example, you can preload registers with +particular data, or put certain commands in the command line history. A line in your |config| file like > :rshada! ~/.my.shada -can be used to load this information. You could even have different ShaDa -files for different types of files (e.g., C code) and load them based on the -file name, using the ":autocmd" command (see |:autocmd|). More information on +can be used to load this information. You could even have different ShaDa +files for different types of files (e.g., C code) and load them based on the +file name, using the ":autocmd" command (see |:autocmd|). More information on ShaDa file format is contained in |shada-format| section. *E136* *E929* *shada-error-handling* -Some errors make Neovim leave temporary file named `{basename}.tmp.X` (X is -any free letter from `a` to `z`) while normally it will create this file, -write to it and then rename `{basename}.tmp.X` to `{basename}`. Such errors +Some errors make Neovim leave temporary file named `{basename}.tmp.X` (X is +any free letter from `a` to `z`) while normally it will create this file, +write to it and then rename `{basename}.tmp.X` to `{basename}`. Such errors include: -- Errors which make Neovim think that read file is not a ShaDa file at all: - non-ShaDa files are not overwritten for safety reasons to avoid accidentally - destroying an unrelated file. This could happen e.g. when typing "nvim -i - file" in place of "nvim -R file" (yes, somebody did that at least with Vim). +- Errors which make Neovim think that read file is not a ShaDa file at all: + non-ShaDa files are not overwritten for safety reasons to avoid accidentally + destroying an unrelated file. This could happen e.g. when typing "nvim -i + file" in place of "nvim -R file" (yes, somebody did that at least with Vim). Such errors are listed at |shada-critical-contents-errors|. -- If writing to the temporary file failed: e.g. because of the insufficient +- If writing to the temporary file failed: e.g. because of the insufficient space left. - If renaming file failed: e.g. because of insufficient permissions. -- If target ShaDa file has different from the Neovim instance's owners (user - and group) and changing them failed. Unix-specific, applies only when +- If target ShaDa file has different from the Neovim instance's owners (user + and group) and changing them failed. Unix-specific, applies only when Neovim was launched from root. -Do not forget to remove the temporary file or replace the target file with -temporary one after getting one of the above errors or all attempts to create -a ShaDa file may fail with |E929|. If you got one of them when using -|:wshada| (and not when exiting Neovim: i.e. when you have Neovim session +Do not forget to remove the temporary file or replace the target file with +temporary one after getting one of the above errors or all attempts to create +a ShaDa file may fail with |E929|. If you got one of them when using +|:wshada| (and not when exiting Neovim: i.e. when you have Neovim session running) you have additional options: -- First thing which you should consider if you got any error, except failure - to write to the temporary file: remove existing file and replace it with the +- First thing which you should consider if you got any error, except failure + to write to the temporary file: remove existing file and replace it with the temporary file. Do it even if you have running Neovim instance. -- Fix the permissions and/or file ownership, free some space and attempt to +- Fix the permissions and/or file ownership, free some space and attempt to write again. Do not remove the existing file. -- Use |:wshada| with bang. Does not help in case of permission error. If - target file was actually the ShaDa file some information may be lost in this - case. To make the matters slightly better use |:rshada| prior to writing, - but this still will loose buffer-local marks and change list entries for any +- Use |:wshada| with bang. Does not help in case of permission error. If + target file was actually the ShaDa file some information may be lost in this + case. To make the matters slightly better use |:rshada| prior to writing, + but this still will loose buffer-local marks and change list entries for any file which is not opened in the current Neovim instance. -- Remove the target file from shell and use |:wshada|. Consequences are not - different from using |:wshada| with bang, but "rm -f" works in some cases +- Remove the target file from shell and use |:wshada|. Consequences are not + different from using |:wshada| with bang, but "rm -f" works in some cases when you don't have write permissions. *:rsh* *:rshada* *E886* @@ -1129,13 +1129,13 @@ running) you have additional options: The information in the file is first read in to make a merge between old and new info. When [!] is used, the old information is not read first, only the - internal info is written (also disables safety checks - described in |shada-error-handling|). If 'shada' is + internal info is written (also disables safety checks + described in |shada-error-handling|). If 'shada' is empty, marks for up to 100 files will be written. - When you get error "E929: All .tmp.X files exist, - cannot write ShaDa file!" check that no old temp files - were left behind (e.g. - ~/.local/share/nvim/shada/main.shada.tmp*). + When you get error "E929: All .tmp.X files exist, + cannot write ShaDa file!" check that no old temp files + were left behind (e.g. + ~/.local/state/nvim/shada/main.shada.tmp*). Note: Executing :wshada will reset all |'quote| marks. @@ -1158,82 +1158,82 @@ running) you have additional options: SHADA FILE FORMAT *shada-format* -ShaDa files are concats of MessagePack entries. Each entry is a concat of +ShaDa files are concats of MessagePack entries. Each entry is a concat of exactly four MessagePack objects: -1. First goes type of the entry. Object type must be an unsigned integer. +1. First goes type of the entry. Object type must be an unsigned integer. Object type must not be equal to zero. 2. Second goes entry timestamp. It must also be an unsigned integer. -3. Third goes the length of the fourth entry. Unsigned integer as well, used +3. Third goes the length of the fourth entry. Unsigned integer as well, used for fast skipping without parsing. -4. Fourth is actual entry data. All currently used ShaDa entries use - containers to hold data: either map or array. All string values in those - containers are either binary (applies to filenames) or UTF-8, yet parser +4. Fourth is actual entry data. All currently used ShaDa entries use + containers to hold data: either map or array. All string values in those + containers are either binary (applies to filenames) or UTF-8, yet parser needs to expect that invalid bytes may be present in a UTF-8 string. Exact format depends on the entry type: Entry type (name) Entry data ~ - 1 (Header) Map containing data that describes the generator - instance that wrote this ShaDa file. It is ignored + 1 (Header) Map containing data that describes the generator + instance that wrote this ShaDa file. It is ignored when reading ShaDa files. Contains the following data: Key Data ~ - generator Binary, software used to generate ShaDa - file. Is equal to "nvim" when ShaDa file was + generator Binary, software used to generate ShaDa + file. Is equal to "nvim" when ShaDa file was written by Neovim. version Binary, generator version. encoding Binary, effective 'encoding' value. max_kbyte Integer, effective |shada-s| limit value. pid Integer, instance process ID. - * It is allowed to have any number of + * It is allowed to have any number of additional keys with any data. - 2 (SearchPattern) Map containing data describing last used search or - substitute pattern. Normally ShaDa file contains two - such entries: one with "ss" key set to true (describes - substitute pattern, see |:substitute|), and one set to - false (describes search pattern, see - |search-commands|). "su" key should be true on one of - the entries. If key value is equal to default then it + 2 (SearchPattern) Map containing data describing last used search or + substitute pattern. Normally ShaDa file contains two + such entries: one with "ss" key set to true (describes + substitute pattern, see |:substitute|), and one set to + false (describes search pattern, see + |search-commands|). "su" key should be true on one of + the entries. If key value is equal to default then it is normally not present. Keys: Key Type Default Description ~ sm Boolean true Effective 'magic' value. sc Boolean false Effective 'smartcase' value. - sl Boolean true True if search pattern comes - with a line offset. See + sl Boolean true True if search pattern comes + with a line offset. See |search-offset|. - se Boolean false True if |search-offset| - requested to place cursor at - (relative to) the end of the + se Boolean false True if |search-offset| + requested to place cursor at + (relative to) the end of the pattern. so Integer 0 Offset value. |search-offset| - su Boolean false True if current entry was the + su Boolean false True if current entry was the last used search pattern. - ss Boolean false True if current entry describes + ss Boolean false True if current entry describes |:substitute| pattern. sh Boolean false True if |v:hlsearch| is on. - With |shada-h| or 'nohlsearch' + With |shada-h| or 'nohlsearch' this key is always false. sp Binary N/A Actual pattern. Required. - sb Boolean false True if search direction is + sb Boolean false True if search direction is backward. - * any none Other keys are allowed for - compatibility reasons, see + * any none Other keys are allowed for + compatibility reasons, see |shada-compatibility|. - 3 (SubString) Array containing last |:substitute| replacement string. - Contains single entry: binary, replacement string used. - More entries are allowed for compatibility reasons, see + 3 (SubString) Array containing last |:substitute| replacement string. + Contains single entry: binary, replacement string used. + More entries are allowed for compatibility reasons, see |shada-compatibility|. - 4 (HistoryEntry) Array containing one entry from history. Should have - two or three entries. First one is history type - (unsigned integer), second is history line (binary), - third is the separator character (unsigned integer, - must be in interval [0, 255]). Third item is only - valid for search history. Possible history types are - listed in |hist-names|, here are the corresponding - numbers: 0 - cmd, 1 - search, 2 - expr, 3 - input, + 4 (HistoryEntry) Array containing one entry from history. Should have + two or three entries. First one is history type + (unsigned integer), second is history line (binary), + third is the separator character (unsigned integer, + must be in interval [0, 255]). Third item is only + valid for search history. Possible history types are + listed in |hist-names|, here are the corresponding + numbers: 0 - cmd, 1 - search, 2 - expr, 3 - input, 4 - debug. - 5 (Register) Map describing one register (|registers|). If key - value is equal to default then it is normally not + 5 (Register) Map describing one register (|registers|). If key + value is equal to default then it is normally not present. Keys: Key Type Def Description ~ rt UInteger 0 Register type: @@ -1261,12 +1261,12 @@ exactly four MessagePack objects: * any none Other keys are allowed for compatibility reasons, see |shada-compatibility|. - 6 (Variable) Array containing two items: variable name (binary) and - variable value (any object). Values are converted - using the same code |msgpackparse()| uses when reading, - |msgpackdump()| when writing, so there may appear - |msgpack-special-dict|s. If there are more then two - entries then the rest are ignored + 6 (Variable) Array containing two items: variable name (binary) and + variable value (any object). Values are converted + using the same code |msgpackparse()| uses when reading, + |msgpackdump()| when writing, so there may appear + |msgpack-special-dict|s. If there are more then two + entries then the rest are ignored (|shada-compatibility|). 7 (GlobalMark) 8 (Jump) @@ -1280,57 +1280,57 @@ exactly four MessagePack objects: Data contained in the map: Key Type Default Description ~ - l UInteger 1 Position line number. Must be + l UInteger 1 Position line number. Must be greater then zero. c UInteger 0 Position column number. - n UInteger 34 ('"') Mark name. Only valid for - GlobalMark and LocalMark + n UInteger 34 ('"') Mark name. Only valid for + GlobalMark and LocalMark entries. f Binary N/A File name. Required. - * any none Other keys are allowed for - compatibility reasons, see + * any none Other keys are allowed for + compatibility reasons, see |shada-compatibility|. - 9 (BufferList) Array containing maps. Each map in the array + 9 (BufferList) Array containing maps. Each map in the array represents one buffer. Possible keys: Key Type Default Description ~ - l UInteger 1 Position line number. Must be + l UInteger 1 Position line number. Must be greater then zero. c UInteger 0 Position column number. f Binary N/A File name. Required. - * any none Other keys are allowed for - compatibility reasons, see + * any none Other keys are allowed for + compatibility reasons, see |shada-compatibility|. - * (Unknown) Any other entry type is allowed for compatibility + * (Unknown) Any other entry type is allowed for compatibility reasons, see |shada-compatibility|. *E575* *E576* -Errors in ShaDa file may have two types: E575 used for all “logical†errors -and E576 used for all “critical†errors. Critical errors trigger behaviour -described in |shada-error-handling| when writing and skipping the rest of the +Errors in ShaDa file may have two types: E575 used for all “logical†errors +and E576 used for all “critical†errors. Critical errors trigger behaviour +described in |shada-error-handling| when writing and skipping the rest of the file when reading and include: *shada-critical-contents-errors* - Any of first three MessagePack objects being not an unsigned integer. -- Third object requesting amount of bytes greater then bytes left in the ShaDa +- Third object requesting amount of bytes greater then bytes left in the ShaDa file. - Entry with zero type. I.e. first object being equal to zero. - MessagePack parser failing to parse the entry data. -- MessagePack parser consuming less or requesting greater bytes then described - in the third object for parsing fourth object. I.e. when fourth object - either contains more then one MessagePack object or it does not contain +- MessagePack parser consuming less or requesting greater bytes then described + in the third object for parsing fourth object. I.e. when fourth object + either contains more then one MessagePack object or it does not contain complete MessagePack object. ============================================================================== Standard Paths *standard-path* -Nvim stores configuration, data, and logs in standard locations. Plugins are -strongly encouraged to follow this pattern also. Use |stdpath()| to get the +Nvim stores configuration, data, and logs in standard locations. Plugins are +strongly encouraged to follow this pattern also. Use |stdpath()| to get the paths. *base-directories* *xdg* The "base" (root) directories conform to the XDG Base Directory Specification. https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html -The $XDG_CONFIG_HOME and $XDG_DATA_HOME environment variables are used if they -exist, otherwise default values (listed below) are used. +The $XDG_CONFIG_HOME, $XDG_DATA_HOME and $XDG_STATE_HOME environment variables +are used if they exist, otherwise default values (listed below) are used. CONFIG DIRECTORY (DEFAULT) ~ *$XDG_CONFIG_HOME* Nvim: stdpath("config") @@ -1342,6 +1342,11 @@ DATA DIRECTORY (DEFAULT) ~ Unix: ~/.local/share ~/.local/share/nvim Windows: ~/AppData/Local ~/AppData/Local/nvim-data +STATE DIRECTORY (DEFAULT) ~ + *$XDG_STATE_HOME* Nvim: stdpath("state") + Unix: ~/.local/state ~/.local/state/nvim + Windows: ~/AppData/Local ~/AppData/Local/nvim-data + Note: Throughout the user manual these defaults are used as placeholders, e.g. "~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config". @@ -1349,7 +1354,7 @@ LOG FILE *$NVIM_LOG_FILE* Besides 'debug' and 'verbose', Nvim keeps a general log file for internal debugging, plugins and RPC clients. > :echo $NVIM_LOG_FILE -By default, the file is located at stdpath('cache')/log unless that path +By default, the file is located at stdpath('log')/log unless that path is inaccessible or if $NVIM_LOG_FILE was set before |startup|. diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index b10bf3498d..bc264bd971 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -472,8 +472,8 @@ parse_query({lang}, {query}) *parse_query()* • `info.patterns` contains information about predicates. Parameters: ~ - {lang} string The language - {query} string A string containing the query (s-expr + {lang} (string) The language + {query} (string) A string containing the query (s-expr syntax) Return: ~ @@ -704,7 +704,7 @@ LanguageTree:register_cbs({self}, {cbs}) *LanguageTree:register_cbs()* Registers callbacks for the parser. Parameters: ~ - {cbs} table An |nvim_buf_attach()|-like table argument + {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. diff --git a/runtime/doc/usr_21.txt b/runtime/doc/usr_21.txt index 44d653a1a7..add5d48073 100644 --- a/runtime/doc/usr_21.txt +++ b/runtime/doc/usr_21.txt @@ -352,12 +352,12 @@ another session. this yourself then. Example: > :mksession! ~/.config/nvim/secret.vim - :wshada! ~/.local/share/nvim/shada/secret.shada + :wshada! ~/.local/state/nvim/shada/secret.shada And to restore this again: > :source ~/.config/nvim/secret.vim - :rshada! ~/.local/share/nvim/shada/secret.shada + :rshada! ~/.local/state/nvim/shada/secret.shada ============================================================================== *21.5* Views diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index e24dd46f49..1a3d6022ca 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -17,7 +17,7 @@ centralized reference of the differences. - Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for your |config|. - Use `$XDG_CONFIG_HOME/nvim` instead of `.vim` to store configuration files. -- Use `$XDG_DATA_HOME/nvim/shada/main.shada` instead of `.viminfo` for persistent +- Use `$XDG_STATE_HOME/nvim/shada/main.shada` instead of `.viminfo` for persistent session information. |shada| ============================================================================== @@ -32,12 +32,12 @@ centralized reference of the differences. - 'autoread' is enabled - 'background' defaults to "dark" (unless set automatically by the terminal/UI) - 'backspace' defaults to "indent,eol,start" -- 'backupdir' defaults to .,~/.local/share/nvim/backup// (|xdg|), auto-created +- 'backupdir' defaults to .,~/.local/state/nvim/backup// (|xdg|), auto-created - 'belloff' defaults to "all" - 'compatible' is always disabled - 'complete' excludes "i" - 'cscopeverbose' is enabled -- 'directory' defaults to ~/.local/share/nvim/swap// (|xdg|), auto-created +- 'directory' defaults to ~/.local/state/nvim/swap// (|xdg|), auto-created - 'display' defaults to "lastline,msgsep" - 'encoding' is UTF-8 (cf. 'fileencoding' for file-content encoding) - 'fillchars' defaults (in effect) to "vert:│,fold:·,sep:│" @@ -65,7 +65,7 @@ centralized reference of the differences. - 'tags' defaults to "./tags;,tags" - 'ttimeoutlen' defaults to 50 - 'ttyfast' is always set -- 'undodir' defaults to ~/.local/share/nvim/undo// (|xdg|), auto-created +- 'undodir' defaults to ~/.local/state/nvim/undo// (|xdg|), auto-created - 'viewoptions' includes "unix,slash", excludes "options" - 'viminfo' includes "!" - 'wildmenu' is enabled diff --git a/runtime/filetype.lua b/runtime/filetype.lua index 47d55d8465..d2510c5494 100644 --- a/runtime/filetype.lua +++ b/runtime/filetype.lua @@ -7,23 +7,23 @@ if vim.g.do_filetype_lua ~= 1 then return end -vim.api.nvim_create_augroup("filetypedetect", {clear = false}) +vim.api.nvim_create_augroup('filetypedetect', { clear = false }) -vim.api.nvim_create_autocmd({"BufRead", "BufNewFile"}, { - group = "filetypedetect", +vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { + group = 'filetypedetect', callback = function() - vim.filetype.match(vim.fn.expand("<afile>")) + vim.filetype.match(vim.fn.expand('<afile>')) end, }) -- These *must* be sourced after the autocommand above is created if not vim.g.did_load_ftdetect then - vim.cmd [[ + vim.cmd([[ augroup filetypedetect runtime! ftdetect/*.vim runtime! ftdetect/*.lua augroup END - ]] + ]]) end -- Set a marker so that the ftdetect scripts are not sourced a second time by filetype.vim @@ -31,17 +31,17 @@ vim.g.did_load_ftdetect = 1 -- If filetype.vim is disabled, set up the autocmd to use scripts.vim if vim.g.did_load_filetypes then - vim.api.nvim_create_autocmd({"BufRead", "BufNewFile"}, { - group = "filetypedetect", + vim.api.nvim_create_autocmd({ 'BufRead', 'BufNewFile' }, { + group = 'filetypedetect', command = "if !did_filetype() && expand('<amatch>') !~ g:ft_ignore_pat | runtime! scripts.vim | endif", }) - vim.api.nvim_create_autocmd("StdinReadPost", { - group = "filetypedetect", - command = "if !did_filetype() | runtime! scripts.vim | endif", + vim.api.nvim_create_autocmd('StdinReadPost', { + group = 'filetypedetect', + command = 'if !did_filetype() | runtime! scripts.vim | endif', }) end if not vim.g.ft_ignore_pat then - vim.g.ft_ignore_pat = "\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$" + vim.g.ft_ignore_pat = '\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$' end diff --git a/runtime/ftplugin/abaqus.vim b/runtime/ftplugin/abaqus.vim index b263d0c318..5ce565ef3f 100644 --- a/runtime/ftplugin/abaqus.vim +++ b/runtime/ftplugin/abaqus.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: Abaqus finite element input file (www.abaqus.com) " Maintainer: Carl Osterwisch <osterwischc@asme.org> -" Last Change: 2012 Apr 30 +" Last Change: 2022 May 09 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") | finish | endif @@ -86,11 +86,11 @@ let b:undo_ftplugin .= "|unmap <buffer> [[|unmap <buffer> ]]" \ . "|unmap <buffer> <LocalLeader><LocalLeader>" " Undo must be done in nocompatible mode for <LocalLeader>. -let b:undo_ftplugin = "let s:cpo_save = &cpoptions|" +let b:undo_ftplugin = "let b:cpo_save = &cpoptions|" \ . "set cpoptions&vim|" \ . b:undo_ftplugin - \ . "|let &cpoptions = s:cpo_save" - \ . "|unlet s:cpo_save" + \ . "|let &cpoptions = b:cpo_save" + \ . "|unlet b:cpo_save" " Restore saved compatibility options let &cpoptions = s:cpo_save diff --git a/runtime/ftplugin/query.lua b/runtime/ftplugin/query.lua index c1694961af..3b99d67247 100644 --- a/runtime/ftplugin/query.lua +++ b/runtime/ftplugin/query.lua @@ -3,4 +3,4 @@ -- Last Change: 2022 Mar 29 -- it's a lisp! -vim.cmd [[ runtime! ftplugin/lisp.vim ]] +vim.cmd([[ runtime! ftplugin/lisp.vim ]]) diff --git a/runtime/indent/query.lua b/runtime/indent/query.lua index 55cb73e62b..c86948e95e 100644 --- a/runtime/indent/query.lua +++ b/runtime/indent/query.lua @@ -3,4 +3,4 @@ -- Last Change: 2022 Mar 29 -- it's a lisp! -vim.cmd [[ runtime! indent/lisp.vim ]] +vim.cmd([[ runtime! indent/lisp.vim ]]) diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua index ba6b9d09c9..5da3d2a92f 100644 --- a/runtime/lua/man.lua +++ b/runtime/lua/man.lua @@ -8,7 +8,7 @@ local function highlight_line(line, linenr) local overstrike, escape = false, false local hls = {} -- Store highlight groups as { attr, start, final } local NONE, BOLD, UNDERLINE, ITALIC = 0, 1, 2, 3 - local hl_groups = {[BOLD]="manBold", [UNDERLINE]="manUnderline", [ITALIC]="manItalic"} + local hl_groups = { [BOLD] = 'manBold', [UNDERLINE] = 'manUnderline', [ITALIC] = 'manItalic' } local attr = NONE local byte = 0 -- byte offset @@ -47,7 +47,7 @@ local function highlight_line(line, linenr) end if continue_hl then - hls[#hls + 1] = {attr=attr, start=byte, final=-1} + hls[#hls + 1] = { attr = attr, start = byte, final = -1 } else if attr == NONE then for a, _ in pairs(hl_groups) do @@ -63,7 +63,7 @@ local function highlight_line(line, linenr) -- can be represented in one byte. Any code point above that is represented by -- a leading byte (0xc0 and above) and continuation bytes (0x80 to 0xbf, or -- decimal 128 to 191). - for char in line:gmatch("[^\128-\191][\128-\191]*") do + for char in line:gmatch('[^\128-\191][\128-\191]*') do if overstrike then local last_hl = hls[#hls] if char == prev_char then @@ -93,7 +93,7 @@ local function highlight_line(line, linenr) if last_hl and last_hl.attr == attr and last_hl.final == byte then last_hl.final = byte + #char else - hls[#hls + 1] = {attr=attr, start=byte, final=byte + #char} + hls[#hls + 1] = { attr = attr, start = byte, final = byte + #char } end overstrike = false @@ -106,25 +106,25 @@ local function highlight_line(line, linenr) -- We only want to match against SGR sequences, which consist of ESC -- followed by '[', then a series of parameter and intermediate bytes in -- the range 0x20 - 0x3f, then 'm'. (See ECMA-48, sections 5.4 & 8.3.117) - local sgr = prev_char:match("^%[([\032-\063]*)m$") + local sgr = prev_char:match('^%[([\032-\063]*)m$') -- Ignore escape sequences with : characters, as specified by ITU's T.416 -- Open Document Architecture and interchange format. - if sgr and not string.find(sgr, ":") then + if sgr and not string.find(sgr, ':') then local match while sgr and #sgr > 0 do -- Match against SGR parameters, which may be separated by ';' - match, sgr = sgr:match("^(%d*);?(.*)") + match, sgr = sgr:match('^(%d*);?(.*)') add_attr_hl(match + 0) -- coerce to number end escape = false - elseif not prev_char:match("^%[[\032-\063]*$") then + elseif not prev_char:match('^%[[\032-\063]*$') then -- Stop looking if this isn't a partial CSI sequence escape = false end - elseif char == "\027" then + elseif char == '\027' then escape = true prev_char = '' - elseif char == "\b" then + elseif char == '\b' then overstrike = true prev_char = chars[#chars] byte = byte - #prev_char @@ -143,7 +143,7 @@ local function highlight_line(line, linenr) hl_groups[hl.attr], linenr - 1, hl.start, - hl.final + hl.final, } end end @@ -152,8 +152,8 @@ local function highlight_line(line, linenr) end local function highlight_man_page() - local mod = vim.api.nvim_buf_get_option(0, "modifiable") - vim.api.nvim_buf_set_option(0, "modifiable", true) + local mod = vim.api.nvim_buf_get_option(0, 'modifiable') + vim.api.nvim_buf_set_option(0, 'modifiable', true) local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) for i, line in ipairs(lines) do @@ -166,7 +166,7 @@ local function highlight_man_page() end buf_hls = {} - vim.api.nvim_buf_set_option(0, "modifiable", mod) + vim.api.nvim_buf_set_option(0, 'modifiable', mod) end return { highlight_man_page = highlight_man_page } 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..98921463b3 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! \<Del>"]]) 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,16 +277,40 @@ vim.fn = setmetatable({}, { end t[key] = _fn return _fn - end + 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) +--- Execute Vim script commands. +--- +--- Example: +--- <pre> +--- vim.cmd('echo 42') +--- vim.cmd([[ +--- augroup My_group +--- autocmd! +--- autocmd FileType c setlocal cindent +--- augroup END +--- ]]) +--- vim.cmd({ cmd = 'echo', args = { '"foo"' } }) +--- </pre> +--- +---@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. @@ -291,9 +319,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 +371,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 +383,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 +400,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 +429,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 +484,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 +512,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 +545,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 +565,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 +590,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 +606,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 +638,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 +655,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 +667,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 +685,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 +715,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 +751,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 +785,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, }) --- <Docs described in |vim.empty_dict()| > @@ -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 <buffer=%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("<!doctype.*docbook") + local is_docbook4 = line:find('<!doctype.*docbook') 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_type = 'xml' vim.b[bufnr].docbk_ver = is_docbook4 and 4 or 5 - vim.bo[bufnr].filetype = "docbk" + vim.bo[bufnr].filetype = 'docbk' return end if line:find([[xmlns:xbl="http://www.mozilla.org/xbl"]]) then - vim.bo[bufnr].filetype = "xbl" + vim.bo[bufnr].filetype = 'xbl' return end end - vim.bo[bufnr].filetype = "xml" + vim.bo[bufnr].filetype = '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" + if line:find('^%s*%%') then + vim.bo[bufnr].filetype = 'yacc' return end -- TODO: in the Vim regex, \> 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, "<metatable> = ") + puts(buf, '<metatable> = ') 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 <nomodeline> User LspRequest") + nvim_command('doautocmd <nomodeline> User LspRequest') end) if success then - client.requests[request_id] = { type='pending', bufnr=bufnr, method=method } - nvim_command("doautocmd <nomodeline> User LspRequest") + client.requests[request_id] = { type = 'pending', bufnr = bufnr, method = method } + nvim_command('doautocmd <nomodeline> 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 <nomodeline> User LspRequest") + nvim_command('doautocmd <nomodeline> 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 9b34a551b7..b0bf2c6e5b 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 @@ -678,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 @@ -728,10 +769,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 +803,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 +810,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 +835,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 +867,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 +882,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 <nomodeline> User LspProgressUpdate") + vim.api.nvim_command('doautocmd <nomodeline> 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..29cb27d373 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') + 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 @@ -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 <character, highlight group> 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 <character, highlight group> 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<number string> 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 <text></text> block so that stylize_markdown -- can properly process it as plaintext - value = string.format("<text>\n%s\n</text>", value) + value = string.format('<text>\n%s\n</text>', 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('<cword>'), 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('<cword>'), 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 = {"", "<pre>", "</pre>"}, - code = {"", "<code>", "</code>"}, - text = {"text", "<text>", "</text>"}, + block = { nil, '```+([a-zA-Z0-9_]*)', '```+' }, + pre = { '', '<pre>', '</pre>' }, + code = { '', '<code>', '</code>' }, + text = { 'text', '<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 <buffer> 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", "<cmd>bdelete<cr>", {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', + '<cmd>bdelete<cr>', + { 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..9bbe356f03 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -15,8 +15,8 @@ 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. -function vim.deepcopy(orig) end -- luacheck: no unused +---@return table Table of copied keys and (nested) values. +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)() @@ -57,19 +59,19 @@ 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}} + 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 @@ -105,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 @@ -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) @@ -154,10 +156,10 @@ 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))) + assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) local keys = {} for k, _ in pairs(t) do @@ -169,10 +171,10 @@ 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))) + assert(type(t) == 'table', string.format('Expected table, got %s', type(t))) local values = {} for _, v in pairs(t) do @@ -183,10 +185,11 @@ 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'}} + vim.validate({ func = { func, 'c' }, t = { t, 't' } }) local rettab = {} for k, v in pairs(t) do @@ -197,10 +200,11 @@ 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'}} + vim.validate({ func = { func, 'c' }, t = { t, 't' } }) local rettab = {} for _, entry in pairs(t) do @@ -213,13 +217,13 @@ 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'}} + vim.validate({ t = { t, 't' } }) - for _,v in ipairs(t) do + for _, v in ipairs(t) do if v == value then return true end @@ -231,25 +235,26 @@ 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))) + 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)) + 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 +264,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 @@ -281,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 @@ -294,25 +300,30 @@ 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 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 @@ -332,15 +343,22 @@ 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 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 @@ -349,19 +367,19 @@ end --- Index into a table (first argument) via string keys passed as subsequent arguments. --- Return `nil` if the key does not exist. ---_ +--- --- Examples: --- <pre> --- vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == true --- vim.tbl_get({ key = {}}, 'key', 'nested_key') == nil --- </pre> --- ----@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 = {...} + local keys = { ... } if #keys == 0 then return end @@ -383,18 +401,18 @@ 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'}; - 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 @@ -406,15 +424,15 @@ 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) 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) @@ -431,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 @@ -441,7 +459,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 @@ -468,26 +486,28 @@ end --- </pre> --- ---@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'}} + 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 --- 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 - new_list[#new_list+1] = list[i] + new_list[#new_list + 1] = list[i] end return new_list end @@ -495,40 +515,40 @@ 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'}} + vim.validate({ s = { s, 's' } }) return s:match('^%s*(.*%S)') or '' 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'}} + vim.validate({ s = { s, 's' } }) return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1') 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'}; } + vim.validate({ s = { s, 's' }, prefix = { prefix, 's' } }) return s:sub(1, #prefix) == prefix 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'}; } + vim.validate({ s = { s, 's' }, suffix = { suffix, 's' } }) return #suffix == 0 or s:sub(-#suffix) == suffix end @@ -568,7 +588,7 @@ end --- --- </pre> --- ----@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 @@ -582,18 +602,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 +638,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. + -- 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 +672,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 @@ -665,12 +691,16 @@ 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 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 = {} --- </pre> 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) --- </pre> 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) diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index ab1871fe60..4f2f7b942d 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -2,7 +2,7 @@ " " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" -" Last Change: 2022 May 04 +" Last Change: 2022 May 09 " " WORK IN PROGRESS - The basics works stable, more to come " Note: In general you need at least GDB 7.12 because this provides the @@ -205,8 +205,8 @@ func s:CheckGdbRunning() return 'ok' endfunc +" Open a terminal window without a job, to run the debugged program in. func s:StartDebug_term(dict) - " Open a terminal window without a job, to run the debugged program in. execute s:vertical ? 'vnew' : 'new' let s:pty_job_id = termopen('tail -f /dev/null;#gdb program') if s:pty_job_id == 0 @@ -365,8 +365,8 @@ func s:StartDebug_term(dict) call s:StartDebugCommon(a:dict) endfunc +" Open a window with a prompt buffer to run gdb in. func s:StartDebug_prompt(dict) - " Open a window with a prompt buffer to run gdb in. if s:vertical vertical new else diff --git a/runtime/syntax/query.lua b/runtime/syntax/query.lua index e24ff65360..8f40b1cb8a 100644 --- a/runtime/syntax/query.lua +++ b/runtime/syntax/query.lua @@ -3,4 +3,4 @@ -- Last Change: 2022 Apr 13 -- it's a lisp! -vim.cmd [[ runtime! syntax/lisp.vim ]] +vim.cmd([[ runtime! syntax/lisp.vim ]]) diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index 0e6ec19ff8..5a0dd4f2d7 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -120,9 +120,6 @@ else com! -nargs=* VimFoldt <args> endif -" commands not picked up by the generator (due to non-standard format) {{{2 -syn keyword vimCommand contained py3 - " Deprecated variable options {{{2 if exists("g:vim_minlines") let g:vimsyn_minlines= g:vim_minlines diff --git a/scripts/genvimvim.lua b/scripts/genvimvim.lua index ff60b6cce7..7e9d649cb4 100644 --- a/scripts/genvimvim.lua +++ b/scripts/genvimvim.lua @@ -44,12 +44,13 @@ local function cmd_kw(prev_cmd, cmd) end -- Exclude these from the vimCommand keyword list, they are handled specially --- in syntax/vim.vim (vimAugroupKey, vimAutoCmd). #9327 -local function is_autocmd_cmd(cmd) +-- in syntax/vim.vim (vimAugroupKey, vimAutoCmd, vimSubst). #9327 +local function is_special_cased_cmd(cmd) return (cmd == 'augroup' or cmd == 'autocmd' or cmd == 'doautocmd' - or cmd == 'doautoall') + or cmd == 'doautoall' + or cmd == 'substitute') end local vimcmd_start = 'syn keyword vimCommand contained ' @@ -60,7 +61,7 @@ for _, cmd_desc in ipairs(ex_cmds.cmds) do w('\n' .. vimcmd_start) end local cmd = cmd_desc.command - if cmd:match('%w') and cmd ~= 'z' and not is_autocmd_cmd(cmd) then + if cmd:match('%w') and cmd ~= 'z' and not is_special_cased_cmd(cmd) then w(' ' .. cmd_kw(prev_cmd, cmd)) end prev_cmd = cmd diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua index c32370517c..6a206066b8 100644 --- a/scripts/lua2dox.lua +++ b/scripts/lua2dox.lua @@ -403,6 +403,29 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename) if string.sub(line, 3, 3) == '@' or string.sub(line, 1, 4) == '---@' then -- it's a magic comment state = 'in_magic_comment' local magic = string.sub(line, 4 + offset) + + local magic_split = string_split(magic, ' ') + + local type_index = 2 + if magic_split[1] == 'param' then + type_index = type_index + 1 + end + + if magic_split[type_index] == 'number' or + magic_split[type_index] == 'number|nil' or + magic_split[type_index] == 'string' or + magic_split[type_index] == 'string|nil' or + magic_split[type_index] == 'table' or + magic_split[type_index] == 'table|nil' or + magic_split[type_index] == 'boolean' or + magic_split[type_index] == 'boolean|nil' or + magic_split[type_index] == 'function' or + magic_split[type_index] == 'function|nil' + then + magic_split[type_index] = '(' .. magic_split[type_index] .. ')' + end + magic = table.concat(magic_split, ' ') + outStream:writeln('/// @' .. magic) fn_magic = checkComment4fn(fn_magic,magic) elseif string.sub(line,3,3)=='-' then -- it's a nonmagic doc comment diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index 57f51d9d46..e7e8f0b274 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -239,6 +239,10 @@ preprocess_patch() { LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/highlight\(\.[ch]\)/\1\/highlight_group\2/g' \ "$file" > "$file".tmp && mv "$file".tmp "$file" + # Rename keymap.h to keycodes.h + LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/keymap\.h/\1\/keycodes.h/g' \ + "$file" > "$file".tmp && mv "$file".tmp "$file" + # Rename test_urls.vim to check_urls.vim LC_ALL=C sed -e 's@\( [ab]\)/runtime/doc/test\(_urls\.vim\)@\1/scripts/check\2@g' \ "$file" > "$file".tmp && mv "$file".tmp "$file" diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index e6f70033d0..2a323bdea0 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -185,15 +185,8 @@ if(NOT MSVC) set_source_files_properties( ${EXTERNAL_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion -Wno-missing-noreturn -Wno-missing-format-attribute -Wno-double-promotion") - # gperf generates ANSI-C with incorrect linkage, ignore it. - check_c_compiler_flag(-Wstatic-in-inline HAS_WSTATIC_IN_INLINE) - if(HAS_WSTATIC_IN_INLINE) - set_source_files_properties( - eval/funcs.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion") - else() - set_source_files_properties( - eval/funcs.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion") - endif() + set_source_files_properties( + eval/funcs.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion") endif() if(NOT "${MIN_LOG_LEVEL}" MATCHES "^$") @@ -408,14 +401,9 @@ add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS} DEPENDS ${EX_CMDS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/ex_cmds.lua ) -if(NOT GPERF_PRG) - message(FATAL_ERROR "gperf was not found.") -endif() add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA} COMMAND ${LUA_PRG} ${FUNCS_GENERATOR} - ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA} - COMMAND ${GPERF_PRG} - ${GENERATED_DIR}/funcs.generated.h.gperf --output-file=${GENERATED_FUNCS} + ${CMAKE_CURRENT_LIST_DIR} ${LUA_SHARED_MODULE_SOURCE} ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA} DEPENDS ${FUNCS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/eval.lua ${API_METADATA} ) list(APPEND NVIM_GENERATED_FOR_SOURCES diff --git a/src/nvim/README.md b/src/nvim/README.md index c7cb233c73..9417629691 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -38,7 +38,7 @@ alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to filter the log, e.g. at DEBUG level you might want to exclude UI messages: - tail -F ~/.cache/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log + tail -F ~/.local/state/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log Build with ASAN --------------- diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 45dadae1dd..9842975d62 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -262,7 +262,7 @@ void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *e /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start First line index -/// @param end Last line index (exclusive) +/// @param end Last line index, exclusive /// @param strict_indexing Whether out-of-bounds should be an error. /// @param[out] err Error details, if any /// @return Array of lines, or empty array for unloaded buffer. @@ -358,7 +358,7 @@ static bool check_string_array(Array arr, bool disallow_nl, Error *err) /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start First line index -/// @param end Last line index (exclusive) +/// @param end Last line index, exclusive /// @param strict_indexing Whether out-of-bounds should be an error. /// @param replacement Array of lines to use as replacement /// @param[out] err Error details, if any @@ -514,24 +514,25 @@ end: /// Sets (replaces) a range in the buffer /// -/// This is recommended over nvim_buf_set_lines when only modifying parts of a -/// line, as extmarks will be preserved on non-modified parts of the touched +/// This is recommended over |nvim_buf_set_lines()| when only modifying parts of +/// a line, as extmarks will be preserved on non-modified parts of the touched /// lines. /// -/// Indexing is zero-based and end-exclusive. +/// Indexing is zero-based. Row indices are end-inclusive, and column indices +/// are end-exclusive. /// -/// To insert text at a given index, set `start` and `end` ranges to the same -/// index. To delete a range, set `replacement` to an array containing -/// an empty string, or simply an empty array. +/// To insert text at a given `(row, column)` location, use `start_row = end_row +/// = row` and `start_col = end_col = col`. To delete the text in a range, use +/// `replacement = {}`. /// -/// Prefer nvim_buf_set_lines when adding or deleting entire lines only. +/// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines. /// /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start_row First line index -/// @param start_col First column -/// @param end_row Last line index -/// @param end_col Last column +/// @param start_col Starting column (byte offset) on first line +/// @param end_row Last line index, inclusive +/// @param end_col Ending column (byte offset) on last line, exclusive /// @param replacement Array of lines to use as replacement /// @param[out] err Error details, if any void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, Integer start_col, @@ -760,16 +761,17 @@ end: /// This differs from |nvim_buf_get_lines()| in that it allows retrieving only /// portions of a line. /// -/// Indexing is zero-based. Column indices are end-exclusive. +/// Indexing is zero-based. Row indices are end-inclusive, and column indices +/// are end-exclusive. /// /// Prefer |nvim_buf_get_lines()| when retrieving entire lines. /// /// @param channel_id /// @param buffer Buffer handle, or 0 for current buffer /// @param start_row First line index -/// @param start_col Starting byte offset of first line -/// @param end_row Last line index -/// @param end_col Ending byte offset of last line (exclusive) +/// @param start_col Starting column (byte offset) on first line +/// @param end_row Last line index, inclusive +/// @param end_col Ending column (byte offset) on last line, exclusive /// @param opts Optional parameters. Currently unused. /// @param[out] err Error details, if any /// @return Array of lines, or empty array for unloaded buffer. diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 5baffaf505..78f8ed3cca 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -155,5 +155,44 @@ return { create_augroup = { "clear"; }; + cmd = { + "cmd"; + "range"; + "count"; + "reg"; + "bang"; + "args"; + "magic"; + "mods"; + "nargs"; + "addr"; + "nextcmd"; + }; + cmd_magic = { + "file"; + "bar"; + }; + cmd_mods = { + "silent"; + "emsg_silent"; + "sandbox"; + "noautocmd"; + "browse"; + "confirm"; + "hide"; + "keepalt"; + "keepjumps"; + "keepmarks"; + "keeppatterns"; + "lockmarks"; + "noswapfile"; + "tab"; + "verbose"; + "vertical"; + "split"; + }; + cmd_opts = { + "output"; + }; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index eb86964a72..542e5c4953 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -19,6 +19,7 @@ #include "nvim/decoration.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" +#include "nvim/ex_cmds_defs.h" #include "nvim/extmark.h" #include "nvim/fileio.h" #include "nvim/getchar.h" @@ -1690,3 +1691,175 @@ int init_sign_text(char **sign_text, char *text) return OK; } + +/// Check if a string contains only whitespace characters. +bool string_iswhite(String str) +{ + for (size_t i = 0; i < str.size; i++) { + if (!ascii_iswhite(str.data[i])) { + // Found a non-whitespace character + return false; + } else if (str.data[i] == NUL) { + // Terminate at first occurence of a NUL character + break; + } + } + return true; +} + +// Add modifier string for command into the command line. Includes trailing whitespace if non-empty. +// @return OK or FAIL. +static int add_cmd_modifier_str(char *cmdline, size_t *pos, const size_t bufsize, + CmdParseInfo *cmdinfo) +{ +#define APPEND_MODIFIER(...) \ + do { \ + if (*pos < bufsize) { \ + *pos += (size_t)snprintf(cmdline + *pos, bufsize - *pos, __VA_ARGS__); \ + } \ + if (*pos < bufsize) { \ + cmdline[*pos] = ' '; \ + *pos += 1; \ + } else { \ + goto err; \ + } \ + } while (0) + +#define APPEND_MODIFIER_IF(cond, mod) \ + do { \ + if (cond) { \ + APPEND_MODIFIER(mod); \ + } \ + } while (0) + + if (cmdinfo->cmdmod.tab != 0) { + APPEND_MODIFIER("%dtab", cmdinfo->cmdmod.tab - 1); + } + if (cmdinfo->verbose != -1) { + APPEND_MODIFIER("%ldverbose", cmdinfo->verbose); + } + + switch (cmdinfo->cmdmod.split & (WSP_ABOVE | WSP_BELOW | WSP_TOP | WSP_BOT)) { + case WSP_ABOVE: + APPEND_MODIFIER("aboveleft"); + break; + case WSP_BELOW: + APPEND_MODIFIER("belowright"); + break; + case WSP_TOP: + APPEND_MODIFIER("topleft"); + break; + case WSP_BOT: + APPEND_MODIFIER("botright"); + break; + default: + break; + } + + APPEND_MODIFIER_IF(cmdinfo->cmdmod.split & WSP_VERT, "vertical"); + + if (cmdinfo->emsg_silent) { + APPEND_MODIFIER("silent!"); + } else if (cmdinfo->silent) { + APPEND_MODIFIER("silent"); + } + + APPEND_MODIFIER_IF(cmdinfo->sandbox, "sandbox"); + APPEND_MODIFIER_IF(cmdinfo->noautocmd, "noautocmd"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.browse, "browse"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.confirm, "confirm"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.hide, "hide"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.keepalt, "keepalt"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.keepjumps, "keepjumps"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.keepmarks, "keepmarks"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.keeppatterns, "keeppatterns"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.lockmarks, "lockmarks"); + APPEND_MODIFIER_IF(cmdinfo->cmdmod.noswapfile, "noswapfile"); + + return OK; +err: + return FAIL; + +#undef APPEND_MODIFIER +#undef APPEND_MODIFIER_IF +} + +/// Build cmdline string for command, used by `nvim_cmd()`. +/// +/// @return OK or FAIL. +int build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdinfo, char **args, + size_t argc) +{ + const size_t bufsize = IOSIZE; + size_t pos = 0; + char *cmdline = xcalloc(bufsize, sizeof(char)); + +#define CMDLINE_APPEND(...) \ + do { \ + if (pos < bufsize) { \ + pos += (size_t)snprintf(cmdline + pos, bufsize - pos, __VA_ARGS__); \ + } else { \ + goto err; \ + } \ + } while (0) + + // Command modifiers. + if (add_cmd_modifier_str(cmdline, &pos, bufsize, cmdinfo) == FAIL) { + goto err; + } + + // Command range / count. + if (eap->argt & EX_RANGE) { + if (eap->addr_count == 1) { + CMDLINE_APPEND("%ld", eap->line2); + } else if (eap->addr_count > 1) { + CMDLINE_APPEND("%ld,%ld", eap->line1, eap->line2); + eap->addr_count = 2; // Make sure address count is not greater than 2 + } + } + + // Keep the index of the position where command name starts, so eap->cmd can point to it. + size_t cmdname_idx = pos; + CMDLINE_APPEND("%s", eap->cmd); + eap->cmd = cmdline + cmdname_idx; + + // Command bang. + if (eap->argt & EX_BANG && eap->forceit) { + CMDLINE_APPEND("!"); + } + + // Command register. + if (eap->argt & EX_REGSTR && eap->regname) { + CMDLINE_APPEND(" %c", eap->regname); + } + + // Iterate through each argument and store the starting position and length of each argument in + // the cmdline string in `eap->args` and `eap->arglens`, respectively. + eap->args = xcalloc(argc, sizeof(char *)); + eap->arglens = xcalloc(argc, sizeof(size_t)); + for (size_t i = 0; i < argc; i++) { + eap->args[i] = cmdline + pos + 1; // add 1 to skip the leading space. + eap->arglens[i] = STRLEN(args[i]); + CMDLINE_APPEND(" %s", args[i]); + } + eap->argc = argc; + // If there isn't an argument, make eap->arg point to end of cmd + eap->arg = argc > 0 ? eap->args[0] : cmdline + pos; + + // Replace, :make and :grep with 'makeprg' and 'grepprg'. + char *p = replace_makeprg(eap, eap->arg, cmdlinep); + if (p != eap->arg) { + // If replace_makeprg modified the cmdline string, correct the argument pointers. + assert(argc == 1); + eap->arg = p; + eap->args[0] = p; + } + + *cmdlinep = cmdline; + return OK; +err: + xfree(cmdline); + return FAIL; + +#undef CMDLINE_APPEND +} diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index c4a301839f..02f406d686 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -10,10 +10,14 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/vimscript.h" #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/eval.h" #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" #include "nvim/ex_cmds2.h" +#include "nvim/ops.h" +#include "nvim/strings.h" +#include "nvim/vim.h" #include "nvim/viml/parser/expressions.h" #include "nvim/viml/parser/parser.h" #include "nvim/window.h" @@ -22,7 +26,9 @@ # include "api/vimscript.c.generated.h" #endif -/// Executes Vimscript (multiline block of Ex-commands), like anonymous +#define IS_USER_CMDIDX(idx) ((int)(idx) < 0) + +/// Executes Vimscript (multiline block of Ex commands), like anonymous /// |:source|. /// /// Unlike |nvim_command()| this function supports heredocs, script-scope (s:), @@ -32,6 +38,7 @@ /// /// @see |execute()| /// @see |nvim_command()| +/// @see |nvim_cmd()| /// /// @param src Vimscript code /// @param output Capture and return all (non-error, non-shell |:!|) output @@ -89,13 +96,16 @@ theend: return (String)STRING_INIT; } -/// Executes an ex-command. +/// Executes an Ex command. /// /// On execution error: fails with VimL error, does not update v:errmsg. /// -/// @see |nvim_exec()| +/// Prefer using |nvim_cmd()| or |nvim_exec()| over this. To evaluate multiple lines of Vim script +/// or an Ex command directly, use |nvim_exec()|. To construct an Ex command using a structured +/// format and then execute it, use |nvim_cmd()|. To modify an Ex command before evaluating it, use +/// |nvim_parse_cmd()| in conjunction with |nvim_cmd()|. /// -/// @param command Ex-command string +/// @param command Ex command string /// @param[out] err Error details (Vim error), if any void nvim_command(String command, Error *err) FUNC_API_SINCE(1) @@ -978,3 +988,370 @@ end: xfree(cmdline); return result; } + +/// Executes an Ex command. +/// +/// Unlike |nvim_command()| this command takes a structured Dictionary instead of a String. This +/// allows for easier construction and manipulation of an Ex command. This also allows for things +/// such as having spaces inside a command argument, expanding filenames in a command that otherwise +/// doesn't expand filenames, etc. +/// +/// @see |nvim_exec()| +/// @see |nvim_command()| +/// +/// @param cmd Command to execute. Must be a Dictionary that can contain the same values as +/// the return value of |nvim_parse_cmd()| except "addr", "nargs" and "nextcmd" +/// which are ignored if provided. All values except for "cmd" are optional. +/// @param opts Optional parameters. +/// - output: (boolean, default false) Whether to return command output. +/// @param[out] err Error details, if any. +/// @return Command output (non-error, non-shell |:!|) if `output` is true, else empty string. +String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error *err) + FUNC_API_SINCE(10) +{ + exarg_T ea; + memset(&ea, 0, sizeof(ea)); + ea.verbose_save = -1; + ea.save_msg_silent = -1; + + CmdParseInfo cmdinfo; + memset(&cmdinfo, 0, sizeof(cmdinfo)); + cmdinfo.verbose = -1; + + char *cmdline = NULL; + char *cmdname = NULL; + char **args = NULL; + size_t argc = 0; + + String retv = (String)STRING_INIT; + +#define OBJ_TO_BOOL(var, value, default, varname) \ + do { \ + var = api_object_to_bool(value, varname, default, err); \ + if (ERROR_SET(err)) { \ + goto end; \ + } \ + } while (0) + +#define VALIDATION_ERROR(...) \ + do { \ + api_set_error(err, kErrorTypeValidation, __VA_ARGS__); \ + goto end; \ + } while (0) + + bool output; + OBJ_TO_BOOL(output, opts->output, false, "'output'"); + + // First, parse the command name and check if it exists and is valid. + if (!HAS_KEY(cmd->cmd) || cmd->cmd.type != kObjectTypeString + || cmd->cmd.data.string.data[0] == NUL) { + VALIDATION_ERROR("'cmd' must be a non-empty String"); + } + + cmdname = string_to_cstr(cmd->cmd.data.string); + ea.cmd = cmdname; + + char *p = find_ex_command(&ea, NULL); + + // If this looks like an undefined user command and there are CmdUndefined + // autocommands defined, trigger the matching autocommands. + if (p != NULL && ea.cmdidx == CMD_SIZE && ASCII_ISUPPER(*ea.cmd) + && has_event(EVENT_CMDUNDEFINED)) { + p = xstrdup(cmdname); + int ret = apply_autocmds(EVENT_CMDUNDEFINED, (char_u *)p, (char_u *)p, true, NULL); + xfree(p); + // If the autocommands did something and didn't cause an error, try + // finding the command again. + p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd; + } + + if (p == NULL || ea.cmdidx == CMD_SIZE) { + VALIDATION_ERROR("Command not found: %s", cmdname); + } + if (is_cmd_ni(ea.cmdidx)) { + VALIDATION_ERROR("Command not implemented: %s", cmdname); + } + + // Get the command flags so that we can know what type of arguments the command uses. + // Not required for a user command since `find_ex_command` already deals with it in that case. + if (!IS_USER_CMDIDX(ea.cmdidx)) { + ea.argt = get_cmd_argt(ea.cmdidx); + } + + // Parse command arguments since it's needed to get the command address type. + if (HAS_KEY(cmd->args)) { + if (cmd->args.type != kObjectTypeArray) { + VALIDATION_ERROR("'args' must be an Array"); + } + // Check if every argument is valid + for (size_t i = 0; i < cmd->args.data.array.size; i++) { + Object elem = cmd->args.data.array.items[i]; + if (elem.type != kObjectTypeString) { + VALIDATION_ERROR("Command argument must be a String"); + } else if (string_iswhite(elem.data.string)) { + VALIDATION_ERROR("Command argument must have non-whitespace characters"); + } + } + + argc = cmd->args.data.array.size; + bool argc_valid; + + // Check if correct number of arguments is used. + switch (ea.argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) { + case EX_EXTRA | EX_NOSPC | EX_NEEDARG: + argc_valid = argc == 1; + break; + case EX_EXTRA | EX_NOSPC: + argc_valid = argc <= 1; + break; + case EX_EXTRA | EX_NEEDARG: + argc_valid = argc >= 1; + break; + case EX_EXTRA: + argc_valid = true; + break; + default: + argc_valid = argc == 0; + break; + } + + if (!argc_valid) { + argc = 0; // Ensure that args array isn't erroneously freed at the end. + VALIDATION_ERROR("Incorrect number of arguments supplied"); + } + + if (argc != 0) { + args = xcalloc(argc, sizeof(char *)); + + for (size_t i = 0; i < argc; i++) { + args[i] = string_to_cstr(cmd->args.data.array.items[i].data.string); + } + } + } + + // Simply pass the first argument (if it exists) as the arg pointer to `set_cmd_addr_type()` + // since it only ever checks the first argument. + set_cmd_addr_type(&ea, argc > 0 ? (char_u *)args[0] : NULL); + + if (HAS_KEY(cmd->range)) { + if (!(ea.argt & EX_RANGE)) { + VALIDATION_ERROR("Command cannot accept a range"); + } else if (cmd->range.type != kObjectTypeArray) { + VALIDATION_ERROR("'range' must be an Array"); + } else if (cmd->range.data.array.size > 2) { + VALIDATION_ERROR("'range' cannot contain more than two elements"); + } + + Array range = cmd->range.data.array; + ea.addr_count = (int)range.size; + + for (size_t i = 0; i < range.size; i++) { + Object elem = range.items[i]; + if (elem.type != kObjectTypeInteger || elem.data.integer < 0) { + VALIDATION_ERROR("'range' element must be a non-negative Integer"); + } + } + + if (range.size > 0) { + ea.line1 = range.items[0].data.integer; + ea.line2 = range.items[range.size - 1].data.integer; + } + + if (invalid_range(&ea) != NULL) { + VALIDATION_ERROR("Invalid range provided"); + } + } + if (ea.addr_count == 0) { + if (ea.argt & EX_DFLALL) { + set_cmd_dflall_range(&ea); // Default range for range=% + } else { + ea.line1 = ea.line2 = get_cmd_default_range(&ea); // Default range. + + if (ea.addr_type == ADDR_OTHER) { + // Default is 1, not cursor. + ea.line2 = 1; + } + } + } + + if (HAS_KEY(cmd->count)) { + if (!(ea.argt & EX_COUNT)) { + VALIDATION_ERROR("Command cannot accept a count"); + } else if (cmd->count.type != kObjectTypeInteger || cmd->count.data.integer < 0) { + VALIDATION_ERROR("'count' must be a non-negative Integer"); + } + set_cmd_count(&ea, cmd->count.data.integer, true); + } + + if (HAS_KEY(cmd->reg)) { + if (!(ea.argt & EX_REGSTR)) { + VALIDATION_ERROR("Command cannot accept a register"); + } else if (cmd->reg.type != kObjectTypeString || cmd->reg.data.string.size != 1) { + VALIDATION_ERROR("'reg' must be a single character"); + } + char regname = cmd->reg.data.string.data[0]; + if (regname == '=') { + VALIDATION_ERROR("Cannot use register \"="); + } else if (!valid_yank_reg(regname, ea.cmdidx != CMD_put && !IS_USER_CMDIDX(ea.cmdidx))) { + VALIDATION_ERROR("Invalid register: \"%c", regname); + } + ea.regname = (uint8_t)regname; + } + + OBJ_TO_BOOL(ea.forceit, cmd->bang, false, "'bang'"); + if (ea.forceit && !(ea.argt & EX_BANG)) { + VALIDATION_ERROR("Command cannot accept a bang"); + } + + if (HAS_KEY(cmd->magic)) { + if (cmd->magic.type != kObjectTypeDictionary) { + VALIDATION_ERROR("'magic' must be a Dictionary"); + } + + Dict(cmd_magic) magic = { 0 }; + if (!api_dict_to_keydict(&magic, KeyDict_cmd_magic_get_field, + cmd->magic.data.dictionary, err)) { + goto end; + } + + OBJ_TO_BOOL(cmdinfo.magic.file, magic.file, ea.argt & EX_XFILE, "'magic.file'"); + OBJ_TO_BOOL(cmdinfo.magic.bar, magic.bar, ea.argt & EX_TRLBAR, "'magic.bar'"); + } else { + cmdinfo.magic.file = ea.argt & EX_XFILE; + cmdinfo.magic.bar = ea.argt & EX_TRLBAR; + } + + if (HAS_KEY(cmd->mods)) { + if (cmd->mods.type != kObjectTypeDictionary) { + VALIDATION_ERROR("'mods' must be a Dictionary"); + } + + Dict(cmd_mods) mods = { 0 }; + if (!api_dict_to_keydict(&mods, KeyDict_cmd_mods_get_field, cmd->mods.data.dictionary, err)) { + goto end; + } + + if (HAS_KEY(mods.tab)) { + if (mods.tab.type != kObjectTypeInteger || mods.tab.data.integer < 0) { + VALIDATION_ERROR("'mods.tab' must be a non-negative Integer"); + } + cmdinfo.cmdmod.tab = (int)mods.tab.data.integer + 1; + } + + if (HAS_KEY(mods.verbose)) { + if (mods.verbose.type != kObjectTypeInteger || mods.verbose.data.integer <= 0) { + VALIDATION_ERROR("'mods.verbose' must be a non-negative Integer"); + } + cmdinfo.verbose = mods.verbose.data.integer; + } + + bool vertical; + OBJ_TO_BOOL(vertical, mods.vertical, false, "'mods.vertical'"); + cmdinfo.cmdmod.split |= (vertical ? WSP_VERT : 0); + + if (HAS_KEY(mods.split)) { + if (mods.split.type != kObjectTypeString) { + VALIDATION_ERROR("'mods.split' must be a String"); + } + + if (STRCMP(mods.split.data.string.data, "aboveleft") == 0 + || STRCMP(mods.split.data.string.data, "leftabove") == 0) { + cmdinfo.cmdmod.split |= WSP_ABOVE; + } else if (STRCMP(mods.split.data.string.data, "belowright") == 0 + || STRCMP(mods.split.data.string.data, "rightbelow") == 0) { + cmdinfo.cmdmod.split |= WSP_BELOW; + } else if (STRCMP(mods.split.data.string.data, "topleft") == 0) { + cmdinfo.cmdmod.split |= WSP_TOP; + } else if (STRCMP(mods.split.data.string.data, "botright") == 0) { + cmdinfo.cmdmod.split |= WSP_BOT; + } else { + VALIDATION_ERROR("Invalid value for 'mods.split'"); + } + } + + OBJ_TO_BOOL(cmdinfo.silent, mods.silent, false, "'mods.silent'"); + OBJ_TO_BOOL(cmdinfo.emsg_silent, mods.emsg_silent, false, "'mods.emsg_silent'"); + OBJ_TO_BOOL(cmdinfo.sandbox, mods.sandbox, false, "'mods.sandbox'"); + OBJ_TO_BOOL(cmdinfo.noautocmd, mods.noautocmd, false, "'mods.noautocmd'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.browse, mods.browse, false, "'mods.browse'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.confirm, mods.confirm, false, "'mods.confirm'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.hide, mods.hide, false, "'mods.hide'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.keepalt, mods.keepalt, false, "'mods.keepalt'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.keepjumps, mods.keepjumps, false, "'mods.keepjumps'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.keepmarks, mods.keepmarks, false, "'mods.keepmarks'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.keeppatterns, mods.keeppatterns, false, "'mods.keeppatterns'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.lockmarks, mods.lockmarks, false, "'mods.lockmarks'"); + OBJ_TO_BOOL(cmdinfo.cmdmod.noswapfile, mods.noswapfile, false, "'mods.noswapfile'"); + + if (cmdinfo.sandbox && !(ea.argt & EX_SBOXOK)) { + VALIDATION_ERROR("Command cannot be run in sandbox"); + } + } + + // Finally, build the command line string that will be stored inside ea.cmdlinep. + // This also sets the values of ea.cmd, ea.arg, ea.args and ea.arglens. + if (build_cmdline_str(&cmdline, &ea, &cmdinfo, args, argc) == FAIL) { + goto end; + } + ea.cmdlinep = &cmdline; + + garray_T capture_local; + const int save_msg_silent = msg_silent; + garray_T * const save_capture_ga = capture_ga; + + if (output) { + ga_init(&capture_local, 1, 80); + capture_ga = &capture_local; + } + + try_start(); + if (output) { + msg_silent++; + } + + WITH_SCRIPT_CONTEXT(channel_id, { + execute_cmd(&ea, &cmdinfo); + }); + + if (output) { + capture_ga = save_capture_ga; + msg_silent = save_msg_silent; + } + try_end(err); + + if (ERROR_SET(err)) { + goto clear_ga; + } + + if (output && capture_local.ga_len > 1) { + retv = (String){ + .data = capture_local.ga_data, + .size = (size_t)capture_local.ga_len, + }; + // redir usually (except :echon) prepends a newline. + if (retv.data[0] == '\n') { + memmove(retv.data, retv.data + 1, retv.size - 1); + retv.data[retv.size - 1] = '\0'; + retv.size = retv.size - 1; + } + goto end; + } +clear_ga: + if (output) { + ga_clear(&capture_local); + } +end: + xfree(cmdline); + xfree(cmdname); + xfree(ea.args); + xfree(ea.arglens); + for (size_t i = 0; i < argc; i++) { + xfree(args[i]); + } + xfree(args); + + return retv; + +#undef OBJ_TO_BOOL +#undef VALIDATION_ERROR +} diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 30e5edb4d0..18c8a2c250 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2366,7 +2366,7 @@ static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, bool ignore_case) { // First try the short file name, then the long file name. char_u *match = fname_match(rmp, buf->b_sfname, ignore_case); - if (match == NULL) { + if (match == NULL && rmp->regprog != NULL) { match = fname_match(rmp, buf->b_ffname, ignore_case); } return match; @@ -2387,7 +2387,7 @@ static char_u *fname_match(regmatch_T *rmp, char_u *name, bool ignore_case) rmp->rm_ic = p_fic || ignore_case; if (vim_regexec(rmp, name, (colnr_T)0)) { match = name; - } else { + } else if (rmp->regprog != NULL) { // Replace $(HOME) with '~' and try matching again. p = home_replace_save(NULL, name); if (vim_regexec(rmp, p, (colnr_T)0)) { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 90a6f81cc0..c2e61271c7 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -29,7 +29,7 @@ #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/main.h" #include "nvim/mark.h" #include "nvim/mbyte.h" diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index cf5f86b3f7..ee00736b63 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -80,9 +80,6 @@ typedef enum { kSomeMatchStrPos, ///< Data for matchstrpos(). } SomeMatchType; -KHASH_MAP_INIT_STR(functions, VimLFuncDef) - - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/funcs.c.generated.h" @@ -134,14 +131,11 @@ char *get_function_name(expand_T *xp, int idx) return (char *)name; } } - while ((size_t)++intidx < ARRAY_SIZE(functions) - && functions[intidx].name[0] == '\0') {} - if ((size_t)intidx >= ARRAY_SIZE(functions)) { + const char *const key = functions[++intidx].name; + if (!key) { return NULL; } - - const char *const key = functions[intidx].name; const size_t key_len = strlen(key); memcpy(IObuff, key, key_len); IObuff[key_len] = '('; @@ -178,18 +172,19 @@ char *get_expr_name(expand_T *xp, int idx) /// @param[in] name Name of the function. /// /// @return pointer to the function definition or NULL if not found. -const VimLFuncDef *find_internal_func(const char *const name) +const EvalFuncDef *find_internal_func(const char *const name) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE FUNC_ATTR_NONNULL_ALL { size_t len = strlen(name); - return find_internal_func_gperf(name, len); + int index = find_internal_func_hash(name, len); + return index >= 0 ? &functions[index] : NULL; } int call_internal_func(const char_u *const fname, const int argcount, typval_T *const argvars, typval_T *const rettv) FUNC_ATTR_NONNULL_ALL { - const VimLFuncDef *const fdef = find_internal_func((const char *)fname); + const EvalFuncDef *const fdef = find_internal_func((const char *)fname); if (fdef == NULL) { return ERROR_UNKNOWN; } else if (argcount < fdef->min_argc) { @@ -207,7 +202,7 @@ int call_internal_method(const char_u *const fname, const int argcount, typval_T typval_T *const rettv, typval_T *const basetv) FUNC_ATTR_NONNULL_ALL { - const VimLFuncDef *const fdef = find_internal_func((const char *)fname); + const EvalFuncDef *const fdef = find_internal_func((const char *)fname); if (fdef == NULL) { return ERROR_UNKNOWN; } else if (fdef->base_arg == BASE_NONE) { @@ -9842,6 +9837,10 @@ static void f_stdpath(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_string = get_xdg_home(kXDGDataHome); } else if (strequal(p, "cache")) { rettv->vval.v_string = get_xdg_home(kXDGCacheHome); + } else if (strequal(p, "state")) { + rettv->vval.v_string = get_xdg_home(kXDGStateHome); + } else if (strequal(p, "log")) { + rettv->vval.v_string = get_xdg_home(kXDGStateHome); } else if (strequal(p, "config_dirs")) { get_xdg_var_list(kXDGConfigDirs, rettv); } else if (strequal(p, "data_dirs")) { diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h index c6a0cb959e..4ab4c8f800 100644 --- a/src/nvim/eval/funcs.h +++ b/src/nvim/eval/funcs.h @@ -9,19 +9,19 @@ typedef void (*FunPtr)(void); /// Prototype of C function that implements VimL function typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data); -/// Special flags for base_arg @see VimLFuncDef +/// Special flags for base_arg @see EvalFuncDef #define BASE_NONE 0 ///< Not a method (no base argument). #define BASE_LAST UINT8_MAX ///< Use the last argument as the method base. /// Structure holding VimL function definition -typedef struct fst { +typedef struct { char *name; ///< Name of the function. uint8_t min_argc; ///< Minimal number of arguments. uint8_t max_argc; ///< Maximal number of arguments. uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST. VimLFunc func; ///< Function implementation. FunPtr data; ///< Userdata for function implementation. -} VimLFuncDef; +} EvalFuncDef; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/funcs.h.generated.h" diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index a51f805984..d8dd3da9e6 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -175,6 +175,9 @@ enum { /// Arguments used for Ex commands. struct exarg { char *arg; ///< argument of the command + char **args; ///< starting position of command arguments + size_t *arglens; ///< length of command arguments + size_t argc; ///< number of command arguments char *nextcmd; ///< next command (NULL if none) char *cmd; ///< the name of the command (except for :make) char **cmdlinep; ///< pointer to pointer of allocated cmdline diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index fc66677537..2173494be9 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -41,7 +41,7 @@ #include "nvim/highlight_group.h" #include "nvim/if_cscope.h" #include "nvim/input.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/lua/executor.h" #include "nvim/main.h" #include "nvim/mark.h" @@ -1218,7 +1218,7 @@ static char *skip_colon_white(const char *p, bool skipleadingwhite) /// Set the addr type for command /// /// @param p pointer to character after command name in cmdline -static void set_cmd_addr_type(exarg_T *eap, char_u *p) +void set_cmd_addr_type(exarg_T *eap, char_u *p) { // ea.addr_type for user commands is set by find_ucmd if (IS_USER_CMDIDX(eap->cmdidx)) { @@ -1239,8 +1239,48 @@ static void set_cmd_addr_type(exarg_T *eap, char_u *p) } } +/// Get default range number for command based on its address type +linenr_T get_cmd_default_range(exarg_T *eap) +{ + switch (eap->addr_type) { + case ADDR_LINES: + case ADDR_OTHER: + // Default is the cursor line number. Avoid using an invalid + // line number though. + return MIN(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count); + break; + case ADDR_WINDOWS: + return CURRENT_WIN_NR; + break; + case ADDR_ARGUMENTS: + return MIN(curwin->w_arg_idx + 1, ARGCOUNT); + break; + case ADDR_LOADED_BUFFERS: + case ADDR_BUFFERS: + return curbuf->b_fnum; + break; + case ADDR_TABS: + return CURRENT_TAB_NR; + break; + case ADDR_TABS_RELATIVE: + case ADDR_UNSIGNED: + return 1; + break; + case ADDR_QUICKFIX: + return (linenr_T)qf_get_cur_idx(eap); + break; + case ADDR_QUICKFIX_VALID: + return qf_get_cur_valid_idx(eap); + break; + default: + return 0; + // Will give an error later if a range is found. + break; + } +} + /// Set default command range for -range=% based on the addr type of the command -static void set_cmd_default_range(exarg_T *eap) +void set_cmd_dflall_range(exarg_T *eap) { buf_T *buf; @@ -1320,6 +1360,25 @@ static void parse_register(exarg_T *eap) } } +// Change line1 and line2 of Ex command to use count +void set_cmd_count(exarg_T *eap, long count, bool validate) +{ + if (eap->addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3 + eap->line2 = count; + if (eap->addr_count == 0) { + eap->addr_count = 1; + } + } else { + eap->line1 = eap->line2; + eap->line2 += count - 1; + eap->addr_count++; + // Be vi compatible: no error message for out of range. + if (validate && eap->line2 > curbuf->b_ml.ml_line_count) { + eap->line2 = curbuf->b_ml.ml_line_count; + } + } +} + static int parse_count(exarg_T *eap, char **errormsg, bool validate) { // Check for a count. When accepting a EX_BUFNAME, don't use "123foo" as a @@ -1338,25 +1397,19 @@ static int parse_count(exarg_T *eap, char **errormsg, bool validate) } return FAIL; } - if (eap->addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3 - eap->line2 = n; - if (eap->addr_count == 0) { - eap->addr_count = 1; - } - } else { - eap->line1 = eap->line2; - eap->line2 += n - 1; - eap->addr_count++; - // Be vi compatible: no error message for out of range. - if (validate && eap->line2 > curbuf->b_ml.ml_line_count) { - eap->line2 = curbuf->b_ml.ml_line_count; - } - } + set_cmd_count(eap, n, validate); } return OK; } +/// Check if command is not implemented +bool is_cmd_ni(cmdidx_T cmdidx) +{ + return !IS_USER_CMDIDX(cmdidx) && (cmdnames[cmdidx].cmd_func == ex_ni + || cmdnames[cmdidx].cmd_func == ex_script_ni); +} + /// Parse command line and return information about the first command. /// /// @param cmdline Command line string @@ -1394,14 +1447,17 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er if (eap->save_msg_silent != -1) { cmdinfo->silent = !!msg_silent; msg_silent = eap->save_msg_silent; + eap->save_msg_silent = -1; } if (eap->did_esilent) { cmdinfo->emsg_silent = true; emsg_silent--; + eap->did_esilent = false; } if (eap->did_sandbox) { cmdinfo->sandbox = true; sandbox--; + eap->did_sandbox = false; } if (cmdmod.save_ei != NULL) { cmdinfo->noautocmd = true; @@ -1411,6 +1467,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er if (eap->verbose_save != -1) { cmdinfo->verbose = p_verbose; p_verbose = eap->verbose_save; + eap->verbose_save = -1; } else { cmdinfo->verbose = -1; } @@ -1424,7 +1481,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er if (*eap->cmd == '*') { eap->cmd = skipwhite(eap->cmd + 1); } - p = find_command(eap, NULL); + p = find_ex_command(eap, NULL); // Set command address type and parse command range set_cmd_addr_type(eap, (char_u *)p); @@ -1494,7 +1551,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er } // Set default range for command if required if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) { - set_cmd_default_range(eap); + set_cmd_dflall_range(eap); } // Parse register and count @@ -1519,6 +1576,148 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er return true; } +/// Execute an Ex command using parsed command line information. +/// Does not do any validation of the Ex command arguments. +/// +/// @param eap Ex-command arguments +/// @param cmdinfo Command parse information +void execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo) +{ +#define ERROR(msg) \ + do { \ + emsg(msg); \ + goto end; \ + } while (0) + + char *errormsg = NULL; + cmdmod_T save_cmdmod = cmdmod; + cmdmod = cmdinfo->cmdmod; + + // Apply command modifiers + if (cmdinfo->silent) { + eap->save_msg_silent = msg_silent; + msg_silent++; + } + if (cmdinfo->emsg_silent) { + eap->did_esilent = true; + emsg_silent++; + } + if (cmdinfo->sandbox) { + eap->did_sandbox = true; + sandbox++; + } + if (cmdinfo->noautocmd) { + cmdmod.save_ei = (char *)vim_strsave(p_ei); + set_string_option_direct("ei", -1, (char_u *)"all", OPT_FREE, SID_NONE); + } + if (cmdinfo->verbose != -1) { + eap->verbose_save = p_verbose; + p_verbose = cmdinfo->verbose; + } + + if (!MODIFIABLE(curbuf) && (eap->argt & EX_MODIFY) + // allow :put in terminals + && !(curbuf->terminal && eap->cmdidx == CMD_put)) { + ERROR(_(e_modifiable)); + } + if (text_locked() && !(eap->argt & EX_CMDWIN) + && !IS_USER_CMDIDX(eap->cmdidx)) { + ERROR(_(get_text_locked_msg())); + } + // Disallow editing another buffer when "curbuf->b_ro_locked" is set. + // Do allow ":checktime" (it is postponed). + // Do allow ":edit" (check for an argument later). + // Do allow ":file" with no arguments + if (!(eap->argt & EX_CMDWIN) + && eap->cmdidx != CMD_checktime + && eap->cmdidx != CMD_edit + && !(eap->cmdidx == CMD_file && *eap->arg == NUL) + && !IS_USER_CMDIDX(eap->cmdidx) + && curbuf_locked()) { + ERROR(_(e_cannot_edit_other_buf)); + } + + if (((eap->argt & EX_WHOLEFOLD) || eap->addr_count >= 2) && !global_busy + && eap->addr_type == ADDR_LINES) { + // Put the first line at the start of a closed fold, put the last line + // at the end of a closed fold. + (void)hasFolding(eap->line1, &eap->line1, NULL); + (void)hasFolding(eap->line2, NULL, &eap->line2); + } + + // If filename expansion is enabled, expand filenames + if (cmdinfo->magic.file) { + if (expand_filename(eap, (char_u **)eap->cmdlinep, &errormsg) == FAIL) { + ERROR(errormsg); + } + } + + // Accept buffer name. Cannot be used at the same time with a buffer + // number. Don't do this for a user command. + if ((eap->argt & EX_BUFNAME) && *eap->arg != NUL && eap->addr_count == 0 + && !IS_USER_CMDIDX(eap->cmdidx)) { + if (eap->args == NULL) { + // If argument positions are not specified, search the argument for the buffer name. + // :bdelete, :bwipeout and :bunload take several arguments, separated by spaces: + // find next space (skipping over escaped characters). + // The others take one argument: ignore trailing spaces. + char *p; + + if (eap->cmdidx == CMD_bdelete || eap->cmdidx == CMD_bwipeout + || eap->cmdidx == CMD_bunload) { + p = (char *)skiptowhite_esc((char_u *)eap->arg); + } else { + p = eap->arg + STRLEN(eap->arg); + while (p > eap->arg && ascii_iswhite(p[-1])) { + p--; + } + } + eap->line2 = buflist_findpat((char_u *)eap->arg, (char_u *)p, (eap->argt & EX_BUFUNL) != 0, + false, false); + eap->addr_count = 1; + eap->arg = skipwhite(p); + } else { + // If argument positions are specified, just use the first argument + eap->line2 = buflist_findpat((char_u *)eap->args[0], + (char_u *)(eap->args[0] + eap->arglens[0]), + (eap->argt & EX_BUFUNL) != 0, false, false); + eap->addr_count = 1; + // Shift each argument by 1 + if (eap->args != NULL) { + for (size_t i = 0; i < eap->argc - 1; i++) { + eap->args[i] = eap->args[i + 1]; + } + // Make the last argument point to the NUL terminator at the end of string + eap->args[eap->argc - 1] = eap->args[eap->argc - 1] + eap->arglens[eap->argc - 1]; + eap->argc -= 1; + } + eap->arg = eap->args[0]; + } + if (eap->line2 < 0) { // failed + goto end; + } + } + + // Execute the command + if (IS_USER_CMDIDX(eap->cmdidx)) { + // Execute a user-defined command. + do_ucmd(eap); + } else { + // Call the function to execute the command. + eap->errmsg = NULL; + (cmdnames[eap->cmdidx].cmd_func)(eap); + if (eap->errmsg != NULL) { + ERROR(_(eap->errmsg)); + } + } +end: + // Undo command modifiers + undo_cmdmod(eap, msg_scroll); + cmdmod = save_cmdmod; + +#undef ERROR +} + /// Execute one Ex command. /// /// If 'sourcing' is TRUE, the command will be included in the error message. @@ -1606,7 +1805,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter if (*ea.cmd == '*') { ea.cmd = skipwhite(ea.cmd + 1); } - p = find_command(&ea, NULL); + p = find_ex_command(&ea, NULL); // Count this line for profiling if skip is TRUE. if (do_profiling == PROF_YES @@ -1732,7 +1931,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter xfree(p); // If the autocommands did something and didn't cause an error, try // finding the command again. - p = (ret && !aborting()) ? find_command(&ea, NULL) : ea.cmd; + p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd; } if (p == NULL) { @@ -1759,10 +1958,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter } // set when Not Implemented - const int ni = !IS_USER_CMDIDX(ea.cmdidx) - && (cmdnames[ea.cmdidx].cmd_func == ex_ni - || cmdnames[ea.cmdidx].cmd_func == ex_script_ni); - + const int ni = is_cmd_ni(ea.cmdidx); // Forced commands. if (*p == '!' && ea.cmdidx != CMD_substitute @@ -1976,7 +2172,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter } if ((ea.argt & EX_DFLALL) && ea.addr_count == 0) { - set_cmd_default_range(&ea); + set_cmd_dflall_range(&ea); } // Parse register and count @@ -2544,6 +2740,7 @@ static void undo_cmdmod(const exarg_T *eap, int save_msg_scroll) } + /// Parse the address range, if any, in "eap". /// May set the last search pattern, unless "silent" is true. /// @@ -2557,47 +2754,7 @@ int parse_cmd_address(exarg_T *eap, char **errormsg, bool silent) // Repeat for all ',' or ';' separated addresses. for (;;) { eap->line1 = eap->line2; - switch (eap->addr_type) { - case ADDR_LINES: - case ADDR_OTHER: - // Default is the cursor line number. Avoid using an invalid - // line number though. - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - eap->line2 = curbuf->b_ml.ml_line_count; - } else { - eap->line2 = curwin->w_cursor.lnum; - } - break; - case ADDR_WINDOWS: - eap->line2 = CURRENT_WIN_NR; - break; - case ADDR_ARGUMENTS: - eap->line2 = curwin->w_arg_idx + 1; - if (eap->line2 > ARGCOUNT) { - eap->line2 = ARGCOUNT; - } - break; - case ADDR_LOADED_BUFFERS: - case ADDR_BUFFERS: - eap->line2 = curbuf->b_fnum; - break; - case ADDR_TABS: - eap->line2 = CURRENT_TAB_NR; - break; - case ADDR_TABS_RELATIVE: - case ADDR_UNSIGNED: - eap->line2 = 1; - break; - case ADDR_QUICKFIX: - eap->line2 = (linenr_T)qf_get_cur_idx(eap); - break; - case ADDR_QUICKFIX_VALID: - eap->line2 = qf_get_cur_valid_idx(eap); - break; - case ADDR_NONE: - // Will give an error later if a range is found. - break; - } + eap->line2 = get_cmd_default_range(eap); eap->cmd = skipwhite(eap->cmd); lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent, eap->addr_count == 0, address_count++); @@ -2772,7 +2929,7 @@ static void append_command(char *cmd) /// "full" is set to TRUE if the whole command name matched. /// /// @return NULL for an ambiguous user command. -static char *find_command(exarg_T *eap, int *full) +char *find_ex_command(exarg_T *eap, int *full) FUNC_ATTR_NONNULL_ARG(1) { int len; @@ -2859,7 +3016,7 @@ static char *find_command(exarg_T *eap, int *full) for (; (int)eap->cmdidx < CMD_SIZE; eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) { - if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd, + if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, eap->cmd, (size_t)len) == 0) { if (full != NULL && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) { @@ -3076,7 +3233,7 @@ int cmd_exists(const char *const name) ea.cmd = (char *)((*name == '2' || *name == '3') ? name + 1 : name); ea.cmdidx = (cmdidx_T)0; int full = false; - p = find_command(&ea, &full); + p = find_ex_command(&ea, &full); if (p == NULL) { return 3; } @@ -3108,7 +3265,7 @@ void f_fullcommand(typval_T *argvars, typval_T *rettv, FunPtr fptr) ea.cmd = (*name == '2' || *name == '3') ? name + 1 : name; ea.cmdidx = (cmdidx_T)0; - char *p = find_command(&ea, NULL); + char *p = find_ex_command(&ea, NULL); if (p == NULL || ea.cmdidx == CMD_SIZE) { return; } @@ -3431,7 +3588,7 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff) xp->xp_shell = TRUE; #endif // When still after the command name expand executables. - if ((char_u *)xp->xp_pattern == (char_u *)skipwhite(arg)) { + if (xp->xp_pattern == skipwhite(arg)) { xp->xp_context = EXPAND_SHELLCMD; } } @@ -4416,7 +4573,7 @@ static void ex_script_ni(exarg_T *eap) /// Check range in Ex command for validity. /// /// @return NULL when valid, error message when invalid. -static char *invalid_range(exarg_T *eap) +char *invalid_range(exarg_T *eap) { buf_T *buf; if (eap->line1 < 0 || eap->line2 < 0 || eap->line1 > eap->line2) { @@ -4535,7 +4692,7 @@ static char *skip_grep_pat(exarg_T *eap) /// For the ":make" and ":grep" commands insert the 'makeprg'/'grepprg' option /// in the command line, so that things like % get expanded. -static char *replace_makeprg(exarg_T *eap, char *p, char **cmdlinep) +char *replace_makeprg(exarg_T *eap, char *p, char **cmdlinep) { char *new_cmdline; char *program; @@ -4773,7 +4930,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp) return OK; } -/// Replace part of the command line, keeping eap->cmd, eap->arg and +/// Replace part of the command line, keeping eap->cmd, eap->arg, eap->args and /// eap->nextcmd correct. /// "src" points to the part that is to be replaced, of length "srclen". /// "repl" is the replacement string. @@ -4792,6 +4949,7 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch i += STRLEN(eap->nextcmd); // add space for next command } char *new_cmdline = xmalloc(i); + size_t offset = (size_t)(src - *cmdlinep); /* * Copy the stuff before the expanded part. @@ -4799,7 +4957,7 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch * Copy what came after the expanded part. * Copy the next commands, if there are any. */ - i = (size_t)(src - *cmdlinep); // length of part before match + i = offset; // length of part before match memmove(new_cmdline, *cmdlinep, i); memmove(new_cmdline + i, repl, len); @@ -4814,6 +4972,19 @@ static char *repl_cmdline(exarg_T *eap, char *src, size_t srclen, char *repl, ch } eap->cmd = new_cmdline + (eap->cmd - *cmdlinep); eap->arg = new_cmdline + (eap->arg - *cmdlinep); + + for (size_t j = 0; j < eap->argc; j++) { + if (offset >= (size_t)(eap->args[j] - *cmdlinep)) { + // If replaced text is after or in the same position as the argument, + // the argument's position relative to the beginning of the cmdline stays the same. + eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep); + } else { + // Otherwise, argument gets shifted alongside the replaced text. + // The amount of the shift is equal to the difference of the old and new string length. + eap->args[j] = new_cmdline + (eap->args[j] - *cmdlinep) + (len - srclen); + } + } + if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command) { eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep); } @@ -5077,7 +5248,9 @@ static int get_tabpage_arg(exarg_T *eap) tab_number = 0; } else { tab_number = (int)eap->line2; - if (!unaccept_arg0 && *skipwhite(*eap->cmdlinep) == '-') { + char *cmdp = eap->cmd; + while (--cmdp > *eap->cmdlinep && (*cmdp == ' ' || ascii_isdigit(*cmdp))) {} + if (!unaccept_arg0 && *cmdp == '-') { tab_number--; if (tab_number < unaccept_arg0) { eap->errmsg = e_invarg; @@ -6002,7 +6175,7 @@ bool uc_split_args_iter(const char *arg, size_t arglen, size_t *end, char *buf, } /// split and quote args for <f-args> -static char *uc_split_args(char *arg, size_t *lenp) +static char *uc_split_args(char *arg, char **args, size_t *arglens, size_t argc, size_t *lenp) { char *buf; char *p; @@ -6010,61 +6183,107 @@ static char *uc_split_args(char *arg, size_t *lenp) int len; // Precalculate length - p = arg; len = 2; // Initial and final quotes + if (args == NULL) { + p = arg; - while (*p) { - if (p[0] == '\\' && p[1] == '\\') { - len += 2; - p += 2; - } else if (p[0] == '\\' && ascii_iswhite(p[1])) { - len += 1; - p += 2; - } else if (*p == '\\' || *p == '"') { - len += 2; - p += 1; - } else if (ascii_iswhite(*p)) { - p = skipwhite(p); - if (*p == NUL) { - break; + while (*p) { + if (p[0] == '\\' && p[1] == '\\') { + len += 2; + p += 2; + } else if (p[0] == '\\' && ascii_iswhite(p[1])) { + len += 1; + p += 2; + } else if (*p == '\\' || *p == '"') { + len += 2; + p += 1; + } else if (ascii_iswhite(*p)) { + p = skipwhite(p); + if (*p == NUL) { + break; + } + len += 3; // "," + } else { + const int charlen = utfc_ptr2len(p); + + len += charlen; + p += charlen; } - len += 3; // "," - } else { - const int charlen = utfc_ptr2len(p); + } + } else { + for (size_t i = 0; i < argc; i++) { + p = args[i]; + const char *arg_end = args[i] + arglens[i]; + + while (p < arg_end) { + if (*p == '\\' || *p == '"') { + len += 2; + p += 1; + } else { + const int charlen = utfc_ptr2len(p); - len += charlen; - p += charlen; + len += charlen; + p += charlen; + } + } + + if (i != argc - 1) { + len += 3; // "," + } } } buf = xmalloc((size_t)len + 1); - p = arg; q = buf; *q++ = '"'; - while (*p) { - if (p[0] == '\\' && p[1] == '\\') { - *q++ = '\\'; - *q++ = '\\'; - p += 2; - } else if (p[0] == '\\' && ascii_iswhite(p[1])) { - *q++ = p[1]; - p += 2; - } else if (*p == '\\' || *p == '"') { - *q++ = '\\'; - *q++ = *p++; - } else if (ascii_iswhite(*p)) { - p = skipwhite(p); - if (*p == NUL) { - break; + + if (args == NULL) { + p = arg; + while (*p) { + if (p[0] == '\\' && p[1] == '\\') { + *q++ = '\\'; + *q++ = '\\'; + p += 2; + } else if (p[0] == '\\' && ascii_iswhite(p[1])) { + *q++ = p[1]; + p += 2; + } else if (*p == '\\' || *p == '"') { + *q++ = '\\'; + *q++ = *p++; + } else if (ascii_iswhite(*p)) { + p = skipwhite(p); + if (*p == NUL) { + break; + } + *q++ = '"'; + *q++ = ','; + *q++ = '"'; + } else { + mb_copy_char((const char_u **)&p, (char_u **)&q); + } + } + } else { + for (size_t i = 0; i < argc; i++) { + p = args[i]; + const char *arg_end = args[i] + arglens[i]; + + while (p < arg_end) { + if (*p == '\\' || *p == '"') { + *q++ = '\\'; + *q++ = *p++; + } else { + mb_copy_char((const char_u **)&p, (char_u **)&q); + } + } + if (i != argc - 1) { + *q++ = '"'; + *q++ = ','; + *q++ = '"'; } - *q++ = '"'; - *q++ = ','; - *q++ = '"'; - } else { - mb_copy_char((const char_u **)&p, (char_u **)&q); } } + *q++ = '"'; *q = 0; @@ -6201,7 +6420,7 @@ static size_t uc_check_code(char *code, size_t len, char *buf, ucmd_T *cmd, exar case 2: // Quote and split (<f-args>) // This is hard, so only do it once, and cache the result if (*split_buf == NULL) { - *split_buf = uc_split_args(eap->arg, split_len); + *split_buf = uc_split_args(eap->arg, eap->args, eap->arglens, eap->argc, split_len); } result = *split_len; @@ -9887,7 +10106,7 @@ bool cmd_can_preview(char *cmd) if (*ea.cmd == '*') { ea.cmd = skipwhite(ea.cmd + 1); } - char *end = find_command(&ea, NULL); + char *end = find_ex_command(&ea, NULL); switch (ea.cmdidx) { case CMD_substitute: @@ -10278,3 +10497,9 @@ void verify_command(char *cmd) msg("` `.:.`.,:iii;;;;;;;;iii;;;:` `.`` " " `nW"); } + +/// Get argt of command with id +uint32_t get_cmd_argt(cmdidx_T cmdidx) +{ + return cmdnames[(int)cmdidx].cmd_argt; +} diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index d4665ac031..a7e843704f 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -33,12 +33,13 @@ #include "nvim/func_attr.h" #include "nvim/garray.h" #include "nvim/getchar.h" +#include "nvim/globals.h" #include "nvim/highlight.h" #include "nvim/highlight_defs.h" #include "nvim/highlight_group.h" #include "nvim/if_cscope.h" #include "nvim/indent.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/lib/kvec.h" #include "nvim/log.h" #include "nvim/lua/executor.h" @@ -2522,7 +2523,7 @@ char *get_text_locked_msg(void) bool curbuf_locked(void) { if (curbuf->b_ro_locked > 0) { - emsg(_("E788: Not allowed to edit another buffer now")); + emsg(_(e_cannot_edit_other_buf)); return true; } return allbuf_locked(); diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index 045f778e4c..4554af5356 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -27,7 +27,7 @@ #include "nvim/fold.h" #include "nvim/getchar.h" #include "nvim/globals.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/move.h" #include "nvim/option.h" #include "nvim/os/input.h" diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index 945fa5099f..f094a04c07 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -1,9 +1,12 @@ local mpack = require('mpack') local nvimsrcdir = arg[1] -local autodir = arg[2] -local metadata_file = arg[3] -local funcs_file = arg[4] +local shared_file = arg[2] +local autodir = arg[3] +local metadata_file = arg[4] +local funcs_file = arg[5] + +_G.vim = loadfile(shared_file)() if nvimsrcdir == '--help' then print([[ @@ -20,7 +23,9 @@ package.path = nvimsrcdir .. '/?.lua;' .. package.path local funcsfname = autodir .. '/funcs.generated.h' -local gperfpipe = io.open(funcsfname .. '.gperf', 'wb') +local hashy = require'generators.hashy' + +local hashpipe = io.open(funcsfname, 'wb') local funcs = require('eval').funcs local metadata = mpack.unpack(io.open(metadata_file, 'rb'):read("*all")) @@ -38,21 +43,15 @@ local funcsdata = io.open(funcs_file, 'w') funcsdata:write(mpack.pack(funcs)) funcsdata:close() -gperfpipe:write([[ -%language=ANSI-C -%global-table -%readonly-tables -%define initializer-suffix ,0,0,BASE_NONE,NULL,NULL -%define word-array-name functions -%define hash-function-name hash_internal_func_gperf -%define lookup-function-name find_internal_func_gperf -%omit-struct-type -%struct-type -VimLFuncDef; -%% -]]) -for name, def in pairs(funcs) do +local names = vim.tbl_keys(funcs) + +local neworder, hashfun = hashy.hashy_hash("find_internal_func", names, function (idx) + return "functions["..idx.."].name" +end) +hashpipe:write("static const EvalFuncDef functions[] = {\n") +for _, name in ipairs(neworder) do + local def = funcs[name] local args = def.args or 0 if type(args) == 'number' then args = {args, args} @@ -62,7 +61,10 @@ for name, def in pairs(funcs) do local base = def.base or "BASE_NONE" local func = def.func or ('f_' .. name) local data = def.data or "NULL" - gperfpipe:write(('%s, %s, %s, %s, &%s, (FunPtr)%s\n') + hashpipe:write((' { "%s", %s, %s, %s, &%s, (FunPtr)%s },\n') :format(name, args[1], args[2], base, func, data)) end -gperfpipe:close() +hashpipe:write(' { NULL, 0, 0, BASE_NONE, NULL, NULL },\n') +hashpipe:write("};\n\n") +hashpipe:write(hashfun) +hashpipe:close() diff --git a/src/nvim/generators/hashy.lua b/src/nvim/generators/hashy.lua index fac24c810a..b10bafb9f9 100644 --- a/src/nvim/generators/hashy.lua +++ b/src/nvim/generators/hashy.lua @@ -77,7 +77,7 @@ function M.switcher(put, tab, maxlen, worst_buck_size) put "break;\n" end put " default: break;\n" - put " }\n " + put " }\n " else local startidx = #neworder table.insert(neworder, posbuck[keys[1]][1]) @@ -85,7 +85,7 @@ function M.switcher(put, tab, maxlen, worst_buck_size) put("low = "..startidx.."; ") if bucky then put("high = "..endidx.."; ") end end - put " break;\n" + put "break;\n" end end put " default: break;\n" @@ -105,17 +105,23 @@ function M.hashy_hash(name, strings, access) end local neworder = M.switcher(put, len_pos_buckets, maxlen, worst_buck_size) if worst_buck_size > 1 then - error [[ not implemented yet ]] -- TODO(bfredl) + put ([[ + for (int i = low; i < high; i++) { + if (!memcmp(str, ]]..access("i")..[[, len)) { + return i; + } + } + return -1; +]]) else - put [[ - if (low < 0) { + put ([[ + if (low < 0 || memcmp(str, ]]..access("low")..[[, len)) { return -1; } - ]] - put("if(memcmp(str, "..access("low")..", len)) {\n return -1;\n }\n") - put " return low;\n" - put "}\n\n" + return low; +]]) end + put "}\n\n" return neworder, table.concat(stats) end diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index c0a5a14f7b..df45de2abf 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -31,7 +31,7 @@ #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/input.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/lua/executor.h" #include "nvim/main.h" #include "nvim/mbyte.h" diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ef8ff11bf8..1a1f9bd866 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -997,6 +997,7 @@ EXTERN char e_listarg[] INIT(= N_("E686: Argument of %s must be a List")); EXTERN char e_unsupportedoption[] INIT(= N_("E519: Option not supported")); EXTERN char e_fnametoolong[] INIT(= N_("E856: Filename too long")); EXTERN char e_float_as_string[] INIT(= N_("E806: using Float as a String")); +EXTERN char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); EXTERN char e_autocmd_err[] INIT(= N_("E5500: autocmd has thrown an exception: %s")); EXTERN char e_cmdmap_err[] INIT(= N_("E5520: <Cmd> mapping must end with <CR>")); diff --git a/src/nvim/keymap.c b/src/nvim/keycodes.c index b184b42354..676ddcf8d4 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keycodes.c @@ -9,7 +9,7 @@ #include "nvim/charset.h" #include "nvim/edit.h" #include "nvim/eval.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/mouse.h" @@ -17,12 +17,10 @@ #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "keymap.c.generated.h" +# include "keycodes.c.generated.h" #endif -/* - * Some useful tables. - */ +// Some useful tables. static const struct modmasktable { uint16_t mod_mask; ///< Bit-mask for particular key modifier. @@ -43,10 +41,9 @@ static const struct modmasktable { // NOTE: when adding an entry, update MAX_KEY_NAME_LEN! }; -/* - * Shifted key terminal codes and their unshifted equivalent. - * Don't add mouse codes here, they are handled separately! - */ +// Shifted key terminal codes and their unshifted equivalent. +// Don't add mouse codes here, they are handled separately! + #define MOD_KEYS_ENTRY_SIZE 5 static char_u modifier_keys_table[] = @@ -461,10 +458,7 @@ int handle_x_keys(const int key) return key; } -/* - * Return a string which contains the name of the given key when the given - * modifiers are down. - */ +/// @return a string which contains the name of the given key when the given modifiers are down. char_u *get_special_key_name(int c, int modifiers) { static char_u string[MAX_KEY_NAME_LEN + 1]; @@ -481,10 +475,8 @@ char_u *get_special_key_name(int c, int modifiers) c = KEY2TERMCAP1(c); } - /* - * Translate shifted special keys into unshifted keys and set modifier. - * Same for CTRL and ALT modifiers. - */ + // Translate shifted special keys into unshifted keys and set modifier. + // Same for CTRL and ALT modifiers. if (IS_SPECIAL(c)) { for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE) { if (KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1] @@ -500,10 +492,8 @@ char_u *get_special_key_name(int c, int modifiers) // try to find the key in the special key table table_idx = find_special_key_in_table(c); - /* - * When not a known special key, and not a printable character, try to - * extract modifiers. - */ + // When not a known special key, and not a printable character, try to + // extract modifiers. if (c > 0 && utf_char2len(c) == 1) { if (table_idx < 0 @@ -798,10 +788,8 @@ static int extract_modifiers(int key, int *modp, const bool simplify, bool *cons return key; } -/* - * Try to find key "c" in the special key table. - * Return the index when found, -1 when not found. - */ +/// Try to find key "c" in the special key table. +/// @return the index when found, -1 when not found. int find_special_key_in_table(int c) { int i; @@ -844,10 +832,8 @@ int get_special_key_code(const char_u *name) return 0; } -/* - * Look up the given mouse code to return the relevant information in the other - * arguments. Return which button is down or was released. - */ +/// Look up the given mouse code to return the relevant information in the other arguments. +/// @return which button is down or was released. int get_mouse_button(int code, bool *is_click, bool *is_drag) { int i; @@ -1009,7 +995,7 @@ char *replace_termcodes(const char *const from, const size_t from_len, char **co } else { result[dlen++] = *src; } - ++src; + src++; } } result[dlen] = NUL; diff --git a/src/nvim/keymap.h b/src/nvim/keycodes.h index 9febd472f9..631a9f68d3 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keycodes.h @@ -1,13 +1,11 @@ -#ifndef NVIM_KEYMAP_H -#define NVIM_KEYMAP_H +#ifndef NVIM_KEYCODES_H +#define NVIM_KEYCODES_H #include "nvim/strings.h" -/* - * Keycode definitions for special keys. - * - * Any special key code sequences are replaced by these codes. - */ +// Keycode definitions for special keys. +// +// Any special key code sequences are replaced by these codes. // // For MS-DOS some keys produce codes larger than 0xff. They are split into two @@ -15,66 +13,49 @@ // #define K_NUL (0xce) // for MS-DOS: special key follows -/* - * K_SPECIAL is the first byte of a special key code and is always followed by - * two bytes. - * The second byte can have any value. ASCII is used for normal termcap - * entries, 0x80 and higher for special keys, see below. - * The third byte is guaranteed to be between 0x02 and 0x7f. - */ - +/// K_SPECIAL is the first byte of a special key code and is always followed by +/// two bytes. +/// The second byte can have any value. ASCII is used for normal termcap +/// entries, 0x80 and higher for special keys, see below. +/// The third byte is guaranteed to be between 0x02 and 0x7f. #define K_SPECIAL (0x80) -/* - * Positive characters are "normal" characters. - * Negative characters are special key codes. Only characters below -0x200 - * are used to so that the absolute value can't be mistaken for a single-byte - * character. - */ +/// Positive characters are "normal" characters. +/// Negative characters are special key codes. Only characters below -0x200 +/// are used to so that the absolute value can't be mistaken for a single-byte +/// character. #define IS_SPECIAL(c) ((c) < 0) -/* - * Characters 0x0100 - 0x01ff have a special meaning for abbreviations. - * Multi-byte characters also have ABBR_OFF added, thus are above 0x0200. - */ +/// Characters 0x0100 - 0x01ff have a special meaning for abbreviations. +/// Multi-byte characters also have ABBR_OFF added, thus are above 0x0200. #define ABBR_OFF 0x100 -/* - * NUL cannot be in the input string, therefore it is replaced by - * K_SPECIAL KS_ZERO KE_FILLER - */ +/// NUL cannot be in the input string, therefore it is replaced by +/// K_SPECIAL KS_ZERO KE_FILLER #define KS_ZERO 255 -/* - * K_SPECIAL cannot be in the input string, therefore it is replaced by - * K_SPECIAL KS_SPECIAL KE_FILLER - */ +/// K_SPECIAL cannot be in the input string, therefore it is replaced by +/// K_SPECIAL KS_SPECIAL KE_FILLER #define KS_SPECIAL 254 -/* - * KS_EXTRA is used for keys that have no termcap name - * K_SPECIAL KS_EXTRA KE_xxx - */ +/// KS_EXTRA is used for keys that have no termcap name +/// K_SPECIAL KS_EXTRA KE_xxx #define KS_EXTRA 253 -/* - * KS_MODIFIER is used when a modifier is given for a (special) key - * K_SPECIAL KS_MODIFIER bitmask - */ +/// KS_MODIFIER is used when a modifier is given for a (special) key +/// K_SPECIAL KS_MODIFIER bitmask #define KS_MODIFIER 252 -/* - * These are used for the GUI - * K_SPECIAL KS_xxx KE_FILLER - */ +// These are used for the GUI +// K_SPECIAL KS_xxx KE_FILLER + #define KS_MOUSE 251 #define KS_MENU 250 #define KS_VER_SCROLLBAR 249 #define KS_HOR_SCROLLBAR 248 -/* - * Used for switching Select mode back on after a mapping or menu. - */ +// Used for switching Select mode back on after a mapping or menu. + #define KS_SELECT 245 #define K_SELECT_STRING (char_u *)"\200\365X" @@ -87,30 +68,24 @@ // Used for menu in a tab pages line. #define KS_TABMENU 239 -/* - * Filler used after KS_SPECIAL and others - */ +/// Filler used after KS_SPECIAL and others #define KE_FILLER ('X') -/* - * translation of three byte code "K_SPECIAL a b" into int "K_xxx" and back - */ +// translation of three byte code "K_SPECIAL a b" into int "K_xxx" and back + #define TERMCAP2KEY(a, b) (-((a) + ((int)(b) << 8))) #define KEY2TERMCAP0(x) ((-(x)) & 0xff) #define KEY2TERMCAP1(x) (((unsigned)(-(x)) >> 8) & 0xff) -/* - * get second or third byte when translating special key code into three bytes - */ +// get second or third byte when translating special key code into three bytes + #define K_SECOND(c) ((c) == K_SPECIAL ? KS_SPECIAL : (c) == \ NUL ? KS_ZERO : KEY2TERMCAP0(c)) #define K_THIRD(c) (((c) == K_SPECIAL || (c) == \ NUL) ? KE_FILLER : KEY2TERMCAP1(c)) -/* - * get single int code from second byte after K_SPECIAL - */ +/// get single int code from second byte after K_SPECIAL #define TO_SPECIAL(a, b) ((a) == KS_SPECIAL ? K_SPECIAL : (a) == \ KS_ZERO ? K_ZERO : TERMCAP2KEY(a, b)) @@ -247,9 +222,8 @@ enum key_extra { KE_COMMAND = 104, // <Cmd> special key }; -/* - * the three byte codes are replaced with the following int when using vgetc() - */ +// the three byte codes are replaced with the following int when using vgetc() + #define K_ZERO TERMCAP2KEY(KS_ZERO, KE_FILLER) #define K_UP TERMCAP2KEY('k', 'u') @@ -430,10 +404,9 @@ enum key_extra { #define K_TABLINE TERMCAP2KEY(KS_TABLINE, KE_FILLER) #define K_TABMENU TERMCAP2KEY(KS_TABMENU, KE_FILLER) -/* - * Symbols for pseudo keys which are translated from the real key symbols - * above. - */ +// Symbols for pseudo keys which are translated from the real key symbols +// above. + #define K_LEFTMOUSE TERMCAP2KEY(KS_EXTRA, KE_LEFTMOUSE) #define K_LEFTMOUSE_NM TERMCAP2KEY(KS_EXTRA, KE_LEFTMOUSE_NM) #define K_LEFTDRAG TERMCAP2KEY(KS_EXTRA, KE_LEFTDRAG) @@ -486,11 +459,8 @@ enum key_extra { #define MOD_MASK_MULTI_CLICK (MOD_MASK_2CLICK|MOD_MASK_3CLICK| \ MOD_MASK_4CLICK) -/* - * The length of the longest special key name, including modifiers. - * Current longest is <M-C-S-T-D-A-4-ScrollWheelRight> (length includes '<' and - * '>'). - */ +/// The length of the longest special key name, including modifiers. +/// Current longest is <M-C-S-T-D-A-4-ScrollWheelRight> (length includes '<' and '>'). #define MAX_KEY_NAME_LEN 32 // Maximum length of a special key event as tokens. This includes modifiers. @@ -524,6 +494,6 @@ enum { }; #ifdef INCLUDE_GENERATED_DECLARATIONS -# include "keymap.h.generated.h" +# include "keycodes.h.generated.h" #endif -#endif // NVIM_KEYMAP_H +#endif // NVIM_KEYCODES_H diff --git a/src/nvim/log.c b/src/nvim/log.c index 7d50ecf69e..815d53b570 100644 --- a/src/nvim/log.c +++ b/src/nvim/log.c @@ -51,7 +51,7 @@ static bool log_try_create(char *fname) /// Initializes path to log file. Sets $NVIM_LOG_FILE if empty. /// -/// Tries $NVIM_LOG_FILE, or falls back to $XDG_CACHE_HOME/nvim/log. Path to log +/// Tries $NVIM_LOG_FILE, or falls back to $XDG_STATE_HOME/nvim/log. Path to log /// file is cached, so only the first call has effect, unless first call was not /// successful. Failed initialization indicates either a bug in expand_env() /// or both $NVIM_LOG_FILE and $HOME environment variables are undefined. @@ -69,16 +69,16 @@ static bool log_path_init(void) || log_file_path[0] == '\0' || os_isdir((char_u *)log_file_path) || !log_try_create(log_file_path)) { - // Make kXDGCacheHome if it does not exist. - char *cachehome = get_xdg_home(kXDGCacheHome); + // Make kXDGStateHome if it does not exist. + char *loghome = get_xdg_home(kXDGStateHome); char *failed_dir = NULL; bool log_dir_failure = false; - if (!os_isdir((char_u *)cachehome)) { - log_dir_failure = (os_mkdir_recurse(cachehome, 0700, &failed_dir) != 0); + if (!os_isdir((char_u *)loghome)) { + log_dir_failure = (os_mkdir_recurse(loghome, 0700, &failed_dir) != 0); } - XFREE_CLEAR(cachehome); + XFREE_CLEAR(loghome); // Invalid $NVIM_LOG_FILE or failed to expand; fall back to default. - char *defaultpath = stdpaths_user_cache_subpath("log"); + char *defaultpath = stdpaths_user_state_subpath("log", 0, true); size_t len = xstrlcpy(log_file_path, defaultpath, size); xfree(defaultpath); // Fall back to .nvimlog diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 29ed40af03..9758cee0a5 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -1863,8 +1863,8 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) if (cmd->uc_argt & EX_NOSPC) { // Commands where nargs = 1 or "?" fargs is the same as args lua_rawseti(lstate, -2, 1); - } else { - // Commands with more than one possible argument we split + } else if (eap->args == NULL) { + // For commands with more than one possible argument, split if argument list isn't available. lua_pop(lstate, 1); // Pop the reference of opts.args size_t length = STRLEN(eap->arg); size_t end = 0; @@ -1881,6 +1881,13 @@ void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap) } } xfree(buf); + } else { + // If argument list is available, just use it. + lua_pop(lstate, 1); + for (size_t i = 0; i < eap->argc; i++) { + lua_pushlstring(lstate, eap->args[i], eap->arglens[i]); + lua_rawseti(lstate, -2, (int)i + 1); + } } lua_setfield(lstate, -2, "fargs"); diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 4ea9329a71..c7408c6260 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1992,6 +1992,31 @@ theend: convert_setup(&vimconv, NULL, NULL); } +/// @return true if string "s" is a valid utf-8 string. +/// When "end" is NULL stop at the first NUL. +/// When "end" is positive stop there. +bool utf_valid_string(const char_u *s, const char_u *end) +{ + const char_u *p = s; + + while (end == NULL ? *p != NUL : p < end) { + int l = utf8len_tab_zero[*p]; + if (l == 0) { + return false; // invalid lead byte + } + if (end != NULL && p + l > end) { + return false; // incomplete byte sequence + } + p++; + while (--l > 0) { + if ((*p++ & 0xc0) != 0x80) { + return false; // invalid trail byte + } + } + } + return true; +} + /* * If the cursor moves on an trail byte, set the cursor on the lead byte. * Thus it moves left if necessary. diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 14084df4d4..7b254f1b62 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -18,7 +18,7 @@ #include "nvim/ex_docmd.h" #include "nvim/garray.h" #include "nvim/getchar.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/memory.h" #include "nvim/menu.h" #include "nvim/message.h" diff --git a/src/nvim/message.c b/src/nvim/message.c index 29473ac2b6..52eafe6e26 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -24,7 +24,7 @@ #include "nvim/getchar.h" #include "nvim/highlight.h" #include "nvim/input.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/main.h" #include "nvim/mbyte.h" #include "nvim/memory.h" diff --git a/src/nvim/normal.c b/src/nvim/normal.c index c54cc3ed09..a983ff4436 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -33,7 +33,7 @@ #include "nvim/getchar.h" #include "nvim/globals.h" #include "nvim/indent.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/log.h" #include "nvim/main.h" #include "nvim/mark.h" diff --git a/src/nvim/option.c b/src/nvim/option.c index 66d9d2843c..b1e9226937 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -49,7 +49,7 @@ #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/indent_c.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/macros.h" #include "nvim/mbyte.h" #include "nvim/memfile.h" @@ -491,17 +491,17 @@ void set_init_1(bool clean_arg) #endif false); - char *backupdir = stdpaths_user_data_subpath("backup", 2, true); + char *backupdir = stdpaths_user_state_subpath("backup", 2, true); const size_t backupdir_len = strlen(backupdir); backupdir = xrealloc(backupdir, backupdir_len + 3); memmove(backupdir + 2, backupdir, backupdir_len + 1); memmove(backupdir, ".,", 2); set_string_default("backupdir", backupdir, true); - set_string_default("viewdir", stdpaths_user_data_subpath("view", 2, true), + set_string_default("viewdir", stdpaths_user_state_subpath("view", 2, true), true); - set_string_default("directory", stdpaths_user_data_subpath("swap", 2, true), + set_string_default("directory", stdpaths_user_state_subpath("swap", 2, true), true); - set_string_default("undodir", stdpaths_user_data_subpath("undo", 2, true), + set_string_default("undodir", stdpaths_user_state_subpath("undo", 2, true), true); // Set default for &runtimepath. All necessary expansions are performed in // this function. diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 64e5a7f229..c99d2869da 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -13,7 +13,7 @@ #include "nvim/ex_cmds2.h" #include "nvim/fileio.h" #include "nvim/getchar.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/main.h" #include "nvim/mbyte.h" #include "nvim/memory.h" diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index 5b824d23f4..5d6ffc1db1 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -14,6 +14,7 @@ static const char *xdg_env_vars[] = { [kXDGConfigHome] = "XDG_CONFIG_HOME", [kXDGDataHome] = "XDG_DATA_HOME", [kXDGCacheHome] = "XDG_CACHE_HOME", + [kXDGStateHome] = "XDG_STATE_HOME", [kXDGRuntimeDir] = "XDG_RUNTIME_DIR", [kXDGConfigDirs] = "XDG_CONFIG_DIRS", [kXDGDataDirs] = "XDG_DATA_DIRS", @@ -24,6 +25,7 @@ static const char *const xdg_defaults_env_vars[] = { [kXDGConfigHome] = "LOCALAPPDATA", [kXDGDataHome] = "LOCALAPPDATA", [kXDGCacheHome] = "TEMP", + [kXDGStateHome] = "LOCALAPPDATA", [kXDGRuntimeDir] = NULL, [kXDGConfigDirs] = NULL, [kXDGDataDirs] = NULL, @@ -38,6 +40,7 @@ static const char *const xdg_defaults[] = { [kXDGConfigHome] = "~\\AppData\\Local", [kXDGDataHome] = "~\\AppData\\Local", [kXDGCacheHome] = "~\\AppData\\Local\\Temp", + [kXDGStateHome] = "~\\AppData\\Local", [kXDGRuntimeDir] = NULL, [kXDGConfigDirs] = NULL, [kXDGDataDirs] = NULL, @@ -45,6 +48,7 @@ static const char *const xdg_defaults[] = { [kXDGConfigHome] = "~/.config", [kXDGDataHome] = "~/.local/share", [kXDGCacheHome] = "~/.cache", + [kXDGStateHome] = "~/.local/state", [kXDGRuntimeDir] = NULL, [kXDGConfigDirs] = "/etc/xdg/", [kXDGDataDirs] = "/usr/local/share/:/usr/share/", @@ -133,15 +137,26 @@ char *stdpaths_user_conf_subpath(const char *fname) /// Return subpath of $XDG_DATA_HOME /// /// @param[in] fname New component of the path. +/// +/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}` +char *stdpaths_user_data_subpath(const char *fname) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +{ + return concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true); +} + +/// Return subpath of $XDG_STATE_HOME +/// +/// @param[in] fname New component of the path. /// @param[in] trailing_pathseps Amount of trailing path separators to add. /// @param[in] escape_commas If true, all commas will be escaped. /// -/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`. -char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathseps, - const bool escape_commas) +/// @return [allocated] `$XDG_STATE_HOME/nvim/{fname}`. +char *stdpaths_user_state_subpath(const char *fname, const size_t trailing_pathseps, + const bool escape_commas) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - char *ret = concat_fnames_realloc(get_xdg_home(kXDGDataHome), fname, true); + char *ret = concat_fnames_realloc(get_xdg_home(kXDGStateHome), fname, true); const size_t len = strlen(ret); const size_t numcommas = (escape_commas ? memcnt(ret, ',', len) : 0); if (numcommas || trailing_pathseps) { diff --git a/src/nvim/os/stdpaths_defs.h b/src/nvim/os/stdpaths_defs.h index 44c30df373..f94c511fe7 100644 --- a/src/nvim/os/stdpaths_defs.h +++ b/src/nvim/os/stdpaths_defs.h @@ -7,6 +7,7 @@ typedef enum { kXDGConfigHome, ///< XDG_CONFIG_HOME kXDGDataHome, ///< XDG_DATA_HOME kXDGCacheHome, ///< XDG_CACHE_HOME + kXDGStateHome, ///< XDG_STATE_HOME kXDGRuntimeDir, ///< XDG_RUNTIME_DIR kXDGConfigDirs, ///< XDG_CONFIG_DIRS kXDGDataDirs, ///< XDG_DATA_DIRS diff --git a/src/nvim/search.c b/src/nvim/search.c index bee17e861a..9143632c64 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -5160,7 +5160,7 @@ static void fuzzy_match_in_list(list_T *const l, char_u *const str, const bool m int j = 0; const char_u *p = str; while (*p != NUL) { - if (!ascii_iswhite(utf_ptr2char((char *)p))) { + if (!ascii_iswhite(utf_ptr2char((char *)p)) || matchseq) { tv_list_append_number(items[match_count].lmatchpos, matches[j]); j++; } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index a3d88a4963..abb6c68474 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1447,7 +1447,7 @@ static const char *shada_get_default_file(void) FUNC_ATTR_WARN_UNUSED_RESULT { if (default_shada_file == NULL) { - char *shada_dir = stdpaths_user_data_subpath("shada", 0, false); + char *shada_dir = stdpaths_user_state_subpath("shada", 0, false); default_shada_file = concat_fnames_realloc(shada_dir, "main.shada", true); } return default_shada_file; diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index f099d1b34e..6f0bd04d39 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -302,6 +302,7 @@ #define CF_UPPER 0x02 static char *e_spell_trunc = N_("E758: Truncated spell file"); +static char *e_illegal_character_in_word = N_("E1280: Illegal character in word"); static char *e_afftrailing = N_("Trailing text in %s line %d: %s"); static char *e_affname = N_("Affix name too long in %s line %d: %s"); static char *msg_compressing = N_("Compressing word tree..."); @@ -3927,6 +3928,11 @@ static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, co char_u foldword[MAXWLEN]; int res = OK; + // Avoid adding illegal bytes to the word tree. + if (!utf_valid_string(word, NULL)) { + return FAIL; + } + (void)spell_casefold(curwin, word, len, foldword, MAXWLEN); for (const char_u *p = pfxlist; res == OK; p++) { if (!need_affix || (p != NULL && *p != NUL)) { @@ -5525,6 +5531,11 @@ void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo int i; char_u *spf; + if (!utf_valid_string(word, NULL)) { + emsg(_(e_illegal_character_in_word)); + return; + } + if (idx == 0) { // use internal wordlist if (int_wordlist == NULL) { int_wordlist = vim_tempname(); diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index db0e6c8762..d82e337aa6 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -27,7 +27,7 @@ #include "nvim/highlight.h" #include "nvim/highlight_group.h" #include "nvim/indent_c.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/lua/executor.h" #include "nvim/macros.h" #include "nvim/mbyte.h" diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index f7d33de4fe..2d3102707c 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -56,7 +56,7 @@ #include "nvim/getchar.h" #include "nvim/highlight.h" #include "nvim/highlight_group.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/log.h" #include "nvim/macros.h" #include "nvim/main.h" @@ -404,7 +404,7 @@ void terminal_enter(void) // Disable these options in terminal-mode. They are nonsense because cursor is // placed at end of buffer to "follow" output. #11072 - win_T *save_curwin = curwin; + handle_T save_curwin = curwin->handle; bool save_w_p_cul = curwin->w_p_cul; char_u *save_w_p_culopt = NULL; char_u save_w_p_culopt_flags = curwin->w_p_culopt_flags; @@ -442,7 +442,7 @@ void terminal_enter(void) RedrawingDisabled = s->save_rd; apply_autocmds(EVENT_TERMLEAVE, NULL, NULL, false, curbuf); - if (save_curwin == curwin) { // save_curwin may be invalid (window closed)! + if (save_curwin == curwin->handle) { // Else: window was closed. curwin->w_p_cul = save_w_p_cul; if (save_w_p_culopt) { xfree(curwin->w_p_culopt); diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim index a31cdbb49a..9eb768f124 100644 --- a/src/nvim/testdir/test_buffer.vim +++ b/src/nvim/testdir/test_buffer.vim @@ -61,4 +61,15 @@ func Test_buffer_scheme() set shellslash& endfunc +" this was using a NULL pointer after failing to use the pattern +func Test_buf_pattern_invalid() + vsplit 0000000 + silent! buf [0--]\&\zs*\zs*e + bwipe! + + vsplit 00000000000000000000000000 + silent! buf [0--]\&\zs*\zs*e + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_matchfuzzy.vim b/src/nvim/testdir/test_matchfuzzy.vim index d53f8b0f4d..533aec8d9a 100644 --- a/src/nvim/testdir/test_matchfuzzy.vim +++ b/src/nvim/testdir/test_matchfuzzy.vim @@ -135,6 +135,9 @@ func Test_matchfuzzypos() " match multiple words (separated by space) call assert_equal([['foo bar baz'], [[8, 9, 10, 0, 1, 2]], [369]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo')) + call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo', {'matchseq': 1})) + call assert_equal([['foo bar baz'], [[0, 1, 2, 8, 9, 10]], [369]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz')) + call assert_equal([['foo bar baz'], [[0, 1, 2, 3, 4, 5, 10]], [326]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz', {'matchseq': 1})) call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('one two')) call assert_equal([[], [], []], ['foo bar']->matchfuzzypos(" \t ")) call assert_equal([['grace'], [[1, 2, 3, 4, 2, 3, 4, 0, 1, 2, 3, 4]], [657]], ['grace']->matchfuzzypos('race ace grace')) diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index 56ed97cdd9..ce21b8bdc9 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -776,14 +776,6 @@ func Test_spell_screendump() call delete('XtestSpell') endfunc -func Test_spell_single_word() - new - silent! norm 0R00 - spell! ß - silent 0norm 0r$ Dvz= - bwipe! -endfunc - let g:test_data_aff1 = [ \"SET ISO8859-1", \"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ", diff --git a/src/nvim/testdir/test_spell_utf8.vim b/src/nvim/testdir/test_spell_utf8.vim index 3d159f3352..1d323df67e 100644 --- a/src/nvim/testdir/test_spell_utf8.vim +++ b/src/nvim/testdir/test_spell_utf8.vim @@ -768,4 +768,10 @@ func Test_spellfile_value() set spellfile=Xdir/Xtest.utf-8.add,Xtest_other.add endfunc +" Invalid bytes may cause trouble when creating the word list. +func Test_check_for_valid_word() + call assert_fails("spellgood! 0\xac", 'E1280:') +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim index 30e00e7ad4..848860649e 100644 --- a/src/nvim/testdir/test_undo.vim +++ b/src/nvim/testdir/test_undo.vim @@ -733,4 +733,21 @@ func Test_undofile_cryptmethod_blowfish2() set undofile& undolevels& cryptmethod& endfunc +func Test_undo_mark() + new + " The undo is applied to the only line. + call setline(1, 'hello') + call feedkeys("ggyiw$p", 'xt') + undo + call assert_equal([0, 1, 1, 0], getpos("'[")) + call assert_equal([0, 1, 1, 0], getpos("']")) + " The undo removes the last line. + call feedkeys("Goaaaa\<Esc>", 'xt') + call feedkeys("obbbb\<Esc>", 'xt') + undo + call assert_equal([0, 2, 1, 0], getpos("'[")) + call assert_equal([0, 2, 1, 0], getpos("']")) + bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/undo.c b/src/nvim/undo.c index d2dc333855..529eef19a3 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2418,10 +2418,11 @@ static void u_undoredo(int undo, bool do_buf_event) changed_lines(top + 1, 0, bot, newsize - oldsize, do_buf_event); - // set '[ and '] mark + // Set the '[ mark. if (top + 1 < curbuf->b_op_start.lnum) { curbuf->b_op_start.lnum = top + 1; } + // Set the '] mark. if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) { curbuf->b_op_end.lnum = top + 1; } else if (top + newsize > curbuf->b_op_end.lnum) { @@ -2442,6 +2443,14 @@ static void u_undoredo(int undo, bool do_buf_event) newlist = uep; } + // Ensure the '[ and '] marks are within bounds. + if (curbuf->b_op_start.lnum > curbuf->b_ml.ml_line_count) { + curbuf->b_op_start.lnum = curbuf->b_ml.ml_line_count; + } + if (curbuf->b_op_end.lnum > curbuf->b_ml.ml_line_count) { + curbuf->b_op_end.lnum = curbuf->b_ml.ml_line_count; + } + // Adjust Extmarks ExtmarkUndoObject undo_info; if (undo) { diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 4e269bc9d4..1c05387da3 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -31,7 +31,7 @@ enum { NUMBUFLEN = 65, }; #define ROOT_UID 0 #include "nvim/gettext.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/macros.h" // special attribute addition: Put message in history diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d68f299277..f39aa2f20b 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1,5 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') +local lfs = require('lfs') local fmt = string.format local assert_alive = helpers.assert_alive @@ -25,6 +26,7 @@ local tmpname = helpers.tmpname local write_file = helpers.write_file local exec_lua = helpers.exec_lua local exc_exec = helpers.exc_exec +local insert = helpers.insert local pcall_err = helpers.pcall_err local format_string = helpers.format_string @@ -3473,4 +3475,149 @@ describe('API', function() pcall_err(meths.parse_cmd, '4,6Fubar', {})) end) end) + describe('nvim_cmd', function() + it('works', function () + meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) + eq(true, meths.get_option_value("cursorline", {})) + end) + it('captures output', function() + eq("foo", meths.cmd({ cmd = "echo", args = { '"foo"' } }, { output = true })) + end) + it('sets correct script context', function() + meths.cmd({ cmd = "set", args = { "cursorline" } }, {}) + local str = meths.exec([[verbose set cursorline?]], true) + neq(nil, str:find("cursorline\n\tLast set from API client %(channel id %d+%)")) + end) + it('works with range', function() + insert [[ + line1 + line2 + line3 + line4 + you didn't expect this + line5 + line6 + ]] + meths.cmd({ cmd = "del", range = {2, 4} }, {}) + expect [[ + line1 + you didn't expect this + line5 + line6 + ]] + end) + it('works with count', function() + insert [[ + line1 + line2 + line3 + line4 + you didn't expect this + line5 + line6 + ]] + meths.cmd({ cmd = "del", range = { 2 }, count = 4 }, {}) + expect [[ + line1 + line5 + line6 + ]] + end) + it('works with register', function() + insert [[ + line1 + line2 + line3 + line4 + you didn't expect this + line5 + line6 + ]] + meths.cmd({ cmd = "del", range = { 2, 4 }, reg = 'a' }, {}) + meths.exec("1put a", false) + expect [[ + line1 + line2 + line3 + line4 + you didn't expect this + line5 + line6 + ]] + end) + it('works with bang', function () + meths.create_user_command("Foo", 'echo "<bang>"', { bang = true }) + eq("!", meths.cmd({ cmd = "Foo", bang = true }, { output = true })) + eq("", meths.cmd({ cmd = "Foo", bang = false }, { output = true })) + end) + it('works with modifiers', function() + meths.create_user_command("Foo", 'set verbose', {}) + eq(" verbose=1", meths.cmd({ cmd = "Foo", mods = { verbose = 1 } }, { output = true })) + eq(0, meths.get_option_value("verbose", {})) + end) + it('works with magic.file', function() + exec_lua([[ + vim.api.nvim_create_user_command("Foo", function(opts) + vim.api.nvim_echo({{ opts.fargs[1] }}, false, {}) + end, { nargs = 1 }) + ]]) + eq(lfs.currentdir(), + meths.cmd({ cmd = "Foo", args = { '%:p:h' }, magic = { file = true } }, + { output = true })) + end) + it('splits arguments correctly', function() + meths.exec([[ + function! FooFunc(...) + echo a:000 + endfunction + ]], false) + meths.create_user_command("Foo", "call FooFunc(<f-args>)", { nargs = '+' }) + eq([=[['a quick', 'brown fox', 'jumps over the', 'lazy dog']]=], + meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}}, + { output = true })) + eq([=[['test \ \\ \"""\', 'more\ tests\" ']]=], + meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } }, + { output = true })) + end) + it('splits arguments correctly for Lua callback', function() + meths.exec_lua([[ + local function FooFunc(opts) + vim.pretty_print(opts.fargs) + end + + vim.api.nvim_create_user_command("Foo", FooFunc, { nargs = '+' }) + ]], {}) + eq([[{ "a quick", "brown fox", "jumps over the", "lazy dog" }]], + meths.cmd({ cmd = "Foo", args = { "a quick", "brown fox", "jumps over the", "lazy dog"}}, + { output = true })) + eq([[{ 'test \\ \\\\ \\"""\\', 'more\\ tests\\" ' }]], + meths.cmd({ cmd = "Foo", args = { [[test \ \\ \"""\]], [[more\ tests\" ]] } }, + { output = true })) + end) + it('works with buffer names', function() + command("edit foo.txt | edit bar.txt") + meths.cmd({ cmd = "buffer", args = { "foo.txt" } }, {}) + eq("foo.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t")) + meths.cmd({ cmd = "buffer", args = { "bar.txt" } }, {}) + eq("bar.txt", funcs.fnamemodify(meths.buf_get_name(0), ":t")) + end) + it('triggers CmdUndefined event if command is not found', function() + meths.exec_lua([[ + vim.api.nvim_create_autocmd("CmdUndefined", + { pattern = "Foo", + callback = function() + vim.api.nvim_create_user_command("Foo", "echo 'foo'", {}) + end + }) + ]], {}) + eq("foo", meths.cmd({ cmd = "Foo" }, { output = true })) + end) + it('errors if command is not implemented', function() + eq("Command not implemented: popup", pcall_err(meths.cmd, { cmd = "popup" }, {})) + end) + it('works with empty arguments list', function() + meths.cmd({ cmd = "update" }, {}) + meths.cmd({ cmd = "buffer", count = 0 }, {}) + end) + end) end) diff --git a/test/functional/editor/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua index 2494daf99b..3b2c1db350 100644 --- a/test/functional/editor/tabpage_spec.lua +++ b/test/functional/editor/tabpage_spec.lua @@ -7,6 +7,7 @@ local neq = helpers.neq local feed = helpers.feed local eval = helpers.eval local exec = helpers.exec +local funcs = helpers.funcs describe('tabpage', function() before_each(clear) @@ -51,5 +52,13 @@ describe('tabpage', function() ]]) neq(999, eval('g:win_closed')) end) -end) + it(":tabmove handles modifiers and addr", function() + command('tabnew | tabnew | tabnew') + eq(4, funcs.nvim_tabpage_get_number(0)) + command(' silent :keepalt :: ::: silent! - tabmove') + eq(3, funcs.nvim_tabpage_get_number(0)) + command(' silent :keepalt :: ::: silent! -2 tabmove') + eq(1, funcs.nvim_tabpage_get_number(0)) + end) +end) diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index f589f5955f..86cdf4ef56 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -766,8 +766,21 @@ function tests.code_action_filter() isPreferred = true, command = 'preferred_command', } + local quickfix_action = { + title = 'Action 3', + kind = 'quickfix', + command = 'quickfix_command', + } + local quickfix_foo_action = { + title = 'Action 4', + kind = 'quickfix.foo', + command = 'quickfix_foo_command', + } + expect_request('textDocument/codeAction', function() + return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, } + end) expect_request('textDocument/codeAction', function() - return nil, { action, preferred_action, } + return nil, { action, preferred_action, quickfix_action, quickfix_foo_action, } end) notify('shutdown') end; diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua index 6620c9acef..36a53d8d26 100644 --- a/test/functional/options/defaults_spec.lua +++ b/test/functional/options/defaults_spec.lua @@ -163,7 +163,7 @@ describe('startup defaults', function() end) it("'shadafile' ('viminfofile')", function() - local env = {XDG_DATA_HOME='Xtest-userdata', XDG_CONFIG_HOME='Xtest-userconfig'} + local env = {XDG_DATA_HOME='Xtest-userdata', XDG_STATE_HOME='Xtest-userstate', XDG_CONFIG_HOME='Xtest-userconfig'} clear{args={}, args_rm={'-i'}, env=env} -- Default 'shadafile' is empty. -- This means use the default location. :help shada-file-name @@ -178,7 +178,7 @@ describe('startup defaults', function() clear{args={}, args_rm={'-i'}, env=env} eq({ f }, eval('v:oldfiles')) os.remove('Xtest-foo') - rmdir('Xtest-userdata') + rmdir('Xtest-userstate') -- Handles viminfo/viminfofile as alias for shada/shadafile. eq('\n shadafile=', eval('execute("set shadafile?")')) @@ -206,7 +206,7 @@ describe('startup defaults', function() describe('$NVIM_LOG_FILE', function() local xdgdir = 'Xtest-startup-xdg-logpath' - local xdgcachedir = xdgdir..'/nvim' + local xdgstatedir = xdgdir..'/nvim' after_each(function() os.remove('Xtest-logpath') rmdir(xdgdir) @@ -218,21 +218,21 @@ describe('startup defaults', function() }}) eq('Xtest-logpath', eval('$NVIM_LOG_FILE')) end) - it('defaults to stdpath("cache")/log if empty', function() - eq(true, mkdir(xdgdir) and mkdir(xdgcachedir)) + it('defaults to stdpath("log")/log if empty', function() + eq(true, mkdir(xdgdir) and mkdir(xdgstatedir)) clear({env={ - XDG_CACHE_HOME=xdgdir, + XDG_STATE_HOME=xdgdir, NVIM_LOG_FILE='', -- Empty is invalid. }}) - eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgstatedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) - it('defaults to stdpath("cache")/log if invalid', function() - eq(true, mkdir(xdgdir) and mkdir(xdgcachedir)) + it('defaults to stdpath("log")/log if invalid', function() + eq(true, mkdir(xdgdir) and mkdir(xdgstatedir)) clear({env={ - XDG_CACHE_HOME=xdgdir, + XDG_STATE_HOME=xdgdir, NVIM_LOG_FILE='.', -- Any directory is invalid. }}) - eq(xdgcachedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) + eq(xdgstatedir..'/log', string.gsub(eval('$NVIM_LOG_FILE'), '\\', '/')) end) end) end) @@ -264,6 +264,7 @@ describe('XDG-based defaults', function() XDG_CONFIG_HOME=nil, XDG_DATA_HOME=nil, XDG_CACHE_HOME=nil, + XDG_STATE_HOME=nil, XDG_RUNTIME_DIR=nil, XDG_CONFIG_DIRS=nil, XDG_DATA_DIRS=nil, @@ -293,6 +294,7 @@ describe('XDG-based defaults', function() local env_sep = iswin() and ';' or ':' local data_dir = iswin() and 'nvim-data' or 'nvim' + local state_dir = iswin() and 'nvim-data' or 'nvim' local root_path = iswin() and 'C:' or '' describe('with too long XDG variables', function() @@ -303,6 +305,7 @@ describe('XDG-based defaults', function() .. env_sep.. root_path .. ('/b'):rep(2048) .. (env_sep .. root_path .. '/c'):rep(512)), XDG_DATA_HOME=(root_path .. ('/X'):rep(4096)), + XDG_STATE_HOME=(root_path .. ('/X'):rep(4096)), XDG_DATA_DIRS=(root_path .. ('/A'):rep(2048) .. env_sep .. root_path .. ('/B'):rep(2048) .. (env_sep .. root_path .. '/C'):rep(512)), @@ -355,13 +358,13 @@ describe('XDG-based defaults', function() .. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after' .. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after' ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/')) - eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup//', + eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. state_dir .. '/backup//', (meths.get_option('backupdir'):gsub('\\', '/'))) - eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/swap//', + eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/swap//', (meths.get_option('directory')):gsub('\\', '/')) - eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo//', + eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/undo//', (meths.get_option('undodir')):gsub('\\', '/')) - eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view//', + eq(root_path .. ('/X'):rep(4096) .. '/' .. state_dir .. '/view//', (meths.get_option('viewdir')):gsub('\\', '/')) end) end) @@ -372,6 +375,7 @@ describe('XDG-based defaults', function() XDG_CONFIG_HOME='$XDG_DATA_HOME', XDG_CONFIG_DIRS='$XDG_DATA_DIRS', XDG_DATA_HOME='$XDG_CONFIG_HOME', + XDG_STATE_HOME='$XDG_CONFIG_HOME', XDG_DATA_DIRS='$XDG_CONFIG_DIRS', }}) end) @@ -405,13 +409,13 @@ describe('XDG-based defaults', function() .. ',$XDG_DATA_DIRS/nvim/after' .. ',$XDG_DATA_HOME/nvim/after' ):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/')) - eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'), + eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'), meths.get_option('backupdir'):gsub('\\', '/')) - eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'), + eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'), meths.get_option('directory'):gsub('\\', '/')) - eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'), + eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'), meths.get_option('undodir'):gsub('\\', '/')) - eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'), + eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'), meths.get_option('viewdir'):gsub('\\', '/')) meths.command('set all&') eq(('$XDG_DATA_HOME/nvim' @@ -425,13 +429,13 @@ describe('XDG-based defaults', function() .. ',$XDG_DATA_DIRS/nvim/after' .. ',$XDG_DATA_HOME/nvim/after' ):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/')) - eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'), + eq(('.,$XDG_CONFIG_HOME/' .. state_dir .. '/backup//'), meths.get_option('backupdir'):gsub('\\', '/')) - eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'), + eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/swap//'), meths.get_option('directory'):gsub('\\', '/')) - eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'), + eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/undo//'), meths.get_option('undodir'):gsub('\\', '/')) - eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'), + eq(('$XDG_CONFIG_HOME/' .. state_dir .. '/view//'), meths.get_option('viewdir'):gsub('\\', '/')) end) end) @@ -442,6 +446,7 @@ describe('XDG-based defaults', function() XDG_CONFIG_HOME=', , ,', XDG_CONFIG_DIRS=',-,-,' .. env_sep .. '-,-,-', XDG_DATA_HOME=',=,=,', + XDG_STATE_HOME=',=,=,', XDG_DATA_DIRS=',≡,≡,' .. env_sep .. '≡,≡,≡', }}) end) @@ -484,13 +489,13 @@ describe('XDG-based defaults', function() .. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after' .. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after' ), meths.get_option('runtimepath')) - eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2), + eq('.,\\,=\\,=\\,' .. path_sep .. state_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2), meths.get_option('backupdir')) - eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2), + eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2), meths.get_option('directory')) - eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2), + eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2), meths.get_option('undodir')) - eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2), + eq('\\,=\\,=\\,' .. path_sep ..'' .. state_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2), meths.get_option('viewdir')) end) end) @@ -499,8 +504,9 @@ end) describe('stdpath()', function() -- Windows appends 'nvim-data' instead of just 'nvim' to prevent collisions - -- due to XDG_CONFIG_HOME and XDG_DATA_HOME being the same. + -- due to XDG_CONFIG_HOME, XDG_DATA_HOME and XDG_STATE_HOME being the same. local datadir = iswin() and 'nvim-data' or 'nvim' + local statedir = iswin() and 'nvim-data' or 'nvim' local env_sep = iswin() and ';' or ':' it('acceptance', function() @@ -509,6 +515,7 @@ describe('stdpath()', function() eq('nvim', funcs.fnamemodify(funcs.stdpath('cache'), ':t')) eq('nvim', funcs.fnamemodify(funcs.stdpath('config'), ':t')) eq(datadir, funcs.fnamemodify(funcs.stdpath('data'), ':t')) + eq(statedir, funcs.fnamemodify(funcs.stdpath('state'), ':t')) eq('table', type(funcs.stdpath('config_dirs'))) eq('table', type(funcs.stdpath('data_dirs'))) assert_alive() -- Check for crash. #8393 @@ -582,6 +589,39 @@ describe('stdpath()', function() end) end) + describe('with "state"' , function () + it('knows XDG_STATE_HOME', function() + clear({env={ + XDG_STATE_HOME=alter_slashes('/home/docwhat/.local'), + }}) + eq(alter_slashes('/home/docwhat/.local/'..statedir), funcs.stdpath('state')) + end) + + it('handles changes during runtime', function() + clear({env={ + XDG_STATE_HOME=alter_slashes('/home/original'), + }}) + eq(alter_slashes('/home/original/'..statedir), funcs.stdpath('state')) + command("let $XDG_STATE_HOME='"..alter_slashes('/home/new').."'") + eq(alter_slashes('/home/new/'..statedir), funcs.stdpath('state')) + end) + + it("doesn't expand $VARIABLES", function() + clear({env={ + XDG_STATE_HOME='$VARIABLES', + VARIABLES='this-should-not-happen', + }}) + eq(alter_slashes('$VARIABLES/'..statedir), funcs.stdpath('state')) + end) + + it("doesn't expand ~/", function() + clear({env={ + XDG_STATE_HOME=alter_slashes('~/frobnitz'), + }}) + eq(alter_slashes('~/frobnitz/'..statedir), funcs.stdpath('state')) + end) + end) + describe('with "cache"' , function () it('knows XDG_CACHE_HOME', function() clear({env={ diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 33a8976b79..4cb7636825 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2753,12 +2753,33 @@ describe('LSP', function() vim.lsp.commands['executed_preferred'] = function() end end + vim.lsp.commands['quickfix_command'] = function(cmd) + vim.lsp.commands['executed_quickfix'] = function() + end + end local bufnr = vim.api.nvim_get_current_buf() vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID) vim.lsp.buf.code_action({ filter = function(a) return a.isPreferred end, apply = true, }) + vim.lsp.buf.code_action({ + -- expect to be returned actions 'quickfix' and 'quickfix.foo' + context = { only = {'quickfix'}, }, + apply = true, + filter = function(a) + if a.kind == 'quickfix.foo' then + vim.lsp.commands['filtered_quickfix_foo'] = function() end + return false + elseif a.kind == 'quickfix' then + return true + else + assert(nil, 'unreachable') + end + end, + }) ]]) elseif ctx.method == 'shutdown' then eq('function', exec_lua[[return type(vim.lsp.commands['executed_preferred'])]]) + eq('function', exec_lua[[return type(vim.lsp.commands['filtered_quickfix_foo'])]]) + eq('function', exec_lua[[return type(vim.lsp.commands['executed_quickfix'])]]) client.stop() end end diff --git a/test/symbolic/klee/nvim/keymap.c b/test/symbolic/klee/nvim/keymap.c index ed5f95a344..1f7f0e0911 100644 --- a/test/symbolic/klee/nvim/keymap.c +++ b/test/symbolic/klee/nvim/keymap.c @@ -1,7 +1,7 @@ #include <stdbool.h> #include "nvim/types.h" -#include "nvim/keymap.h" +#include "nvim/keycodes.h" #include "nvim/ascii.h" #include "nvim/eval/typval.h" diff --git a/test/symbolic/klee/viml_expressions_lexer.c b/test/symbolic/klee/viml_expressions_lexer.c index ee7dc312e9..03c9d66ca4 100644 --- a/test/symbolic/klee/viml_expressions_lexer.c +++ b/test/symbolic/klee/viml_expressions_lexer.c @@ -17,7 +17,7 @@ #include "nvim/charset.c" #include "nvim/garray.c" #include "nvim/gettext.c" -#include "nvim/keymap.c" +#include "nvim/keycodes.c" #include "nvim/viml/parser/expressions.c" #define INPUT_SIZE 7 diff --git a/test/symbolic/klee/viml_expressions_parser.c b/test/symbolic/klee/viml_expressions_parser.c index 9a876ed3fa..b0e1d71127 100644 --- a/test/symbolic/klee/viml_expressions_parser.c +++ b/test/symbolic/klee/viml_expressions_parser.c @@ -17,7 +17,7 @@ #include "nvim/garray.c" #include "nvim/gettext.c" #include "nvim/viml/parser/expressions.c" -#include "nvim/keymap.c" +#include "nvim/keycodes.c" #define INPUT_SIZE 50 diff --git a/test/unit/keymap_spec.lua b/test/unit/keycodes_spec.lua index 1f1f32bb9e..5bf27c9232 100644 --- a/test/unit/keymap_spec.lua +++ b/test/unit/keycodes_spec.lua @@ -5,10 +5,10 @@ local ffi = helpers.ffi local eq = helpers.eq local neq = helpers.neq -local keymap = helpers.cimport('./src/nvim/keymap.h') +local keymap = helpers.cimport('./src/nvim/keycodes.h') local NULL = helpers.NULL -describe('keymap.c', function() +describe('keycodes.c', function() describe('find_special_key()', function() local srcp = ffi.new('const unsigned char *[1]') diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index d494a96907..21d1f7906a 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -39,7 +39,6 @@ set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads" CACHE PATH "Dependencies dow option(USE_BUNDLED "Use bundled dependencies." ON) -option(USE_BUNDLED_GPERF "Use the bundled version of gperf." ${USE_BUNDLED}) option(USE_BUNDLED_UNIBILIUM "Use the bundled unibilium." ${USE_BUNDLED}) option(USE_BUNDLED_LIBTERMKEY "Use the bundled libtermkey." ${USE_BUNDLED}) option(USE_BUNDLED_LIBVTERM "Use the bundled libvterm." ${USE_BUNDLED}) @@ -109,10 +108,6 @@ else() set(DEPS_C_COMPILER "${CMAKE_C_COMPILER}") endif() -if(USE_BUNDLED_GPERF) - enable_language(CXX) -endif() - if(CMAKE_CXX_COMPILER) set(DEPS_CXX_COMPILER "${CMAKE_CXX_COMPILER}") endif() @@ -170,15 +165,12 @@ set(LIBVTERM_URL https://www.leonerd.org.uk/code/libvterm/libvterm-0.1.4.tar.gz) set(LIBVTERM_SHA256 bc70349e95559c667672fc8c55b9527d9db9ada0fb80a3beda533418d782d3dd) set(LUV_VERSION 1.43.0-0) -set(LUV_URL https://github.com/luvit/luv/archive/${LUV_VERSION}.tar.gz) -set(LUV_SHA256 a36865f34db029e2caa01245a41341a067038c09e94459b50db1346d9fdf82f0) +set(LUV_URL https://github.com/luvit/luv/archive/c51e7052ec4f0a25058f70c1b4ee99dd36180e59.tar.gz) +set(LUV_SHA256 cabb7e650f35992686eb95ae167c71614e281cd2979fc804e4e70f8051555728) set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.9.tar.gz) set(LUA_COMPAT53_SHA256 ad05540d2d96a48725bb79a1def35cf6652a4e2ec26376e2617c8ce2baa6f416) -set(GPERF_URL https://github.com/neovim/deps/raw/ff5b4b18a87397a8564016071ae64f64bcd8c635/opt/gperf-3.1.tar.gz) -set(GPERF_SHA256 588546b945bba4b70b6a3a616e80b4ab466e3f33024a352fc2198112cdbb3ae2) - # cat.exe curl.exe curl-ca-bundle.crt diff.exe tee.exe xxd.exe set(WINTOOLS_URL https://github.com/neovim/deps/raw/d66e306abf5b846484b4f2adffd896bce7e065d2/opt/win32tools.zip) set(WINTOOLS_SHA256 2fb2f8d69070b3f16e029913fb95008e6be33893d77fc358012396c275a0fdb7) @@ -242,10 +234,6 @@ if(USE_BUNDLED_LUV) include(BuildLuv) endif() -if(USE_BUNDLED_GPERF) - include(BuildGperf) -endif() - if(USE_BUNDLED_GETTEXT) include(BuildGettext) endif() diff --git a/third-party/cmake/BuildGperf.cmake b/third-party/cmake/BuildGperf.cmake deleted file mode 100644 index 5401191150..0000000000 --- a/third-party/cmake/BuildGperf.cmake +++ /dev/null @@ -1,68 +0,0 @@ -# Gperf recipe. Gperf is only required when building Neovim, when -# cross compiling we still want to build for the HOST system, whenever -# writing a recipe that is meant for cross-compile, use the HOSTDEPS_* variables -# instead of DEPS_* - check the main CMakeLists.txt for a list. - -# BuildGperf(CONFIGURE_COMMAND ... BUILD_COMMAND ... INSTALL_COMMAND ...) -# Reusable function to build Gperf, wraps ExternalProject_Add. -# Failing to pass a command argument will result in no command being run -function(BuildGperf) - cmake_parse_arguments(_gperf - "" - "" - "CONFIGURE_COMMAND;BUILD_COMMAND;INSTALL_COMMAND" - ${ARGN}) - - if(NOT _gperf_CONFIGURE_COMMAND AND NOT _gperf_BUILD_COMMAND - AND NOT _gperf_INSTALL_COMMAND) - message(FATAL_ERROR "Must pass at least one of CONFIGURE_COMMAND, BUILD_COMMAND, INSTALL_COMMAND") - endif() - - ExternalProject_Add(gperf - PREFIX ${DEPS_BUILD_DIR} - URL ${GPERF_URL} - DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/gperf - DOWNLOAD_COMMAND ${CMAKE_COMMAND} - -DPREFIX=${DEPS_BUILD_DIR} - -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/gperf - -DURL=${GPERF_URL} - -DEXPECTED_SHA256=${GPERF_SHA256} - -DTARGET=gperf - -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR} - -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND "${_gperf_CONFIGURE_COMMAND}" - BUILD_COMMAND "${_gperf_BUILD_COMMAND}" - INSTALL_COMMAND "${_gperf_INSTALL_COMMAND}") -endfunction() - -set(GPERF_BUILDARGS CC=${HOSTDEPS_C_COMPILER} CXX=${HOSTDEPS_CXX_COMPILER} - LD=${HOSTDEPS_C_COMPILER}) - -if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING)) - - BuildGperf( - CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/src/gperf/configure - --prefix=${HOSTDEPS_INSTALL_DIR} - MAKE=${MAKE_PRG} ${GPERF_BUILDARGS} - INSTALL_COMMAND ${MAKE_PRG} install) - -elseif(MSVC OR MINGW) - - BuildGperf( - CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/GperfCMakeLists.txt - ${DEPS_BUILD_DIR}/src/gperf/CMakeLists.txt - COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/gperf/CMakeLists.txt - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_GENERATOR=${CMAKE_GENERATOR} - -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} - BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} - INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE}) - -else() - message(FATAL_ERROR "Trying to build gperf in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") -endif() diff --git a/third-party/cmake/GperfCMakeLists.txt b/third-party/cmake/GperfCMakeLists.txt deleted file mode 100644 index 15ae305ba8..0000000000 --- a/third-party/cmake/GperfCMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -cmake_minimum_required(VERSION 2.8.12) -project(gperf LANGUAGES C CXX) - -add_executable(gperf - lib/getline.cc - lib/hash.cc - lib/getopt.c - lib/getopt1.c - src/version.cc - src/positions.cc - src/options.cc - src/keyword.cc - src/keyword-list.cc - src/input.cc - src/bool-array.cc - src/hash-table.cc - src/search.cc - src/output.cc - src/main.cc) - -include_directories(lib) - -# Copy the config.h template without modifying it -# because none of the definitions are necessary -execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/src/config.h.in ${CMAKE_BINARY_DIR}/config/config.h) -include_directories(${CMAKE_BINARY_DIR}/config) - -include(GNUInstallDirs) -install(TARGETS gperf - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) |