diff options
95 files changed, 2148 insertions, 1592 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e9384c1982..fa8d05f6b5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -6,62 +6,68 @@ body: - type: markdown attributes: value: | - Before reporting: search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). + _Before reporting:_ search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions such as "How do I...?" belong on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will be closed. - type: input attributes: - label: "Neovim Version" - description: "`nvim --version`:" + label: "Neovim version (nvim -v)" + placeholder: "0.6.0 commit db1b0ee3b30f" validations: required: true - type: input attributes: - label: "Operating system/version:" + label: "Vim (not Nvim) behaves the same?" + description: "Does `vim -u DEFAULTS` have the same issue? Note the exact Vim version (`8.x.yyyy`)." + placeholder: "no, vim 7.3.432" validations: required: true - type: input attributes: - label: "Terminal name/version:" + label: "Operating system/version" + placeholder: "macOS 11.5" validations: required: true - type: input attributes: - label: "TERM environment variable" - description: "echo `$TERM`:" + label: "Terminal name/version" + placeholder: "xterm 3.1" + validations: + required: true + - type: input + attributes: + label: "$TERM environment variable" + placeholder: "echo $TERM" validations: required: true - type: input attributes: label: "Installation" - description: "How did you install neovim: build from repo / system package manager / appimage / homebrew / snap / chocolatey / other (please specify)?" + description: "How did you install neovim: build from repo / system package manager / appimage / homebrew / snap / chocolatey / other (describe)?" placeholder: "Arch User Repository (AUR)" validations: required: true - type: textarea attributes: - label: "Steps to reproduce" + label: "How to reproduce the issue" description: | - Steps to reproduce using `nvim -u NORC` and/or `nvim -u NONE` (please test both). - If you are reporting build failures, please list the exact sequence of steps including all CMake flags (if any). - validations: - required: true - - - type: input - attributes: - label: "Vim" - description: "Does Vim behave differently when called with `vim -u DEFAULTS`? (Please add the specific version, including patch level, of Vim that you tested.)" + - Steps to reproduce using `nvim -u NORC` or `nvim -u NONE` (try both). + - For build failures: list the exact steps including CMake flags (if any). + - For shell-related problems: try `env -i TERM=ansi-256color "$(which nvim)"`. + placeholder: | + nvim -u NONE + :edit foo + yiwp validations: required: true - type: textarea attributes: label: "Expected behavior" - description: "A description of the behavior you expected. May optionally include logs, images, or videos." + description: "Describe the behavior you expect. May include logs, images, or videos." validations: required: true - - type: textarea attributes: label: "Actual behavior" diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 35b9e23489..796707be03 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,4 +2,4 @@ blank_issues_enabled: true contact_links: - name: Question url: https://neovim.discourse.group/ - about: Please ask and answer questions about Neovim on Discourse. + about: Ask questions about configuration and usage of Neovim diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index a9ed2824cb..2b6fa3daf4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -11,7 +11,8 @@ body: - type: input attributes: label: "Feature already in Vim?" - description: "Does the feature already exist in Vim? If possible, please specify which version of Vim it was introduced in." + description: "Does the feature already exist in Vim? If possible, specify which version (or commit) that introduced it." + placeholder: "Yes, Vim 7.3.432" - type: textarea attributes: diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml index ba1905329b..b5b7687bf8 100644 --- a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml @@ -1,69 +1,61 @@ -name: Language server client bug report -description: Report a built-in lsp problem in Neovim +name: Language server (LSP) client bug +description: Report an issue with Neovim LSP labels: [bug, lsp] body: - type: markdown attributes: value: | - Before reporting: search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions such as "How do I...?" or "Why isn't X language server/feature working?" belong on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will be closed. + _Before reporting:_ search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions such as "How do I...?" or "Why isn't X language server/feature working?" belong on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will be closed. - type: input attributes: - label: "Neovim Version" - description: "`nvim --version`:" + label: "Neovim version (nvim -v)" + placeholder: "0.6.0 commit db1b0ee3b30f" validations: required: true - type: input attributes: - label: "Language server name/version:" + label: "Language server name/version" + placeholder: "rls 0.5.2" validations: required: true - type: input attributes: - label: "Operating system/version:" + label: "Operating system/version" + placeholder: "emacs 23" validations: required: true - type: textarea attributes: - label: Checkhealth + label: ':checkhealth' description: | - Paste the results from `nvim -c ":checkhealth nvim lspconfig"` here: + Paste the results from `nvim -c ":checkhealth nvim lspconfig"` render: markdown - - type: markdown - attributes: - value: | - Note: if the issue is with an autocompletion or other LSP plugin, please report it at that plugin's issue tracker. Download the minimal config with `wget https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua` and modify it to include any specific commands or servers pertaining to your issues. - type: textarea attributes: - label: "Steps to reproduce" + label: 'Steps to reproduce using "nvim -u minimal_init.lua"' description: | - Steps to reproduce using `nvim -u minimal_init.lua`: + - Download the minimal config with `curl -LO https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua` and modify it to include any specific commands or servers pertaining to your issues. + - _Note_: if the issue is with an autocompletion or other LSP plugin, report to that plugin's issue tracker. validations: required: true - type: textarea attributes: label: "Expected behavior" - description: "A description of the behavior you expected. May optionally include logs, images, or videos." + description: "Describe the behavior you expect. May include logs, images, or videos." - type: textarea attributes: label: "Actual behavior" - - type: markdown - attributes: - value: | - Please upload `lsp.log` before and after the problem in a [secret gist](https://gist.github.com/). Paste the url to the gist in the text field below. - - You can set the log level by adding the Lua command - `vim.lsp.set_log_level("debug")` - after setting up LSP in your config. - - You can find the location of the log with the command - `:lua print(vim.lsp.get_log_path())` - - type: input attributes: - label: "Link to uploaded log file" + label: "Log file" + placeholder: "https://gist.github.com/prakhar1989/1b0a2c9849b2e1e912fb" + description: | + - Upload `lsp.log` before and after the problem in a [secret gist](https://gist.github.com/). Paste the URL to the gist. + - You can set the log level by adding `vim.lsp.set_log_level("debug")` after setting up LSP in your config. + - You can find the location of the log with `:lua print(vim.lsp.get_log_path())` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e362ddd82..da222bbc90 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,6 +11,7 @@ low-risk/isolated tasks: - Try a [good first issue](../../labels/good-first-issue) or [complexity:low] issue. - Fix bugs found by [Clang](#clang-scan-build), [PVS](#pvs-studio) or [Coverity](#coverity). +- [Improve documentation][wiki-contribute-help] Reporting problems ------------------ @@ -18,17 +19,17 @@ Reporting problems - [Check the FAQ][wiki-faq]. - [Search existing issues][github-issues] (including closed!) - Update Neovim to the latest version to see if your problem persists. -- Disable plugins incrementally, to narrow down the cause of the issue. +- [Bisect](https://neovim.io/doc/user/starting.html#bisect) your config: disable plugins incrementally, to narrow down the cause of the issue. +- [Bisect][git-bisect] Neovim's source code to find the cause of a regression, if you can. This is _extremely_ helpful. - When reporting a crash, [include a stacktrace](https://github.com/neovim/neovim/wiki/FAQ#backtrace-linux). - Use [ASAN/UBSAN](#clang-sanitizers-asan-and-ubsan) to get detailed errors for segfaults and undefined behavior. -- [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful. -- Check `$NVIM_LOG_FILE`, if it exists. +- Check the logs. `:edit $NVIM_LOG_FILE` - Include `cmake --system-information` for build-related issues. Developer guidelines -------------------- -- Nvim contributors should read `:help dev`. +- Nvim developers should read `:help dev`. - External UI developers should read `:help dev-ui`. - API client developers should read `:help dev-api-client`. - Nvim developers are _strongly encouraged_ to install `ninja` for faster builds. @@ -37,13 +38,12 @@ Developer guidelines make distclean make # Nvim build system uses ninja automatically, if available. ``` -- [Improve documentation][wiki-contribute-help] Pull requests (PRs) --------------------- -- To avoid duplicate work, create a draft pull request as soon as possible. -- Your PR must include **test coverage.** See [test/README.md][run-tests]. +- To avoid duplicate work, create a draft pull request. +- Your PR must include [test coverage][run-tests]. - Avoid cosmetic changes to unrelated files in the same commit. - Use a [feature branch][git-feature-branch] instead of the master branch. - Use a **rebase workflow** for small PRs. @@ -68,21 +68,19 @@ Pull requests have two stages: Draft and Ready for review. 1. [Create a Draft PR][pr-draft] while you are _not_ requesting feedback as you are still working on the PR. + - You can skip this if your PR is ready for review. 2. [Change your PR to ready][pr-ready] when the PR is ready for review. + - You can convert back to Draft at any time. -You can convert the state of your PR back to Draft (or Ready for review) at any -time. You can also skip the Draft stage if your PR is ready for review from the -beginning. - -Do __not__ add any labels like `[RFC]` or `[WIP]` in the title to indicate the +Do __not__ add labels like `[RFC]` or `[WIP]` in the title to indicate the state of your PR: this just adds noise. Non-Draft PRs are assumed to be open -for comments by default; if you want feedback from specific people, `@`-ping -them in a comment. +for comments; if you want feedback from specific people, `@`-mention them in +a comment. ### Commit messages Follow the [conventional commits guidelines][conventional_commits] to *make reviews easier* and to make -the VCS/git logs more valuable. The general structure of a commit message is as follows: +the VCS/git logs more valuable. The general structure of a commit message is: ``` <type>([optional scope]): <description> @@ -92,43 +90,27 @@ the VCS/git logs more valuable. The general structure of a commit message is as [optional footer(s)] ``` -- Prefix the commit subject with one of the following _types_: - - `build`: all changes related to the build system (involving scripts, configurations or tools) and package dependencies. - - `ci`: all changes related to the continuous integration and deployment system - involving scripts, configurations or tools. - - `docs`: all documentation changes. This includes both external documentation for users as well as internal documentation for developers. - - `feat`: new abilities or functionality. - - `fix`: a bug fix. - - `perf`: performance improvements. - - `refactor`: modification of the code base which neither adds a feature nor fixes a bug - such as removing redundant code, simplifying code, renaming variables, etc. - - `revert`: revert previous commits. - - `test`: all changes related to tests such as refactoring existing tests or adding new tests. - - `vim-patch`: all patches from upstream Vim. The commit messages for patches has [slightly different rules](https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim#pull-requests) as not to interfere with existing scripts. - - `chore`: Lastly, if none of the types above fits you may use `chore` as the type. - -- Append optional scope to _type_ such as `(lsp)`, `(treesitter)`, `(float)`, ... - -- The _description_ shouldn't start with a capital letter or end in a period. - +- Prefix the commit subject with one of these [_types_](https://github.com/commitizen/conventional-commit-types/blob/master/index.json): + - `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `test`, `vim-patch`, `chore` + - You can **ignore this for "fixup" commits** or any commits you expect to be squashed. +- Append optional scope to _type_ such as `(lsp)`, `(treesitter)`, `(float)`, … +- _Description_ shouldn't start with a capital letter or end in a period. +- Use the _imperative voice_: "Fix bug" rather than "Fixed bug" or "Fixes bug." - Try to keep the first line under 72 characters. +- A blank line must follow the subject. +- Breaking API changes must be indicated by + 1. "!" after the type/scope, and + 2. a "BREAKING CHANGE" footer describing the change. + Example: + ``` + refactor(provider)!: drop support for Python 2 -- A blank line must separate the subject from the description. - -- A breaking API change must be indicated by appending `!` after the type/scope and at the very beginning of the footer with a **BREAKING CHANGE**. - - Example: - - ``` - refactor(provider)!: drop support for Python 2 - - BREAKING CHANGE: refactor to use Python 3 features since Python 2 is no longer supported. - ``` - -- Use the _imperative voice_: "Fix bug" rather than "Fixed bug" or "Fixes bug." + BREAKING CHANGE: refactor to use Python 3 features since Python 2 is no longer supported. + ``` ### Automated builds (CI) -Each pull request must pass the automated builds on [Travis CI], [sourcehut] -and [AppVeyor]. +Each pull request must pass the automated builds on [sourcehut] and [GitHub Actions]. - CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings will fail the build. @@ -282,9 +264,8 @@ as context, use the `-W` argument as well. [wiki-faq]: https://github.com/neovim/neovim/wiki/FAQ [review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist [3174]: https://github.com/neovim/neovim/issues/3174 -[Travis CI]: https://travis-ci.org/neovim/neovim [sourcehut]: https://builds.sr.ht/~jmk -[AppVeyor]: https://ci.appveyor.com/project/neovim/neovim +[GitHub Actions]: https://github.com/neovim/neovim/actions [Merge a Vim patch]: https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim [Clang report]: https://neovim.io/doc/reports/clang/ [complexity:low]: https://github.com/neovim/neovim/issues?q=is%3Aopen+is%3Aissue+label%3Acomplexity%3Alow @@ -1,7 +1,7 @@ [](https://neovim.io) [Documentation](https://neovim.io/doc/general/) | -[Chat](https://gitter.im/neovim/neovim) | +[Chat](https://app.element.io/#/room/#neovim:matrix.org) | [Twitter](https://twitter.com/Neovim) [](https://github.com/neovim/neovim/actions?query=workflow%3A%22CI%22) @@ -64,7 +64,7 @@ To install to a non-default location: make CMAKE_INSTALL_PREFIX=/full/path/ make install -To inspect the build, these CMake features are useful: +CMake hints for inspecting the build: - `cmake --build build --target help` lists all build targets. - `build/CMakeCache.txt` (or `cmake -LAH build/`) contains the resolved values of all CMake variables. diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 87c2e11a1e..03e182cb33 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -914,6 +914,8 @@ TermLeave After leaving |Terminal-mode|. After TermClose. *TermClose* TermClose When a |terminal| job ends. + Sets these |v:event| keys: + status *TermResponse* TermResponse After the response to t_RV is received from the terminal. The value of |v:termresponse| diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index aec0178da2..60a3f870a9 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -46,7 +46,7 @@ NVIM IS... WELL DOCUMENTED *design-documented* item is easier to find. -NVIM IS... HIGH SPEED AND SMALL IN SIZE *design-speed-size* +NVIM IS... FAST AND SMALL *design-speed-size* Keep Nvim small and fast. - Computers are becoming faster and bigger each year. Vim can grow too, but @@ -191,8 +191,8 @@ definitions. The |lua-vim| :help is generated from the docstrings. Docstring format: - Lines in the main description start with `---` -- Special tokens start with `--@` followed by the token name: - `--@see`, `--@param`, `--@returns` +- Special tokens start with `---@` followed by the token name: + `---@see`, `---@param`, `---@returns` - Limited markdown is supported. - List-items start with `-` (useful to nest or "indent") - Use `<pre>` for code samples. @@ -211,11 +211,11 @@ vim.paste in src/nvim/lua/vim.lua like this: > --- end)() --- </pre> --- - --@see |paste| + ---@see |paste| --- - --@param lines ... - --@param phase ... - --@returns false if client should cancel the paste. + ---@param lines ... + ---@param phase ... + ---@returns false if client should cancel the paste. LUA *dev-lua* diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index a76298c86c..e02d80252f 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1641,6 +1641,7 @@ v:event Dictionary of event data for the current |autocommand|. Valid |v:false| if not. changed_window Is |v:true| if the the event fired while changing window (or tab) on |DirChanged|. + status Job status or exit code, -1 means "unknown". |TermClose| *v:exception* *exception-variable* v:exception The value of the exception most recently caught and not diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 4d32be97d3..b04d9c267a 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1510,11 +1510,6 @@ reset({client_id}, {buffer_client_map}) *vim.lsp.diagnostic.reset()* {buffer_client_map} table map of buffers to active clients - *vim.lsp.diagnostic.restore_extmarks()* -restore_extmarks({bufnr}, {last}) - Parameters: ~ - {last} number last line that was changed - save({diagnostics}, {bufnr}, {client_id}) *vim.lsp.diagnostic.save()* Save diagnostics to the current buffer. @@ -1526,10 +1521,6 @@ save({diagnostics}, {bufnr}, {client_id}) *vim.lsp.diagnostic.save()* {bufnr} number {client_id} number - *vim.lsp.diagnostic.save_extmarks()* -save_extmarks({bufnr}, {client_id}) - TODO: Documentation - set_loclist({opts}) *vim.lsp.diagnostic.set_loclist()* Sets the location list @@ -1966,7 +1957,9 @@ diagnostics_to_items({diagnostics_by_bufnr}, {predicate}) Parameters: ~ {diagnostics_by_bufnr} table bufnr -> Diagnostic [] {predicate} an optional function to filter the - diagnostics. + diagnostics. If present, only + diagnostic items matching will be + included. Return: ~ table (A list of items) @@ -1999,6 +1992,8 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()* |softtabstop| get_line({uri}, {row}) *vim.lsp.util.get_line()* + Gets the zero-indexed line from the given uri. + Parameters: ~ {uri} string uri of the resource to get the line from {row} number zero-indexed line number @@ -2007,6 +2002,8 @@ get_line({uri}, {row}) *vim.lsp.util.get_line()* string the line at row in filename get_lines({uri}, {rows}) *vim.lsp.util.get_lines()* + Gets the zero-indexed lines from the given uri. + Parameters: ~ {uri} string uri of the resource to get the lines from {rows} number[] zero-indexed line numbers @@ -2014,9 +2011,6 @@ get_lines({uri}, {rows}) *vim.lsp.util.get_lines()* Return: ~ table<number string> a table mapping rows to lines -get_markdown_fences() *vim.lsp.util.get_markdown_fences()* - TODO: Documentation - get_progress_messages() *vim.lsp.util.get_progress_messages()* TODO: Documentation @@ -2197,6 +2191,8 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()* or nil rename({old_fname}, {new_fname}, {opts}) *vim.lsp.util.rename()* + Rename old_fname to new_fname + Parameters: ~ {opts} (table) diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index fd1bedd8ef..28667d5bd1 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -616,6 +616,73 @@ regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()* indices will be relative {start}. ------------------------------------------------------------------------------ +VIM.DIFF *lua-diff* + +vim.diff({a}, {b}, {opts}) *vim.diff()* + Run diff on strings {a} and {b}. Any indices returned by this + function, either directly or via callback arguments, are + 1-based. + + Examples: > + vim.diff('a\n', 'b\nc\n') + --> + @@ -1 +1,2 @@ + -a + +b + +c + + vim.diff('a\n', 'b\nc\n', {hunk_lines = true}) + --> + { + {1, 1, 1, 2} + } +< + Parameters: ~ + {a} First string to compare + {b} Second string to compare + {opts} Optional parameters: + • `on_hunk` (callback): + Invoked for each hunk in the diff. Return a + negative number to cancel the callback for any + remaining hunks. + Args: + • `start_a` (integer): Start line of hunk in {a}. + • `count_a` (integer): Hunk size in {a}. + • `start_b` (integer): Start line of hunk in {b}. + • `count_b` (integer): Hunk size in {b}. + • `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 + used. + • `algorithm` (string): + Diff algorithm to use. Values: + • "myers" the default algorithm + • "minimal" spend extra time to generate the + smallest possible diff + • "patience" patience diff algorithm + • "histogram" histogram diff algorithm + • `ctxlen` (integer): Context length + • `interhunkctxlen` (integer): + Inter hunk context length + • `ignore_whitespace` (boolean): + Ignore whitespace + • `ignore_whitespace_change` (boolean): + Ignore whitespace change + • `ignore_whitespace_change_at_eol` (boolean) + Ignore whitespace change at end-of-line. + • `ignore_cr_at_eol` (boolean) + Ignore carriage return at end-of-line + • `ignore_blank_lines` (boolean) + Ignore blank lines + • `indent_heuristic` (boolean): + Use the indent heuristic for the internal + diff library. + + Return: ~ + See {opts.result_type}. nil if {opts.on_hunk} is given. + +------------------------------------------------------------------------------ VIM *lua-builtin* vim.api.{func}({...}) *vim.api* @@ -1110,7 +1177,9 @@ make_dict_accessor({scope}) *vim.make_dict_accessor()* TODO: Documentation notify({msg}, {log_level}, {_opts}) *vim.notify()* - Notification provider without a runtime, writes to :Messages + Notification provider + + Without a runtime, writes to :Messages Parameters: ~ {msg} Content of the notification to show to the @@ -1119,6 +1188,9 @@ notify({msg}, {log_level}, {_opts}) *vim.notify()* {opts} Dictionary with optional options (timeout, etc) + See also: ~ + :help nvim_notify + paste({lines}, {phase}) *vim.paste()* Paste handler, invoked by |nvim_paste()| when a conforming UI (such as the |TUI|) pastes text into the editor. diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt index 6dbc54463c..e0589ba7b8 100644 --- a/runtime/doc/nvim_terminal_emulator.txt +++ b/runtime/doc/nvim_terminal_emulator.txt @@ -134,6 +134,10 @@ Example: > programs can set this by emitting an escape sequence. - |'channel'| Terminal PTY |job-id|. Can be used with |chansend()| to send input to the terminal. +- The |TermClose| event gives the terminal job exit code in the |v:event| + "status" field. For example, this autocmd closes terminal buffers if the job + exited without error: > + autocmd TermClose * if !v:event.status | exe 'bdelete! '..expand('<abuf>') | endif Use |jobwait()| to check if the terminal job has finished: > let running = jobwait([&channel], 0)[0] == -1 diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 10b849aa3e..364d4c5167 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3080,17 +3080,16 @@ A jump table for the options with a short description can be found at |Q_op|. *'hidden'* *'hid'* *'nohidden'* *'nohid'* 'hidden' 'hid' boolean (default on) global - When off a buffer is unloaded when it is |abandon|ed. When on a - buffer becomes hidden when it is |abandon|ed. If the buffer is still - displayed in another window, it does not become hidden, of course. - The commands that move through the buffer list sometimes make a buffer - hidden although the 'hidden' option is off: When the buffer is - modified, 'autowrite' is off or writing is not possible, and the '!' - flag was used. See also |windows.txt|. - To only make one buffer hidden use the 'bufhidden' option. - This option is set for one command with ":hide {command}" |:hide|. - WARNING: It's easy to forget that you have changes in hidden buffers. - Think twice when using ":q!" or ":qa!". + When off a buffer is unloaded (including loss of undo information) + when it is |abandon|ed. When on a buffer becomes hidden when it is + |abandon|ed. A buffer displayed in another window does not become + hidden, of course. + Commands that move through the buffer list sometimes hide a buffer + although the 'hidden' option is off: when the buffer is modified, + 'autowrite' is off or writing is not possible, and the '!' flag was + used. See also |windows|. + To hide a specific buffer use the 'bufhidden' option. + 'hidden' is set for one command with ":hide {command}" |:hide|. *'history'* *'hi'* 'history' 'hi' number (Vim default: 10000, Vi default: 0) diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 162909ce45..62e1e130ee 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -460,20 +460,14 @@ defined while executing a function, user command or autocommand, the script in which it was defined is reported. *K* -[count]K Run a program to lookup the keyword under the - cursor. The name of the program is given with the - 'keywordprg' (kp) option (default is "man"). The - keyword is formed of letters, numbers and the - characters in 'iskeyword'. The keyword under or - right of the cursor is used. The same can be done - with the command > - :!{program} {keyword} +[count]K Runs the program given by 'keywordprg' to lookup the + |word| (defined by 'iskeyword') under or right of the + cursor. Default is "man". Works like this: > + :tabnew | terminal {program} {keyword} < Special cases: - If 'keywordprg' begins with ":" it is invoked as a Vim command with [count]. - - If 'keywordprg' is empty, the ":help" command is - used. It's a good idea to include more characters - in 'iskeyword' then, to be able to find more help. + - If 'keywordprg' is empty, |:help| is used. - When 'keywordprg' is equal to "man", a [count] before "K" is inserted after the "man" command and before the keyword. For example, using "2K" while diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 9c75a49ac1..333da58128 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -533,8 +533,13 @@ au BufNewFile,BufRead *.drac,*.drc,*lvs,*lpe setf dracula " Datascript au BufNewFile,BufRead *.ds setf datascript -" dsl -au BufNewFile,BufRead *.dsl setf dsl +" dsl: DSSSL or Structurizr +au BufNewFile,BufRead *.dsl + \ if getline(1) =~ '^\s*<\!' | + \ setf dsl | + \ else | + \ setf structurizr | + \ endif " DTD (Document Type Definition for XML) au BufNewFile,BufRead *.dtd setf dtd diff --git a/runtime/lua/vim/F.lua b/runtime/lua/vim/F.lua index 7925ff6e44..09467eb8c6 100644 --- a/runtime/lua/vim/F.lua +++ b/runtime/lua/vim/F.lua @@ -2,8 +2,8 @@ local F = {} --- Returns {a} if it is not nil, otherwise returns {b}. --- ---@param a ---@param b +---@param a +---@param b function F.if_nil(a, b) if a == nil then return b end return a diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua index 0012dce081..4cb1994419 100644 --- a/runtime/lua/vim/highlight.lua +++ b/runtime/lua/vim/highlight.lua @@ -2,7 +2,7 @@ local api = vim.api local highlight = {} ---@private +---@private function highlight.create(higroup, hi_info, default) local options = {} -- TODO: Add validation @@ -12,7 +12,7 @@ function highlight.create(higroup, hi_info, default) vim.cmd(string.format([[highlight %s %s %s]], default and "default" or "", higroup, table.concat(options, " "))) end ---@private +---@private function highlight.link(higroup, link_to, force) vim.cmd(string.format([[highlight%s link %s %s]], force and "!" or " default", higroup, link_to)) end @@ -20,11 +20,11 @@ end --- Highlight range between two positions --- ---@param bufnr number of buffer to apply highlighting to ---@param ns namespace to add highlight to ---@param higroup highlight group to use for highlighting ---@param rtype type of range (:help setreg, default charwise) ---@param inclusive boolean indicating whether the range is end-inclusive (default false) +---@param bufnr number of buffer to apply highlighting to +---@param ns namespace to add highlight to +---@param higroup highlight group to use for highlighting +---@param rtype type of range (:help setreg, default charwise) +---@param inclusive boolean indicating whether the range is end-inclusive (default false) function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive) rtype = rtype or 'v' inclusive = inclusive or false diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index ca8db73d43..df48c10881 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -55,21 +55,21 @@ lsp._request_name_to_capability = { -- TODO improve handling of scratch buffers with LSP attached. ---@private +---@private --- Concatenates and writes a list of strings to the Vim error buffer. --- ---@param {...} (List of strings) List to write to the buffer +---@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") end ---@private +---@private --- Returns the buffer number for the given {bufnr}. --- ---@param bufnr (number) Buffer number to resolve. Defaults to the current +---@param bufnr (number) Buffer number to resolve. Defaults to the current ---buffer if not given. ---@returns bufnr (number) Number of requested buffer +---@returns bufnr (number) Number of requested buffer local function resolve_bufnr(bufnr) validate { bufnr = { bufnr, 'n', true } } if bufnr == nil or bufnr == 0 then @@ -78,21 +78,21 @@ local function resolve_bufnr(bufnr) return bufnr end ---@private +---@private --- Called by the client when trying to call a method that's not --- supported in any of the servers registered for the current buffer. ---@param method (string) name of the method +---@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) log.warn(msg) return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg) end ---@private +---@private --- Checks whether a given path is a directory. --- ---@param filename (string) path to check ---@returns true if {filename} exists and is a directory, false otherwise +---@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'}} local stat = uv.fs_stat(filename) @@ -108,10 +108,10 @@ local valid_encodings = { } local client_index = 0 ---@private +---@private --- Returns a new, unused client id. --- ---@returns (number) client id +---@returns (number) client id local function next_client_id() client_index = client_index + 1 return client_index @@ -124,11 +124,11 @@ local uninitialized_clients = {} -- Tracks all buffers attached to a client. local all_client_active_buffers = {} ---@private +---@private --- Invokes a function for each LSP client attached to the buffer {bufnr}. --- ---@param bufnr (Number) of buffer ---@param fn (function({client}, {client_id}, {bufnr}) Function to run on +---@param bufnr (Number) of buffer +---@param fn (function({client}, {client_id}, {bufnr}) Function to run on ---each client attached to that buffer. local function for_each_buffer_client(bufnr, fn) validate { @@ -154,11 +154,11 @@ lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_rever ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1; }) ---@private +---@private --- Normalizes {encoding} to valid LSP encoding names. --- ---@param encoding (string) Encoding to normalize ---@returns (string) normalized encoding name +---@param encoding (string) Encoding to normalize +---@returns (string) normalized encoding name local function validate_encoding(encoding) validate { encoding = { encoding, 's' }; @@ -167,13 +167,13 @@ local function validate_encoding(encoding) or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding)) end ---@internal +---@internal --- Parses a command invocation into the command itself and its args. If there --- are no arguments, an empty table is returned as the second argument. --- ---@param input (List) ---@returns (string) the command ---@returns (list of strings) its arguments +---@param input (List) +---@returns (string) the command +---@returns (list of strings) its arguments function lsp._cmd_parts(input) vim.validate{cmd={ input, @@ -192,12 +192,12 @@ function lsp._cmd_parts(input) return cmd, cmd_args end ---@private +---@private --- Augments a validator function with support for optional (nil) values. --- ---@param fn (function(v)) The original validator function; should return a +---@param fn (function(v)) The original validator function; should return a ---bool. ---@returns (function(v)) The augmented function. Also returns true if {v} is +---@returns (function(v)) The augmented function. Also returns true if {v} is ---`nil`. local function optional_validator(fn) return function(v) @@ -205,14 +205,14 @@ local function optional_validator(fn) end end ---@private +---@private --- Validates a client configuration as given to |vim.lsp.start_client()|. --- ---@param config (table) ---@returns (table) "Cleaned" config, containing only the command, its +---@param config (table) +---@returns (table) "Cleaned" config, containing only the command, its ---arguments, and a valid encoding. --- ---@see |vim.lsp.start_client()| +---@see |vim.lsp.start_client()| local function validate_client_config(config) validate { config = { config, 't' }; @@ -253,11 +253,11 @@ local function validate_client_config(config) } end ---@private +---@private --- Returns full text of buffer {bufnr} as a string. --- ---@param bufnr (number) Buffer handle, or 0 for current. ---@returns Buffer text as string. +---@param bufnr (number) Buffer handle, or 0 for current. +---@returns Buffer text as string. local function buf_get_full_text(bufnr) local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n') if nvim_buf_get_option(bufnr, 'eol') then @@ -266,14 +266,14 @@ local function buf_get_full_text(bufnr) return text end ---@private +---@private --- Memoizes a function. On first run, the function return value is saved and --- immediately returned on subsequent runs. If the function returns a multival, --- only the first returned value will be memoized and returned. The function will only be run once, --- even if it has side-effects. --- ---@param fn (function) Function to run ---@returns (function) Memoized function +---@param fn (function) Function to run +---@returns (function) Memoized function local function once(fn) local value local ran = false @@ -426,11 +426,11 @@ do end ---@private +---@private --- Default handler for the 'textDocument/didOpen' LSP notification. --- ---@param bufnr (Number) Number of the buffer, or 0 for current ---@param client Client object +---@param bufnr (Number) Number of the buffer, or 0 for current +---@param client Client object local function text_document_did_open_handler(bufnr, client) changetracking.init(client, bufnr) if not client.resolved_capabilities.text_document_open_close then @@ -548,16 +548,16 @@ end --- --- The following parameters describe fields in the {config} table. --- ---@param root_dir: (string) Directory where the LSP server will base +---@param root_dir: (string) Directory where the LSP server will base --- its rootUri on initialization. --- ---@param cmd: (required, string or list treated like |jobstart()|) Base command +---@param cmd: (required, string or list treated like |jobstart()|) Base command --- that initiates the LSP client. --- ---@param cmd_cwd: (string, default=|getcwd()|) Directory to launch +---@param cmd_cwd: (string, default=|getcwd()|) Directory to launch --- the `cmd` process. Not related to `root_dir`. --- ---@param cmd_env: (table) Environment flags to pass to the LSP on +---@param cmd_env: (table) Environment flags to pass to the LSP on --- spawn. Can be specified using keys like a map or as a list with `k=v` --- pairs or both. Non-string values are coerced to string. --- Example: @@ -565,7 +565,7 @@ end --- { "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; } --- </pre> --- ---@param capabilities Map overriding the default capabilities defined by +---@param capabilities Map overriding the default capabilities defined by --- |vim.lsp.protocol.make_client_capabilities()|, passed to the language --- server on initialization. Hint: use make_client_capabilities() and modify --- its result. @@ -573,41 +573,41 @@ end --- `{[vim.type_idx]=vim.types.dictionary}`, else it will be encoded as an --- array. --- ---@param handlers Map of language server method names to |lsp-handler| +---@param handlers Map of language server method names to |lsp-handler| --- ---@param settings Map with language server specific settings. These are +---@param settings Map with language server specific settings. These are --- returned to the language server if requested via `workspace/configuration`. --- Keys are case-sensitive. --- ---@param init_options Values to pass in the initialization request +---@param init_options Values to pass in the initialization request --- as `initializationOptions`. See `initialize` in the LSP spec. --- ---@param name (string, default=client-id) Name in log messages. +---@param name (string, default=client-id) Name in log messages. -- ---@param workspace_folders (table) List of workspace folders passed to the +---@param workspace_folders (table) List of workspace folders passed to the --- language server. Defaults to root_dir if not set. See `workspaceFolders` in --- the LSP spec --- ---@param get_language_id function(bufnr, filetype) -> language ID as string. +---@param get_language_id function(bufnr, filetype) -> language ID as string. --- Defaults to the filetype. --- ---@param offset_encoding (default="utf-16") One of "utf-8", "utf-16", +---@param offset_encoding (default="utf-16") One of "utf-8", "utf-16", --- or "utf-32" which is the encoding that the LSP server expects. Client does --- not verify this is correct. --- ---@param on_error Callback with parameters (code, ...), invoked +---@param on_error Callback with parameters (code, ...), invoked --- when the client operation throws an error. `code` is a number describing --- the error. Other arguments may be passed depending on the error kind. See --- |vim.lsp.client_errors| for possible errors. --- Use `vim.lsp.client_errors[code]` to get human-friendly name. --- ---@param before_init Callback with parameters (initialize_params, config) +---@param before_init Callback with parameters (initialize_params, config) --- invoked before the LSP "initialize" phase, where `params` contains the --- parameters being sent to the server and `config` is the config that was --- passed to |vim.lsp.start_client()|. You can use this to modify parameters before --- they are sent. --- ---@param on_init Callback (client, initialize_result) invoked after LSP +---@param on_init Callback (client, initialize_result) invoked after LSP --- "initialize", where `result` is a table of `capabilities` and anything else --- the server may send. For example, clangd sends --- `initialize_result.offsetEncoding` if `capabilities.offsetEncoding` was @@ -617,24 +617,24 @@ end --- `workspace/didChangeConfiguration` notification should be sent --- to the server during on_init. --- ---@param on_exit Callback (code, signal, client_id) invoked on client +---@param on_exit Callback (code, signal, client_id) invoked on client --- exit. --- - code: exit code of the process --- - signal: number describing the signal used to terminate (if any) --- - client_id: client handle --- ---@param on_attach Callback (client, bufnr) invoked when client +---@param on_attach Callback (client, bufnr) invoked when client --- attaches to a buffer. --- ---@param trace: "off" | "messages" | "verbose" | nil passed directly to the language +---@param trace: "off" | "messages" | "verbose" | nil passed directly to the language --- server in the initialize request. Invalid/empty values will default to "off" ---@param flags: A table with flags for the client. The current (experimental) flags are: +---@param flags: A table with flags for the client. The current (experimental) flags are: --- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits --- - debounce_text_changes (number, default nil): Debounce didChange --- notifications to the server by the given number in milliseconds. No debounce --- occurs if nil --- ---@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be +---@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be --- fully initialized. Use `on_init` to do any actions once --- the client has been initialized. function lsp.start_client(config) @@ -657,22 +657,22 @@ function lsp.start_client(config) local dispatch = {} - --@private + ---@private --- Returns the handler associated with an LSP method. --- Returns the default handler if the user hasn't set a custom one. --- - --@param method (string) LSP method name - --@returns (fn) The handler for the given method, if defined, or the default from |vim.lsp.handlers| + ---@param method (string) LSP method name + ---@returns (fn) The handler for the given method, if defined, or the default from |vim.lsp.handlers| local function resolve_handler(method) return handlers[method] or default_handlers[method] end - --@private + ---@private --- Handles a notification sent by an LSP server by invoking the --- corresponding handler. --- - --@param method (string) LSP method name - --@param params (table) The parameters for that method. + ---@param method (string) LSP method name + ---@param params (table) The parameters for that method. function dispatch.notification(method, params) local _ = log.debug() and log.debug('notification', method, params) local handler = resolve_handler(method) @@ -682,11 +682,11 @@ function lsp.start_client(config) end end - --@private + ---@private --- Handles a request from an LSP server by invoking the corresponding handler. --- - --@param method (string) LSP method name - --@param params (table) The parameters for that method + ---@param method (string) LSP method name + ---@param params (table) The parameters for that method function dispatch.server_request(method, params) local _ = log.debug() and log.debug('server_request', method, params) local handler = resolve_handler(method) @@ -698,12 +698,12 @@ function lsp.start_client(config) return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound) end - --@private + ---@private --- Invoked when the client operation throws an error. --- - --@param code (number) Error code - --@param err (...) Other arguments may be passed depending on the error kind - --@see |vim.lsp.client_errors| for possible errors. Use + ---@param code (number) Error code + ---@param err (...) Other arguments may be passed depending on the error kind + ---@see |vim.lsp.client_errors| for possible errors. Use ---`vim.lsp.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 }) @@ -717,11 +717,11 @@ function lsp.start_client(config) end end - --@private + ---@private --- Invoked on client exit. --- - --@param code (number) exit code of the process - --@param signal (number) the signal used to terminate (if any) + ---@param code (number) exit code of the process + ---@param signal (number) the signal used to terminate (if any) function dispatch.on_exit(code, signal) active_clients[client_id] = nil uninitialized_clients[client_id] = nil @@ -766,7 +766,7 @@ function lsp.start_client(config) -- Store the uninitialized_clients for cleanup in case we exit before initialize finishes. uninitialized_clients[client_id] = client; - --@private + ---@private local function initialize() local valid_traces = { off = 'off'; messages = 'messages'; verbose = 'verbose'; @@ -869,23 +869,23 @@ function lsp.start_client(config) end) end - --@private + ---@private --- Sends a request to the server. --- --- This is a thin wrapper around {client.rpc.request} with some additional --- checks for capabilities and handler availability. --- - --@param method (string) LSP method name. - --@param params (table) LSP request params. - --@param handler (function, optional) Response |lsp-handler| for this method. - --@param bufnr (number) Buffer handle (0 for current). - --@returns ({status}, [request_id]): {status} is a bool indicating + ---@param method (string) LSP method name. + ---@param params (table) LSP request params. + ---@param handler (function, optional) Response |lsp-handler| for this method. + ---@param bufnr (number) Buffer handle (0 for current). + ---@returns ({status}, [request_id]): {status} is a bool indicating ---whether the request was successful. If it is `false`, then it will ---always be `false` (the client has shutdown). If it was ---successful, then it will return {request_id} as the ---second result. You can use this with `client.cancel_request(request_id)` ---to cancel the-request. - --@see |vim.lsp.buf_request()| + ---@see |vim.lsp.buf_request()| function client.request(method, params, handler, bufnr) if not handler then handler = resolve_handler(method) @@ -900,21 +900,21 @@ function lsp.start_client(config) end) end - --@private + ---@private --- Sends a request to the server and synchronously waits for the response. --- --- This is a wrapper around {client.request} --- - --@param method (string) LSP method name. - --@param params (table) LSP request params. - --@param timeout_ms (number, optional, default=1000) Maximum time in + ---@param method (string) LSP method name. + ---@param params (table) LSP request params. + ---@param timeout_ms (number, optional, default=1000) Maximum time in ---milliseconds to wait for a result. - --@param bufnr (number) Buffer handle (0 for current). - --@returns { err=err, result=result }, a dictionary, where `err` and `result` come from the |lsp-handler|. + ---@param bufnr (number) Buffer handle (0 for current). + ---@returns { err=err, result=result }, a dictionary, where `err` and `result` come from the |lsp-handler|. ---On timeout, cancel or error, returns `(nil, err)` where `err` is a ---string describing the failure reason. If the request was unsuccessful ---returns `nil`. - --@see |vim.lsp.buf_request_sync()| + ---@see |vim.lsp.buf_request_sync()| function client.request_sync(method, params, timeout_ms, bufnr) local request_result = nil local function _sync_handler(err, _, result) @@ -936,25 +936,25 @@ function lsp.start_client(config) return request_result end - --@private + ---@private --- Sends a notification to an LSP server. --- - --@param method (string) LSP method name. - --@param params (optional, table) LSP request params. - --@param bufnr (number) Buffer handle, or 0 for current. - --@returns {status} (bool) true if the notification was successful. + ---@param method (string) LSP method name. + ---@param params (optional, table) LSP request params. + ---@param bufnr (number) Buffer handle, or 0 for current. + ---@returns {status} (bool) true if the notification was successful. ---If it is false, then it will always be false ---(the client has shutdown). function client.notify(...) return rpc.notify(...) end - --@private + ---@private --- Cancels a request with a given request id. --- - --@param id (number) id of request to cancel - --@returns true if any client returns true; false otherwise - --@see |vim.lsp.client.notify()| + ---@param id (number) id of request to cancel + ---@returns true if any client returns true; false otherwise + ---@see |vim.lsp.client.notify()| function client.cancel_request(id) validate{id = {id, 'n'}} return rpc.notify("$/cancelRequest", { id = id }) @@ -963,14 +963,14 @@ function lsp.start_client(config) -- Track this so that we can escalate automatically if we've alredy tried a -- graceful shutdown local graceful_shutdown_failed = false - --@private + ---@private --- Stops a client, optionally with force. --- ---By default, it will just ask the - server to shutdown without force. If --- you request to stop a client which has previously been requested to --- shutdown, it will automatically escalate and force shutdown. --- - --@param force (bool, optional) + ---@param force (bool, optional) function client.stop(force) lsp.diagnostic.reset(client_id, all_buffer_active_clients) @@ -1000,18 +1000,18 @@ function lsp.start_client(config) end) end - --@private + ---@private --- Checks whether a client is stopped. --- - --@returns (bool) true if client is stopped or in the process of being + ---@returns (bool) true if client is stopped or in the process of being ---stopped; false otherwise function client.is_stopped() return rpc.handle:is_closing() end - --@private + ---@private --- Runs the on_attach function from the client's config if it was defined. - --@param bufnr (number) Buffer number + ---@param bufnr (number) Buffer number function client._on_attach(bufnr) text_document_did_open_handler(bufnr, client) if config.on_attach then @@ -1025,8 +1025,8 @@ function lsp.start_client(config) return client_id end ---@private ---@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size) +---@private +---@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size) --- Notify all attached clients that a buffer has changed. local text_document_did_change_handler do @@ -1076,8 +1076,8 @@ end --- --- Without calling this, the server won't be notified of changes to a buffer. --- ---- @param bufnr (number) Buffer handle, or 0 for current ---- @param client_id (number) Client id +---@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}; @@ -1158,17 +1158,17 @@ end --- Gets a client by id, or nil if the id is invalid. --- The returned client may not yet be fully initialized. -- ---@param client_id client id number +---@param client_id client id number --- ---@returns |vim.lsp.client| object, or nil +---@returns |vim.lsp.client| object, or nil function lsp.get_client_by_id(client_id) return active_clients[client_id] or uninitialized_clients[client_id] end --- Returns list of buffers attached to client_id. -- ---@param client_id client id ---@returns list of buffer ids +---@param client_id client id +---@returns list of buffer ids function lsp.get_buffers_by_client_id(client_id) local active_client_buffers = all_client_active_buffers[client_id] if active_client_buffers then @@ -1190,8 +1190,8 @@ end --- By default asks the server to shutdown, unless stop was requested --- already for this client, then force-shutdown is attempted. --- ---@param client_id client id or |vim.lsp.client| object, or list thereof ---@param force boolean (optional) shutdown forcefully +---@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} for _, id in ipairs(ids) do @@ -1207,7 +1207,7 @@ end --- Gets all active clients. --- ---@returns Table of |vim.lsp.client| objects +---@returns Table of |vim.lsp.client| objects function lsp.get_active_clients() return vim.tbl_values(active_clients) end @@ -1238,13 +1238,13 @@ nvim_command("autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()") --- Sends an async request for all active clients attached to the --- buffer. --- ---@param bufnr (number) Buffer handle, or 0 for current. ---@param method (string) LSP method name ---@param params (optional, table) Parameters to send to the server ---@param handler (optional, function) See |lsp-handler| +---@param bufnr (number) Buffer handle, or 0 for current. +---@param method (string) LSP method name +---@param params (optional, table) Parameters to send to the server +---@param handler (optional, function) See |lsp-handler| -- If nil, follows resolution strategy defined in |lsp-handler-configuration| -- ---@returns 2-tuple: +---@returns 2-tuple: --- - Map of client-id:request-id pairs for all successful requests. --- - Function which can be used to cancel all the requests. You could instead --- iterate all clients and call their `cancel_request()` methods. @@ -1296,14 +1296,14 @@ end ---Parameters are the same as |vim.lsp.buf_request()| but the return result and callback are ---different. --- ---@param bufnr (number) Buffer handle, or 0 for current. ---@param method (string) LSP method name ---@param params (optional, table) Parameters to send to the server ---@param callback (function) The callback to call when all requests are finished. +---@param bufnr (number) Buffer handle, or 0 for current. +---@param method (string) LSP method name +---@param params (optional, table) Parameters to send to the server +---@param callback (function) The callback to call when all requests are finished. -- Unlike `buf_request`, this will collect all the responses from each server instead of handling them. -- A map of client_id:request_result will be provided to the callback -- ---@returns (function) A function that will cancel all requests which is the same as the one returned from `buf_request`. +---@returns (function) A function that will cancel all requests which is the same as the one returned from `buf_request`. function lsp.buf_request_all(bufnr, method, params, callback) local request_results = {} local result_count = 0 @@ -1337,13 +1337,13 @@ end --- Parameters are the same as |vim.lsp.buf_request()| but the return result is --- different. Wait maximum of {timeout_ms} (default 1000) ms. --- ---@param bufnr (number) Buffer handle, or 0 for current. ---@param method (string) LSP method name ---@param params (optional, table) Parameters to send to the server ---@param timeout_ms (optional, number, default=1000) Maximum time in +---@param bufnr (number) Buffer handle, or 0 for current. +---@param method (string) LSP method name +---@param params (optional, table) Parameters to send to the server +---@param timeout_ms (optional, number, default=1000) Maximum time in --- milliseconds to wait for a result. --- ---@returns Map of client_id:request_result. On timeout, cancel or error, +---@returns Map of client_id:request_result. On timeout, cancel or error, --- returns `(nil, err)` where `err` is a string describing the failure --- reason. function lsp.buf_request_sync(bufnr, method, params, timeout_ms) @@ -1366,11 +1366,11 @@ function lsp.buf_request_sync(bufnr, method, params, timeout_ms) end --- Send a notification to a server ---@param bufnr [number] (optional): The number of the buffer ---@param method [string]: Name of the request method ---@param params [string]: Arguments to send to the server +---@param bufnr [number] (optional): The number of the buffer +---@param method [string]: Name of the request method +---@param params [string]: Arguments to send to the server --- ---@returns true if any client returns true; false otherwise +---@returns true if any client returns true; false otherwise function lsp.buf_notify(bufnr, method, params) validate { bufnr = { bufnr, 'n', true }; @@ -1385,14 +1385,14 @@ end --- Implements 'omnifunc' compatible LSP completion. --- ---@see |complete-functions| ---@see |complete-items| ---@see |CompleteDone| +---@see |complete-functions| +---@see |complete-items| +---@see |CompleteDone| --- ---@param findstart 0 or 1, decides behavior ---@param base If findstart=0, text to match against +---@param findstart 0 or 1, decides behavior +---@param base If findstart=0, text to match against --- ---@returns (number) Decided by `findstart`: +---@returns (number) Decided by `findstart`: --- - 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) @@ -1438,8 +1438,8 @@ end ---Checks whether a client is stopped. --- ---@param client_id (Number) ---@returns true if client is stopped, false otherwise. +---@param client_id (Number) +---@returns true if client is stopped, false otherwise. function lsp.client_is_stopped(client_id) return active_clients[client_id] == nil end @@ -1447,7 +1447,7 @@ end --- Gets a map of client_id:client pairs for the given buffer, where each value --- is a |vim.lsp.client| object. --- ---@param bufnr (optional, number): Buffer handle, or 0 for current +---@param bufnr (optional, number): Buffer handle, or 0 for current function lsp.buf_get_clients(bufnr) bufnr = resolve_bufnr(bufnr) local result = {} @@ -1472,9 +1472,9 @@ lsp.log_levels = log.levels --- --- Use `lsp.log_levels` for reverse lookup. --- ---@see |vim.lsp.log_levels| +---@see |vim.lsp.log_levels| --- ---@param level [number|string] the case insensitive level name or number +---@param level [number|string] the case insensitive level name or number function lsp.set_log_level(level) if type(level) == 'string' or type(level) == 'number' then log.set_level(level) @@ -1484,7 +1484,7 @@ function lsp.set_log_level(level) end --- Gets the path of the logfile used by the LSP client. ---@returns (String) Path to logfile. +---@returns (String) Path to logfile. function lsp.get_log_path() return log.get_filename() end @@ -1495,8 +1495,8 @@ function lsp.for_each_buffer_client(bufnr, fn) end --- Function to manage overriding defaults for LSP handlers. ---@param handler (function) See |lsp-handler| ---@param override_config (table) Table containing the keys to override behavior of the {handler} +---@param handler (function) See |lsp-handler| +---@param override_config (table) Table containing the keys to override behavior of the {handler} function lsp.with(handler, override_config) return function(err, method, params, client_id, bufnr, config) return handler(err, method, params, client_id, bufnr, vim.tbl_deep_extend("force", config or {}, override_config)) diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua index 29f8d6c3bc..250af0a0a7 100644 --- a/runtime/lua/vim/lsp/buf.lua +++ b/runtime/lua/vim/lsp/buf.lua @@ -5,7 +5,7 @@ local util = require 'vim.lsp.util' local M = {} ---@private +---@private --- Returns nil if {status} is false or nil, otherwise returns the rest of the --- arguments. local function ok_or_nil(status, ...) @@ -13,31 +13,31 @@ local function ok_or_nil(status, ...) return ... end ---@private +---@private --- Swallows errors. --- ---@param fn Function to run ---@param ... Function arguments ---@returns Result of `fn(...)` if there are no errors, otherwise nil. +---@param fn Function to run +---@param ... Function arguments +---@returns Result of `fn(...)` if there are no errors, otherwise nil. --- Returns nil if errors occur during {fn}, otherwise returns local function npcall(fn, ...) return ok_or_nil(pcall(fn, ...)) end ---@private +---@private --- Sends an async request to all active clients attached to the current --- buffer. --- ---@param method (string) LSP method name ---@param params (optional, table) Parameters to send to the server ---@param handler (optional, functionnil) See |lsp-handler|. Follows |lsp-handler-resolution| +---@param method (string) LSP method name +---@param params (optional, table) Parameters to send to the server +---@param handler (optional, functionnil) See |lsp-handler|. Follows |lsp-handler-resolution| -- ---@returns 2-tuple: +---@returns 2-tuple: --- - Map of client-id:request-id pairs for all successful requests. --- - Function which can be used to cancel all the requests. You could instead --- iterate all clients and call their `cancel_request()` methods. --- ---@see |vim.lsp.buf_request()| +---@see |vim.lsp.buf_request()| local function request(method, params, handler) validate { method = {method, 's'}; @@ -49,7 +49,7 @@ end --- Checks whether the language servers attached to the current buffer are --- ready. --- ---@returns `true` if server responds. +---@returns `true` if server responds. function M.server_ready() return not not vim.lsp.buf_notify(0, "window/progress", {}) end @@ -62,7 +62,7 @@ function M.hover() end --- Jumps to the declaration of the symbol under the cursor. ---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead. +---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead. --- function M.declaration() local params = util.make_position_params() @@ -100,22 +100,22 @@ end --- Retrieves the completion items at the current cursor position. Can only be --- called in Insert mode. --- ---@param context (context support not yet implemented) Additional information +---@param context (context support not yet implemented) Additional information --- about the context in which a completion was triggered (how it was triggered, --- and by which trigger character, if applicable) --- ---@see |vim.lsp.protocol.constants.CompletionTriggerKind| +---@see |vim.lsp.protocol.constants.CompletionTriggerKind| function M.completion(context) local params = util.make_position_params() params.context = context return request('textDocument/completion', params) end ---@private +---@private --- If there is more than one client that supports the given method, --- asks the user to select one. -- ---@returns The client that the user selected or nil +---@returns The client that the user selected or nil local function select_client(method) local clients = vim.tbl_values(vim.lsp.buf_get_clients()); clients = vim.tbl_filter(function (client) @@ -146,11 +146,11 @@ end --- Formats the current buffer. --- ---@param options (optional, table) Can be used to specify FormattingOptions. +---@param options (optional, table) Can be used to specify FormattingOptions. --- Some unspecified options will be automatically derived from the current --- Neovim options. -- ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting +---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting function M.formatting(options) local client = select_client("textDocument/formatting") if client == nil then return end @@ -168,9 +168,9 @@ end --- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]] --- </pre> --- ---@param options Table with valid `FormattingOptions` entries ---@param timeout_ms (number) Request timeout ---@see |vim.lsp.buf.formatting_seq_sync| +---@param options Table with valid `FormattingOptions` entries +---@param timeout_ms (number) Request timeout +---@see |vim.lsp.buf.formatting_seq_sync| function M.formatting_sync(options, timeout_ms) local client = select_client("textDocument/formatting") if client == nil then return end @@ -195,9 +195,9 @@ end --- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_seq_sync()]] --- </pre> --- ---@param options (optional, table) `FormattingOptions` entries ---@param timeout_ms (optional, number) Request timeout ---@param order (optional, table) List of client names. Formatting is requested from clients +---@param options (optional, table) `FormattingOptions` entries +---@param timeout_ms (optional, number) Request timeout +---@param order (optional, table) List of client names. Formatting is requested from clients ---in the following order: first all clients that are not in the `order` list, then ---the remaining clients in the order as they occur in the `order` list. function M.formatting_seq_sync(options, timeout_ms, order) @@ -230,10 +230,10 @@ end --- Formats a given range. --- ---@param options Table with valid `FormattingOptions` entries. ---@param start_pos ({number, number}, optional) mark-indexed position. +---@param options Table with valid `FormattingOptions` entries. +---@param start_pos ({number, number}, optional) mark-indexed position. ---Defaults to the start of the last visual selection. ---@param end_pos ({number, number}, optional) mark-indexed position. +---@param end_pos ({number, number}, optional) mark-indexed position. ---Defaults to the end of the last visual selection. function M.range_formatting(options, start_pos, end_pos) local client = select_client("textDocument/rangeFormatting") @@ -246,7 +246,7 @@ end --- Renames all references to the symbol under the cursor. --- ---@param new_name (string) If not provided, the user will be prompted for a new +---@param new_name (string) If not provided, the user will be prompted for a new ---name using |input()|. function M.rename(new_name) -- TODO(ashkan) use prepareRename @@ -260,8 +260,8 @@ end --- Lists all the references to the symbol under the cursor in the quickfix window. --- ---@param context (table) Context for the request ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references +---@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 } } local params = util.make_position_params() @@ -279,7 +279,7 @@ function M.document_symbol() request('textDocument/documentSymbol', params) end ---@private +---@private local function pick_call_hierarchy_item(call_hierarchy_items) if not call_hierarchy_items then return end if #call_hierarchy_items == 1 then @@ -297,7 +297,7 @@ local function pick_call_hierarchy_item(call_hierarchy_items) return choice end ---@private +---@private local function call_hierarchy(method) local params = util.make_position_params() request('textDocument/prepareCallHierarchy', params, function(err, _, result) @@ -389,7 +389,7 @@ end --- call, the user is prompted to enter a string on the command line. An empty --- string means no filtering is done. --- ---@param query (string, optional) +---@param query (string, optional) function M.workspace_symbol(query) query = query or npcall(vfn.input, "Query: ") local params = {query = query} @@ -424,7 +424,7 @@ end --- Requests code actions from all clients and calls the handler exactly once --- with all aggregated results ---@private +---@private local function code_action_request(params) local bufnr = vim.api.nvim_get_current_buf() local method = 'textDocument/codeAction' @@ -439,9 +439,9 @@ end --- Selects a code action from the input list that is available at the current --- cursor position. --- ---@param context: (table, optional) Valid `CodeActionContext` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction +--- +---@param context: (table, optional) Valid `CodeActionContext` object +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction function M.code_action(context) validate { context = { context, 't', true } } context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() } @@ -452,10 +452,10 @@ end --- Performs |vim.lsp.buf.code_action()| for a given range. --- ---@param context: (table, optional) Valid `CodeActionContext` object ---@param start_pos ({number, number}, optional) mark-indexed position. +---@param context: (table, optional) Valid `CodeActionContext` object +---@param start_pos ({number, number}, optional) mark-indexed position. ---Defaults to the start of the last visual selection. ---@param end_pos ({number, number}, optional) mark-indexed position. +---@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 } } @@ -467,8 +467,8 @@ end --- Executes an LSP server command. --- ---@param command A valid `ExecuteCommandParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand +---@param command A valid `ExecuteCommandParams` object +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand function M.execute_command(command) validate { command = { command.command, 's' }, diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua index fe581e42ad..ca5a44077e 100644 --- a/runtime/lua/vim/lsp/codelens.lua +++ b/runtime/lua/vim/lsp/codelens.lua @@ -22,11 +22,11 @@ local namespaces = setmetatable({}, { end; }) ---@private +---@private M.__namespaces = namespaces ---@private +---@private local function execute_lens(lens, bufnr, client_id) local line = lens.range.start.line api.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1) @@ -151,7 +151,7 @@ function M.save(lenses, bufnr, client_id) end ---@private +---@private local function resolve_lenses(lenses, bufnr, client_id, callback) lenses = lenses or {} local num_lens = vim.tbl_count(lenses) @@ -160,7 +160,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback) return end - --@private + ---@private local function countdown() num_lens = num_lens - 1 if num_lens == 0 then diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index a244e3d6a4..45aeb17465 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -8,7 +8,7 @@ local util = require('vim.lsp.util') local if_nil = vim.F.if_nil ---@class DiagnosticSeverity +---@class DiagnosticSeverity local DiagnosticSeverity = protocol.DiagnosticSeverity local to_severity = function(severity) @@ -46,14 +46,14 @@ end ---@brief lsp-diagnostic --- ---@class Diagnostic ---@field range Range ---@field message string ---@field severity DiagnosticSeverity|nil ---@field code number | string ---@field source string ---@field tags DiagnosticTag[] ---@field relatedInformation DiagnosticRelatedInformation[] +---@class Diagnostic +---@field range Range +---@field message string +---@field severity DiagnosticSeverity|nil +---@field code number | string +---@field source string +---@field tags DiagnosticTag[] +---@field relatedInformation DiagnosticRelatedInformation[] local M = {} @@ -167,12 +167,12 @@ end local _diagnostic_namespaces = _make_namespace_table("vim_lsp_diagnostics", true) local _sign_namespaces = _make_namespace_table("vim_lsp_signs", false) ---@private +---@private function M._get_diagnostic_namespace(client_id) return _diagnostic_namespaces[client_id] end ---@private +---@private function M._get_sign_namespace(client_id) return _sign_namespaces[client_id] end @@ -255,7 +255,7 @@ local _diagnostic_counts = function(diagnostics) return counts end ---@private +---@private --- Set the different diagnostic cache after `textDocument/publishDiagnostics` ---@param diagnostics Diagnostic[] ---@param bufnr number @@ -291,7 +291,7 @@ local function set_diagnostic_cache(diagnostics, bufnr, client_id) end ---@private +---@private --- Clear the cached diagnostics ---@param bufnr number ---@param client_id number @@ -512,7 +512,7 @@ local _next_diagnostic = function(position, search_forward, bufnr, opts, client_ end end ---@private +---@private --- Helper function to return a position from a diagnostic --- ---@return table {row, col} @@ -527,7 +527,7 @@ local function _diagnostic_pos(opts, diagnostic) return to_position(diagnostic.range.start, bufnr) end ---@private +---@private -- Move to the diagnostic position local function _diagnostic_move_pos(name, opts, pos) opts = opts or {} @@ -858,7 +858,7 @@ end --- Callback scheduled for after leaving insert mode --- --- Used to handle ---@private +---@private function M._execute_scheduled_display(bufnr, client_id) local args = _bufs_waiting_to_update[bufnr][client_id] if not args then @@ -924,20 +924,20 @@ end -- Diagnostic Private Highlight Utilies {{{ --- Get the severity highlight name ---@private +---@private function M._get_severity_highlight_name(severity) return virtual_text_highlight_map[severity] end --- Get floating severity highlight name ---@private +---@private function M._get_floating_severity_highlight_name(severity) return floating_highlight_map[severity] end --- This should be called to update the highlights for the LSP client. function M._define_default_signs_and_highlights() - --@private + ---@private local function define_default_sign(name, properties) if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then vim.fn.sign_define(name, properties) @@ -1054,8 +1054,8 @@ function M.on_publish_diagnostics(_, _, params, client_id, _, config) end -- restores the extmarks set by M.display ---- @param last number last line that was changed --- @private +---@param last number last line that was changed +---@private local function restore_extmarks(bufnr, last) for client_id, extmarks in pairs(diagnostic_cache_extmarks[bufnr]) do local ns = M._get_diagnostic_namespace(client_id) @@ -1084,7 +1084,7 @@ local function restore_extmarks(bufnr, last) end -- caches the extmarks set by M.display --- @private +---@private local function save_extmarks(bufnr, client_id) bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr if not diagnostic_attached_buffers[bufnr] then @@ -1101,7 +1101,7 @@ local function save_extmarks(bufnr, client_id) diagnostic_cache_extmarks[bufnr][client_id] = api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {details = true}) end ---@private +---@private --- Display diagnostics for the buffer, given a configuration. function M.display(diagnostics, bufnr, client_id, config) if diagnostic_disabled[bufnr][client_id] then @@ -1187,10 +1187,10 @@ end --- for redrawing diagnostics after making changes in diagnostics --- configuration. |lsp-handler-configuration| --- ---- @param bufnr (optional, number): Buffer handle, defaults to current ---- @param client_id (optional, number): Redraw diagnostics for the given ---- client. The default is to redraw diagnostics for all attached ---- clients. +---@param bufnr (optional, number): Buffer handle, defaults to current +---@param client_id (optional, number): Redraw diagnostics for the given +--- client. The default is to redraw diagnostics for all attached +--- clients. function M.redraw(bufnr, client_id) bufnr = get_bufnr(bufnr) if not client_id then @@ -1410,10 +1410,10 @@ function M.set_loclist(opts) end --- Disable diagnostics for the given buffer and client ---- @param bufnr (optional, number): Buffer handle, defaults to current ---- @param client_id (optional, number): Disable diagnostics for the given ---- client. The default is to disable diagnostics for all attached ---- clients. +---@param bufnr (optional, number): Buffer handle, defaults to current +---@param client_id (optional, number): Disable diagnostics for the given +--- client. The default is to disable diagnostics for all attached +--- clients. -- Note that when diagnostics are disabled for a buffer, the server will still -- send diagnostic information and the client will still process it. The -- diagnostics are simply not displayed to the user. @@ -1429,10 +1429,10 @@ function M.disable(bufnr, client_id) end --- Enable diagnostics for the given buffer and client ---- @param bufnr (optional, number): Buffer handle, defaults to current ---- @param client_id (optional, number): Enable diagnostics for the given ---- client. The default is to enable diagnostics for all attached ---- clients. +---@param bufnr (optional, number): Buffer handle, defaults to current +---@param client_id (optional, number): Enable diagnostics for the given +--- client. The default is to enable diagnostics for all attached +--- clients. function M.enable(bufnr, client_id) if not client_id then return vim.lsp.for_each_buffer_client(bufnr, function(client) diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua index b7f1ea0ab6..befb9fcec3 100644 --- a/runtime/lua/vim/lsp/handlers.lua +++ b/runtime/lua/vim/lsp/handlers.lua @@ -9,9 +9,9 @@ local M = {} -- FIXME: DOC: Expose in vimdocs ---@private +---@private --- Writes to error buffer. ---@param ... (table of strings) Will be concatenated before being written +---@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") @@ -22,7 +22,7 @@ M['workspace/executeCommand'] = function() -- Error handling is done implicitly by wrapping all handlers; see end of this file end ---@private +---@private local function progress_handler(_, _, params, 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) @@ -189,7 +189,7 @@ end ---@private +---@private --- Return a function that converts LSP responses to list items and opens the list --- --- The returned function has an optional {config} parameter that accepts a table @@ -197,8 +197,8 @@ end --- --- loclist: (boolean) use the location list (default is to use the quickfix list) --- ---- @param map_result function `((resp, bufnr) -> list)` to convert the response ---- @param entity name of the resource used in a `not found` error message +---@param map_result function `((resp, bufnr) -> list)` to convert the response +---@param entity name of the resource used in a `not found` error message local function response_to_list(map_result, entity) return function(_, _, result, _, bufnr, config) if not result or vim.tbl_isempty(result) then @@ -289,11 +289,11 @@ end --see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover M['textDocument/hover'] = M.hover ---@private +---@private --- Jumps to a location. Used as a handler for multiple LSP methods. ---@param _ (not used) ---@param method (string) LSP method name ---@param result (table) result of LSP method; a location or a list of locations. +---@param _ (not used) +---@param method (string) LSP method name +---@param result (table) result of LSP method; a location or a list of locations. ---(`textDocument/definition` can return `Location` or `Location[]` local function location_handler(_, method, result) if result == nil or vim.tbl_isempty(result) then @@ -377,13 +377,13 @@ M['textDocument/documentHighlight'] = function(_, _, result, _, bufnr, _) util.buf_highlight_references(bufnr, result) end ---@private +---@private --- --- Displays call hierarchy in the quickfix window. --- ---@param direction `"from"` for incoming calls and `"to"` for outgoing calls ---@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`, ---@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`, +---@param direction `"from"` for incoming calls and `"to"` for outgoing calls +---@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`, +---@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`, local make_call_hierarchy_handler = function(direction) return function(_, _, result) if not result then return end diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua index 73fafb9715..a2d5c3a774 100644 --- a/runtime/lua/vim/lsp/log.lua +++ b/runtime/lua/vim/lsp/log.lua @@ -18,14 +18,14 @@ local log_date_format = "%FT%H:%M:%S%z" do local path_sep = vim.loop.os_uname().version:match("Windows") and "\\" or "/" - --@private + ---@private local function path_join(...) return table.concat(vim.tbl_flatten{...}, path_sep) end local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log') --- Returns the log filename. - --@returns (string) log filename + ---@returns (string) log filename function log.get_filename() return logfilename end @@ -77,7 +77,7 @@ end vim.tbl_add_reverse_lookup(log.levels) --- Sets the current log level. ---@param level (string or number) One of `vim.lsp.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)) @@ -89,8 +89,8 @@ function log.set_level(level) end --- Checks whether the level is sufficient for logging. ---@param level number log level ---@returns (bool) true if would log, false if not +---@param level number log level +---@returns (bool) true if would log, false if not function log.should_log(level) return level >= current_log_level end diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua index 6d02b9ba74..ded8af5773 100644 --- a/runtime/lua/vim/lsp/protocol.lua +++ b/runtime/lua/vim/lsp/protocol.lua @@ -5,14 +5,14 @@ local if_nil = vim.F.if_nil local protocol = {} --[=[ ---@private +---@private --- Useful for interfacing with: --- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md function transform_schema_comments() nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]] nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]] end ---@private +---@private function transform_schema_to_table() transform_schema_comments() nvim.command [[silent! '<,'>s/: \S\+//]] diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua index 4c5f02af9d..eedb708118 100644 --- a/runtime/lua/vim/lsp/rpc.lua +++ b/runtime/lua/vim/lsp/rpc.lua @@ -5,11 +5,11 @@ local protocol = require('vim.lsp.protocol') local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap -- TODO replace with a better implementation. ---@private +---@private --- Encodes to JSON. --- ---@param data (table) Data to encode ---@returns (string) Encoded object +---@param data (table) Data to encode +---@returns (string) Encoded object local function json_encode(data) local status, result = pcall(vim.fn.json_encode, data) if status then @@ -18,11 +18,11 @@ local function json_encode(data) return nil, result end end ---@private +---@private --- Decodes from JSON. --- ---@param data (string) Data to decode ---@returns (table) Decoded JSON object +---@param data (string) Data to decode +---@returns (table) Decoded JSON object local function json_decode(data) local status, result = pcall(vim.fn.json_decode, data) if status then @@ -32,10 +32,10 @@ local function json_decode(data) end end ---@private +---@private --- Checks whether a given path exists and is a directory. ---@param filename (string) path to check ---@returns (bool) +---@param filename (string) path to check +---@returns (bool) local function is_dir(filename) local stat = vim.loop.fs_stat(filename) return stat and stat.type == 'directory' or false @@ -43,7 +43,7 @@ end local NIL = vim.NIL ---@private +---@private local recursive_convert_NIL recursive_convert_NIL = function(v, tbl_processed) if v == NIL then @@ -63,15 +63,15 @@ recursive_convert_NIL = function(v, tbl_processed) return v end ---@private +---@private --- Returns its argument, but converts `vim.NIL` to Lua `nil`. ---@param v (any) Argument ---@returns (any) +---@param v (any) Argument +---@returns (any) local function convert_NIL(v) return recursive_convert_NIL(v, {}) end ---@private +---@private --- Merges current process env with the given env and returns the result as --- a list of "k=v" strings. --- @@ -81,8 +81,8 @@ end --- in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", } --- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", } --- </pre> ---@param env (table) table of environment variable assignments ---@returns (table) list of `"k=v"` strings +---@param env (table) table of environment variable assignments +---@returns (table) list of `"k=v"` strings local function env_merge(env) if env == nil then return env @@ -97,11 +97,11 @@ local function env_merge(env) return final_env end ---@private +---@private --- Embeds the given string into a table and correctly computes `Content-Length`. --- ---@param encoded_message (string) ---@returns (table) table containing encoded message and `Content-Length` attribute +---@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'; @@ -109,11 +109,11 @@ local function format_message_with_content_length(encoded_message) } end ---@private +---@private --- Parses an LSP Message's header --- ---@param header: The header to parse. ---@returns Parsed headers +---@param header: The header to parse. +---@returns Parsed headers local function parse_headers(header) if type(header) ~= 'string' then return nil @@ -141,7 +141,7 @@ end -- case insensitive pattern. local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end) ---@private +---@private --- The actual workhorse. local function request_parser_loop() local buffer = '' -- only for header part @@ -203,8 +203,8 @@ local client_errors = vim.tbl_add_reverse_lookup { --- Constructs an error message from an LSP error object. --- ---@param err (table) The error object ---@returns (string) The formatted error message +---@param err (table) The error object +---@returns (string) The formatted error message local function format_rpc_error(err) validate { err = { err, 't' }; @@ -233,9 +233,9 @@ end --- Creates an RPC response object/table. --- ---@param code RPC error code defined in `vim.lsp.protocol.ErrorCodes` ---@param message (optional) arbitrary message to send to server ---@param data (optional) arbitrary data to send to server +---@param code RPC error code defined in `vim.lsp.protocol.ErrorCodes` +---@param message (optional) arbitrary message to send to server +---@param data (optional) arbitrary data to send to server 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') @@ -250,38 +250,38 @@ end local default_dispatchers = {} ---@private +---@private --- Default dispatcher for notifications sent to an LSP server. --- ---@param method (string) The invoked LSP method ---@param params (table): Parameters for the invoked LSP method +---@param method (string) The invoked LSP method +---@param params (table): Parameters for the invoked LSP method function default_dispatchers.notification(method, params) local _ = log.debug() and log.debug('notification', method, params) end ---@private +---@private --- Default dispatcher for requests sent to an LSP server. --- ---@param method (string) The invoked LSP method ---@param params (table): Parameters for the invoked LSP method ---@returns `nil` and `vim.lsp.protocol.ErrorCodes.MethodNotFound`. +---@param method (string) The invoked LSP method +---@param params (table): Parameters for the invoked LSP method +---@returns `nil` and `vim.lsp.protocol.ErrorCodes.MethodNotFound`. function default_dispatchers.server_request(method, params) local _ = log.debug() and log.debug('server_request', method, params) return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound) end ---@private +---@private --- Default dispatcher for when a client exits. --- ---@param code (number): Exit code ---@param signal (number): Number describing the signal used to terminate (if +---@param code (number): Exit code +---@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 }) end ---@private +---@private --- Default dispatcher for client errors. --- ---@param code (number): Error code ---@param err (any): Details about the error +---@param code (number): Error code +---@param err (any): Details about the error ---any) function default_dispatchers.on_error(code, err) local _ = log.error() and log.error('client_error:', client_errors[code], err) @@ -290,25 +290,25 @@ end --- Starts an LSP server process and create an LSP RPC client object to --- interact with it. --- ---@param cmd (string) Command to start the LSP server. ---@param cmd_args (table) List of additional string arguments to pass to {cmd}. ---@param dispatchers (table, optional) Dispatchers for LSP message types. Valid +---@param cmd (string) Command to start the LSP server. +---@param cmd_args (table) List of additional string arguments to pass to {cmd}. +---@param dispatchers (table, optional) Dispatchers for LSP message types. Valid ---dispatcher names are: --- - `"notification"` --- - `"server_request"` --- - `"on_error"` --- - `"on_exit"` ---@param extra_spawn_params (table, optional) Additional context for the LSP +---@param extra_spawn_params (table, optional) Additional context for the LSP --- server process. May contain: --- - {cwd} (string) Working directory for the LSP server process --- - {env} (table) Additional environment variables for LSP server process ---@returns Client RPC object. +---@returns Client RPC object. --- ---@returns Methods: +---@returns Methods: --- - `notify()` |vim.lsp.rpc.notify()| --- - `request()` |vim.lsp.rpc.request()| --- ---@returns Members: +---@returns Members: --- - {pid} (number) The LSP server's PID. --- - {handle} A handle for low-level interaction with the LSP server process --- |vim.loop|. @@ -358,10 +358,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) local handle, pid do - --@private + ---@private --- Callback for |vim.loop.spawn()| Closes all streams and runs the `on_exit` dispatcher. - --@param code (number) Exit code - --@param signal (number) Signal that was used to terminate (if any) + ---@param code (number) Exit code + ---@param signal (number) Signal that was used to terminate (if any) local function onexit(code, signal) stdin:close() stdout:close() @@ -385,12 +385,12 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end end - --@private + ---@private --- Encodes {payload} into a JSON-RPC message and sends it to the remote --- process. --- - --@param payload (table) Converted into a JSON string, see |json_encode()| - --@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing. + ---@param payload (table) Converted into a JSON string, see |json_encode()| + ---@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", payload) if handle == nil or handle:is_closing() then return false end @@ -406,9 +406,9 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) -- `start()` -- --- Sends a notification to the LSP server. - --@param method (string) The invoked LSP method - --@param params (table): Parameters for the invoked LSP method - --@returns (bool) `true` if notification could be sent, `false` if not + ---@param method (string) The invoked LSP method + ---@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"; @@ -417,7 +417,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) } end - --@private + ---@private --- sends an error object to the remote LSP process. local function send_response(request_id, err, result) return encode_and_send { @@ -433,10 +433,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) -- --- Sends a request to the LSP server and runs {callback} upon response. --- - --@param method (string) The invoked LSP method - --@param params (table) Parameters for the invoked LSP method - --@param callback (function) Callback to invoke - --@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not + ---@param method (string) The invoked LSP method + ---@param params (table) Parameters for the invoked LSP method + ---@param callback (function) Callback to invoke + ---@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not local function request(method, params, callback) validate { callback = { callback, 'f' }; @@ -463,13 +463,13 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end end) - --@private + ---@private local function on_error(errkind, ...) assert(client_errors[errkind]) -- TODO what to do if this fails? pcall(dispatchers.on_error, errkind, ...) end - --@private + ---@private local function pcall_handler(errkind, status, head, ...) if not status then on_error(errkind, head, ...) @@ -477,7 +477,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) end return status, head, ... end - --@private + ---@private local function try_call(errkind, fn, ...) return pcall_handler(errkind, pcall(fn, ...)) end @@ -486,7 +486,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params) -- time and log them. This would require storing the timestamp. I could call -- them with an error then, perhaps. - --@private + ---@private local function handle_body(body) local decoded, err = json_decode(body) if not decoded then diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d682fdc17e..a4b3298fd8 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -40,10 +40,10 @@ local loclist_type_map = { } ---@private --- Check the border given by opts or the default border for the additional --- size it adds to a float. ---@returns size of border in height and width +---@private +--- Check the border given by opts or the default border for the additional +--- size it adds to a float. +---@returns size of border in height and width local function get_border_size(opts) local border = opts and opts.border or default_border local height = 0 @@ -86,7 +86,7 @@ local function get_border_size(opts) return { height = height, width = width } end ---@private +---@private local function split_lines(value) return split(value, '\n', true) end @@ -95,11 +95,11 @@ end --- --- CAUTION: Changes in-place! --- ---@param lines (table) Original list of strings ---@param A (table) Start position; a 2-tuple of {line, col} numbers ---@param B (table) End position; a 2-tuple of {line, col} numbers ---@param new_lines A list of strings to replace the original ---@returns (table) The modified {lines} object +---@param lines (table) Original list of strings +---@param A (table) Start position; a 2-tuple of {line, col} numbers +---@param B (table) End position; a 2-tuple of {line, col} numbers +---@param new_lines A list of strings to replace the original +---@returns (table) The modified {lines} object function M.set_lines(lines, A, B, new_lines) -- 0-indexing to 1-indexing local i_0 = A[1] + 1 @@ -133,7 +133,7 @@ function M.set_lines(lines, A, B, new_lines) return lines end ---@private +---@private local function sort_by_key(fn) return function(a,b) local ka, kb = fn(a), fn(b) @@ -147,12 +147,12 @@ local function sort_by_key(fn) return false end end ---@private +---@private local edit_sort_key = sort_by_key(function(e) return {e.A[1], e.A[2], e.i} end) ---@private +---@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 --- 1-indexed @@ -238,8 +238,8 @@ function M.get_progress_messages() end --- Applies a list of text edits to a buffer. ---@param text_edits (table) list of `TextEdit` objects ---@param buf_nr (number) Buffer id +---@param text_edits (table) list of `TextEdit` objects +---@param buf_nr (number) Buffer id ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit function M.apply_text_edits(text_edits, bufnr) if not next(text_edits) then return end @@ -295,11 +295,11 @@ end -- function M.glob_to_regex(glob) -- end ---@private +---@private --- Finds the first line and column of the difference between old and new lines ---@param old_lines table list of lines ---@param new_lines table list of lines ---@returns (int, int) start_line_idx and start_col_idx of range +---@param old_lines table list of lines +---@param new_lines table list of lines +---@returns (int, int) start_line_idx and start_col_idx of range local function first_difference(old_lines, new_lines, start_line_idx) local line_count = math.min(#old_lines, #new_lines) if line_count == 0 then return 1, 1 end @@ -325,12 +325,12 @@ local function first_difference(old_lines, new_lines, start_line_idx) end ---@private +---@private --- Finds the last line and column of the differences between old and new lines ---@param old_lines table list of lines ---@param new_lines table list of lines ---@param start_char integer First different character idx of range ---@returns (int, int) end_line_idx and end_col_idx of range +---@param old_lines table list of lines +---@param new_lines table list of lines +---@param start_char integer First different character idx of range +---@returns (int, int) end_line_idx and end_col_idx of range local function last_difference(old_lines, new_lines, start_char, end_line_idx) local line_count = math.min(#old_lines, #new_lines) if line_count == 0 then return 0,0 end @@ -369,14 +369,14 @@ local function last_difference(old_lines, new_lines, start_char, end_line_idx) end ---@private +---@private --- Get the text of the range defined by start and end line/column ---@param lines table list of lines ---@param start_char integer First different character idx of range ---@param end_char integer Last different character idx of range ---@param start_line integer First different line idx of range ---@param end_line integer Last different line idx of range ---@returns string text extracted from defined region +---@param lines table list of lines +---@param start_char integer First different character idx of range +---@param end_char integer Last different character idx of range +---@param start_line integer First different line idx of range +---@param end_line integer Last different line idx of range +---@returns string text extracted from defined region local function extract_text(lines, start_line, start_char, end_line, end_char) if start_line == #lines + end_line + 1 then if end_line == 0 then return '' end @@ -396,14 +396,14 @@ local function extract_text(lines, start_line, start_char, end_line, end_char) return result end ---@private +---@private --- Compute the length of the substituted range ---@param lines table list of lines ---@param start_char integer First different character idx of range ---@param end_char integer Last different character idx of range ---@param start_line integer First different line idx of range ---@param end_line integer Last different line idx of range ---@returns (int, int) end_line_idx and end_col_idx of range +---@param lines table list of lines +---@param start_char integer First different character idx of range +---@param end_char integer Last different character idx of range +---@param start_line integer First different line idx of range +---@param end_line integer Last different line idx of range +---@returns (int, int) end_line_idx and end_col_idx of range local function compute_length(lines, start_line, start_char, end_line, end_char) local adj_end_line = #lines + end_line + 1 local adj_end_char @@ -424,12 +424,12 @@ local function compute_length(lines, start_line, start_char, end_line, end_char) end --- Returns the range table for the difference between old and new lines ---@param old_lines table list of lines ---@param new_lines table list of lines ---@param start_line_idx int line to begin search for first difference ---@param end_line_idx int line to begin search for last difference ---@param offset_encoding string encoding requested by language server ---@returns table start_line_idx and start_col_idx of range +---@param old_lines table list of lines +---@param new_lines table list of lines +---@param start_line_idx int line to begin search for first difference +---@param end_line_idx int line to begin search for last difference +---@param offset_encoding string encoding requested by language server +---@returns table start_line_idx and start_col_idx of range function M.compute_diff(old_lines, new_lines, start_line_idx, end_line_idx, offset_encoding) local start_line, start_char = first_difference(old_lines, new_lines, start_line_idx) local end_line, end_char = last_difference(vim.list_slice(old_lines, start_line, #old_lines), @@ -469,9 +469,9 @@ end --- Can be used to extract the completion items from a --- `textDocument/completion` request, which may return one of --- `CompletionItem[]`, `CompletionList` or null. ---@param result (table) The result of a `textDocument/completion` request ---@returns (table) List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion +---@param result (table) The result of a `textDocument/completion` request +---@returns (table) List of completion items +---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) if type(result) == 'table' and result.items then -- result is a `CompletionList` @@ -515,12 +515,12 @@ function M.apply_text_document_edit(text_document_edit, index) M.apply_text_edits(text_document_edit.edits, bufnr) end ---@private +---@private --- Recursively parses snippets in a completion entry. --- ---@param input (string) Snippet text to parse for snippets ---@param inner (bool) Whether this function is being called recursively ---@returns 2-tuple of strings: The first is the parsed result, the second is the +---@param input (string) Snippet text to parse for snippets +---@param inner (bool) Whether this function is being called recursively +---@returns 2-tuple of strings: The first is the parsed result, the second is the ---unparsed rest of the input local function parse_snippet_rec(input, inner) local res = "" @@ -577,28 +577,28 @@ end --- Parses snippets in a completion entry. --- ---@param input (string) unparsed snippet ---@returns (string) parsed snippet +---@param input (string) unparsed snippet +---@returns (string) parsed snippet function M.parse_snippet(input) local res, _ = parse_snippet_rec(input, false) return res end ---@private +---@private --- Sorts by CompletionItem.sortText. --- ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion local function sort_completion_items(items) table.sort(items, function(a, b) return (a.sortText or a.label) < (b.sortText or b.label) end) end ---@private +---@private --- Returns text that should be inserted when selecting completion item. The --- precedence is as follows: textEdit.newText > insertText > label ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +--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 local insert_text_format = protocol.InsertTextFormat[item.insertTextFormat] @@ -618,7 +618,7 @@ local function get_completion_word(item) return item.label end ---@private +---@private --- Some language servers return complementary candidates whose prefixes do not --- match are also returned. So we exclude completion candidates whose prefix --- does not match. @@ -633,9 +633,9 @@ end --- the client must handle it properly even if it receives a value outside the --- specification. --- ---@param completion_item_kind (`vim.lsp.protocol.completionItemKind`) ---@returns (`vim.lsp.protocol.completionItemKind`) ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion +---@param completion_item_kind (`vim.lsp.protocol.completionItemKind`) +---@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" end @@ -643,12 +643,12 @@ end --- Turns the result of a `textDocument/completion` request into vim-compatible --- |complete-items|. --- ---@param result The result of a `textDocument/completion` call, e.g. from +---@param result The result of a `textDocument/completion` call, e.g. from ---|vim.lsp.buf.completion()|, which may be one of `CompletionItem[]`, --- `CompletionList` or `null` ---@param prefix (string) the prefix to filter the completion items ---@returns { matches = complete-items table, incomplete = bool } ---@see |complete-items| +---@param prefix (string) the prefix to filter the completion items +---@returns { matches = complete-items table, incomplete = bool } +---@see |complete-items| function M.text_document_completion_list_to_complete_items(result, prefix) local items = M.extract_completion_items(result) if vim.tbl_isempty(items) then @@ -698,8 +698,8 @@ end --- Rename old_fname to new_fname --- ---@param opts (table) +--- +---@param opts (table) -- overwrite? bool -- ignoreIfExists? bool function M.rename(old_fname, new_fname, opts) @@ -754,8 +754,8 @@ end --- Applies a `WorkspaceEdit`. --- ---@param workspace_edit (table) `WorkspaceEdit` --- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit +---@param workspace_edit (table) `WorkspaceEdit` +--see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit) if workspace_edit.documentChanges then for idx, change in ipairs(workspace_edit.documentChanges) do @@ -794,10 +794,10 @@ end --- window for `textDocument/hover`, for parsing the result of --- `textDocument/signatureHelp`, and potentially others. --- ---@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`) ---@param contents (table, optional, default `{}`) List of strings to extend with converted lines ---@returns {contents}, extended with lines of converted markdown. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover +---@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`) +---@param contents (table, optional, default `{}`) List of strings to extend with converted lines +---@returns {contents}, extended with lines of converted markdown. +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover function M.convert_input_to_markdown_lines(input, contents) contents = contents or {} -- MarkedString variation 1 @@ -844,11 +844,11 @@ end --- Converts `textDocument/SignatureHelp` response to markdown lines. --- ---@param signature_help Response of `textDocument/SignatureHelp` ---@param ft optional filetype that will be use as the `lang` for the label markdown code block ---@param triggers optional list of trigger characters from the lsp server. used to better determine parameter offsets ---@returns list of lines of converted markdown. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp +---@param signature_help Response of `textDocument/SignatureHelp` +---@param ft optional filetype that will be use as the `lang` for the label markdown code block +---@param triggers optional list of trigger characters from the lsp server. used to better determine parameter offsets +---@returns list of lines of converted markdown. +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers) if not signature_help.signatures then return @@ -943,10 +943,10 @@ end --- Creates a table with sensible default options for a floating window. The --- table can be passed to |nvim_open_win()|. --- ---@param width (number) window width (in character cells) ---@param height (number) window height (in character cells) ---@param opts (table, optional) ---@returns (table) Options +---@param width (number) window width (in character cells) +---@param height (number) window height (in character cells) +---@param opts (table, optional) +---@returns (table) Options function M.make_floating_popup_options(width, height, opts) validate { opts = { opts, 't', true }; @@ -997,8 +997,8 @@ end --- Jumps to a location. --- ---@param location (`Location`|`LocationLink`) ---@returns `true` if the jump succeeded +---@param location (`Location`|`LocationLink`) +---@returns `true` if the jump succeeded function M.jump_to_location(location) -- location may be Location or LocationLink local uri = location.uri or location.targetUri @@ -1028,8 +1028,8 @@ end --- - for Location, range is shown (e.g., function definition) --- - for LocationLink, targetRange is shown (e.g., body of function definition) --- ---@param location a single `Location` or `LocationLink` ---@returns (bufnr,winnr) buffer and window number of floating window or nil +---@param location a single `Location` or `LocationLink` +---@returns (bufnr,winnr) buffer and window number of floating window or nil function M.preview_location(location, opts) -- location may be LocationLink or Location (more useful for the former) local uri = location.targetUri or location.uri @@ -1052,7 +1052,7 @@ function M.preview_location(location, opts) return M.open_floating_preview(contents, syntax, opts) end ---@private +---@private local function find_window_by_var(name, value) for _, win in ipairs(api.nvim_list_wins()) do if npcall(api.nvim_win_get_var, win, name) == value then @@ -1088,10 +1088,10 @@ function M._trim(contents, opts) return contents end --- Generates a table mapping markdown code block lang to vim syntax, --- based on g:markdown_fenced_languages --- @return a table of lang -> syntax mappings --- @private +--- Generates a table mapping markdown code block lang to vim syntax, +--- based on g:markdown_fenced_languages +---@return a table of lang -> syntax mappings +---@private local function get_markdown_fences() local fences = {} for _, fence in pairs(vim.g.markdown_fenced_languages or {}) do @@ -1227,7 +1227,7 @@ function M.stylize_markdown(bufnr, contents, opts) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped) local idx = 1 - --@private + ---@private -- keep track of syntaxes we already inlcuded. -- no need to include the same syntax more than once local langs = {} @@ -1276,26 +1276,26 @@ end --- Creates autocommands to close a preview window when events happen. --- ---@param events (table) list of events ---@param winnr (number) window id of preview window ---@see |autocmd-events| +---@param events (table) list of events +---@param winnr (number) window id of preview window +---@see |autocmd-events| function M.close_preview_autocmd(events, winnr) if #events > 0 then api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)") end end ---@internal +---@internal --- Computes size of float needed to show contents (with optional wrapping) --- ---@param contents table of lines to show in window ---@param opts dictionary with optional fields --- - height of floating window --- - width of floating window --- - wrap_at character to wrap at for computing height --- - max_width maximal width of floating window --- - max_height maximal height of floating window ---@returns width,height size of float +---@param contents table of lines to show in window +---@param opts dictionary with optional fields +--- - height of floating window +--- - width of floating window +--- - wrap_at character to wrap at for computing height +--- - max_width maximal width of floating window +--- - 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' }; @@ -1362,9 +1362,9 @@ end --- Shows contents in a floating window. --- ---@param contents table of lines to show in window ---@param syntax string of syntax to set for opened buffer ---@param opts dictionary with optional fields +---@param contents table of lines to show in window +---@param syntax string of syntax to set for opened buffer +---@param opts dictionary with optional fields --- - height of floating window --- - width of floating window --- - wrap boolean enable wrapping of long lines (defaults to true) @@ -1378,7 +1378,7 @@ end --- - focus_id if a popup with this id is opened, then focus it --- - close_events list of events that closes the floating window --- - focusable (boolean, default true): Make float focusable ---@returns bufnr,winnr buffer and window number of the newly created floating +---@returns bufnr,winnr buffer and window number of the newly created floating ---preview window function M.open_floating_preview(contents, syntax, opts) validate { @@ -1474,7 +1474,7 @@ do --[[ References ]] --- Removes document highlights from a buffer. --- - --@param bufnr buffer id + ---@param bufnr buffer id function M.buf_clear_references(bufnr) validate { bufnr = {bufnr, 'n', true} } api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1) @@ -1482,8 +1482,8 @@ do --[[ References ]] --- Shows a list of document highlights for a certain buffer. --- - --@param bufnr buffer id - --@param references List of `DocumentHighlight` objects to highlight + ---@param bufnr buffer id + ---@param references List of `DocumentHighlight` objects to highlight ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight function M.buf_highlight_references(bufnr, references) validate { bufnr = {bufnr, 'n', true} } @@ -1505,24 +1505,24 @@ local position_sort = sort_by_key(function(v) return {v.start.line, v.start.character} end) --- Gets the zero-indexed line from the given uri. +--- Gets the zero-indexed line from the given uri. +---@param uri string uri of the resource to get the line from +---@param row number zero-indexed line number +---@return string the line at row in filename -- For non-file uris, we load the buffer and get the line. -- If a loaded buffer exists, then that is used. -- Otherwise we get the line using libuv which is a lot faster than loading the buffer. ---@param uri string uri of the resource to get the line from ---@param row number zero-indexed line number ---@return string the line at row in filename function M.get_line(uri, row) return M.get_lines(uri, { row })[row] end --- Gets the zero-indexed lines from the given uri. +--- Gets the zero-indexed lines from the given uri. +---@param uri string uri of the resource to get the lines from +---@param rows number[] zero-indexed line numbers +---@return table<number string> a table mapping rows to lines -- For non-file uris, we load the buffer and get the lines. -- If a loaded buffer exists, then that is used. -- Otherwise we get the lines using libuv which is a lot faster than loading the buffer. ---@param uri string uri of the resource to get the lines from ---@param rows number[] zero-indexed line numbers ---@return table<number string> a table mapping rows to lines function M.get_lines(uri, rows) rows = type(rows) == "table" and rows or { rows } @@ -1590,8 +1590,8 @@ end --- Returns the items with the byte position calculated correctly and in sorted --- order, for display in quickfix and location lists. --- ---@param locations (table) list of `Location`s or `LocationLink`s ---@returns (table) list of items +---@param locations (table) list of `Location`s or `LocationLink`s +---@returns (table) list of items function M.locations_to_items(locations) local items = {} local grouped = setmetatable({}, { @@ -1648,7 +1648,7 @@ end --- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|. --- Defaults to current window. --- ---@param items (table) list of items +---@param items (table) list of items function M.set_loclist(items, win_id) vim.fn.setloclist(win_id or 0, {}, ' ', { title = 'Language Server'; @@ -1659,7 +1659,7 @@ end --- Fills quickfix list with given list of items. --- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|. --- ---@param items (table) list of items +---@param items (table) list of items function M.set_qflist(items) vim.fn.setqflist({}, ' ', { title = 'Language Server'; @@ -1676,9 +1676,9 @@ end --- Converts symbols to quickfix list items. --- ---@param symbols DocumentSymbol[] or SymbolInformation[] +---@param symbols DocumentSymbol[] or SymbolInformation[] function M.symbols_to_items(symbols, bufnr) - --@private + ---@private local function _symbols_to_items(_symbols, _items, _bufnr) for _, symbol in ipairs(_symbols) do if symbol.location then -- SymbolInformation type @@ -1714,8 +1714,8 @@ function M.symbols_to_items(symbols, bufnr) end --- Removes empty lines from the beginning and end. ---@param lines (table) list of lines to trim ---@returns (table) trimmed list of lines +---@param lines (table) list of lines to trim +---@returns (table) trimmed list of lines function M.trim_empty_lines(lines) local start = 1 for i = 1, #lines do @@ -1739,8 +1739,8 @@ end --- --- CAUTION: Modifies the input in-place! --- ---@param lines (table) list of lines ---@returns (string) filetype or 'markdown' if it was unchanged. +---@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("^```(.*)") if language_id then @@ -1763,7 +1763,7 @@ function M.try_trim_markdown_code_blocks(lines) end local str_utfindex = vim.str_utfindex ---@private +---@private local function make_position_param() local row, col = unpack(api.nvim_win_get_cursor(0)) row = row - 1 @@ -1777,8 +1777,8 @@ end --- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position. --- ---@returns `TextDocumentPositionParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams +---@returns `TextDocumentPositionParams` object +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams function M.make_position_params() return { textDocument = M.make_text_document_params(); @@ -1791,7 +1791,7 @@ end --- `textDocument/codeAction`, `textDocument/colorPresentation`, --- `textDocument/rangeFormatting`. --- ---@returns { textDocument = { uri = `current_file_uri` }, range = { start = +---@returns { textDocument = { uri = `current_file_uri` }, range = { start = ---`current_position`, end = `current_position` } } function M.make_range_params() local position = make_position_param() @@ -1804,11 +1804,11 @@ end --- Using the given range in the current buffer, creates an object that --- is similar to |vim.lsp.util.make_range_params()|. --- ---@param start_pos ({number, number}, optional) mark-indexed position. +---@param start_pos ({number, number}, optional) mark-indexed position. ---Defaults to the start of the last visual selection. ---@param end_pos ({number, number}, optional) mark-indexed position. +---@param end_pos ({number, number}, optional) mark-indexed position. ---Defaults to the end of the last visual selection. ---@returns { textDocument = { uri = `current_file_uri` }, range = { start = +---@returns { textDocument = { uri = `current_file_uri` }, range = { start = ---`start_position`, end = `end_position` } } function M.make_given_range_params(start_pos, end_pos) validate { @@ -1844,23 +1844,23 @@ end --- Creates a `TextDocumentIdentifier` object for the current buffer. --- ---@returns `TextDocumentIdentifier` ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier +---@returns `TextDocumentIdentifier` +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier function M.make_text_document_params() return { uri = vim.uri_from_bufnr(0) } end --- Create the workspace params ---@param added ---@param removed +---@param added +---@param removed function M.make_workspace_params(added, removed) return { event = { added = added; removed = removed; } } end --- Returns visual width of tabstop. --- ---@see |softtabstop| ---@param bufnr (optional, number): Buffer handle, defaults to current ---@returns (number) tabstop visual width +---@see |softtabstop| +---@param bufnr (optional, number): Buffer handle, defaults to current +---@returns (number) tabstop visual width function M.get_effective_tabstop(bufnr) validate { bufnr = {bufnr, 'n', true} } local bo = bufnr and vim.bo[bufnr] or vim.bo @@ -1870,9 +1870,9 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ---@param options Table with valid `FormattingOptions` entries ---@returns `DocumentFormattingParams` object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting +---@param options Table with valid `FormattingOptions` entries +---@returns `DocumentFormattingParams` object +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) validate { options = {options, 't', true} } options = vim.tbl_extend('keep', options or {}, { @@ -1887,10 +1887,10 @@ end --- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer. --- ---@param buf buffer id (0 for current) ---@param row 0-indexed line ---@param col 0-indexed byte offset in line ---@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf} +---@param buf buffer id (0 for current) +---@param row 0-indexed line +---@param col 0-indexed byte offset in line +---@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf} function M.character_offset(bufnr, row, col) local uri = vim.uri_from_bufnr(bufnr) local line = M.get_line(uri, row) @@ -1903,9 +1903,9 @@ end --- Helper function to return nested values in language server settings --- ---@param settings a table of language server settings ---@param section a string indicating the field of the settings table ---@returns (table or string) The value of settings accessed via section +---@param settings a table of language server settings +---@param section a string indicating the field of the settings table +---@returns (table or string) The value of settings accessed via section function M.lookup_section(settings, section) for part in vim.gsplit(section, '.', true) do settings = settings[part] @@ -1920,10 +1920,10 @@ end --- Convert diagnostics grouped by bufnr to a list of items for use in the --- quickfix or location list. --- ---@param diagnostics_by_bufnr table bufnr -> Diagnostic[] ---@param predicate an optional function to filter the diagnostics. --- If present, only diagnostic items matching will be included. ---@return table (A list of items) +---@param diagnostics_by_bufnr table bufnr -> Diagnostic[] +---@param predicate an optional function to filter the diagnostics. +--- If present, only diagnostic items matching will be included. +---@return table (A list of items) function M.diagnostics_to_items(diagnostics_by_bufnr, predicate) local items = {} for bufnr, diagnostics in pairs(diagnostics_by_bufnr or {}) do diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 33c2b2c46c..032b2b2cb5 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -12,8 +12,8 @@ local vim = vim or {} --- same functions as those in the input table. Userdata and threads are not --- copied and will throw an error. --- ---@param orig Table to copy ---@returns New table of copied keys and (nested) values. +---@param orig Table to copy +---@returns New table of copied keys and (nested) values. function vim.deepcopy(orig) end -- luacheck: no unused vim.deepcopy = (function() local function _id(v) @@ -52,14 +52,14 @@ end)() --- Splits a string at each instance of a separator. --- ---@see |vim.split()| ---@see https://www.lua.org/pil/20.2.html ---@see http://lua-users.org/wiki/StringLibraryTutorial +---@see |vim.split()| +---@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 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 function vim.gsplit(s, sep, plain) vim.validate{s={s,'s'},sep={sep,'s'},plain={plain,'b',true}} @@ -101,12 +101,12 @@ end --- split(x*yz*o, "*", true) --> {'x','yz','o'} --- </pre> -- ---@see |vim.gsplit()| +---@see |vim.gsplit()| --- ---@param s String to split ---@param sep Separator string or pattern ---@param plain If `true` use `sep` literally (passed to String.find) ---@returns List-like table of the split components. +---@param s String to split +---@param sep Separator string or pattern +---@param plain If `true` use `sep` literally (passed to String.find) +---@returns List-like table of the split components. function vim.split(s,sep,plain) local t={} for c in vim.gsplit(s, sep, plain) do table.insert(t,c) end return t @@ -115,10 +115,10 @@ end --- Return a list of all keys used in a table. --- However, the order of the return table of keys is not guaranteed. --- ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua +---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ---@param t Table ---@returns list of keys +---@param t Table +---@returns list of keys function vim.tbl_keys(t) assert(type(t) == 'table', string.format("Expected table, got %s", type(t))) @@ -132,8 +132,8 @@ end --- Return a list of all values used in a table. --- However, the order of the return table of values is not guaranteed. --- ---@param t Table ---@returns list of values +---@param t Table +---@returns list of values function vim.tbl_values(t) assert(type(t) == 'table', string.format("Expected table, got %s", type(t))) @@ -146,8 +146,8 @@ end --- Apply a function to all values of a table. --- ---@param func function or callable table ---@param t table +---@param func function or callable table +---@param t table function vim.tbl_map(func, t) vim.validate{func={func,'c'},t={t,'t'}} @@ -160,8 +160,8 @@ end --- Filter a table using a predicate function --- ---@param func function or callable table ---@param t table +---@param func function or callable table +---@param t table function vim.tbl_filter(func, t) vim.validate{func={func,'c'},t={t,'t'}} @@ -176,9 +176,9 @@ end --- Checks if a list-like (vector) table contains `value`. --- ---@param t Table to check ---@param value Value to compare ---@returns true if `t` contains `value` +---@param t Table to check +---@param value Value to compare +---@returns true if `t` contains `value` function vim.tbl_contains(t, value) vim.validate{t={t,'t'}} @@ -192,16 +192,16 @@ end --- Checks if a table is empty. --- ---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua +---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua --- ---@param t Table to check +---@param t Table to check function vim.tbl_isempty(t) assert(type(t) == 'table', string.format("Expected table, got %s", type(t))) return next(t) == nil end --- we only merge empty tables or tables that are not a list ---@private +---@private local function can_merge(v) return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v)) end @@ -242,26 +242,26 @@ end --- Merges two or more map-like tables. --- ---@see |extend()| +---@see |extend()| --- ---@param behavior Decides what to do if a key is found in more than one map: +---@param behavior 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 ... Two or more map-like tables. function vim.tbl_extend(behavior, ...) return tbl_extend(behavior, false, ...) end --- Merges recursively two or more map-like tables. --- ---@see |tbl_extend()| +---@see |tbl_extend()| --- ---@param behavior Decides what to do if a key is found in more than one map: +---@param behavior 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 ... Two or more map-like tables. function vim.tbl_deep_extend(behavior, ...) return tbl_extend(behavior, true, ...) end @@ -292,7 +292,7 @@ end --- `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. +---@param o table The table to add the reverse to. function vim.tbl_add_reverse_lookup(o) local keys = vim.tbl_keys(o) for _, k in ipairs(keys) do @@ -309,13 +309,13 @@ end --- --- NOTE: This mutates dst! --- ---@see |vim.tbl_extend()| +---@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 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 function vim.list_extend(dst, src, start, finish) vim.validate { dst = {dst, 't'}; @@ -332,10 +332,10 @@ end --- Creates a copy of a list-like table such that any nested tables are --- "unrolled" and appended to the result. --- ---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua +---@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 List-like table +---@returns Flattened copy of the given list-like table. function vim.tbl_flatten(t) local result = {} local function _tbl_flatten(_t) @@ -359,8 +359,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 +---@returns `true` if array-like table, else `false`. function vim.tbl_islist(t) if type(t) ~= 'table' then return false @@ -395,9 +395,9 @@ end --- vim.tbl_count({ 1, 2 }) => 2 --- </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 +---@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 function vim.tbl_count(t) vim.validate{t={t,'t'}} @@ -408,10 +408,10 @@ end --- Creates a copy of a table containing only elements from start to end (inclusive) --- ---@param list table table ---@param start integer Start range of slice ---@param finish integer End range of slice ---@returns Copy of table sliced from start to finish (inclusive) +---@param list table table +---@param start integer Start range of slice +---@param finish integer End range of slice +---@returns 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 @@ -422,9 +422,9 @@ 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 +---@see https://www.lua.org/pil/20.2.html +---@param s String to trim +---@returns String with whitespace removed from its beginning and end function vim.trim(s) vim.validate{s={s,'s'}} return s:match('^%s*(.*%S)') or '' @@ -432,9 +432,9 @@ end --- Escapes magic chars in a Lua pattern. --- ---@see https://github.com/rxi/lume ---@param s String to escape ---@returns %-escaped pattern string +---@see https://github.com/rxi/lume +---@param s String to escape +---@returns %-escaped pattern string function vim.pesc(s) vim.validate{s={s,'s'}} return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1') @@ -442,9 +442,9 @@ end --- Tests if `s` starts with `prefix`. --- ---@param s (string) a string ---@param prefix (string) a prefix ---@return (boolean) true if `prefix` is a prefix of s +---@param s (string) a string +---@param prefix (string) a prefix +---@return (boolean) true if `prefix` is a prefix of s function vim.startswith(s, prefix) vim.validate { s = {s, 's'}; prefix = {prefix, 's'}; } return s:sub(1, #prefix) == prefix @@ -452,9 +452,9 @@ end --- Tests if `s` ends with `suffix`. --- ---@param s (string) a string ---@param suffix (string) a suffix ---@return (boolean) true if `suffix` is a suffix of s +---@param s (string) a string +---@param suffix (string) a suffix +---@return (boolean) true if `suffix` is a suffix of s function vim.endswith(s, suffix) vim.validate { s = {s, 's'}; suffix = {suffix, 's'}; } return #suffix == 0 or s:sub(-#suffix) == suffix @@ -486,7 +486,7 @@ end --- => error('arg1: expected even number, got 3') --- </pre> --- ---@param opt Map of parameter names to validations. Each key is a parameter +---@param opt Map of parameter names to validations. 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 @@ -570,8 +570,8 @@ do end --- Returns true if object `f` can be called as a function. --- ---@param f Any object ---@return true if `f` is callable, else false +---@param f Any object +---@return true if `f` is callable, else false function vim.is_callable(f) if type(f) == 'function' then return true end local m = getmetatable(f) diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index de997b2d86..a09e0a9cf7 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -28,9 +28,9 @@ setmetatable(M, { --- --- It is not recommended to use this, use vim.treesitter.get_parser() instead. --- ---- @param bufnr The buffer the parser will be tied to ---- @param lang The language of the parser ---- @param opts Options to pass to the created language tree +---@param bufnr The buffer the parser will be tied to +---@param lang The language of the parser +---@param opts Options to pass to the created language tree function M._create_parser(bufnr, lang, opts) language.require_language(lang) if bufnr == 0 then @@ -71,11 +71,11 @@ end --- If needed this will create the parser. --- Unconditionnally attach the provided callback --- ---- @param bufnr The buffer the parser should be tied to ---- @param lang The filetype of this parser ---- @param opts Options object to pass to the created language tree +---@param bufnr The buffer the parser should be tied to +---@param lang The filetype of this parser +---@param opts Options object to pass to the created language tree --- ---- @returns The parser +---@returns The parser function M.get_parser(bufnr, lang, opts) opts = opts or {} @@ -97,9 +97,9 @@ end --- Gets a string parser --- ---- @param str The string to parse ---- @param lang The language of this string ---- @param opts Options to pass to the created language tree +---@param str The string to parse +---@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 { str = { str, 'string' }, diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index bf5bd791c3..22b528838c 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -122,8 +122,8 @@ end --- Creates a new highlighter using @param tree --- ---- @param tree The language tree to use for highlighting ---- @param opts Table used to configure the highlighter +---@param tree The language tree to use for highlighting +---@param opts Table used to configure the highlighter --- - queries: Table to overwrite queries used by the highlighter function TSHighlighter.new(tree, opts) local self = setmetatable({}, TSHighlighter) @@ -217,7 +217,7 @@ end --- Gets the query used for @param lang --- ---- @param lang A language used by the highlighter. +---@param lang A language used by the highlighter. function TSHighlighter:get_query(lang) if not self._queries[lang] then self._queries[lang] = TSHighlighterQuery.new(lang) diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index 6dc37c7848..89ddd6cd5a 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -6,9 +6,9 @@ local M = {} --- --- Parsers are searched in the `parser` runtime directory. --- ---- @param lang The language the parser should parse ---- @param path Optional path the parser is located at ---- @param silent Don't throw an error if language not found +---@param lang The language the parser should parse +---@param path Optional path the parser is located at +---@param silent Don't throw an error if language not found function M.require_language(lang, path, silent) if vim._ts_has_language(lang) then return true @@ -40,7 +40,7 @@ end --- --- Inspecting provides some useful informations on the language like node names, ... --- ---- @param lang The language. +---@param lang The language. function M.inspect_language(lang) M.require_language(lang) return vim._ts_inspect_language(lang) diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 899d90e464..7e392f72a4 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -9,12 +9,12 @@ LanguageTree.__index = LanguageTree --- The language can contain child languages with in its range, --- hence the tree. --- ---- @param source Can be a bufnr or a string of text to parse ---- @param lang The language this tree represents ---- @param opts Options table ---- @param opts.injections A table of language to injection query strings. ---- This is useful for overriding the built-in runtime file ---- searching for the injection language query per language. +---@param source Can be a bufnr or a string of text to parse +---@param lang The language this tree represents +---@param opts Options table +---@param opts.injections A table of language to injection query strings. +--- This is useful for overriding the built-in runtime file +--- searching for the injection language query per language. function LanguageTree.new(source, lang, opts) language.require_language(lang) opts = opts or {} @@ -171,8 +171,8 @@ end --- Invokes the callback for each LanguageTree and it's children recursively --- ---- @param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string) ---- @param include_self Whether to include the invoking tree in the results. +---@param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string) +---@param include_self Whether to include the invoking tree in the results. function LanguageTree:for_each_child(fn, include_self) if include_self then fn(self, self._lang) @@ -187,8 +187,8 @@ end --- --- Note, this includes the invoking language tree's trees as well. --- ---- @param fn The callback to invoke. The callback is invoked with arguments ---- (tree: TSTree, languageTree: LanguageTree) +---@param fn The callback to invoke. The callback is invoked with arguments +--- (tree: TSTree, languageTree: LanguageTree) function LanguageTree:for_each_tree(fn) for _, tree in ipairs(self._trees) do fn(tree, self) @@ -203,7 +203,7 @@ end --- --- If the language already exists as a child, it will first be removed. --- ---- @param lang The language to add. +---@param lang The language to add. function LanguageTree:add_child(lang) if self._children[lang] then self:remove_child(lang) @@ -219,7 +219,7 @@ end --- Removes a child language from this tree. --- ---- @param lang The language to remove. +---@param lang The language to remove. function LanguageTree:remove_child(lang) local child = self._children[lang] @@ -259,7 +259,7 @@ end --- --- Note, this call invalidates the tree and requires it to be parsed again. --- ---- @param regions A list of regions this tree should manage and parse. +---@param regions 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 @@ -299,7 +299,7 @@ end --- --- TODO: Allow for an offset predicate to tailor the injection range --- instead of using the entire nodes range. ---- @private +---@private function LanguageTree:_get_injections() if not self._injection_query then return {} end @@ -449,7 +449,7 @@ function LanguageTree:_on_detach(...) end --- Registers callbacks for the parser ---- @param cbs An `nvim_buf_attach`-like table argument with the following keys : +---@param cbs An `nvim_buf_attach`-like table argument with the following keys : --- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback. --- `on_changedtree` : a callback that will be called every time the tree has syntactical changes. --- it will only be passed one argument, that is a table of the ranges (as node ranges) that @@ -497,7 +497,7 @@ end --- --- This goes down the tree to recursively check childs. --- ---- @param range A range, that is a `{ start_line, start_col, end_line, end_col }` table. +---@param range A range, that is a `{ start_line, start_col, end_line, end_col }` table. function LanguageTree:contains(range) for _, tree in pairs(self._trees) do if tree_contains(tree, range) then @@ -510,7 +510,7 @@ end --- Gets the appropriate language that contains @param range --- ---- @param range A text range, see |LanguageTree:contains| +---@param range A text range, see |LanguageTree:contains| function LanguageTree:language_for_range(range) for _, child in pairs(self._children) do if child:contains(range) then diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 4ecd91d295..66da179ea3 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -36,9 +36,9 @@ end --- Gets the list of files used to make up a query --- ---- @param lang The language ---- @param query_name The name of the query to load ---- @param is_included Internal parameter, most of the time left as `nil` +---@param lang The language +---@param query_name The name of the query to load +---@param is_included Internal parameter, most of the time left as `nil` 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)) @@ -112,19 +112,19 @@ local explicit_queries = setmetatable({}, { --- This allows users to override any runtime files and/or configuration --- set by plugins. --- ---- @param lang string: The language to use for the query ---- @param query_name string: The name of the query (i.e. "highlights") ---- @param text string: The query text (unparsed). +---@param lang string: The language to use for the query +---@param query_name string: The name of the query (i.e. "highlights") +---@param text string: The query text (unparsed). function M.set_query(lang, query_name, text) explicit_queries[lang][query_name] = M.parse_query(lang, text) end --- Returns the runtime query {query_name} for {lang}. --- ---- @param lang The language to use for the query ---- @param query_name The name of the query (i.e. "highlights") +---@param lang The language to use for the query +---@param query_name The name of the query (i.e. "highlights") --- ---- @return The corresponding query, parsed. +---@return The corresponding query, parsed. function M.get_query(lang, query_name) if explicit_queries[lang][query_name] then return explicit_queries[lang][query_name] @@ -151,10 +151,10 @@ end --- -` info.captures` also points to `captures`. --- - `info.patterns` contains information about predicates. --- ---- @param lang The language ---- @param query A string containing the query (s-expr syntax) +---@param lang The language +---@param query A string containing the query (s-expr syntax) --- ---- @returns The query +---@returns The query function M.parse_query(lang, query) language.require_language(lang) local self = setmetatable({}, Query) @@ -168,8 +168,8 @@ end --- Gets the text corresponding to a given node --- ---- @param node the node ---- @param bsource The buffer or string from which the node is extracted +---@param node the node +---@param bsource The buffer or string from which the node is extracted 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_() @@ -327,9 +327,9 @@ local directive_handlers = { --- Adds a new predicate to be used in queries --- ---- @param name the name of the predicate, without leading # ---- @param handler the handler function to be used ---- signature will be (match, pattern, bufnr, predicate) +---@param name the name of the predicate, without leading # +---@param handler the handler function to be used +--- 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)) @@ -340,9 +340,9 @@ end --- Adds a new directive to be used in queries --- ---- @param name the name of the directive, without leading # ---- @param handler the handler function to be used ---- signature will be (match, pattern, bufnr, predicate) +---@param name the name of the directive, without leading # +---@param handler the handler function to be used +--- 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)) @@ -351,12 +351,12 @@ function M.add_directive(name, handler, force) directive_handlers[name] = handler end ---- @return The list of supported directives. +---@return The list of supported directives. function M.list_directives() return vim.tbl_keys(directive_handlers) end ---- @return The list of supported predicates. +---@return The list of supported predicates. function M.list_predicates() return vim.tbl_keys(predicate_handlers) end @@ -465,13 +465,13 @@ end --- end --- </pre> --- ---- @param node The node under which the search will occur ---- @param source The source buffer or string to exctract text from ---- @param start The starting line of the search ---- @param stop The stopping line of the search (end-exclusive) +---@param node The node under which the search will occur +---@param source The source buffer or string to exctract text from +---@param start The starting line of the search +---@param stop The stopping line of the search (end-exclusive) --- ---- @returns The matching capture id ---- @returns The captured node +---@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 source = vim.api.nvim_get_current_buf() @@ -522,13 +522,13 @@ end --- end --- </pre> --- ---- @param node The node under which the search will occur ---- @param source The source buffer or string to search ---- @param start The starting line of the search ---- @param stop The stopping line of the search (end-exclusive) +---@param node The node under which the search will occur +---@param source The source buffer or string to search +---@param start The starting line of the search +---@param stop The stopping line of the search (end-exclusive) --- ---- @returns The matching pattern id ---- @returns The matching match +---@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 source = vim.api.nvim_get_current_buf() diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua index 82c9a31464..a3e79a0f2b 100644 --- a/runtime/lua/vim/uri.lua +++ b/runtime/lua/vim/uri.lua @@ -9,7 +9,7 @@ do local schar = string.char --- Convert hex to char - --@private + ---@private local function hex_to_char(hex) return schar(tonumber(hex, 16)) end @@ -38,7 +38,7 @@ do tohex = function(b) return string.format("%02x", b) end end - --@private + ---@private local function percent_encode_char(char) return "%"..tohex(sbyte(char), 2) end @@ -50,14 +50,14 @@ do end ---@private +---@private local function is_windows_file_uri(uri) return uri:match('^file:/+[a-zA-Z]:') ~= nil end --- Get a URI from a file path. ---@param path (string): Path to file ---@return URI +---@param path (string): Path to file +---@return URI local function uri_from_fname(path) local volume_path, fname = path:match("^([a-zA-Z]:)(.*)") local is_windows = volume_path ~= nil @@ -77,8 +77,8 @@ end local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*):.*' --- Get a URI from a bufnr ---@param bufnr (number): Buffer number ---@return URI +---@param bufnr (number): Buffer number +---@return URI local function uri_from_bufnr(bufnr) local fname = vim.api.nvim_buf_get_name(bufnr) local scheme = fname:match(URI_SCHEME_PATTERN) @@ -90,8 +90,8 @@ local function uri_from_bufnr(bufnr) end --- Get a filename from a URI ---@param uri (string): The URI ---@return Filename +---@param uri (string): The URI +---@return Filename local function uri_to_fname(uri) local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri) if scheme ~= 'file' then @@ -109,9 +109,9 @@ local function uri_to_fname(uri) end --- Return or create a buffer for a uri. ---@param uri (string): The URI ---@return bufnr. ---@note Creates buffer but does not load it +---@param uri (string): The URI +---@return bufnr. +---@note Creates buffer but does not load it local function uri_to_bufnr(uri) local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri) if scheme == 'file' then diff --git a/src/nvim/README.md b/src/nvim/README.md index affc5c79cc..4efb42b896 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -75,8 +75,108 @@ Logs will be written to `${HOME}/logs/*san.PID` then. For more information: https://github.com/google/sanitizers/wiki/SanitizerCommonFlags -TUI debugging -------------- +Debug: Performance +------------------ + +### Profiling (easy) + +For debugging performance bottlenecks in any code, there is a simple (and very +effective) approach: + +1. Run the slow code in a loop. +2. Break execution ~5 times and save the stacktrace. +3. The cause of the bottleneck will (almost always) appear in most of the stacktraces. + +### Profiling (fancy) + +For more advanced profiling, consider `perf` + `flamegraph`. + +### USDT profiling (powerful) + +Or you can use USDT probes via `NVIM_PROBE` ([#12036](https://github.com/neovim/neovim/pull/12036)). + +> USDT is basically a way to define stable probe points in userland binaries. +> The benefit of bcc is the ability to define logic to go along with the probe +> points. + +Tools: +- bpftrace provides an awk-like language to the kernel bytecode, BPF. +- BCC provides a subset of C. Provides more complex logic than bpftrace, but takes a bit more effort. + +Example using bpftrace to track slow vim functions, and print out any files +that were opened during the trace. At the end, it prints a histogram of +function timing: + + #!/usr/bin/env bpftrace + + BEGIN { + @depth = -1; + } + + tracepoint:sched:sched_process_fork /@pidmap[args->parent_pid]/ { + @pidmap[args->child_pid] = 1; + } + + tracepoint:sched:sched_process_exit /@pidmap[args->pid]/ { + delete(@pidmap[args->pid]); + } + + usdt:build/bin/nvim:neovim:eval__call_func__entry { + @pidmap[pid] = 1; + @depth++; + @funcentry[@depth] = nsecs; + } + + usdt:build/bin/nvim:neovim:eval__call_func__return { + $func = str(arg0); + $msecs = (nsecs - @funcentry[@depth]) / 1000000; + + @time_histo = hist($msecs); + + if ($msecs >= 1000) { + printf("%u ms for %s\n", $msecs, $func); + print(@files); + } + + clear(@files); + delete(@funcentry[@depth]); + @depth--; + } + + tracepoint:syscalls:sys_enter_open, + tracepoint:syscalls:sys_enter_openat { + if (@pidmap[pid] == 1 && @depth >= 0) { + @files[str(args->filename)] = count(); + } + } + + END { + clear(@depth); + } + + $ sudo bpftrace funcslower.bt + 1527 ms for Slower + @files[/usr/lib/libstdc++.so.6]: 2 + @files[/etc/fish/config.fish]: 2 + <snip> + + ^C + @time_histo: + [0] 71430 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| + [1] 346 | | + [2, 4) 208 | | + [4, 8) 91 | | + [8, 16) 22 | | + [16, 32) 85 | | + [32, 64) 7 | | + [64, 128) 0 | | + [128, 256) 0 | | + [256, 512) 6 | | + [512, 1K) 1 | | + [1K, 2K) 5 | | + +Debug: TUI +---------- ### TUI troubleshoot diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index eae4581f42..9f16da4078 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -21,12 +21,12 @@ #include "nvim/api/window.h" #include "nvim/api/deprecated.h" -static Map(String, MsgpackRpcRequestHandler) *methods = NULL; +static Map(String, MsgpackRpcRequestHandler) methods = MAP_INIT; static void msgpack_rpc_add_method_handler(String method, MsgpackRpcRequestHandler handler) { - map_put(String, MsgpackRpcRequestHandler)(methods, method, handler); + map_put(String, MsgpackRpcRequestHandler)(&methods, method, handler); } /// @param name API method name @@ -37,7 +37,7 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, { String m = { .data = (char *)name, .size = name_len }; MsgpackRpcRequestHandler rv = - map_get(String, MsgpackRpcRequestHandler)(methods, m); + map_get(String, MsgpackRpcRequestHandler)(&methods, m); if (!rv.fn) { api_set_error(error, kErrorTypeException, "Invalid method: %.*s", diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c deleted file mode 100644 index eb96192af2..0000000000 --- a/src/nvim/api/private/handle.c +++ /dev/null @@ -1,40 +0,0 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - -#include <assert.h> -#include <stdint.h> - -#include "nvim/vim.h" -#include "nvim/map.h" -#include "nvim/api/private/handle.h" - -#define HANDLE_INIT(name) name##_handles = pmap_new(handle_T)() - -#define HANDLE_IMPL(type, name) \ - static PMap(handle_T) *name##_handles = NULL; /* NOLINT */ \ - \ - type *handle_get_##name(handle_T handle) \ - { \ - return pmap_get(handle_T)(name##_handles, handle); \ - } \ - \ - void handle_register_##name(type *name) \ - { \ - pmap_put(handle_T)(name##_handles, name->handle, name); \ - } \ - \ - void handle_unregister_##name(type *name) \ - { \ - pmap_del(handle_T)(name##_handles, name->handle); \ - } - -HANDLE_IMPL(buf_T, buffer) -HANDLE_IMPL(win_T, window) -HANDLE_IMPL(tabpage_T, tabpage) - -void handle_init(void) -{ - HANDLE_INIT(buffer); - HANDLE_INIT(window); - HANDLE_INIT(tabpage); -} diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h deleted file mode 100644 index 26e9dc3314..0000000000 --- a/src/nvim/api/private/handle.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef NVIM_API_PRIVATE_HANDLE_H -#define NVIM_API_PRIVATE_HANDLE_H - -#include "nvim/vim.h" -#include "nvim/buffer_defs.h" -#include "nvim/api/private/defs.h" - -#define HANDLE_DECLS(type, name) \ - type *handle_get_##name(handle_T handle); \ - void handle_register_##name(type *name); \ - void handle_unregister_##name(type *name); - -// handle_get_buffer handle_register_buffer, handle_unregister_buffer -HANDLE_DECLS(buf_T, buffer) -// handle_get_window handle_register_window, handle_unregister_window -HANDLE_DECLS(win_T, window) -// handle_get_tabpage handle_register_tabpage, handle_unregister_tabpage -HANDLE_DECLS(tabpage_T, tabpage) - -void handle_init(void); - - -#endif // NVIM_API_PRIVATE_HANDLE_H - diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 3ec6151090..eedcfd69b8 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -9,7 +9,6 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" -#include "nvim/api/private/handle.h" #include "nvim/api/vim.h" #include "nvim/msgpack_rpc/helpers.h" #include "nvim/lua/executor.h" @@ -1725,7 +1724,7 @@ const char *describe_ns(NS ns_id) { String name; handle_T id; - map_foreach(namespace_ids, name, id, { + map_foreach(&namespace_ids, name, id, { if ((NS)id == ns_id && name.size) { return name.data; } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 055abb797f..ecce6afa26 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -101,6 +101,14 @@ #define api_free_window(value) #define api_free_tabpage(value) +EXTERN PMap(handle_T) buffer_handles INIT(= MAP_INIT); +EXTERN PMap(handle_T) window_handles INIT(= MAP_INIT); +EXTERN PMap(handle_T) tabpage_handles INIT(= MAP_INIT); + +#define handle_get_buffer(h) pmap_get(handle_T)(&buffer_handles, (h)) +#define handle_get_window(h) pmap_get(handle_T)(&window_handles, (h)) +#define handle_get_tabpage(h) pmap_get(handle_T)(&tabpage_handles, (h)) + /// Structure used for saving state for :try /// /// Used when caller is supposed to be operating when other VimL code is being diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 63e6ad883a..713980ca68 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -37,24 +37,18 @@ typedef struct { bool wildmenu_active; } UIData; -static PMap(uint64_t) *connected_uis = NULL; - -void remote_ui_init(void) - FUNC_API_NOEXPORT -{ - connected_uis = pmap_new(uint64_t)(); -} +static PMap(uint64_t) connected_uis = MAP_INIT; void remote_ui_disconnect(uint64_t channel_id) FUNC_API_NOEXPORT { - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id); if (!ui) { return; } UIData *data = ui->data; api_free_array(data->buffer); // Destroy pending screen updates. - pmap_del(uint64_t)(connected_uis, channel_id); + pmap_del(uint64_t)(&connected_uis, channel_id); xfree(ui->data); ui->data = NULL; // Flag UI as "stopped". ui_detach_impl(ui, channel_id); @@ -73,7 +67,7 @@ void remote_ui_wait_for_attach(void) } LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, - pmap_has(uint64_t)(connected_uis, CHAN_STDIO)); + pmap_has(uint64_t)(&connected_uis, CHAN_STDIO)); } /// Activates UI events on the channel. @@ -95,7 +89,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictionary options, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (pmap_has(uint64_t)(connected_uis, channel_id)) { + if (pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI already attached to channel: %" PRId64, channel_id); return; @@ -172,7 +166,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, data->wildmenu_active = false; ui->data = data; - pmap_put(uint64_t)(connected_uis, channel_id, ui); + pmap_put(uint64_t)(&connected_uis, channel_id, ui); ui_attach_impl(ui, channel_id); } @@ -195,7 +189,7 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height, void nvim_ui_detach(uint64_t channel_id, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -208,7 +202,7 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Error *err) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -220,7 +214,7 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width, return; } - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id); ui->width = (int)width; ui->height = (int)height; ui_refresh(); @@ -230,12 +224,12 @@ void nvim_ui_set_option(uint64_t channel_id, String name, Object value, Error *error) FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(error, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; } - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id); ui_set_option(ui, false, name, value, error); } @@ -310,7 +304,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, Integer height, Error *err) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -328,7 +322,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err) FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; @@ -339,7 +333,7 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err) return; } - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id); if (!ui->ui_ext[kUIPopupmenu]) { api_set_error(err, kErrorTypeValidation, "It must support the ext_popupmenu option"); @@ -369,13 +363,13 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Float row, Float col, Error *err) FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY { - if (!pmap_has(uint64_t)(connected_uis, channel_id)) { + if (!pmap_has(uint64_t)(&connected_uis, channel_id)) { api_set_error(err, kErrorTypeException, "UI not attached to channel: %" PRId64, channel_id); return; } - UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); + UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id); if (!ui->ui_ext[kUIPopupmenu]) { api_set_error(err, kErrorTypeValidation, "UI must support the ext_popupmenu option"); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 400dbb126c..90c43a1b04 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -58,22 +58,16 @@ # include "api/vim.c.generated.h" #endif -void api_vim_init(void) - FUNC_API_NOEXPORT -{ - namespace_ids = map_new(String, handle_T)(); -} - void api_vim_free_all_mem(void) FUNC_API_NOEXPORT { String name; handle_T id; - map_foreach(namespace_ids, name, id, { + map_foreach(&namespace_ids, name, id, { (void)id; xfree(name.data); }) - map_free(String, handle_T)(namespace_ids); + map_destroy(String, handle_T)(&namespace_ids); } /// Executes Vimscript (multiline block of Ex-commands), like anonymous @@ -1568,14 +1562,14 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) Integer nvim_create_namespace(String name) FUNC_API_SINCE(5) { - handle_T id = map_get(String, handle_T)(namespace_ids, name); + handle_T id = map_get(String, handle_T)(&namespace_ids, name); if (id > 0) { return id; } id = next_namespace_id++; if (name.size > 0) { String name_alloc = copy_string(name); - map_put(String, handle_T)(namespace_ids, name_alloc, id); + map_put(String, handle_T)(&namespace_ids, name_alloc, id); } return (Integer)id; } @@ -1590,7 +1584,7 @@ Dictionary nvim_get_namespaces(void) String name; handle_T id; - map_foreach(namespace_ids, name, id, { + map_foreach(&namespace_ids, name, id, { PUT(retval, name.data, INTEGER_OBJ(id)); }) diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index d6873da6d2..4fd353ce5c 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -6,7 +6,7 @@ #include "nvim/api/private/defs.h" #include "nvim/map.h" -EXTERN Map(String, handle_T) *namespace_ids INIT(= NULL); +EXTERN Map(String, handle_T) namespace_ids INIT(= MAP_INIT); EXTERN handle_T next_namespace_id INIT(= 1); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index bec9808183..417953eb14 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -5,7 +5,7 @@ #include "nvim/autocmd.h" -#include "nvim/api/private/handle.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/buffer.h" #include "nvim/charset.h" @@ -1150,7 +1150,7 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) block_autocmds(); // We don't want BufEnter/WinEnter autocommands. if (need_append) { win_append(lastwin, aucmd_win); - handle_register_window(aucmd_win); + pmap_put(handle_T)(&window_handles, aucmd_win->handle, aucmd_win); win_config_float(aucmd_win, aucmd_win->w_float_config); } // Prevent chdir() call in win_enter_ext(), through do_autochdir() @@ -1191,7 +1191,7 @@ void aucmd_restbuf(aco_save_T *aco) win_found: win_remove(curwin, NULL); - handle_unregister_window(curwin); + pmap_del(handle_T)(&window_handles, curwin->handle); if (curwin->w_grid_alloc.chars != NULL) { ui_comp_remove_grid(&curwin->w_grid_alloc); ui_call_win_hide(curwin->w_grid_alloc.handle); diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 29d4fc786a..fdb3ffdc7e 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -24,7 +24,6 @@ #include <inttypes.h> #include <assert.h> -#include "nvim/api/private/handle.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" #include "nvim/ascii.h" @@ -532,7 +531,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last) } if (buf->terminal) { - terminal_close(buf->terminal, NULL); + terminal_close(buf->terminal, -1); } // Always remove the buffer when there is no file name. @@ -757,7 +756,7 @@ void buf_freeall(buf_T *buf, int flags) */ static void free_buffer(buf_T *buf) { - handle_unregister_buffer(buf); + pmap_del(handle_T)(&buffer_handles, buf->b_fnum); buf_free_count++; // b:changedtick uses an item in buf_T. free_buffer_stuff(buf, kBffClearWinInfo); @@ -1841,7 +1840,7 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum, lastbuf = buf; buf->b_fnum = top_file_num++; - handle_register_buffer(buf); + pmap_put(handle_T)(&buffer_handles, buf->b_fnum, buf); if (top_file_num < 0) { // wrap around (may cause duplicates) EMSG(_("W14: Warning: List of file names overflow")); if (emsg_silent == 0) { diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index b03d69a04c..0ae8dd3664 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -863,8 +863,8 @@ struct file_buffer { int b_mapped_ctrl_c; // modes where CTRL-C is mapped MarkTree b_marktree[1]; - Map(uint64_t, ExtmarkItem) *b_extmark_index; - Map(uint64_t, ExtmarkNs) *b_extmark_ns; // extmark namespaces + Map(uint64_t, ExtmarkItem) b_extmark_index[1]; + Map(uint64_t, ExtmarkNs) b_extmark_ns[1]; // extmark namespaces // array of channel_id:s which have asked to receive updates for this // buffer. diff --git a/src/nvim/change.c b/src/nvim/change.c index 41e1e3911b..13b86e9244 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -1837,7 +1837,7 @@ void truncate_line(int fixpos) /// Delete "nlines" lines at the cursor. /// Saves the lines for undo first if "undo" is true. -void del_lines(long nlines, int undo) +void del_lines(long nlines, bool undo) { long n; linenr_T first = curwin->w_cursor.lnum; diff --git a/src/nvim/channel.c b/src/nvim/channel.c index a0db1bcdfd..6f12d2eab8 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -32,13 +32,9 @@ static uint64_t next_chan_id = CHAN_STDERR+1; /// Teardown the module void channel_teardown(void) { - if (!channels) { - return; - } - Channel *channel; - map_foreach_value(channels, channel, { + map_foreach_value(&channels, channel, { channel_close(channel->id, kChannelPartAll, NULL); }); } @@ -152,7 +148,6 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error) /// Initializes the module void channel_init(void) { - channels = pmap_new(uint64_t)(); channel_alloc(kChannelStreamStderr); rpc_init(); } @@ -177,7 +172,7 @@ Channel *channel_alloc(ChannelStreamType type) chan->exit_status = -1; chan->streamtype = type; assert(chan->id <= VARNUMBER_MAX); - pmap_put(uint64_t)(channels, chan->id, chan); + pmap_put(uint64_t)(&channels, chan->id, chan); return chan; } @@ -249,7 +244,7 @@ static void free_channel_event(void **argv) callback_reader_free(&chan->on_stderr); callback_free(&chan->on_exit); - pmap_del(uint64_t)(channels, chan->id); + pmap_del(uint64_t)(&channels, chan->id); multiqueue_free(chan->events); xfree(chan); } @@ -259,7 +254,7 @@ static void channel_destroy_early(Channel *chan) if ((chan->id != --next_chan_id)) { abort(); } - pmap_del(uint64_t)(channels, chan->id); + pmap_del(uint64_t)(&channels, chan->id); chan->id = 0; if ((--chan->refcount != 0)) { @@ -698,9 +693,7 @@ static void channel_process_exit_cb(Process *proc, int status, void *data) { Channel *chan = data; if (chan->term) { - char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN]; - snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status); - terminal_close(chan->term, msg); + terminal_close(chan->term, status); } // If process did not exit, we only closed the handle of a detached process. @@ -901,7 +894,7 @@ Array channel_all_info(void) { Channel *channel; Array ret = ARRAY_DICT_INIT; - map_foreach_value(channels, channel, { + map_foreach_value(&channels, channel, { ADD(ret, DICTIONARY_OBJ(channel_info(channel->id))); }); return ret; diff --git a/src/nvim/channel.h b/src/nvim/channel.h index df858e1602..9bc0df3615 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -89,7 +89,7 @@ struct Channel { bool callback_scheduled; }; -EXTERN PMap(uint64_t) *channels INIT(= NULL); +EXTERN PMap(uint64_t) channels INIT(= MAP_INIT); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "channel.h.generated.h" @@ -98,7 +98,7 @@ EXTERN PMap(uint64_t) *channels INIT(= NULL); /// @returns Channel with the id or NULL if not found static inline Channel *find_channel(uint64_t id) { - return pmap_get(uint64_t)(channels, id); + return pmap_get(uint64_t)(&channels, id); } static inline Stream *channel_instream(Channel *chan) diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 74cb9a26b7..5168ed6d0f 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -13,12 +13,7 @@ # include "decoration.c.generated.h" #endif -static PMap(uint64_t) *hl_decors; - -void decor_init(void) -{ - hl_decors = pmap_new(uint64_t)(); -} +static PMap(uint64_t) hl_decors; /// Add highlighting to a buffer, bounded by two cursor positions, /// with an offset. @@ -77,7 +72,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, Decoration *decor_hl(int hl_id) { assert(hl_id > 0); - Decoration **dp = (Decoration **)pmap_ref(uint64_t)(hl_decors, + Decoration **dp = (Decoration **)pmap_ref(uint64_t)(&hl_decors, (uint64_t)hl_id, true); if (*dp) { return *dp; @@ -150,7 +145,7 @@ bool decor_redraw_reset(buf_T *buf, DecorState *state) } } kv_size(state->active) = 0; - return buf->b_extmark_index; + return map_size(buf->b_extmark_index); } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index fec8da2c3c..ffe60ab043 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1652,8 +1652,8 @@ static void init_prompt(int cmdchar_todo) check_cursor(); } -// Return TRUE if the cursor is in the editable position of the prompt line. -int prompt_curpos_editable(void) +/// @return true if the cursor is in the editable position of the prompt line. +bool prompt_curpos_editable(void) { return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count && curwin->w_cursor.col >= (int)STRLEN(prompt_text()); @@ -8124,8 +8124,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // again when auto-formatting. if (has_format_option(FO_AUTO) && has_format_option(FO_WHITE_PAR)) { - char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, - TRUE); + char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true); int len; len = (int)STRLEN(ptr); diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 789936fdff..5e18a77b6d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -265,7 +265,7 @@ static partial_T *vvlua_partial; #endif static uint64_t last_timer_id = 1; -static PMap(uint64_t) *timers = NULL; +static PMap(uint64_t) timers = MAP_INIT; static const char *const msgpack_type_names[] = { [kMPNil] = "nil", @@ -326,7 +326,6 @@ void eval_init(void) { vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; - timers = pmap_new(uint64_t)(); struct vimvar *p; init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE); @@ -4883,7 +4882,7 @@ bool garbage_collect(bool testing) // Channels { Channel *data; - map_foreach_value(channels, data, { + map_foreach_value(&channels, data, { set_ref_in_callback_reader(&data->on_data, copyID, NULL, NULL); set_ref_in_callback_reader(&data->on_stderr, copyID, NULL, NULL); set_ref_in_callback(&data->on_exit, copyID, NULL, NULL); @@ -4893,7 +4892,7 @@ bool garbage_collect(bool testing) // Timers { timer_T *timer; - map_foreach_value(timers, timer, { + map_foreach_value(&timers, timer, { set_ref_in_callback(&timer->callback, copyID, NULL, NULL); }) } @@ -7304,7 +7303,7 @@ static bool set_ref_in_callback_reader(CallbackReader *reader, int copyID, timer_T *find_timer_by_nr(varnumber_T xx) { - return pmap_get(uint64_t)(timers, xx); + return pmap_get(uint64_t)(&timers, xx); } void add_timer_info(typval_T *rettv, timer_T *timer) @@ -7331,9 +7330,9 @@ void add_timer_info(typval_T *rettv, timer_T *timer) void add_timer_info_all(typval_T *rettv) { - tv_list_alloc_ret(rettv, timers->table->n_occupied); + tv_list_alloc_ret(rettv, map_size(&timers)); timer_T *timer; - map_foreach_value(timers, timer, { + map_foreach_value(&timers, timer, { if (!timer->stopped) { add_timer_info(rettv, timer); } @@ -7413,7 +7412,7 @@ uint64_t timer_start(const long timeout, timer->tw.blockable = true; time_watcher_start(&timer->tw, timer_due_cb, timeout, timeout); - pmap_put(uint64_t)(timers, timer->timer_id, timer); + pmap_put(uint64_t)(&timers, timer->timer_id, timer); return timer->timer_id; } @@ -7435,7 +7434,7 @@ static void timer_close_cb(TimeWatcher *tw, void *data) timer_T *timer = (timer_T *)data; multiqueue_free(timer->tw.events); callback_free(&timer->callback); - pmap_del(uint64_t)(timers, timer->timer_id); + pmap_del(uint64_t)(&timers, timer->timer_id); timer_decref(timer); } @@ -7449,7 +7448,7 @@ static void timer_decref(timer_T *timer) void timer_stop_all(void) { timer_T *timer; - map_foreach_value(timers, timer, { + map_foreach_value(&timers, timer, { timer_stop(timer); }) } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 0c099085a0..f7a1327c87 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -715,7 +715,7 @@ sortend: void ex_retab(exarg_T *eap) { linenr_T lnum; - int got_tab = FALSE; + bool got_tab = false; long num_spaces = 0; long num_tabs; long len; @@ -766,10 +766,11 @@ void ex_retab(exarg_T *eap) start_vcol = vcol; start_col = col; } - if (ptr[col] == ' ') + if (ptr[col] == ' ') { num_spaces++; - else - got_tab = TRUE; + } else { + got_tab = true; + } } else { if (got_tab || (eap->forceit && num_spaces > 1)) { /* Retabulate this string of white-space */ @@ -824,7 +825,7 @@ void ex_retab(exarg_T *eap) col = start_col + len; } } - got_tab = FALSE; + got_tab = false; num_spaces = 0; } if (ptr[col] == NUL) @@ -1386,11 +1387,11 @@ static void do_filter( * Adjust '[ and '] (set by buf_write()). */ curwin->w_cursor.lnum = line1; - del_lines(linecount, TRUE); - curbuf->b_op_start.lnum -= linecount; /* adjust '[ */ - curbuf->b_op_end.lnum -= linecount; /* adjust '] */ - write_lnum_adjust(-linecount); /* adjust last line - for next write */ + del_lines(linecount, true); + curbuf->b_op_start.lnum -= linecount; // adjust '[ + curbuf->b_op_end.lnum -= linecount; // adjust '] + write_lnum_adjust(-linecount); // adjust last line + // for next write foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum); } else { /* @@ -3835,7 +3836,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, _("replace with %s (y/n/a/q/l/^E/^Y)?"), sub); msg_no_more = FALSE; msg_scroll = i; - showruler(TRUE); + showruler(true); ui_cursor_goto(msg_row, msg_col); RedrawingDisabled = temp; @@ -5171,21 +5172,21 @@ void fix_help_buffer(void) if (in_example && len > 0 && !ascii_iswhite(line[0])) { /* End of example: non-white or '<' in first column. */ if (line[0] == '<') { - /* blank-out a '<' in the first column */ - line = ml_get_buf(curbuf, lnum, TRUE); + // blank-out a '<' in the first column + line = ml_get_buf(curbuf, lnum, true); line[0] = ' '; } in_example = false; } if (!in_example && len > 0) { if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' ')) { - /* blank-out a '>' in the last column (start of example) */ - line = ml_get_buf(curbuf, lnum, TRUE); + // blank-out a '>' in the last column (start of example) + line = ml_get_buf(curbuf, lnum, true); line[len - 1] = ' '; in_example = true; } else if (line[len - 1] == '~') { - /* blank-out a '~' at the end of line (header marker) */ - line = ml_get_buf(curbuf, lnum, TRUE); + // blank-out a '~' at the end of line (header marker) + line = ml_get_buf(curbuf, lnum, true); line[len - 1] = ' '; } } @@ -5204,10 +5205,11 @@ void fix_help_buffer(void) && TOLOWER_ASC(fname[7]) == 'x' && fname[8] == NUL) ) { - for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum) { - line = ml_get_buf(curbuf, lnum, FALSE); - if (strstr((char *)line, "*local-additions*") == NULL) + for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; lnum++) { + line = ml_get_buf(curbuf, lnum, false); + if (strstr((char *)line, "*local-additions*") == NULL) { continue; + } /* Go through all directories in 'runtimepath', skipping * $VIMRUNTIME. */ diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 7cab3eb650..0f98c9cd34 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -5734,18 +5734,13 @@ HistoryType get_histtype(const char *const name, const size_t len, static int last_maptick = -1; /* last seen maptick */ -/* - * Add the given string to the given history. If the string is already in the - * history then it is moved to the front. "histype" may be one of he HIST_ - * values. - */ -void -add_to_history ( - int histype, - char_u *new_entry, - int in_map, /* consider maptick when inside a mapping */ - int sep /* separator character used (search hist) */ -) +/// Add the given string to the given history. If the string is already in the +/// history then it is moved to the front. "histype" may be one of he HIST_ +/// values. +/// +/// @parma in_map consider maptick when inside a mapping +/// @param sep separator character used (search hist) +void add_to_history(int histype, char_u *new_entry, int in_map, int sep) { histentry_T *hisptr; diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index 4b2dccd8a4..b4f22dbf33 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -48,20 +48,7 @@ #endif static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) { - if (!buf->b_extmark_ns) { - if (!put) { - return NULL; - } - buf->b_extmark_ns = map_new(uint64_t, ExtmarkNs)(); - buf->b_extmark_index = map_new(uint64_t, ExtmarkItem)(); - } - - ExtmarkNs *ns = map_ref(uint64_t, ExtmarkNs)(buf->b_extmark_ns, ns_id, put); - if (put && ns->map == NULL) { - ns->map = map_new(uint64_t, uint64_t)(); - ns->free_id = 1; - } - return ns; + return map_ref(uint64_t, ExtmarkNs)(buf->b_extmark_ns, ns_id, put); } @@ -195,7 +182,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_row, colnr_T u_col) { - if (!buf->b_extmark_ns) { + if (!map_size(buf->b_extmark_ns)) { return false; } @@ -215,12 +202,9 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, } // the value is either zero or the lnum (row+1) if highlight was present. - static Map(uint64_t, ssize_t) *delete_set = NULL; + static Map(uint64_t, ssize_t) delete_set = MAP_INIT; typedef struct { Decoration *decor; int row1; } DecorItem; static kvec_t(DecorItem) decors; - if (delete_set == NULL) { - delete_set = map_new(uint64_t, ssize_t)(); - } MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, l_row, l_col, itr); @@ -231,7 +215,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, || (mark.row == u_row && mark.col > u_col)) { break; } - ssize_t *del_status = map_ref(uint64_t, ssize_t)(delete_set, mark.id, + ssize_t *del_status = map_ref(uint64_t, ssize_t)(&delete_set, mark.id, false); if (del_status) { marktree_del_itr(buf->b_marktree, itr, false); @@ -240,7 +224,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, decor_redraw(buf, it.row1, mark.row, it.decor); decor_free(it.decor); } - map_del(uint64_t, ssize_t)(delete_set, mark.id); + map_del(uint64_t, ssize_t)(&delete_set, mark.id); continue; } @@ -261,7 +245,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, kv_push(decors, ((DecorItem) { .decor = item.decor, .row1 = mark.row })); } - map_put(uint64_t, ssize_t)(delete_set, other, decor_id); + map_put(uint64_t, ssize_t)(&delete_set, other, decor_id); } else if (item.decor) { decor_redraw(buf, mark.row, mark.row, item.decor); decor_free(item.decor); @@ -276,7 +260,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, } uint64_t id; ssize_t decor_id; - map_foreach(delete_set, id, decor_id, { + map_foreach(&delete_set, id, decor_id, { mtpos_t pos = marktree_lookup(buf->b_marktree, id, itr); assert(itr->node); marktree_del_itr(buf->b_marktree, itr, false); @@ -286,7 +270,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, decor_free(it.decor); } }); - map_clear(uint64_t, ssize_t)(delete_set); + map_clear(uint64_t, ssize_t)(&delete_set); kv_size(decors) = 0; return marks_cleared; } @@ -383,7 +367,7 @@ ExtmarkInfo extmark_from_id(buf_T *buf, uint64_t ns_id, uint64_t id) // free extmarks from the buffer void extmark_free_all(buf_T *buf) { - if (!buf->b_extmark_ns) { + if (!map_size(buf->b_extmark_ns)) { return; } @@ -395,17 +379,17 @@ void extmark_free_all(buf_T *buf) map_foreach(buf->b_extmark_ns, id, ns, { (void)id; - map_free(uint64_t, uint64_t)(ns.map); + map_destroy(uint64_t, uint64_t)(ns.map); }); - map_free(uint64_t, ExtmarkNs)(buf->b_extmark_ns); - buf->b_extmark_ns = NULL; + map_destroy(uint64_t, ExtmarkNs)(buf->b_extmark_ns); + map_init(uint64_t, ExtmarkNs, buf->b_extmark_ns); map_foreach(buf->b_extmark_index, id, item, { (void)id; decor_free(item.decor); }); - map_free(uint64_t, ExtmarkItem)(buf->b_extmark_index); - buf->b_extmark_index = NULL; + map_destroy(uint64_t, ExtmarkItem)(buf->b_extmark_index); + map_init(uint64_t, ExtmarkItem, buf->b_extmark_index); } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index ee8be8429f..3d058e1d09 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -11,7 +11,7 @@ #include <fcntl.h> #include "nvim/vim.h" -#include "nvim/api/private/handle.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii.h" #include "nvim/fileio.h" #include "nvim/buffer.h" diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 6989c29d57..51a8a85aa0 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -2961,7 +2961,7 @@ static void foldlevelIndent(fline_T *flp) linenr_T lnum = flp->lnum + flp->off; buf = flp->wp->w_buffer; - s = skipwhite(ml_get_buf(buf, lnum, FALSE)); + s = skipwhite(ml_get_buf(buf, lnum, false)); /* empty line or lines starting with a character in 'foldignore': level * depends on surrounding lines */ @@ -3123,7 +3123,7 @@ static void foldlevelMarker(fline_T *flp) flp->start = 0; flp->lvl_next = flp->lvl; - s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, FALSE); + s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, false); while (*s) { if (*s == cstart && STRNCMP(s + 1, startmarker, foldstartmarkerlen - 1) == 0) { diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 1d41cabfa4..c14b465f92 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -321,8 +321,6 @@ end output:write([[ void msgpack_rpc_init_method_table(void) { - methods = map_new(String, MsgpackRpcRequestHandler)(); - ]]) for i = 1, #functions do diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 2b6c5b9f37..28f58e2c34 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -52,7 +52,6 @@ #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/fileio.h" -#include "nvim/api/private/handle.h" /// Index in scriptin diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 29ee7aae56..7341ac9393 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -25,22 +25,16 @@ static bool hlstate_active = false; static kvec_t(HlEntry) attr_entries = KV_INITIAL_VALUE; -static Map(HlEntry, int) *attr_entry_ids; -static Map(int, int) *combine_attr_entries; -static Map(int, int) *blend_attr_entries; -static Map(int, int) *blendthrough_attr_entries; +static Map(HlEntry, int) attr_entry_ids = MAP_INIT; +static Map(int, int) combine_attr_entries = MAP_INIT; +static Map(int, int) blend_attr_entries = MAP_INIT; +static Map(int, int) blendthrough_attr_entries = MAP_INIT; /// highlight entries private to a namespace -static Map(ColorKey, ColorItem) *ns_hl; +static Map(ColorKey, ColorItem) ns_hl; void highlight_init(void) { - attr_entry_ids = map_new(HlEntry, int)(); - combine_attr_entries = map_new(int, int)(); - blend_attr_entries = map_new(int, int)(); - blendthrough_attr_entries = map_new(int, int)(); - ns_hl = map_new(ColorKey, ColorItem)(); - // index 0 is no attribute, add dummy entry: kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown, .id1 = 0, .id2 = 0 })); @@ -71,7 +65,7 @@ static int get_attr_entry(HlEntry entry) entry.id2 = 0; } - int id = map_get(HlEntry, int)(attr_entry_ids, entry); + int id = map_get(HlEntry, int)(&attr_entry_ids, entry); if (id > 0) { return id; } @@ -104,7 +98,7 @@ static int get_attr_entry(HlEntry entry) id = (int)next_id; kv_push(attr_entries, entry); - map_put(HlEntry, int)(attr_entry_ids, entry, id); + map_put(HlEntry, int)(&attr_entry_ids, entry, id); Array inspect = hl_inspect(id); @@ -154,7 +148,7 @@ void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id) { DecorProvider *p = get_decor_provider(ns_id, true); if ((attrs.rgb_ae_attr & HL_DEFAULT) - && map_has(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id))) { + && map_has(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id))) { return; } int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs); @@ -162,7 +156,7 @@ void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id) .link_id = link_id, .version = p->hl_valid, .is_default = (attrs.rgb_ae_attr & HL_DEFAULT) }; - map_put(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id), it); + map_put(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id), it); } int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault) @@ -177,7 +171,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault) } DecorProvider *p = get_decor_provider(ns_id, true); - ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id)); + ColorItem it = map_get(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id)); // TODO(bfredl): map_ref true even this? bool valid_cache = it.version >= p->hl_valid; @@ -220,7 +214,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault) it.attr_id = fallback ? -1 : hl_get_syn_attr((int)ns_id, hl_id, attrs); it.version = p->hl_valid-tmp; it.is_default = attrs.rgb_ae_attr & HL_DEFAULT; - map_put(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id), it); + map_put(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id), it); } if (it.is_default && nodefault) { @@ -395,28 +389,28 @@ void clear_hl_tables(bool reinit) { if (reinit) { kv_size(attr_entries) = 1; - map_clear(HlEntry, int)(attr_entry_ids); - map_clear(int, int)(combine_attr_entries); - map_clear(int, int)(blend_attr_entries); - map_clear(int, int)(blendthrough_attr_entries); + map_clear(HlEntry, int)(&attr_entry_ids); + map_clear(int, int)(&combine_attr_entries); + map_clear(int, int)(&blend_attr_entries); + map_clear(int, int)(&blendthrough_attr_entries); memset(highlight_attr_last, -1, sizeof(highlight_attr_last)); highlight_attr_set_all(); highlight_changed(); screen_invalidate_highlights(); } else { kv_destroy(attr_entries); - map_free(HlEntry, int)(attr_entry_ids); - map_free(int, int)(combine_attr_entries); - map_free(int, int)(blend_attr_entries); - map_free(int, int)(blendthrough_attr_entries); - map_free(ColorKey, ColorItem)(ns_hl); + map_destroy(HlEntry, int)(&attr_entry_ids); + map_destroy(int, int)(&combine_attr_entries); + map_destroy(int, int)(&blend_attr_entries); + map_destroy(int, int)(&blendthrough_attr_entries); + map_destroy(ColorKey, ColorItem)(&ns_hl); } } void hl_invalidate_blends(void) { - map_clear(int, int)(blend_attr_entries); - map_clear(int, int)(blendthrough_attr_entries); + map_clear(int, int)(&blend_attr_entries); + map_clear(int, int)(&blendthrough_attr_entries); highlight_changed(); update_window_hl(curwin, true); } @@ -437,7 +431,7 @@ int hl_combine_attr(int char_attr, int prim_attr) // TODO(bfredl): could use a struct for clearer intent. int combine_tag = (char_attr << 16) + prim_attr; - int id = map_get(int, int)(combine_attr_entries, combine_tag); + int id = map_get(int, int)(&combine_attr_entries, combine_tag); if (id > 0) { return id; } @@ -494,7 +488,7 @@ int hl_combine_attr(int char_attr, int prim_attr) id = get_attr_entry((HlEntry){ .attr = new_en, .kind = kHlCombine, .id1 = char_attr, .id2 = prim_attr }); if (id > 0) { - map_put(int, int)(combine_attr_entries, combine_tag, id); + map_put(int, int)(&combine_attr_entries, combine_tag, id); } return id; @@ -550,8 +544,8 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through) int combine_tag = (back_attr << 16) + front_attr; Map(int, int) *map = (*through - ? blendthrough_attr_entries - : blend_attr_entries); + ? &blendthrough_attr_entries + : &blend_attr_entries); int id = map_get(int, int)(map, combine_tag); if (id > 0) { return id; diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5799c3ee98..cbc2273bc9 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -13,7 +13,6 @@ #include "nvim/func_attr.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/private/handle.h" #include "nvim/api/vim.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/vim.h" @@ -40,6 +39,7 @@ #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/lua/treesitter.h" +#include "nvim/lua/xdiff.h" #include "luv/luv.h" @@ -68,7 +68,8 @@ typedef struct { } #if __has_feature(address_sanitizer) - PMap(handle_T) *nlua_ref_markers = NULL; + static PMap(handle_T) nlua_ref_markers = MAP_INIT; + static bool nlua_track_refs = false; # define NLUA_TRACK_REFS #endif @@ -517,6 +518,10 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL // internal vim._treesitter... API nlua_add_treesitter(lstate); + // vim.diff + lua_pushcfunction(lstate, &nlua_xdl_diff); + lua_setfield(lstate, -2, "diff"); + lua_setglobal(lstate, "vim"); { @@ -564,7 +569,7 @@ void nlua_init(void) #ifdef NLUA_TRACK_REFS const char *env = os_getenv("NVIM_LUA_NOTRACK"); if (!env || !*env) { - nlua_ref_markers = pmap_new(handle_T)(); + nlua_track_refs = true; } #endif @@ -595,10 +600,10 @@ void nlua_free_all_mem(void) fprintf(stderr, "%d lua references were leaked!", nlua_refcount); } - if (nlua_ref_markers) { + if (nlua_track_refs) { // in case there are leaked luarefs, leak the associated memory // to get LeakSanitizer stacktraces on exit - pmap_free(handle_T)(nlua_ref_markers); + pmap_destroy(handle_T)(&nlua_ref_markers); } #endif @@ -997,9 +1002,9 @@ LuaRef nlua_ref(lua_State *lstate, int index) if (ref > 0) { nlua_refcount++; #ifdef NLUA_TRACK_REFS - if (nlua_ref_markers) { + if (nlua_track_refs) { // dummy allocation to make LeakSanitizer track our luarefs - pmap_put(handle_T)(nlua_ref_markers, ref, xmalloc(3)); + pmap_put(handle_T)(&nlua_ref_markers, ref, xmalloc(3)); } #endif } @@ -1013,8 +1018,8 @@ void nlua_unref(lua_State *lstate, LuaRef ref) nlua_refcount--; #ifdef NLUA_TRACK_REFS // NB: don't remove entry from map to track double-unref - if (nlua_ref_markers) { - xfree(pmap_get(handle_T)(nlua_ref_markers, ref)); + if (nlua_track_refs) { + xfree(pmap_get(handle_T)(&nlua_ref_markers, ref)); } #endif luaL_unref(lstate, LUA_REGISTRYINDEX, ref); diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 2dfcd9a958..ed475c324f 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -18,7 +18,7 @@ #include "tree_sitter/api.h" #include "nvim/lua/treesitter.h" -#include "nvim/api/private/handle.h" +#include "nvim/api/private/helpers.h" #include "nvim/memline.h" #include "nvim/buffer.h" @@ -105,7 +105,7 @@ static struct luaL_Reg treecursor_meta[] = { { NULL, NULL } }; -static PMap(cstr_t) *langs; +static PMap(cstr_t) langs = MAP_INIT; static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) { @@ -123,8 +123,6 @@ static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) /// all global state is stored in the regirstry of the lua_State void tslua_init(lua_State *L) { - langs = pmap_new(cstr_t)(); - // type metatables build_meta(L, TS_META_PARSER, parser_meta); build_meta(L, TS_META_TREE, tree_meta); @@ -137,7 +135,7 @@ void tslua_init(lua_State *L) int tslua_has_language(lua_State *L) { const char *lang_name = luaL_checkstring(L, 1); - lua_pushboolean(L, pmap_has(cstr_t)(langs, lang_name)); + lua_pushboolean(L, pmap_has(cstr_t)(&langs, lang_name)); return 1; } @@ -146,7 +144,7 @@ int tslua_add_language(lua_State *L) const char *path = luaL_checkstring(L, 1); const char *lang_name = luaL_checkstring(L, 2); - if (pmap_has(cstr_t)(langs, lang_name)) { + if (pmap_has(cstr_t)(&langs, lang_name)) { return 0; } @@ -189,7 +187,7 @@ int tslua_add_language(lua_State *L) TREE_SITTER_LANGUAGE_VERSION, lang_version); } - pmap_put(cstr_t)(langs, xstrdup(lang_name), lang); + pmap_put(cstr_t)(&langs, xstrdup(lang_name), lang); lua_pushboolean(L, true); return 1; @@ -199,7 +197,7 @@ int tslua_inspect_lang(lua_State *L) { const char *lang_name = luaL_checkstring(L, 1); - TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name); + TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { return luaL_error(L, "no such language: %s", lang_name); } @@ -247,7 +245,7 @@ int tslua_push_parser(lua_State *L) // Gather language name const char *lang_name = luaL_checkstring(L, 1); - TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name); + TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { return luaL_error(L, "no such language: %s", lang_name); } @@ -1175,7 +1173,7 @@ int tslua_parse_query(lua_State *L) } const char *lang_name = lua_tostring(L, 1); - TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name); + TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { return luaL_error(L, "no such language: %s", lang_name); } diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 8cecaa51dd..ed435439a4 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -178,8 +178,8 @@ end --- Return a human-readable representation of the given object. --- ---@see https://github.com/kikito/inspect.lua ---@see https://github.com/mpeterv/vinspect +---@see https://github.com/kikito/inspect.lua +---@see https://github.com/mpeterv/vinspect local function inspect(object, options) -- luacheck: no unused error(object, options) -- Stub for gen_vimdoc.py end @@ -203,15 +203,15 @@ do --- end)(vim.paste) --- </pre> --- - --@see |paste| + ---@see |paste| --- - --@param lines |readfile()|-style list of lines to paste. |channel-lines| - --@param phase -1: "non-streaming" paste: the call contains all lines. + ---@param lines |readfile()|-style list of lines to paste. |channel-lines| + ---@param phase -1: "non-streaming" paste: the call contains all lines. --- If paste is "streamed", `phase` indicates the stream state: --- - 1: starts the paste (exactly once) --- - 2: continues the paste (zero or more times) --- - 3: ends the paste (exactly once) - --@returns false if client should cancel the paste. + ---@returns false if client should cancel the paste. function vim.paste(lines, phase) local call = vim.api.nvim_call_function local now = vim.loop.now() @@ -279,7 +279,7 @@ function vim.schedule_wrap(cb) end --- <Docs described in |vim.empty_dict()| > ---@private +---@private function vim.empty_dict() return setmetatable({}, vim._empty_dict_mt) end @@ -338,12 +338,12 @@ end --- Get a table of lines with start, end columns for a region marked by two points --- ---@param bufnr number of buffer ---@param pos1 (line, column) tuple marking beginning of region ---@param pos2 (line, column) tuple marking end of region ---@param regtype type of selection (:help setreg) ---@param inclusive boolean indicating whether the selection is end-inclusive ---@return region lua table of the form {linenr = {startcol,endcol}} +---@param bufnr number of buffer +---@param pos1 (line, column) tuple marking beginning of region +---@param pos2 (line, column) tuple marking end of region +---@param regtype type of selection (:help setreg) +---@param inclusive boolean indicating whether the selection is end-inclusive +---@return region lua table of the form {linenr = {startcol,endcol}} function vim.region(bufnr, pos1, pos2, regtype, inclusive) if not vim.api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) @@ -390,9 +390,9 @@ end --- Use to do a one-shot timer that calls `fn` --- Note: The {fn} is |schedule_wrap|ped automatically, so API functions are --- safe to call. ---@param fn Callback to call once `timeout` expires ---@param timeout Number of milliseconds to wait before calling `fn` ---@return timer luv timer object +---@param fn Callback to call once `timeout` expires +---@param timeout Number of milliseconds to wait before calling `fn` +---@return timer luv timer object function vim.defer_fn(fn, timeout) vim.validate { fn = { fn, 'c', true}; } local timer = vim.loop.new_timer() @@ -408,11 +408,12 @@ end --- Notification provider ---- without a runtime, writes to :Messages --- see :help nvim_notify ---@param msg Content of the notification to show to the user ---@param log_level Optional log level ---@param opts Dictionary with optional options (timeout, etc) +--- +--- Without a runtime, writes to :Messages +---@see :help nvim_notify +---@param msg Content of the notification to show to the user +---@param log_level Optional log level +---@param opts Dictionary with optional options (timeout, etc) function vim.notify(msg, log_level, _opts) if log_level == vim.log.levels.ERROR then @@ -429,21 +430,21 @@ local on_keystroke_callbacks = {} --- Register a lua {fn} with an {id} to be run after every keystroke. --- ---@param fn function: Function to call. It should take one argument, which is a string. +---@param fn function: Function to call. It should take one argument, which is a string. --- The string will contain the literal keys typed. --- See |i_CTRL-V| --- --- If {fn} is nil, it removes the callback for the associated {ns_id} ---@param ns_id number? Namespace ID. If not passed or 0, will generate and return a new +---@param ns_id number? Namespace ID. If not passed or 0, will generate and return a new --- namespace ID from |nvim_create_namesapce()| --- ---@return number Namespace ID associated with {fn} +---@return number Namespace ID associated with {fn} --- ---@note {fn} will be automatically removed if an error occurs while calling. +---@note {fn} will be automatically removed if an error occurs while calling. --- This is to prevent the annoying situation of every keystroke erroring --- while trying to remove a broken callback. ---@note {fn} will not be cleared from |nvim_buf_clear_namespace()| ---@note {fn} will receive the keystrokes after mappings have been evaluated +---@note {fn} will not be cleared from |nvim_buf_clear_namespace()| +---@note {fn} will receive the keystrokes after mappings have been evaluated function vim.register_keystroke_callback(fn, ns_id) vim.validate { fn = { fn, 'c', true}, @@ -459,7 +460,7 @@ function vim.register_keystroke_callback(fn, ns_id) end --- Function that executes the keystroke callbacks. ---@private +---@private function vim._log_keystroke(char) local failed_ns_ids = {} local failed_messages = {} diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c new file mode 100644 index 0000000000..d50f874a82 --- /dev/null +++ b/src/nvim/lua/xdiff.c @@ -0,0 +1,334 @@ +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "nvim/vim.h" +#include "nvim/xdiff/xdiff.h" +#include "nvim/lua/xdiff.h" +#include "nvim/lua/converter.h" +#include "nvim/lua/executor.h" +#include "nvim/api/private/helpers.h" + +typedef enum { + kNluaXdiffModeUnified = 0, + kNluaXdiffModeOnHunkCB, + kNluaXdiffModeLocations, +} NluaXdiffMode; + +typedef struct { + lua_State *lstate; + Error *err; +} hunkpriv_t; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "lua/xdiff.c.generated.h" +#endif + +static int write_string(void *priv, mmbuffer_t *mb, int nbuf) +{ + luaL_Buffer *buf = (luaL_Buffer *)priv; + for (int i = 0; i < nbuf; i++) { + const long size = mb[i].size; + for (long total = 0; total < size; total += LUAL_BUFFERSIZE) { + const int tocopy = MIN((int)(size - total), LUAL_BUFFERSIZE); + char *p = luaL_prepbuffer(buf); + if (!p) { + return -1; + } + memcpy(p, mb[i].ptr + total, (unsigned)tocopy); + luaL_addsize(buf, (unsigned)tocopy); + } + } + return 0; +} + +// hunk_func callback used when opts.hunk_lines = true +static int hunk_locations_cb(long start_a, long count_a, + long start_b, long count_b, void *cb_data) +{ + // Mimic extra offsets done by xdiff, see: + // src/nvim/xdiff/xemit.c:284 + // src/nvim/xdiff/xutils.c:(356,368) + if (count_a > 0) { + start_a += 1; + } + if (count_b > 0) { + start_b += 1; + } + + lua_State * lstate = (lua_State *)cb_data; + lua_createtable(lstate, 0, 0); + + lua_pushinteger(lstate, start_a); + lua_rawseti(lstate, -2, 1); + lua_pushinteger(lstate, count_a); + lua_rawseti(lstate, -2, 2); + lua_pushinteger(lstate, start_b); + lua_rawseti(lstate, -2, 3); + lua_pushinteger(lstate, count_b); + lua_rawseti(lstate, -2, 4); + + lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2)+1); + + return 0; +} + +// hunk_func callback used when opts.on_hunk is given +static int call_on_hunk_cb(long start_a, long count_a, + long start_b, long count_b, void *cb_data) +{ + // Mimic extra offsets done by xdiff, see: + // src/nvim/xdiff/xemit.c:284 + // src/nvim/xdiff/xutils.c:(356,368) + if (count_a > 0) { + start_a += 1; + } + if (count_b > 0) { + start_b += 1; + } + + hunkpriv_t *priv = (hunkpriv_t *)cb_data; + lua_State * lstate = priv->lstate; + Error *err = priv->err; + const int fidx = lua_gettop(lstate); + lua_pushvalue(lstate, fidx); + lua_pushinteger(lstate, start_a); + lua_pushinteger(lstate, count_a); + lua_pushinteger(lstate, start_b); + lua_pushinteger(lstate, count_b); + + if (lua_pcall(lstate, 4, 1, 0) != 0) { + api_set_error(err, kErrorTypeException, + "error running function on_hunk: %s", + lua_tostring(lstate, -1)); + return -1; + } + + int r = 0; + if (lua_isnumber(lstate, -1)) { + r = (int)lua_tonumber(lstate, -1); + } + + lua_pop(lstate, 1); + lua_settop(lstate, fidx); + return r; +} + +static mmfile_t get_string_arg(lua_State *lstate, int idx) +{ + if (lua_type(lstate, idx) != LUA_TSTRING) { + luaL_argerror(lstate, idx, "expected string"); + } + mmfile_t mf; + mf.ptr = (char *)lua_tolstring(lstate, idx, (size_t *)&mf.size); + return mf; +} + +// Helper function for validating option types +static bool check_xdiff_opt(ObjectType actType, ObjectType expType, + const char *name, Error *err) +{ + if (actType != expType) { + const char * type_str = + expType == kObjectTypeString ? "string" : + expType == kObjectTypeInteger ? "integer" : + expType == kObjectTypeBoolean ? "boolean" : + expType == kObjectTypeLuaRef ? "function" : + "NA"; + + api_set_error(err, kErrorTypeValidation, "%s is not a %s", name, + type_str); + return true; + } + + return false; +} + +static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, + xdemitconf_t *cfg, + xpparam_t *params, Error *err) +{ + const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err); + + NluaXdiffMode mode = kNluaXdiffModeUnified; + + bool had_on_hunk = false; + bool had_result_type_indices = false; + for (size_t i = 0; i < opts.size; i++) { + String k = opts.items[i].key; + Object *v = &opts.items[i].value; + if (strequal("on_hunk", k.data)) { + if (check_xdiff_opt(v->type, kObjectTypeLuaRef, "on_hunk", err)) { + goto exit_1; + } + had_on_hunk = true; + nlua_pushref(lstate, v->data.luaref); + } else if (strequal("result_type", k.data)) { + if (check_xdiff_opt(v->type, kObjectTypeString, "result_type", err)) { + goto exit_1; + } + if (strequal("unified", v->data.string.data)) { + } else if (strequal("indices", v->data.string.data)) { + had_result_type_indices = true; + } else { + api_set_error(err, kErrorTypeValidation, "not a valid result_type"); + goto exit_1; + } + } else if (strequal("algorithm", k.data)) { + if (check_xdiff_opt(v->type, kObjectTypeString, "algorithm", err)) { + goto exit_1; + } + if (strequal("myers", v->data.string.data)) { + // default + } else if (strequal("minimal", v->data.string.data)) { + cfg->flags |= XDF_NEED_MINIMAL; + } else if (strequal("patience", v->data.string.data)) { + cfg->flags |= XDF_PATIENCE_DIFF; + } else if (strequal("histogram", v->data.string.data)) { + cfg->flags |= XDF_HISTOGRAM_DIFF; + } else { + api_set_error(err, kErrorTypeValidation, "not a valid algorithm"); + goto exit_1; + } + } else if (strequal("ctxlen", k.data)) { + if (check_xdiff_opt(v->type, kObjectTypeInteger, "ctxlen", err)) { + goto exit_1; + } + cfg->ctxlen = v->data.integer; + } else if (strequal("interhunkctxlen", k.data)) { + if (check_xdiff_opt(v->type, kObjectTypeInteger, "interhunkctxlen", + err)) { + goto exit_1; + } + cfg->interhunkctxlen = v->data.integer; + } else { + struct { + const char *name; + unsigned long value; + } flags[] = { + { "ignore_whitespace" , XDF_IGNORE_WHITESPACE }, + { "ignore_whitespace_change" , XDF_IGNORE_WHITESPACE_CHANGE }, + { "ignore_whitespace_change_at_eol", XDF_IGNORE_WHITESPACE_AT_EOL }, + { "ignore_cr_at_eol" , XDF_IGNORE_CR_AT_EOL }, + { "ignore_blank_lines" , XDF_IGNORE_BLANK_LINES }, + { "indent_heuristic" , XDF_INDENT_HEURISTIC }, + { NULL , 0 }, + }; + bool key_used = false; + for (size_t j = 0; flags[j].name; j++) { + if (strequal(flags[j].name, k.data)) { + if (check_xdiff_opt(v->type, kObjectTypeBoolean, flags[j].name, + err)) { + goto exit_1; + } + if (v->data.boolean) { + params->flags |= flags[j].value; + } + key_used = true; + break; + } + } + + if (key_used) { + continue; + } + + api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + goto exit_1; + } + } + + if (had_on_hunk) { + mode = kNluaXdiffModeOnHunkCB; + cfg->hunk_func = call_on_hunk_cb; + } else if (had_result_type_indices) { + mode = kNluaXdiffModeLocations; + cfg->hunk_func = hunk_locations_cb; + } + +exit_1: + api_free_dictionary(opts); + return mode; +} + +int nlua_xdl_diff(lua_State *lstate) +{ + if (lua_gettop(lstate) < 2) { + return luaL_error(lstate, "Expected at least 2 arguments"); + } + mmfile_t ma = get_string_arg(lstate, 1); + mmfile_t mb = get_string_arg(lstate, 2); + + Error err = ERROR_INIT; + + xdemitconf_t cfg; + xpparam_t params; + xdemitcb_t ecb; + + memset(&cfg , 0, sizeof(cfg)); + memset(¶ms, 0, sizeof(params)); + memset(&ecb , 0, sizeof(ecb)); + + NluaXdiffMode mode = kNluaXdiffModeUnified; + + if (lua_gettop(lstate) == 3) { + if (lua_type(lstate, 3) != LUA_TTABLE) { + return luaL_argerror(lstate, 3, "expected table"); + } + + mode = process_xdl_diff_opts(lstate, &cfg, ¶ms, &err); + + if (ERROR_SET(&err)) { + goto exit_0; + } + } + + luaL_Buffer buf; + hunkpriv_t *priv = NULL; + switch (mode) { + case kNluaXdiffModeUnified: + luaL_buffinit(lstate, &buf); + ecb.priv = &buf; + ecb.outf = write_string; + break; + case kNluaXdiffModeOnHunkCB: + priv = xmalloc(sizeof(*priv)); + priv->lstate = lstate; + priv->err = &err; + ecb.priv = priv; + break; + case kNluaXdiffModeLocations: + lua_createtable(lstate, 0, 0); + ecb.priv = lstate; + break; + } + + if (xdl_diff(&ma, &mb, ¶ms, &cfg, &ecb) == -1) { + if (!ERROR_SET(&err)) { + api_set_error(&err, kErrorTypeException, + "Error while performing diff operation"); + } + } + + XFREE_CLEAR(priv); + +exit_0: + if (ERROR_SET(&err)) { + luaL_where(lstate, 1); + lua_pushstring(lstate, err.msg); + api_clear_error(&err); + lua_concat(lstate, 2); + return lua_error(lstate); + } else if (mode == kNluaXdiffModeUnified) { + luaL_pushresult(&buf); + return 1; + } else if (mode == kNluaXdiffModeLocations) { + return 1; + } + return 0; +} diff --git a/src/nvim/lua/xdiff.h b/src/nvim/lua/xdiff.h new file mode 100644 index 0000000000..cae7c98e81 --- /dev/null +++ b/src/nvim/lua/xdiff.h @@ -0,0 +1,12 @@ +#ifndef NVIM_LUA_XDIFF_H +#define NVIM_LUA_XDIFF_H + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "lua/xdiff.h.generated.h" +#endif + +#endif // NVIM_LUA_XDIFF_H diff --git a/src/nvim/main.c b/src/nvim/main.c index 136608afdf..9fc82a75af 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -78,7 +78,6 @@ #include "nvim/api/ui.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/private/handle.h" #include "nvim/api/private/dispatch.h" #ifndef WIN32 # include "nvim/os/pty_process_unix.h" @@ -126,8 +125,6 @@ void event_init(void) signal_init(); // finish mspgack-rpc initialization channel_init(); - remote_ui_init(); - api_vim_init(); terminal_init(); ui_init(); } @@ -160,13 +157,10 @@ void early_init(mparm_T *paramp) { env_init(); fs_init(); - handle_init(); - decor_init(); eval_init(); // init global variables init_path(argv0 ? argv0 : "nvim"); init_normal_cmds(); // Init the table of Normal mode commands. highlight_init(); - syntax_init(); #ifdef WIN32 OSVERSIONINFO ovi; diff --git a/src/nvim/map.c b/src/nvim/map.c index 86dc257e40..ccd332192e 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -54,56 +54,48 @@ INITIALIZER_DECLARE(T, U, __VA_ARGS__); \ __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \ \ - Map(T, U) *map_##T##_##U##_new() \ + void map_##T##_##U##_destroy(Map(T, U) *map) \ { \ - Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \ - rv->table = kh_init(T##_##U##_map); \ - return rv; \ - } \ - \ - void map_##T##_##U##_free(Map(T, U) *map) \ - { \ - kh_destroy(T##_##U##_map, map->table); \ - xfree(map); \ + kh_dealloc(T##_##U##_map, &map->table); \ } \ \ U map_##T##_##U##_get(Map(T, U) *map, T key) \ { \ khiter_t k; \ \ - if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \ + if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \ return INITIALIZER(T, U); \ } \ \ - return kh_val(map->table, k); \ + return kh_val(&map->table, k); \ } \ \ bool map_##T##_##U##_has(Map(T, U) *map, T key) \ { \ - return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \ + return kh_get(T##_##U##_map, &map->table, key) != kh_end(&map->table); \ } \ \ T map_##T##_##U##_key(Map(T, U) *map, T key) \ { \ khiter_t k; \ \ - if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \ + if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \ abort(); /* Caller must check map_has(). */ \ } \ \ - return kh_key(map->table, k); \ + return kh_key(&map->table, k); \ } \ U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \ { \ int ret; \ U rv = INITIALIZER(T, U); \ - khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \ + khiter_t k = kh_put(T##_##U##_map, &map->table, key, &ret); \ \ if (!ret) { \ - rv = kh_val(map->table, k); \ + rv = kh_val(&map->table, k); \ } \ \ - kh_val(map->table, k) = value; \ + kh_val(&map->table, k) = value; \ return rv; \ } \ \ @@ -112,18 +104,18 @@ int ret; \ khiter_t k; \ if (put) { \ - k = kh_put(T##_##U##_map, map->table, key, &ret); \ + k = kh_put(T##_##U##_map, &map->table, key, &ret); \ if (ret) { \ - kh_val(map->table, k) = INITIALIZER(T, U); \ + kh_val(&map->table, k) = INITIALIZER(T, U); \ } \ } else { \ - k = kh_get(T##_##U##_map, map->table, key); \ - if (k == kh_end(map->table)) { \ + k = kh_get(T##_##U##_map, &map->table, key); \ + if (k == kh_end(&map->table)) { \ return NULL; \ } \ } \ \ - return &kh_val(map->table, k); \ + return &kh_val(&map->table, k); \ } \ \ U map_##T##_##U##_del(Map(T, U) *map, T key) \ @@ -131,9 +123,9 @@ U rv = INITIALIZER(T, U); \ khiter_t k; \ \ - if ((k = kh_get(T##_##U##_map, map->table, key)) != kh_end(map->table)) { \ - rv = kh_val(map->table, k); \ - kh_del(T##_##U##_map, map->table, k); \ + if ((k = kh_get(T##_##U##_map, &map->table, key)) != kh_end(&map->table)) { \ + rv = kh_val(&map->table, k); \ + kh_del(T##_##U##_map, &map->table, k); \ } \ \ return rv; \ @@ -141,7 +133,7 @@ \ void map_##T##_##U##_clear(Map(T, U) *map) \ { \ - kh_clear(T##_##U##_map, map->table); \ + kh_clear(T##_##U##_map, &map->table); \ } static inline khint_t String_hash(String s) @@ -199,7 +191,7 @@ MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER) MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER) -#define EXTMARK_NS_INITIALIZER { 0, 0 } +#define EXTMARK_NS_INITIALIZER { { MAP_INIT }, 1 } MAP_IMPL(uint64_t, ExtmarkNs, EXTMARK_NS_INITIALIZER) #define EXTMARK_ITEM_INITIALIZER { 0, 0, NULL } MAP_IMPL(uint64_t, ExtmarkItem, EXTMARK_ITEM_INITIALIZER) diff --git a/src/nvim/map.h b/src/nvim/map.h index a35a2c1672..d6515878a2 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -18,11 +18,12 @@ KHASH_DECLARE(T##_##U##_map, T, U) \ \ typedef struct { \ - khash_t(T##_##U##_map) *table; \ + khash_t(T##_##U##_map) table; \ } Map(T, U); \ \ Map(T, U) *map_##T##_##U##_new(void); \ void map_##T##_##U##_free(Map(T, U) *map); \ + void map_##T##_##U##_destroy(Map(T, U) *map); \ U map_##T##_##U##_get(Map(T, U) *map, T key); \ bool map_##T##_##U##_has(Map(T, U) *map, T key); \ T map_##T##_##U##_key(Map(T, U) *map, T key); \ @@ -45,7 +46,7 @@ MAP_DECLS(uint64_t, uint64_t) // NB: this is the only way to define a struct both containing and contained // in a map... typedef struct ExtmarkNs { // For namespacing extmarks - Map(uint64_t, uint64_t) *map; // For fast lookup + Map(uint64_t, uint64_t) map[1]; // For fast lookup uint64_t free_id; // For automatically assigning id's } ExtmarkNs; @@ -58,8 +59,10 @@ MAP_DECLS(String, handle_T) MAP_DECLS(ColorKey, ColorItem) -#define map_new(T, U) map_##T##_##U##_new -#define map_free(T, U) map_##T##_##U##_free +#define MAP_INIT { { 0, 0, 0, 0, NULL, NULL, NULL } } +#define map_init(k, v, map) do { *(map) = (Map(k, v))MAP_INIT; } while (false) + +#define map_destroy(T, U) map_##T##_##U##_destroy #define map_get(T, U) map_##T##_##U##_get #define map_has(T, U) map_##T##_##U##_has #define map_key(T, U) map_##T##_##U##_key @@ -68,10 +71,9 @@ MAP_DECLS(ColorKey, ColorItem) #define map_del(T, U) map_##T##_##U##_del #define map_clear(T, U) map_##T##_##U##_clear -#define map_size(map) ((map)->table->size) +#define map_size(map) ((map)->table.size) -#define pmap_new(T) map_new(T, ptr_t) -#define pmap_free(T) map_free(T, ptr_t) +#define pmap_destroy(T) map_destroy(T, ptr_t) #define pmap_get(T) map_get(T, ptr_t) #define pmap_has(T) map_has(T, ptr_t) #define pmap_key(T) map_key(T, ptr_t) @@ -80,12 +82,13 @@ MAP_DECLS(ColorKey, ColorItem) /// @see pmap_del2 #define pmap_del(T) map_del(T, ptr_t) #define pmap_clear(T) map_clear(T, ptr_t) +#define pmap_init(k, map) map_init(k, ptr_t, map) #define map_foreach(map, key, value, block) \ - kh_foreach(map->table, key, value, block) + kh_foreach(&(map)->table, key, value, block) #define map_foreach_value(map, value, block) \ - kh_foreach_value(map->table, value, block) + kh_foreach_value(&(map)->table, value, block) void pmap_del2(PMap(cstr_t) *map, const char *key); diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index d0d843cbf8..a04f250fc3 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -250,7 +250,6 @@ void marktree_put_key(MarkTree *b, int row, int col, uint64_t id) if (!b->root) { b->root = (mtnode_t *)xcalloc(1, ILEN); - b->id2node = pmap_new(uint64_t)(); b->n_nodes++; } mtnode_t *r, *s; @@ -547,9 +546,9 @@ void marktree_clear(MarkTree *b) marktree_free_node(b->root); b->root = NULL; } - if (b->id2node) { - pmap_free(uint64_t)(b->id2node); - b->id2node = NULL; + if (b->id2node->table.keys) { + pmap_destroy(uint64_t)(b->id2node); + pmap_init(uint64_t, b->id2node); } b->n_keys = 0; b->n_nodes = 0; diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h index 3b83e3c44d..7af23765c3 100644 --- a/src/nvim/marktree.h +++ b/src/nvim/marktree.h @@ -63,7 +63,7 @@ typedef struct { uint64_t next_id; // TODO(bfredl): the pointer to node could be part of the larger // Map(uint64_t, ExtmarkItem) essentially; - PMap(uint64_t) *id2node; + PMap(uint64_t) id2node[1]; } MarkTree; diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 8229b8f6bc..4d435bc99f 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -382,7 +382,7 @@ error: */ void ml_setname(buf_T *buf) { - int success = FALSE; + bool success = false; memfile_T *mfp; char_u *fname; char_u *dirp; @@ -418,7 +418,7 @@ void ml_setname(buf_T *buf) /* if the file name is the same we don't have to do anything */ if (fnamecmp(fname, mfp->mf_fname) == 0) { xfree(fname); - success = TRUE; + success = true; break; } /* need to close the swap file before renaming */ @@ -429,7 +429,7 @@ void ml_setname(buf_T *buf) /* try to rename the swap file */ if (vim_rename(mfp->mf_fname, fname) == 0) { - success = TRUE; + success = true; mf_free_fnames(mfp); mf_set_fnames(mfp, fname); ml_upd_block0(buf, UB_SAME_DIR); @@ -758,12 +758,12 @@ void ml_recover(bool checkext) blocknr_T bnum; int page_count; int len; - int directly; + bool directly; linenr_T lnum; char_u *p; int i; long error; - int cannot_open; + bool cannot_open; linenr_T line_count; bool has_error; int idx; @@ -771,7 +771,7 @@ void ml_recover(bool checkext) int txt_start; off_T size; int called_from_main; - int serious_error = TRUE; + bool serious_error = true; long mtime; int attr; int orig_file_status = NOTDONE; @@ -791,10 +791,10 @@ void ml_recover(bool checkext) && vim_strchr((char_u *)"abcdefghijklmnopqrstuvw", TOLOWER_ASC(fname[len - 2])) != NULL && ASCII_ISALPHA(fname[len - 1])) { - directly = TRUE; - fname_used = vim_strsave(fname); /* make a copy for mf_open() */ + directly = true; + fname_used = vim_strsave(fname); // make a copy for mf_open() } else { - directly = FALSE; + directly = false; /* count the number of matching swap files */ len = recover_names(fname, FALSE, 0, NULL); @@ -1018,12 +1018,13 @@ void ml_recover(bool checkext) buf->b_ml.ml_stack = NULL; buf->b_ml.ml_stack_size = 0; /* no stack yet */ - if (curbuf->b_ffname == NULL) - cannot_open = TRUE; - else - cannot_open = FALSE; + if (curbuf->b_ffname == NULL) { + cannot_open = true; + } else { + cannot_open = false; + } - serious_error = FALSE; + serious_error = false; for (; !got_int; line_breakcheck()) { if (hp != NULL) mf_put(mfp, hp, false, false); /* release previous block */ @@ -1796,7 +1797,7 @@ theend: */ char_u *ml_get(linenr_T lnum) { - return ml_get_buf(curbuf, lnum, FALSE); + return ml_get_buf(curbuf, lnum, false); } /* @@ -2096,7 +2097,7 @@ static int ml_append_int( int total_moved = 0; /* init to shut up gcc */ DATA_BL *dp_right, *dp_left; int stack_idx; - int in_left; + bool in_left; int lineadd; blocknr_T bnum_left, bnum_right; linenr_T lnum_left, lnum_right; @@ -2113,22 +2114,22 @@ static int ml_append_int( */ if (db_idx < 0) { /* left block is new, right block is existing */ lines_moved = 0; - in_left = TRUE; - /* space_needed does not change */ - } else { /* left block is existing, right block is new */ + in_left = true; + // space_needed does not change + } else { // left block is existing, right block is new lines_moved = line_count - db_idx - 1; - if (lines_moved == 0) - in_left = FALSE; /* put new line in right block */ - /* space_needed does not change */ - else { + if (lines_moved == 0) { + in_left = false; // put new line in right block + // space_needed does not change + } else { data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) - dp->db_txt_start; total_moved = data_moved + lines_moved * INDEX_SIZE; if ((int)dp->db_free + total_moved >= space_needed) { - in_left = TRUE; /* put new line in left block */ + in_left = true; // put new line in left block space_needed = total_moved; } else { - in_left = FALSE; /* put new line in right block */ + in_left = false; // put new line in right block space_needed += total_moved; } } @@ -2761,7 +2762,7 @@ static void ml_flush_line(buf_T *buf) int start; int count; int i; - static int entered = FALSE; + static bool entered = false; if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL) return; /* nothing to do */ @@ -2770,7 +2771,7 @@ static void ml_flush_line(buf_T *buf) /* This code doesn't work recursively. */ if (entered) return; - entered = TRUE; + entered = true; buf->flush_count++; @@ -2833,7 +2834,7 @@ static void ml_flush_line(buf_T *buf) } xfree(new_line); - entered = FALSE; + entered = false; } buf->b_ml.ml_line_lnum = 0; diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index a2d8859c68..e5743f345b 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -38,7 +38,7 @@ #define log_server_msg(...) #endif -static PMap(cstr_t) *event_strings = NULL; +static PMap(cstr_t) event_strings = MAP_INIT; static msgpack_sbuffer out_buffer; #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -48,7 +48,6 @@ static msgpack_sbuffer out_buffer; void rpc_init(void) { ch_before_blocking_events = multiqueue_new_child(main_loop.events); - event_strings = pmap_new(cstr_t)(); msgpack_sbuffer_init(&out_buffer); } @@ -60,7 +59,6 @@ void rpc_start(Channel *channel) RpcState *rpc = &channel->rpc; rpc->closed = false; rpc->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE); - rpc->subscribed_events = pmap_new(cstr_t)(); rpc->next_request_id = 1; rpc->info = (Dictionary)ARRAY_DICT_INIT; kv_init(rpc->call_stack); @@ -183,11 +181,11 @@ void rpc_subscribe(uint64_t id, char *event) abort(); } - char *event_string = pmap_get(cstr_t)(event_strings, event); + char *event_string = pmap_get(cstr_t)(&event_strings, event); if (!event_string) { event_string = xstrdup(event); - pmap_put(cstr_t)(event_strings, event_string, event_string); + pmap_put(cstr_t)(&event_strings, event_string, event_string); } pmap_put(cstr_t)(channel->rpc.subscribed_events, event_string, event_string); @@ -497,7 +495,7 @@ static void broadcast_event(const char *name, Array args) kvec_t(Channel *) subscribed = KV_INITIAL_VALUE; Channel *channel; - map_foreach_value(channels, channel, { + map_foreach_value(&channels, channel, { if (channel->is_rpc && pmap_has(cstr_t)(channel->rpc.subscribed_events, name)) { kv_push(subscribed, channel); @@ -528,7 +526,7 @@ end: static void unsubscribe(Channel *channel, char *event) { - char *event_string = pmap_get(cstr_t)(event_strings, event); + char *event_string = pmap_get(cstr_t)(&event_strings, event); if (!event_string) { WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'", channel->id, event); @@ -536,7 +534,7 @@ static void unsubscribe(Channel *channel, char *event) } pmap_del(cstr_t)(channel->rpc.subscribed_events, event_string); - map_foreach_value(channels, channel, { + map_foreach_value(&channels, channel, { if (channel->is_rpc && pmap_has(cstr_t)(channel->rpc.subscribed_events, event_string)) { return; @@ -544,7 +542,7 @@ static void unsubscribe(Channel *channel, char *event) }); // Since the string is no longer used by other channels, release it's memory - pmap_del(cstr_t)(event_strings, event_string); + pmap_del(cstr_t)(&event_strings, event_string); xfree(event_string); } @@ -583,7 +581,7 @@ void rpc_free(Channel *channel) unsubscribe(channel, event_string); }); - pmap_free(cstr_t)(channel->rpc.subscribed_events); + pmap_destroy(cstr_t)(channel->rpc.subscribed_events); kv_destroy(channel->rpc.call_stack); api_free_dictionary(channel->rpc.info); } diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index 6ef8c027f0..de328af1ce 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -27,7 +27,7 @@ typedef struct { } RequestEvent; typedef struct { - PMap(cstr_t) *subscribed_events; + PMap(cstr_t) subscribed_events[1]; bool closed; msgpack_unpacker *unpacker; uint32_t next_request_id; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 2a530db934..7b2f77a6f9 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -4931,7 +4931,8 @@ static void nv_ident(cmdarg_T *cap) snprintf(buf, buf_size, ".,.+%" PRId64, (int64_t)(cap->count0 - 1)); } - STRCAT(buf, "! "); + do_cmdline_cmd("tabnew"); + STRCAT(buf, "terminal "); if (cap->count0 == 0 && isman_s) { STRCAT(buf, "man"); } else { @@ -5028,6 +5029,17 @@ static void nv_ident(cmdarg_T *cap) g_tag_at_cursor = true; do_cmdline_cmd(buf); g_tag_at_cursor = false; + + if (cmdchar == 'K' && !kp_ex && !kp_help) { + // Start insert mode in terminal buffer + restart_edit = 'i'; + + add_map((char_u *)"<buffer> <esc> <Cmd>call jobstop(&channel)<CR>", TERM_FOCUS, true); + do_cmdline_cmd("autocmd TermClose <buffer> " + " if !v:event.status |" + " exec 'bdelete! ' .. expand('<abuf>') |" + " endif"); + } } xfree(buf); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index a6eda26d75..178b454e4e 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1121,18 +1121,13 @@ static void put_reedit_in_typebuf(int silent) } } -/* - * Insert register contents "s" into the typeahead buffer, so that it will be - * executed again. - * When "esc" is TRUE it is to be taken literally: Escape CSI characters and - * no remapping. - */ -static int put_in_typebuf( - char_u *s, - bool esc, - bool colon, // add ':' before the line - int silent -) +/// Insert register contents "s" into the typeahead buffer, so that it will be +/// executed again. +/// +/// @param esc when true then it is to be taken literally: Escape CSI +/// characters and no remapping. +/// @param colon add ':' before the line +static int put_in_typebuf(char_u *s, bool esc, bool colon, int silent) { int retval = OK; @@ -1567,8 +1562,8 @@ int op_delete(oparg_T *oap) if (oap->line_count > 1) { lnum = curwin->w_cursor.lnum; - ++curwin->w_cursor.lnum; - del_lines(oap->line_count - 1, TRUE); + curwin->w_cursor.lnum++; + del_lines(oap->line_count - 1, true); curwin->w_cursor.lnum = lnum; } if (u_save_cursor() == FAIL) @@ -1593,7 +1588,7 @@ int op_delete(oparg_T *oap) u_clearline(); // "U" command not possible after "2cc" } } else { - del_lines(oap->line_count, TRUE); + del_lines(oap->line_count, true); beginline(BL_WHITE | BL_FIX); u_clearline(); /* "U" command not possible after "dd" */ } diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 008f5ef63b..92b5e14824 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -35,12 +35,11 @@ // Because `uv_os_getenv` requires allocating, we must manage a map to maintain // the behavior of `os_getenv`. -static PMap(cstr_t) *envmap; +static PMap(cstr_t) envmap = MAP_INIT; static uv_mutex_t mutex; void env_init(void) { - envmap = pmap_new(cstr_t)(); uv_mutex_init(&mutex); } @@ -66,8 +65,8 @@ const char *os_getenv(const char *name) } uv_mutex_lock(&mutex); int r = 0; - if (pmap_has(cstr_t)(envmap, name) - && !!(e = (char *)pmap_get(cstr_t)(envmap, name))) { + if (pmap_has(cstr_t)(&envmap, name) + && !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) { if (e[0] != '\0') { // Found non-empty cached env var. // NOTE: This risks incoherence if an in-process library changes the @@ -75,7 +74,7 @@ const char *os_getenv(const char *name) // that turns out to be a problem, we can just remove this codepath. goto end; } - pmap_del2(envmap, name); + pmap_del2(&envmap, name); } e = xmalloc(size); r = uv_os_getenv(name, e, &size); @@ -88,7 +87,7 @@ const char *os_getenv(const char *name) e = NULL; goto end; } - pmap_put(cstr_t)(envmap, xstrdup(name), e); + pmap_put(cstr_t)(&envmap, xstrdup(name), e); end: // Must do this before ELOG, log.c may call os_setenv. uv_mutex_unlock(&mutex); @@ -157,7 +156,7 @@ int os_setenv(const char *name, const char *value, int overwrite) assert(r != UV_EINVAL); // Destroy the old map item. Do this AFTER uv_os_setenv(), because `value` // could be a previous os_getenv() result. - pmap_del2(envmap, name); + pmap_del2(&envmap, name); // Must do this before ELOG, log.c may call os_setenv. uv_mutex_unlock(&mutex); if (r != 0) { @@ -174,7 +173,7 @@ int os_unsetenv(const char *name) return -1; } uv_mutex_lock(&mutex); - pmap_del2(envmap, name); + pmap_del2(&envmap, name); int r = uv_os_unsetenv(name); // Must do this before ELOG, log.c may call os_setenv. uv_mutex_unlock(&mutex); diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index be4bd9709b..44274e8f1d 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -7,7 +7,6 @@ #include <stdbool.h> #include <string.h> -#include "nvim/api/private/handle.h" #include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/os_unix.h" diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index c3cd210538..4da81f29e3 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -403,8 +403,10 @@ theend: return retval; } -/// Load scripts in "plugin" and "ftdetect" directories of the package. -static int load_pack_plugin(char_u *fname) +/// Load scripts in "plugin" directory of the package. +/// For opt packages, also load scripts in "ftdetect" (start packages already +/// load these from filetype.vim) +static int load_pack_plugin(bool opt, char_u *fname) { static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT @@ -421,7 +423,7 @@ static int load_pack_plugin(char_u *fname) // If runtime/filetype.vim wasn't loaded yet, the scripts will be // found when it loads. - if (eval_to_number(cmd) > 0) { + if (opt && eval_to_number(cmd) > 0) { do_cmdline_cmd("augroup filetypedetect"); vim_snprintf((char *)pat, len, ftpat, ffname); source_all_matches(pat); @@ -441,7 +443,7 @@ static int APP_ADD_DIR; static int APP_LOAD; static int APP_BOTH; -static void add_pack_plugin(char_u *fname, void *cookie) +static void add_pack_plugin(bool opt, char_u *fname, void *cookie) { if (cookie != &APP_LOAD) { char *buf = xmalloc(MAXPATHL); @@ -465,17 +467,27 @@ static void add_pack_plugin(char_u *fname, void *cookie) } if (cookie != &APP_ADD_DIR) { - load_pack_plugin(fname); + load_pack_plugin(opt, fname); } } +static void add_start_pack_plugin(char_u *fname, void *cookie) +{ + add_pack_plugin(false, fname, cookie); +} + +static void add_opt_pack_plugin(char_u *fname, void *cookie) +{ + add_pack_plugin(true, fname, cookie); +} + /// Add all packages in the "start" directory to 'runtimepath'. void add_pack_start_dirs(void) { do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT - add_pack_plugin, &APP_ADD_DIR); + add_start_pack_plugin, &APP_ADD_DIR); do_in_path(p_pp, (char_u *)"start/*", DIP_ALL + DIP_DIR, // NOLINT - add_pack_plugin, &APP_ADD_DIR); + add_start_pack_plugin, &APP_ADD_DIR); } /// Load plugins from all packages in the "start" directory. @@ -483,9 +495,9 @@ void load_start_packages(void) { did_source_packages = true; do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT - add_pack_plugin, &APP_LOAD); + add_start_pack_plugin, &APP_LOAD); do_in_path(p_pp, (char_u *)"start/*", DIP_ALL + DIP_DIR, // NOLINT - add_pack_plugin, &APP_LOAD); + add_start_pack_plugin, &APP_LOAD); } // ":packloadall" @@ -522,7 +534,8 @@ void ex_packadd(exarg_T *eap) res = do_in_path(p_pp, (char_u *)pat, DIP_ALL + DIP_DIR + (round == 2 && res == FAIL ? DIP_ERR : 0), - add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH); + round == 1 ? add_start_pack_plugin : add_opt_pack_plugin, + eap->forceit ? &APP_ADD_DIR : &APP_BOTH); xfree(pat); } } diff --git a/src/nvim/screen.c b/src/nvim/screen.c index e4030b76a3..208ae3488f 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -324,8 +324,7 @@ void update_curbuf(int type) /// @param type set to a NOT_VALID to force redraw of entire screen int update_screen(int type) { - static int did_intro = FALSE; - int did_one; + static bool did_intro = false; // Don't do anything if the screen structures are (not yet) valid. // A VimResized autocmd can invoke redrawing in the middle of a resize, @@ -578,7 +577,7 @@ int update_screen(int type) * Go from top to bottom through the windows, redrawing the ones that need * it. */ - did_one = FALSE; + bool did_one = false; search_hl.rm.regprog = NULL; @@ -597,7 +596,7 @@ int update_screen(int type) if (wp->w_redr_type != 0) { if (!did_one) { - did_one = TRUE; + did_one = true; start_search_hl(); } win_update(wp, &providers); @@ -635,7 +634,7 @@ int update_screen(int type) /* May put up an introductory message when not editing a file */ if (!did_intro) maybe_intro_message(); - did_intro = TRUE; + did_intro = true; for (size_t i = 0; i < kv_size(providers); i++) { DecorProvider *p = kv_A(providers, i); @@ -747,8 +746,7 @@ static void win_update(win_T *wp, Providers *providers) updating. 0 when no mid area updating. */ int bot_start = 999; /* first row of the bot area that needs updating. 999 when no bot area updating */ - int scrolled_down = FALSE; /* TRUE when scrolled down when - w_topline got smaller a bit */ + bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit bool top_to_mod = false; // redraw above mod_top int row; /* current window row to display */ @@ -756,8 +754,8 @@ static void win_update(win_T *wp, Providers *providers) int idx; /* current index in w_lines[] */ int srow; /* starting row of the current line */ - int eof = FALSE; /* if TRUE, we hit the end of the file */ - int didline = FALSE; /* if TRUE, we finished the last line */ + bool eof = false; // if true, we hit the end of the file + bool didline = false; // if true, we finished the last line int i; long j; static bool recursive = false; // being called recursively @@ -1339,7 +1337,7 @@ static void win_update(win_T *wp, Providers *providers) /* stop updating when hit the end of the file */ if (lnum > buf->b_ml.ml_line_count) { - eof = TRUE; + eof = true; break; } @@ -1596,7 +1594,7 @@ static void win_update(win_T *wp, Providers *providers) } if (lnum > buf->b_ml.ml_line_count) { - eof = TRUE; + eof = true; break; } } @@ -1841,10 +1839,10 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, } -/* - * Advance **color_cols and return TRUE when there are columns to draw. - */ -static int advance_color_col(int vcol, int **color_cols) +/// Advance **color_cols +/// +/// @return true when there are columns to draw. +static bool advance_color_col(int vcol, int **color_cols) { while (**color_cols >= 0 && vcol > **color_cols) ++*color_cols; @@ -2062,7 +2060,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int has_syntax = FALSE; /* this buffer has syntax highl. */ int save_did_emsg; int eol_hl_off = 0; // 1 if highlighted char after EOL - int draw_color_col = false; // highlight colorcolumn + bool draw_color_col = false; // highlight colorcolumn int *color_cols = NULL; // pointer to according columns array bool has_spell = false; // this buffer has spell checking # define SPWORDLEN 150 @@ -2139,7 +2137,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int syntax_seqnr = 0; int prev_syntax_id = 0; int conceal_attr = win_hl_attr(wp, HLF_CONCEAL); - int is_concealing = false; + bool is_concealing = false; int boguscols = 0; ///< nonexistent columns added to ///< force wrapping int vcol_off = 0; ///< offset for concealed characters @@ -2430,7 +2428,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, line_attr_lowprio_save = line_attr_lowprio; } - line = ml_get_buf(wp->w_buffer, lnum, FALSE); + line = ml_get_buf(wp->w_buffer, lnum, false); ptr = line; if (has_spell && !number_only) { @@ -2562,8 +2560,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, wp->w_cursor.col = linecol; len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf); - /* spell_move_to() may call ml_get() and make "line" invalid */ - line = ml_get_buf(wp->w_buffer, lnum, FALSE); + // spell_move_to() may call ml_get() and make "line" invalid + line = ml_get_buf(wp->w_buffer, lnum, false); ptr = line + linecol; if (len == 0 || (int)wp->w_cursor.col > ptr - line) { @@ -3095,9 +3093,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, shl == &search_hl ? NULL : cur); pos_inprogress = !(cur == NULL || cur->pos.cur == 0); - /* Need to get the line again, a multi-line regexp - * may have made it invalid. */ - line = ml_get_buf(wp->w_buffer, lnum, FALSE); + // Need to get the line again, a multi-line regexp + // may have made it invalid. + line = ml_get_buf(wp->w_buffer, lnum, false); ptr = line + v; if (shl->lnum == lnum) { @@ -3408,9 +3406,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } else did_emsg = save_did_emsg; - /* Need to get the line again, a multi-line regexp may - * have made it invalid. */ - line = ml_get_buf(wp->w_buffer, lnum, FALSE); + // Need to get the line again, a multi-line regexp may + // have made it invalid. + line = ml_get_buf(wp->w_buffer, lnum, false); ptr = line + v; if (!attr_pri) { @@ -3834,7 +3832,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, n_extra = 0; n_attr = 0; } else if (n_skip == 0) { - is_concealing = TRUE; + is_concealing = true; n_skip = 1; } mb_c = c; @@ -3847,7 +3845,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, } } else { prev_syntax_id = 0; - is_concealing = FALSE; + is_concealing = false; } if (n_skip > 0 && did_decrement_ptr) { @@ -4953,12 +4951,12 @@ win_redr_status_matches ( int fillchar; int attr; int i; - int highlight = TRUE; + bool highlight = true; char_u *selstart = NULL; int selstart_col = 0; char_u *selend = NULL; static int first_match = 0; - int add_left = FALSE; + bool add_left = false; char_u *s; int emenu; int l; @@ -4970,7 +4968,7 @@ win_redr_status_matches ( if (match == -1) { /* don't show match but original text */ match = 0; - highlight = FALSE; + highlight = false; } /* count 1 for the ending ">" */ clen = status_match_len(xp, L_MATCH(match)) + 3; @@ -4979,7 +4977,7 @@ win_redr_status_matches ( else if (match < first_match) { /* jumping left, as far as we can go */ first_match = match; - add_left = TRUE; + add_left = true; } else { /* check if match fits on the screen */ for (i = first_match; i < match; ++i) @@ -4997,8 +4995,9 @@ win_redr_status_matches ( break; } } - if (i == num_matches) - add_left = TRUE; + if (i == num_matches) { + add_left = true; + } } } if (add_left) @@ -5215,7 +5214,7 @@ static void win_redr_status(win_T *wp) grid_puts(&default_grid, NameBuff, row, (int)(this_ru_col - STRLEN(NameBuff) - 1), attr); - win_redr_ruler(wp, TRUE); + win_redr_ruler(wp, true); } /* @@ -5238,14 +5237,14 @@ static void win_redr_status(win_T *wp) */ static void redraw_custom_statusline(win_T *wp) { - static int entered = false; + static bool entered = false; int saved_did_emsg = did_emsg; /* When called recursively return. This can happen when the statusline * contains an expression that triggers a redraw. */ if (entered) return; - entered = TRUE; + entered = true; did_emsg = false; win_redr_custom(wp, false); @@ -5261,12 +5260,11 @@ static void redraw_custom_statusline(win_T *wp) entered = false; } -/* - * Return TRUE if the status line of window "wp" is connected to the status - * line of the window right of it. If not, then it's a vertical separator. - * Only call if (wp->w_vsep_width != 0). - */ -int stl_connected(win_T *wp) +/// Only call if (wp->w_vsep_width != 0). +/// +/// @return true if the status line of window "wp" is connected to the status +/// line of the window right of it. If not, then it's a vertical separator. +bool stl_connected(win_T *wp) { frame_T *fr; @@ -5276,30 +5274,28 @@ int stl_connected(win_T *wp) if (fr->fr_next != NULL) break; } else { - if (fr->fr_next != NULL) - return TRUE; + if (fr->fr_next != NULL) { + return true; + } } fr = fr->fr_parent; } - return FALSE; + return false; } -/* - * Get the value to show for the language mappings, active 'keymap'. - */ -int -get_keymap_str ( - win_T *wp, - char_u *fmt, // format string containing one %s item - char_u *buf, // buffer for the result - int len // length of buffer -) +/// Get the value to show for the language mappings, active 'keymap'. +/// +/// @param fmt format string containing one %s item +/// @param buf buffer for the result +/// @param len length of buffer +bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len) { char_u *p; - if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) - return FALSE; + if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) { + return false; + } { buf_T *old_curbuf = curbuf; @@ -5339,7 +5335,7 @@ win_redr_custom ( bool draw_ruler ) { - static int entered = FALSE; + static bool entered = false; int attr; int curattr; int row; @@ -5365,7 +5361,7 @@ win_redr_custom ( * Avoid trouble by not allowing recursion. */ if (entered) return; - entered = TRUE; + entered = true; /* setup environment for the task at hand */ if (wp == NULL) { @@ -5500,7 +5496,7 @@ win_redr_custom ( } theend: - entered = FALSE; + entered = false; } static void win_redr_border(win_T *wp) @@ -6065,7 +6061,7 @@ next_search_hl ( char_u *ml; matchcol = shl->rm.startpos[0].col; - ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol; + ml = ml_get_buf(shl->buf, lnum, false) + matchcol; if (*ml == NUL) { ++matchcol; shl->lnum = 0; @@ -7333,11 +7329,10 @@ int messaging(void) return !(p_lz && char_avail() && !KeyTyped); } -/* - * Show current status info in ruler and various other places - * If always is FALSE, only show ruler if position has changed. - */ -void showruler(int always) +/// Show current status info in ruler and various other places +/// +/// @param always if false, only show ruler if position has changed. +void showruler(bool always) { if (!always && !redrawing()) return; @@ -7357,7 +7352,7 @@ void showruler(int always) draw_tabline(); } -static void win_redr_ruler(win_T *wp, int always) +static void win_redr_ruler(win_T *wp, bool always) { static bool did_show_ext_ruler = false; @@ -7619,11 +7614,11 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col) /// Set dimensions of the Nvim application "shell". void screen_resize(int width, int height) { - static int busy = FALSE; + static bool recursive = false; // Avoid recursiveness, can happen when setting the window size causes // another window-changed signal. - if (updating_screen || busy) { + if (updating_screen || recursive) { return; } @@ -7643,7 +7638,7 @@ void screen_resize(int width, int height) if (curwin->w_buffer == NULL) return; - ++busy; + recursive = true; Rows = height; Columns = width; @@ -7662,7 +7657,7 @@ void screen_resize(int width, int height) /* The window layout used to be adjusted here, but it now happens in * screenalloc() (also invoked from screenclear()). That is because the - * "busy" check above may skip this, but not screenalloc(). */ + * "recursive" check above may skip this, but not screenalloc(). */ if (State != ASKMORE && State != EXTERNCMD && State != CONFIRM) { screenclear(); @@ -7694,8 +7689,9 @@ void screen_resize(int width, int height) ui_comp_set_screen_valid(true); repeat_message(); } else { - if (curwin->w_p_scb) - do_check_scrollbind(TRUE); + if (curwin->w_p_scb) { + do_check_scrollbind(true); + } if (State & CMDLINE) { redraw_popupmenu = false; update_screen(NOT_VALID); @@ -7720,7 +7716,7 @@ void screen_resize(int width, int height) } ui_flush(); } - busy--; + recursive = false; } /// Check if the new Nvim application "shell" dimensions are valid. @@ -7778,4 +7774,3 @@ win_T *get_win_by_grid_handle(handle_T handle) return NULL; } - diff --git a/src/nvim/search.c b/src/nvim/search.c index b712e09861..b0ee41b245 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -98,7 +98,7 @@ static int saved_spats_last_idx = 0; static bool saved_spats_no_hlsearch = false; static char_u *mr_pattern = NULL; // pattern used by search_regcomp() -static int mr_pattern_alloced = false; // mr_pattern was allocated +static bool mr_pattern_alloced = false; // mr_pattern was allocated /* * Type used by find_pattern_in_path() to remember which included files have @@ -159,19 +159,21 @@ search_regcomp( pat = spats[i].pat; magic = spats[i].magic; no_smartcase = spats[i].no_scs; - } else if (options & SEARCH_HIS) /* put new pattern in history */ - add_to_history(HIST_SEARCH, pat, TRUE, NUL); + } else if (options & SEARCH_HIS) { // put new pattern in history + add_to_history(HIST_SEARCH, pat, true, NUL); + } if (mr_pattern_alloced) { xfree(mr_pattern); - mr_pattern_alloced = FALSE; + mr_pattern_alloced = false; } if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { mr_pattern = reverse_text(pat); - mr_pattern_alloced = TRUE; - } else + mr_pattern_alloced = true; + } else { mr_pattern = pat; + } /* * Save the currently used pattern in the appropriate place, @@ -293,7 +295,7 @@ void free_search_patterns(void) if (mr_pattern_alloced) { xfree(mr_pattern); - mr_pattern_alloced = FALSE; + mr_pattern_alloced = false; mr_pattern = NULL; } } @@ -556,12 +558,12 @@ int searchit( int at_first_line; int extra_col; int start_char_len; - int match_ok; + bool match_ok; long nmatched; int submatch = 0; bool first_match = true; int save_called_emsg = called_emsg; - int break_loop = false; + bool break_loop = false; linenr_T stop_lnum = 0; // stop after this line number when != 0 proftime_T *tm = NULL; // timeout limit or NULL int *timed_out = NULL; // set when timed out or NULL @@ -659,11 +661,12 @@ int searchit( matchpos = regmatch.startpos[0]; endpos = regmatch.endpos[0]; submatch = first_submatch(®match); - /* "lnum" may be past end of buffer for "\n\zs". */ - if (lnum + matchpos.lnum > buf->b_ml.ml_line_count) + // "lnum" may be past end of buffer for "\n\zs". + if (lnum + matchpos.lnum > buf->b_ml.ml_line_count) { ptr = (char_u *)""; - else - ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE); + } else { + ptr = ml_get_buf(buf, lnum + matchpos.lnum, false); + } /* * Forward search in the first line: match should be after @@ -671,14 +674,12 @@ int searchit( * match (this is vi compatible) or on the next char. */ if (dir == FORWARD && at_first_line) { - match_ok = TRUE; - /* - * When the match starts in a next line it's certainly - * past the start position. - * When match lands on a NUL the cursor will be put - * one back afterwards, compare with that position, - * otherwise "/$" will get stuck on end of line. - */ + match_ok = true; + // When the match starts in a next line it's certainly + // past the start position. + // When match lands on a NUL the cursor will be put + // one back afterwards, compare with that position, + // otherwise "/$" will get stuck on end of line. while (matchpos.lnum == 0 && (((options & SEARCH_END) && first_match) ? (nmatched == 1 @@ -696,7 +697,7 @@ int searchit( if (nmatched > 1) { /* end is in next line, thus no match in * this line */ - match_ok = FALSE; + match_ok = false; break; } matchcol = endpos.col; @@ -750,7 +751,7 @@ int searchit( * When putting the new cursor at the end, compare * relative to the end of the match. */ - match_ok = FALSE; + match_ok = false; for (;; ) { /* Remember a position that is before the start * position, we use it if it's the last match in @@ -842,10 +843,9 @@ int searchit( pos->lnum = lnum + endpos.lnum; pos->col = endpos.col; if (endpos.col == 0) { - if (pos->lnum > 1) { /* just in case */ - --pos->lnum; - pos->col = (colnr_T)STRLEN(ml_get_buf(buf, - pos->lnum, FALSE)); + if (pos->lnum > 1) { // just in case + pos->lnum--; + pos->col = (colnr_T)STRLEN(ml_get_buf(buf, pos->lnum, false)); } } else { pos->col--; @@ -888,7 +888,7 @@ int searchit( if ((options & SEARCH_PEEK) && ((lnum - pos->lnum) & 0x3f) == 0 && char_avail()) { - break_loop = TRUE; + break_loop = true; break; } @@ -962,9 +962,10 @@ int searchit( /* A pattern like "\n\zs" may go past the last line. */ if (pos->lnum > buf->b_ml.ml_line_count) { pos->lnum = buf->b_ml.ml_line_count; - pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, FALSE)); - if (pos->col > 0) - --pos->col; + pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, false)); + if (pos->col > 0) { + pos->col--; + } } return submatch + 1; @@ -1465,7 +1466,7 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) break; if (start == 0) start = pos->lnum; - ptr = ml_get_buf(buf, pos->lnum, FALSE); + ptr = ml_get_buf(buf, pos->lnum, false); p = skipwhite(ptr); pos->col = (colnr_T) (p - ptr); @@ -1506,7 +1507,7 @@ int searchc(cmdarg_T *cap, int t_cmd) int col; char_u *p; int len; - int stop = TRUE; + bool stop = true; if (c != NUL) { /* normal search: remember args for repeat */ if (!KeyStuffed) { /* don't remember when redoing */ @@ -1539,8 +1540,9 @@ int searchc(cmdarg_T *cap, int t_cmd) /* Force a move of at least one char, so ";" and "," will move the * cursor, even if the cursor is right in front of char we are looking * at. */ - if (vim_strchr(p_cpo, CPO_SCOLON) == NULL && count == 1 && t_cmd) - stop = FALSE; + if (vim_strchr(p_cpo, CPO_SCOLON) == NULL && count == 1 && t_cmd) { + stop = false; + } } if (dir == BACKWARD) @@ -2257,22 +2259,25 @@ static int check_linecomment(const char_u *line) const char_u *p = line; // scan from start // skip Lispish one-line comments if (curbuf->b_p_lisp) { - if (vim_strchr(p, ';') != NULL) { /* there may be comments */ - int in_str = FALSE; /* inside of string */ + if (vim_strchr(p, ';') != NULL) { // there may be comments + bool in_str = false; // inside of string while ((p = vim_strpbrk(p, (char_u *)"\";")) != NULL) { if (*p == '"') { if (in_str) { - if (*(p - 1) != '\\') /* skip escaped quote */ - in_str = FALSE; + if (*(p - 1) != '\\') { // skip escaped quote + in_str = false; + } } else if (p == line || ((p - line) >= 2 - /* skip #\" form */ - && *(p - 1) != '\\' && *(p - 2) != '#')) - in_str = TRUE; + // skip #\" form + && *(p - 1) != '\\' && *(p - 2) != '#')) { + in_str = true; + } } else if (!in_str && ((p - line) < 2 - || (*(p - 1) != '\\' && *(p - 2) != '#'))) - break; /* found! */ - ++p; + || (*(p - 1) != '\\' && *(p - 2) != '#'))) { + break; // found! + } + p++; } } else p = NULL; @@ -2855,17 +2860,13 @@ finished: return OK; } -/* - * Move back to the end of the word. - * - * Returns FAIL if start of the file was reached. - */ -int -bckend_word( - long count, - int bigword, /* TRUE for "B" */ - int eol /* TRUE: stop at end of line. */ -) +/// Move back to the end of the word. +/// +/// @param bigword TRUE for "B" +/// @param eol if true, then stop at end of line. +/// +/// @return FAIL if start of the file was reached. +int bckend_word(long count, int bigword, bool eol) { int sclass; /* starting class */ int i; @@ -2903,16 +2904,17 @@ bckend_word( return OK; } -/* - * Skip a row of characters of the same class. - * Return TRUE when end-of-file reached, FALSE otherwise. - */ -static int skip_chars(int cclass, int dir) +/// Skip a row of characters of the same class. +/// +/// @return true when end-of-file reached, false otherwise. +static bool skip_chars(int cclass, int dir) { - while (cls() == cclass) - if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) - return TRUE; - return FALSE; + while (cls() == cclass) { + if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) { + return true; + } + } + return false; } /* @@ -2947,14 +2949,10 @@ static void find_first_blank(pos_T *posp) } } -/* - * Skip count/2 sentences and count/2 separating white spaces. - */ -static void -findsent_forward( - long count, - int at_start_sent /* cursor is at start of sentence */ -) +/// Skip count/2 sentences and count/2 separating white spaces. +/// +/// @param at_start_sent cursor is at start of sentence +static void findsent_forward(long count, bool at_start_sent) { while (count--) { findsent(FORWARD, 1L); @@ -3053,8 +3051,9 @@ current_word( if (bck_word(1L, bigword, TRUE) == FAIL) return FAIL; } else { - if (bckend_word(1L, bigword, TRUE) == FAIL) + if (bckend_word(1L, bigword, true) == FAIL) { return FAIL; + } (void)incl(&curwin->w_cursor); } } else { @@ -3126,9 +3125,9 @@ int current_sent(oparg_T *oap, long count, int include) { pos_T start_pos; pos_T pos; - int start_blank; + bool start_blank; int c; - int at_start_sent; + bool at_start_sent; long ncount; start_pos = curwin->w_cursor; @@ -3148,23 +3147,24 @@ extend: * - in a sentence or just after it * - at the start of a sentence */ - at_start_sent = TRUE; + at_start_sent = true; decl(&pos); while (lt(pos, curwin->w_cursor)) { c = gchar_pos(&pos); if (!ascii_iswhite(c)) { - at_start_sent = FALSE; + at_start_sent = false; break; } incl(&pos); } if (!at_start_sent) { findsent(BACKWARD, 1L); - if (equalpos(curwin->w_cursor, start_pos)) - at_start_sent = TRUE; /* exactly at start of sentence */ - else - /* inside a sentence, go to its end (start of next) */ + if (equalpos(curwin->w_cursor, start_pos)) { + at_start_sent = true; // exactly at start of sentence + } else { + // inside a sentence, go to its end (start of next) findsent(FORWARD, 1L); + } } if (include) /* "as" gets twice as much as "is" */ count *= 2; @@ -3185,13 +3185,13 @@ extend: * - in a sentence */ incl(&pos); - at_start_sent = TRUE; - if (!equalpos(pos, curwin->w_cursor)) { /* not just before a sentence */ - at_start_sent = FALSE; + at_start_sent = true; + if (!equalpos(pos, curwin->w_cursor)) { // not just before a sentence + at_start_sent = false; while (lt(pos, curwin->w_cursor)) { c = gchar_pos(&pos); if (!ascii_iswhite(c)) { - at_start_sent = TRUE; + at_start_sent = true; break; } incl(&pos); @@ -3218,10 +3218,10 @@ extend: while (c = gchar_pos(&pos), ascii_iswhite(c)) incl(&pos); if (equalpos(pos, curwin->w_cursor)) { - start_blank = TRUE; - find_first_blank(&start_pos); /* go back to first blank */ + start_blank = true; + find_first_blank(&start_pos); // go back to first blank } else { - start_blank = FALSE; + start_blank = false; findsent(BACKWARD, 1L); start_pos = curwin->w_cursor; } @@ -3232,10 +3232,11 @@ extend: if (start_blank) --ncount; } - if (ncount > 0) - findsent_forward(ncount, TRUE); - else + if (ncount > 0) { + findsent_forward(ncount, true); + } else { decl(&curwin->w_cursor); + } if (include) { /* @@ -3293,7 +3294,7 @@ current_block( pos_T *end_pos; pos_T old_start, old_end; char_u *save_cpo; - int sol = FALSE; /* '{' at start of line */ + bool sol = false; // '{' at start of line old_pos = curwin->w_cursor; old_end = curwin->w_cursor; /* remember where we started */ @@ -3351,7 +3352,7 @@ current_block( sol = (curwin->w_cursor.col == 0); decl(&curwin->w_cursor); while (inindent(1)) { - sol = TRUE; + sol = true; if (decl(&curwin->w_cursor) != 0) { break; } @@ -3410,11 +3411,10 @@ current_block( } -/* - * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". - * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>". - */ -static int in_html_tag(int end_tag) +/// @param end_tag when true, return true if the cursor is on "</aaa>". +/// +/// @return true if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". +static bool in_html_tag(bool end_tag) { char_u *line = get_cursor_line_ptr(); char_u *p; @@ -3444,14 +3444,16 @@ static int in_html_tag(int end_tag) return *p == '/'; } - /* check that there is no '/' after the '<' */ - if (*p == '/') - return FALSE; + // check that there is no '/' after the '<' + if (*p == '/') { + return false; + } /* check that the matching '>' is not preceded by '/' */ for (;; ) { - if (inc(&pos) < 0) - return FALSE; + if (inc(&pos) < 0) { + return false; + } c = *ml_get_pos(&pos); if (c == '>') break; @@ -3502,16 +3504,20 @@ current_tagblock( if (inc_cursor() != 0) break; - if (in_html_tag(FALSE)) { - /* cursor on start tag, move to its '>' */ - while (*get_cursor_pos_ptr() != '>') - if (inc_cursor() < 0) + if (in_html_tag(false)) { + // cursor on start tag, move to its '>' + while (*get_cursor_pos_ptr() != '>') { + if (inc_cursor() < 0) { break; - } else if (in_html_tag(TRUE)) { - /* cursor on end tag, move to just before it */ - while (*get_cursor_pos_ptr() != '<') - if (dec_cursor() < 0) + } + } + } else if (in_html_tag(true)) { + // cursor on end tag, move to just before it + while (*get_cursor_pos_ptr() != '<') { + if (dec_cursor() < 0) { break; + } + } dec_cursor(); old_end = curwin->w_cursor; } @@ -4667,7 +4673,7 @@ find_pattern_in_path( char_u *line; char_u *p; char_u save_char; - int define_matched; + bool define_matched; regmatch_T regmatch; regmatch_T incl_regmatch; regmatch_T def_regmatch; @@ -4904,7 +4910,7 @@ find_pattern_in_path( */ p = line; search_line: - define_matched = FALSE; + define_matched = false; if (def_regmatch.regprog != NULL && vim_regexec(&def_regmatch, line, (colnr_T)0)) { /* @@ -4915,7 +4921,7 @@ search_line: p = def_regmatch.endp[0]; while (*p && !vim_iswordc(*p)) p++; - define_matched = TRUE; + define_matched = true; } /* diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 28276884b0..610a359141 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1399,7 +1399,7 @@ spell_move_to ( clearpos(&found_pos); while (!got_int) { - line = ml_get_buf(wp->w_buffer, lnum, FALSE); + line = ml_get_buf(wp->w_buffer, lnum, false); len = STRLEN(line); if (buflen < len + MAXWLEN + 2) { @@ -1425,7 +1425,7 @@ spell_move_to ( // Need to get the line again, may have looked at the previous // one. - line = ml_get_buf(wp->w_buffer, lnum, FALSE); + line = ml_get_buf(wp->w_buffer, lnum, false); } // Copy the line into "buf" and append the start of the next line if @@ -1433,7 +1433,7 @@ spell_move_to ( STRCPY(buf, line); if (lnum < wp->w_buffer->b_ml.ml_line_count) spell_cat_line(buf + STRLEN(buf), - ml_get_buf(wp->w_buffer, lnum + 1, FALSE), + ml_get_buf(wp->w_buffer, lnum + 1, false), MAXWLEN); p = buf + skip; endp = buf + len; diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 15271e831c..8b95178c84 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -5035,7 +5035,7 @@ static void sug_write(spellinfo_T *spin, char_u *fname) for (linenr_T lnum = 1; lnum <= wcount; ++lnum) { // <sugline>: <sugnr> ... NUL - char_u *line = ml_get_buf(spin->si_spellbuf, lnum, FALSE); + char_u *line = ml_get_buf(spin->si_spellbuf, lnum, false); size_t len = STRLEN(line) + 1; if (fwrite(line, len, 1, fd) == 0) { EMSG(_(e_write)); diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 1d45df8ebd..bdbbc4aacf 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -91,7 +91,7 @@ typedef struct hl_group { // builtin |highlight-groups| static garray_T highlight_ga = GA_EMPTY_INIT_VALUE; -Map(cstr_t, int) *highlight_unames; +Map(cstr_t, int) highlight_unames = MAP_INIT; static inline struct hl_group * HL_TABLE(void) { @@ -365,31 +365,26 @@ static reg_extmatch_T *next_match_extmatch = NULL; * The current state (within the line) of the recognition engine. * When current_state.ga_itemsize is 0 the current state is invalid. */ -static win_T *syn_win; // current window for highlighting -static buf_T *syn_buf; // current buffer for highlighting -static synblock_T *syn_block; // current buffer for highlighting -static proftime_T *syn_tm; // timeout limit -static linenr_T current_lnum = 0; // lnum of current state -static colnr_T current_col = 0; // column of current state -static int current_state_stored = 0; // TRUE if stored current state - // after setting current_finished -static int current_finished = 0; // current line has been finished -static garray_T current_state // current stack of state_items +static win_T *syn_win; // current window for highlighting +static buf_T *syn_buf; // current buffer for highlighting +static synblock_T *syn_block; // current buffer for highlighting +static proftime_T *syn_tm; // timeout limit +static linenr_T current_lnum = 0; // lnum of current state +static colnr_T current_col = 0; // column of current state +static bool current_state_stored = false; // true if stored current state + // after setting current_finished +static bool current_finished = false; // current line has been finished +static garray_T current_state // current stack of state_items = GA_EMPTY_INIT_VALUE; -static int16_t *current_next_list = NULL; // when non-zero, nextgroup list -static int current_next_flags = 0; // flags for current_next_list -static int current_line_id = 0; // unique number for current line +static int16_t *current_next_list = NULL; // when non-zero, nextgroup list +static int current_next_flags = 0; // flags for current_next_list +static int current_line_id = 0; // unique number for current line #define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx] -static int syn_time_on = FALSE; +static bool syn_time_on = false; # define IF_SYN_TIME(p) (p) -void syntax_init(void) -{ - highlight_unames = map_new(cstr_t, int)(); -} - // Set the timeout used for syntax highlighting. // Use NULL to reset, no timeout. void syn_set_timeout(proftime_T *tm) @@ -815,7 +810,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) cur_si = &CUR_STATE(current_state.ga_len - 1); cur_si->si_h_startpos.lnum = found_current_lnum; cur_si->si_h_startpos.col = found_current_col; - update_si_end(cur_si, (int)current_col, TRUE); + update_si_end(cur_si, (int)current_col, true); check_keepend(); } current_col = found_m_endpos.col; @@ -886,7 +881,7 @@ static int syn_match_linecont(linenr_T lnum) */ static void syn_start_line(void) { - current_finished = FALSE; + current_finished = false; current_col = 0; /* @@ -894,7 +889,7 @@ static void syn_start_line(void) * previous line and regions that have "keepend". */ if (!GA_EMPTY(¤t_state)) { - syn_update_ends(TRUE); + syn_update_ends(true); check_state_ends(); } @@ -903,15 +898,13 @@ static void syn_start_line(void) next_seqnr = 1; } -/* - * Check for items in the stack that need their end updated. - * When "startofline" is TRUE the last item is always updated. - * When "startofline" is FALSE the item with "keepend" is forcefully updated. - */ -static void syn_update_ends(int startofline) +/// Check for items in the stack that need their end updated. +/// +/// @param startofline if true the last item is always updated. +/// if false the item with "keepend" is forcefully updated. +static void syn_update_ends(bool startofline) { stateitem_T *cur_si; - int seen_keepend; if (startofline) { /* Check for a match carried over from a previous line with a @@ -946,8 +939,8 @@ static void syn_update_ends(int startofline) if (CUR_STATE(i).si_flags & HL_EXTEND) break; - seen_keepend = FALSE; - for (; i < current_state.ga_len; ++i) { + bool seen_keepend = false; + for (; i < current_state.ga_len; i++) { cur_si = &CUR_STATE(i); if ((cur_si->si_flags & HL_KEEPEND) || (seen_keepend && !startofline) @@ -958,8 +951,9 @@ static void syn_update_ends(int startofline) if (!(cur_si->si_flags & HL_MATCHCONT)) update_si_end(cur_si, (int)current_col, !startofline); - if (!startofline && (cur_si->si_flags & HL_KEEPEND)) - seen_keepend = TRUE; + if (!startofline && (cur_si->si_flags & HL_KEEPEND)) { + seen_keepend = true; + } } } check_keepend(); @@ -1157,17 +1151,15 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf) } } -/* - * Reduce the number of entries in the state stack for syn_buf. - * Returns TRUE if at least one entry was freed. - */ -static int syn_stack_cleanup(void) +/// Reduce the number of entries in the state stack for syn_buf. +/// +/// @return true if at least one entry was freed. +static bool syn_stack_cleanup(void) { synstate_T *p, *prev; disptick_T tick; - int above; int dist; - int retval = FALSE; + bool retval = false; if (syn_block->b_sst_first == NULL) { return retval; @@ -1185,16 +1177,17 @@ static int syn_stack_cleanup(void) * "b_sst_lasttick" (the display tick wraps around). */ tick = syn_block->b_sst_lasttick; - above = FALSE; + bool above = false; prev = syn_block->b_sst_first; for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next) { if (prev->sst_lnum + dist > p->sst_lnum) { if (p->sst_tick > syn_block->b_sst_lasttick) { if (!above || p->sst_tick < tick) tick = p->sst_tick; - above = TRUE; - } else if (!above && p->sst_tick < tick) + above = true; + } else if (!above && p->sst_tick < tick) { tick = p->sst_tick; + } } } @@ -1209,7 +1202,7 @@ static int syn_stack_cleanup(void) prev->sst_next = p->sst_next; syn_stack_free_entry(syn_block, p); p = prev; - retval = TRUE; + retval = true; } } return retval; @@ -1345,7 +1338,7 @@ static synstate_T *store_current_state(void) sp->sst_tick = display_tick; sp->sst_change_lnum = 0; } - current_state_stored = TRUE; + current_state_stored = true; return sp; } @@ -1390,11 +1383,10 @@ static void load_current_state(synstate_T *from) current_lnum = from->sst_lnum; } -/* - * Compare saved state stack "*sp" with the current state. - * Return TRUE when they are equal. - */ -static int syn_stack_equal(synstate_T *sp) +/// Compare saved state stack "*sp" with the current state. +/// +/// @return true when they are equal. +static bool syn_stack_equal(synstate_T *sp) { bufstate_T *bp; reg_extmatch_T *six, *bsx; @@ -1402,7 +1394,7 @@ static int syn_stack_equal(synstate_T *sp) /* First a quick check if the stacks have the same size end nextlist. */ if (sp->sst_stacksize != current_state.ga_len || sp->sst_next_list != current_next_list) { - return FALSE; + return false; } /* Need to compare all states on both stacks. */ @@ -1449,10 +1441,11 @@ static int syn_stack_equal(synstate_T *sp) if (j != NSUBEXP) break; } - if (i < 0) - return TRUE; + if (i < 0) { + return true; + } - return FALSE; + return false; } /* @@ -1495,14 +1488,13 @@ static void validate_current_state(void) ga_set_growsize(¤t_state, 3); } -/* - * Return TRUE if the syntax at start of lnum changed since last time. - * This will only be called just after get_syntax_attr() for the previous - * line, to check if the next line needs to be redrawn too. - */ -int syntax_check_changed(linenr_T lnum) +/// This will only be called just after get_syntax_attr() for the previous +/// line, to check if the next line needs to be redrawn too. +/// +/// @return true if the syntax at start of lnum changed since last time. +bool syntax_check_changed(linenr_T lnum) { - int retval = TRUE; + bool retval = true; synstate_T *sp; /* @@ -1525,8 +1517,9 @@ int syntax_check_changed(linenr_T lnum) * Compare the current state with the previously saved state of * the line. */ - if (syn_stack_equal(sp)) - retval = FALSE; + if (syn_stack_equal(sp)) { + retval = false; + } /* * Store the current state in b_sst_array[] for later use. @@ -1683,15 +1676,15 @@ static int syn_current_attr( (void)push_next_match(); } - current_finished = TRUE; - current_state_stored = FALSE; + current_finished = true; + current_state_stored = false; return 0; } /* if the current or next character is NUL, we will finish the line now */ if (line[current_col] == NUL || line[current_col + 1] == NUL) { - current_finished = TRUE; - current_state_stored = FALSE; + current_finished = true; + current_state_stored = false; } /* @@ -2157,16 +2150,14 @@ static int syn_current_attr( } -/* - * Check if we already matched pattern "idx" at the current column. - */ -static int did_match_already(int idx, garray_T *gap) +/// @return true if we already matched pattern "idx" at the current column. +static bool did_match_already(int idx, garray_T *gap) { for (int i = current_state.ga_len; --i >= 0; ) { if (CUR_STATE(i).si_m_startcol == (int)current_col && CUR_STATE(i).si_m_lnum == (int)current_lnum && CUR_STATE(i).si_idx == idx) { - return TRUE; + return true; } } @@ -2174,11 +2165,11 @@ static int did_match_already(int idx, garray_T *gap) * stack, and can only be matched once anyway. */ for (int i = gap->ga_len; --i >= 0; ) { if (((int *)(gap->ga_data))[i] == idx) { - return TRUE; + return true; } } - return FALSE; + return false; } /* @@ -2214,8 +2205,8 @@ static stateitem_T *push_next_match(void) cur_si->si_next_list = spp->sp_next_list; cur_si->si_extmatch = ref_extmatch(next_match_extmatch); if (spp->sp_type == SPTYPE_START && !(spp->sp_flags & HL_ONELINE)) { - /* Try to find the end pattern in the current line */ - update_si_end(cur_si, (int)(next_match_m_endpos.col), TRUE); + // Try to find the end pattern in the current line + update_si_end(cur_si, (int)(next_match_m_endpos.col), true); check_keepend(); } else { cur_si->si_m_endpos = next_match_m_endpos; @@ -2321,9 +2312,10 @@ static void check_state_ends(void) break; if (had_extend && keepend_level >= 0) { - syn_update_ends(FALSE); - if (GA_EMPTY(¤t_state)) + syn_update_ends(false); + if (GA_EMPTY(¤t_state)) { break; + } } cur_si = &CUR_STATE(current_state.ga_len - 1); @@ -2341,7 +2333,7 @@ static void check_state_ends(void) && SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type == SPTYPE_START && !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) { - update_si_end(cur_si, (int)current_col, TRUE); + update_si_end(cur_si, (int)current_col, true); check_keepend(); if ((current_next_flags & HL_HAS_EOL) && keepend_level < 0 @@ -2457,18 +2449,14 @@ static void check_keepend(void) } } -/* - * Update an entry in the current_state stack for a start-skip-end pattern. - * This finds the end of the current item, if it's in the current line. - * - * Return the flags for the matched END. - */ -static void -update_si_end( - stateitem_T *sip, - int startcol, /* where to start searching for the end */ - int force /* when TRUE overrule a previous end */ -) +/// Update an entry in the current_state stack for a start-skip-end pattern. +/// This finds the end of the current item, if it's in the current line. +/// +/// @param startcol where to start searching for the end +/// @param force when true overrule a previous end +/// +/// @return the flags for the matched END. +static void update_si_end(stateitem_T *sip, int startcol, bool force) { lpos_T hl_endpos; lpos_T end_endpos; @@ -2576,7 +2564,7 @@ find_endpos( regmmatch_T best_regmatch; /* startpos/endpos of best match */ lpos_T pos; char_u *line; - int had_match = false; + bool had_match = false; char_u buf_chartab[32]; // chartab array for syn option iskeyword /* just in case we are invoked for a keyword */ @@ -2758,7 +2746,7 @@ find_endpos( *flagsp = spp->sp_flags; - had_match = TRUE; + had_match = true; break; } @@ -2821,12 +2809,12 @@ syn_add_end_off( col = regmatch->endpos[0].col; off = spp->sp_offsets[idx]; } - /* Don't go past the end of the line. Matters for "rs=e+2" when there - * is a matchgroup. Watch out for match with last NL in the buffer. */ - if (result->lnum > syn_buf->b_ml.ml_line_count) + // Don't go past the end of the line. Matters for "rs=e+2" when there + // is a matchgroup. Watch out for match with last NL in the buffer. + if (result->lnum > syn_buf->b_ml.ml_line_count) { col = 0; - else if (off != 0) { - base = ml_get_buf(syn_buf, result->lnum, FALSE); + } else if (off != 0) { + base = ml_get_buf(syn_buf, result->lnum, false); p = base + col; if (off > 0) { while (off-- > 0 && *p != NUL) { @@ -2872,10 +2860,10 @@ syn_add_start_off( if (result->lnum > syn_buf->b_ml.ml_line_count) { /* a "\n" at the end of the pattern may take us below the last line */ result->lnum = syn_buf->b_ml.ml_line_count; - col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, FALSE)); + col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, false)); } if (off != 0) { - base = ml_get_buf(syn_buf, result->lnum, FALSE); + base = ml_get_buf(syn_buf, result->lnum, false); p = base + col; if (off > 0) { while (off-- && *p != NUL) { @@ -2896,7 +2884,7 @@ syn_add_start_off( */ static char_u *syn_getcurline(void) { - return ml_get_buf(syn_buf, current_lnum, FALSE); + return ml_get_buf(syn_buf, current_lnum, false); } /* @@ -2908,7 +2896,7 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T int r; int timed_out = 0; proftime_T pt; - const int l_syn_time_on = syn_time_on; + const bool l_syn_time_on = syn_time_on; if (l_syn_time_on) { pt = profile_start(); @@ -4247,7 +4235,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing) char_u *errormsg = NULL; int prev_toplvl_grp; int prev_syn_inc_tag; - int source = FALSE; + bool source = false; eap->nextcmd = find_nextcmd(arg); if (eap->skip) @@ -4547,9 +4535,9 @@ syn_cmd_region( int pat_count = 0; /* nr of syn_patterns found */ int syn_id; int matchgroup_id = 0; - int not_enough = FALSE; /* not enough arguments */ - int illegal = FALSE; /* illegal arguments */ - int success = FALSE; + bool not_enough = false; // not enough arguments + bool illegal = false; // illegal arguments + bool success = false; syn_opt_arg_T syn_opt_arg; int conceal_char = NUL; @@ -4607,7 +4595,7 @@ syn_cmd_region( } rest = skipwhite(rest + 1); if (*rest == NUL) { - not_enough = TRUE; + not_enough = true; break; } @@ -4618,7 +4606,7 @@ syn_cmd_region( else { matchgroup_id = syn_check_group(rest, (int)(p - rest)); if (matchgroup_id == 0) { - illegal = TRUE; + illegal = true; break; } } @@ -4712,8 +4700,8 @@ syn_cmd_region( } redraw_curbuf_later(SOME_VALID); - syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */ - success = TRUE; /* don't free the progs and patterns now */ + syn_stack_free_all(curwin->w_s); // Need to recompute all syntax. + success = true; // don't free the progs and patterns now } } } @@ -5865,16 +5853,17 @@ int syn_get_foldlevel(win_T *wp, long lnum) */ void ex_syntime(exarg_T *eap) { - if (STRCMP(eap->arg, "on") == 0) - syn_time_on = TRUE; - else if (STRCMP(eap->arg, "off") == 0) - syn_time_on = FALSE; - else if (STRCMP(eap->arg, "clear") == 0) + if (STRCMP(eap->arg, "on") == 0) { + syn_time_on = true; + } else if (STRCMP(eap->arg, "off") == 0) { + syn_time_on = false; + } else if (STRCMP(eap->arg, "clear") == 0) { syntime_clear(); - else if (STRCMP(eap->arg, "report") == 0) + } else if (STRCMP(eap->arg, "report") == 0) { syntime_report(); - else + } else { EMSG2(_(e_invarg2), eap->arg); + } } static void syn_clear_time(syn_time_T *st) @@ -6426,7 +6415,7 @@ void init_highlight(bool both, bool reset) do_highlight(pp[i], reset, true); } } else if (!had_both) { - // Don't do anything before the call with both == TRUE from main(). + // Don't do anything before the call with both == true from main(). // Not everything has been setup then, and that call will overrule // everything anyway. return; @@ -6467,7 +6456,7 @@ int load_colors(char_u *name) { char_u *buf; int retval = FAIL; - static int recursive = false; + static bool recursive = false; // When being called recursively, this is probably because setting // 'background' caused the highlighting to be reloaded. This means it is @@ -7119,7 +7108,7 @@ void free_highlight(void) xfree(HL_TABLE()[i].sg_name_u); } ga_clear(&highlight_ga); - map_free(cstr_t, int)(highlight_unames); + map_destroy(cstr_t, int)(&highlight_unames); } #endif @@ -7137,11 +7126,10 @@ void restore_cterm_colors(void) cterm_normal_bg_color = 0; } -/* - * Return TRUE if highlight group "idx" has any settings. - * When "check_link" is TRUE also check for an existing link. - */ -static int hl_has_settings(int idx, int check_link) +/// @param check_link if true also check for an existing link. +/// +/// @return TRUE if highlight group "idx" has any settings. +static int hl_has_settings(int idx, bool check_link) { return HL_TABLE()[idx].sg_cleared == 0 && (HL_TABLE()[idx].sg_attr != 0 @@ -7505,7 +7493,7 @@ int syn_name2id_len(const char_u *name, size_t len) // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. - return map_get(cstr_t, int)(highlight_unames, name_u); + return map_get(cstr_t, int)(&highlight_unames, name_u); } /// Lookup a highlight group name and return its attributes. @@ -7609,7 +7597,7 @@ static int syn_add_group(char_u *name) int id = highlight_ga.ga_len; // ID is index plus one - map_put(cstr_t, int)(highlight_unames, name_up, id); + map_put(cstr_t, int)(&highlight_unames, name_up, id); return id; } @@ -7620,7 +7608,7 @@ static void syn_unadd_group(void) { highlight_ga.ga_len--; HlGroup *item = &HL_TABLE()[highlight_ga.ga_len]; - map_del(cstr_t, int)(highlight_unames, item->sg_name_u); + map_del(cstr_t, int)(&highlight_unames, item->sg_name_u); xfree(item->sg_name); xfree(item->sg_name_u); } @@ -7883,8 +7871,9 @@ const char *get_highlight_name(expand_T *const xp, int idx) /// Obtain a highlight group name. -/// When "skip_cleared" is TRUE don't return a cleared entry. -const char *get_highlight_name_ext(expand_T *xp, int idx, int skip_cleared) +/// +/// @param skip_cleared if true don't return a cleared entry. +const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared) FUNC_ATTR_WARN_UNUSED_RESULT { if (idx < 0) { diff --git a/src/nvim/tag.c b/src/nvim/tag.c index d6c6b064b2..a971849f4c 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1371,12 +1371,12 @@ find_tags( tagname_T tn; /* info for get_tagfname() */ int first_file; /* trying first tag file */ tagptrs_T tagp; - int did_open = FALSE; /* did open a tag file */ - int stop_searching = FALSE; /* stop when match found or error */ - int retval = FAIL; /* return value */ - int is_static; /* current tag line is static */ - int is_current; /* file name matches */ - int eof = FALSE; /* found end-of-file */ + bool did_open = false; // did open a tag file + bool stop_searching = false; // stop when match found or error + int retval = FAIL; // return value + int is_static; // current tag line is static + int is_current; // file name matches + bool eof = false; // found end-of-file char_u *p; char_u *s; int i; @@ -1429,12 +1429,12 @@ find_tags( vimconv_T vimconv; int findall = (mincount == MAXCOL || mincount == TAG_MANY); - /* find all matching tags */ - int sort_error = FALSE; /* tags file not sorted */ - int linear; /* do a linear search */ - int sortic = FALSE; /* tag file sorted in nocase */ - int line_error = FALSE; /* syntax error */ - int has_re = (flags & TAG_REGEXP); /* regexp used */ + // find all matching tags + bool sort_error = false; // tags file not sorted + int linear; // do a linear search + bool sortic = false; // tag file sorted in nocase + bool line_error = false; // syntax error + int has_re = (flags & TAG_REGEXP); // regexp used int help_only = (flags & TAG_HELP); int name_only = (flags & TAG_NAMES); int noic = (flags & TAG_NOIC); @@ -1621,7 +1621,7 @@ find_tags( verbose_leave(); } } - did_open = TRUE; /* remember that we found at least one file */ + did_open = true; // remember that we found at least one file state = TS_START; /* we're at the start of the file */ @@ -1638,13 +1638,13 @@ find_tags( if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */ ins_compl_check_keys(30, false); if (got_int || compl_interrupted) { - stop_searching = TRUE; + stop_searching = true; break; } /* When mincount is TAG_MANY, stop when enough matches have been * found (for completion). */ if (mincount == TAG_MANY && match_count >= TAG_MANY) { - stop_searching = TRUE; + stop_searching = true; retval = OK; break; } @@ -1795,7 +1795,7 @@ line_read_in: state = TS_BINARY; else if (tag_file_sorted == '2') { state = TS_BINARY; - sortic = TRUE; + sortic = true; orgpat.regmatch.rm_ic = (p_ic || !noic); } else state = TS_LINEAR; @@ -1878,8 +1878,9 @@ parse_line: i = (int)tagp.tagname[0]; if (sortic) i = TOUPPER_ASC(tagp.tagname[0]); - if (i < search_info.low_char || i > search_info.high_char) - sort_error = TRUE; + if (i < search_info.low_char || i > search_info.high_char) { + sort_error = true; + } /* * Compare the current tag with the searched tag. @@ -1970,7 +1971,7 @@ parse_line: i = parse_tag_line(lbuf, &tagp); if (i == FAIL) { - line_error = TRUE; + line_error = true; break; } @@ -2175,7 +2176,7 @@ parse_line: tag_file_sorted = NUL; if (sort_error) { EMSG2(_("E432: Tags file not sorted: %s"), tag_fname); - sort_error = FALSE; + sort_error = false; } /* @@ -2183,7 +2184,7 @@ parse_line: */ if (match_count >= mincount) { retval = OK; - stop_searching = TRUE; + stop_searching = true; } if (stop_searching || use_cscope) diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index c07a956dde..3335fa500a 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -76,7 +76,6 @@ #include "nvim/event/time.h" #include "nvim/os/input.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/private/handle.h" typedef struct terminal_state { VimState state; @@ -153,11 +152,10 @@ static VTermScreenCallbacks vterm_screen_callbacks = { .sb_popline = term_sb_pop, }; -static PMap(ptr_t) *invalidated_terminals; +static PMap(ptr_t) invalidated_terminals = MAP_INIT; void terminal_init(void) { - invalidated_terminals = pmap_new(ptr_t)(); time_watcher_init(&main_loop, &refresh_timer, NULL); // refresh_timer_cb will redraw the screen which can call vimscript refresh_timer.events = multiqueue_new_child(main_loop.events); @@ -168,8 +166,10 @@ void terminal_teardown(void) time_watcher_stop(&refresh_timer); multiqueue_free(refresh_timer.events); time_watcher_close(&refresh_timer, NULL); - pmap_free(ptr_t)(invalidated_terminals); - invalidated_terminals = NULL; + pmap_destroy(ptr_t)(&invalidated_terminals); + // terminal_destroy might be called after terminal_teardown is invoked + // make sure it is in an empty, valid state + pmap_init(ptr_t, &invalidated_terminals); } // public API {{{ @@ -260,7 +260,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts) return rv; } -void terminal_close(Terminal *term, char *msg) +void terminal_close(Terminal *term, int status) { if (term->closed) { return; @@ -278,8 +278,8 @@ void terminal_close(Terminal *term, char *msg) buf_T *buf = handle_get_buffer(term->buf_handle); term->closed = true; - if (!msg || exiting) { - // If no msg was given, this was called by close_buffer(buffer.c). Or if + if (status == -1 || exiting) { + // If status is -1, this was called by close_buffer(buffer.c). Or if // exiting, we must inform the buffer the terminal no longer exists so that // close_buffer() doesn't call this again. term->buf_handle = 0; @@ -291,11 +291,16 @@ void terminal_close(Terminal *term, char *msg) term->opts.close_cb(term->opts.data); } } else { + char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN]; + snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status); terminal_receive(term, msg, strlen(msg)); } - if (buf) { + if (buf && !is_autocmd_blocked()) { + dict_T *dict = get_vim_var_dict(VV_EVENT); + tv_dict_add_nr(dict, S_LEN("status"), status); apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf); + tv_dict_clear(dict); } } @@ -521,14 +526,12 @@ void terminal_destroy(Terminal *term) } if (!term->refcount) { - // might be destroyed after terminal_teardown is invoked - if (invalidated_terminals - && pmap_has(ptr_t)(invalidated_terminals, term)) { + if (pmap_has(ptr_t)(&invalidated_terminals, term)) { // flush any pending changes to the buffer block_autocmds(); refresh_terminal(term); unblock_autocmds(); - pmap_del(ptr_t)(invalidated_terminals, term); + pmap_del(ptr_t)(&invalidated_terminals, term); } for (size_t i = 0; i < term->sb_current; i++) { xfree(term->sb_buffer[i]); @@ -865,7 +868,7 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) } memcpy(sbrow->cells, cells, sizeof(cells[0]) * c); - pmap_put(ptr_t)(invalidated_terminals, term, NULL); + pmap_put(ptr_t)(&invalidated_terminals, term, NULL); return 1; } @@ -906,7 +909,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) } xfree(sbrow); - pmap_put(ptr_t)(invalidated_terminals, term, NULL); + pmap_put(ptr_t)(&invalidated_terminals, term, NULL); return 1; } @@ -1208,7 +1211,7 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row) term->invalid_end = MAX(term->invalid_end, end_row); } - pmap_put(ptr_t)(invalidated_terminals, term, NULL); + pmap_put(ptr_t)(&invalidated_terminals, term, NULL); if (!refresh_pending) { time_watcher_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0); refresh_pending = true; @@ -1250,10 +1253,10 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data) void *stub; (void)(stub); // don't process autocommands while updating terminal buffers block_autocmds(); - map_foreach(invalidated_terminals, term, stub, { + map_foreach(&invalidated_terminals, term, stub, { refresh_terminal(term); }); - pmap_clear(ptr_t)(invalidated_terminals); + pmap_clear(ptr_t)(&invalidated_terminals); unblock_autocmds(); } diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index c155dbad50..4d29d18330 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -151,7 +151,6 @@ let s:filename_checks = { \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/pacman.conf', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'], \ 'dot': ['file.dot', 'file.gv'], \ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'], - \ 'dsl': ['file.dsl'], \ 'dtd': ['file.dtd'], \ 'dts': ['file.dts', 'file.dtsi'], \ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace'], @@ -809,4 +808,21 @@ func Test_ex_file() filetype off endfunc +func Test_dsl_file() + filetype on + + call writefile([' <!doctype dsssl-spec ['], 'dslfile.dsl') + split dslfile.dsl + call assert_equal('dsl', &filetype) + bwipe! + + call writefile(['workspace {'], 'dslfile.dsl') + split dslfile.dsl + call assert_equal('structurizr', &filetype) + bwipe! + + call delete('dslfile.dsl') + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 5c413d1e16..aff22f5d01 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -1227,7 +1227,7 @@ func Test_normal23_K() set iskeyword-=\| " Only expect "man" to work on Unix - if !has("unix") + if !has("unix") || has('nvim') " Nvim K uses :terminal. #15398 let &keywordprg = k bw! return diff --git a/src/nvim/undo.c b/src/nvim/undo.c index c4b48a6ee2..e1a7dbb2d3 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2762,13 +2762,13 @@ void u_find_first_changed(void) return; for (lnum = 1; lnum < curbuf->b_ml.ml_line_count - && lnum <= uep->ue_size; ++lnum) - if (STRCMP(ml_get_buf(curbuf, lnum, FALSE), - uep->ue_array[lnum - 1]) != 0) { + && lnum <= uep->ue_size; lnum++) { + if (STRCMP(ml_get_buf(curbuf, lnum, false), uep->ue_array[lnum - 1]) != 0) { clearpos(&(uhp->uh_cursor)); uhp->uh_cursor.lnum = lnum; return; } + } if (curbuf->b_ml.ml_line_count != uep->ue_size) { /* lines added or deleted at the end, put the cursor there */ clearpos(&(uhp->uh_cursor)); diff --git a/src/nvim/window.c b/src/nvim/window.c index fefbab822e..eddbe14da2 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5,7 +5,6 @@ #include <inttypes.h> #include <stdbool.h> -#include "nvim/api/private/handle.h" #include "nvim/api/private/helpers.h" #include "nvim/vim.h" #include "nvim/ascii.h" @@ -2605,7 +2604,7 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) { int dir; tabpage_T *ptp = NULL; - int free_tp = FALSE; + bool free_tp = false; // Get here with win->w_buffer == NULL when win_close() detects the tab page // changed. @@ -2710,7 +2709,11 @@ static win_T *win_free_mem( // When deleting the current window of another tab page select a new // current window. if (tp != NULL && win == tp->tp_curwin) { - tp->tp_curwin = wp; + if (win_valid(tp->tp_prevwin) && tp->tp_prevwin != win) { + tp->tp_curwin = tp->tp_prevwin; + } else { + tp->tp_curwin = tp->tp_firstwin; + } } return wp; @@ -3601,7 +3604,7 @@ static tabpage_T *alloc_tabpage(void) static int last_tp_handle = 0; tabpage_T *tp = xcalloc(1, sizeof(tabpage_T)); tp->handle = ++last_tp_handle; - handle_register_tabpage(tp); + pmap_put(handle_T)(&tabpage_handles, tp->handle, tp); // Init t: variables. tp->tp_vars = tv_dict_alloc(); @@ -3616,7 +3619,7 @@ void free_tabpage(tabpage_T *tp) { int idx; - handle_unregister_tabpage(tp); + pmap_del(handle_T)(&tabpage_handles, tp->handle); diff_clear(tp); for (idx = 0; idx < SNAP_COUNT; ++idx) clear_snapshot(tp, idx); @@ -4545,7 +4548,7 @@ static win_T *win_alloc(win_T *after, bool hidden) win_T *new_wp = xcalloc(1, sizeof(win_T)); new_wp->handle = ++last_win_id; - handle_register_window(new_wp); + pmap_put(handle_T)(&window_handles, new_wp->handle, new_wp); grid_assign_handle(&new_wp->w_grid_alloc); @@ -4616,7 +4619,7 @@ win_free ( int i; wininfo_T *wip; - handle_unregister_window(wp); + pmap_del(handle_T)(&window_handles, wp->handle); clearFolding(wp); /* reduce the reference count to the argument list. */ diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index e4aa1dae8e..c49d6405f4 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -347,6 +347,21 @@ describe('API/win', function() eq(2, #meths.list_wins()) eq('', funcs.getcmdwintype()) end) + + it('closing current (float) window of another tabpage #15313', function() + command('tabedit') + eq(2, eval('tabpagenr()')) + local win = meths.open_win(0, true, { + relative='editor', row=10, col=10, width=50, height=10 + }) + local tabpage = eval('tabpagenr()') + command('tabprevious') + eq(1, eval('tabpagenr()')) + meths.win_close(win, false) + + eq(1001, meths.tabpage_get_win(tabpage).id) + helpers.assert_alive() + end) end) describe('hide', function() diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua index b12c24b58d..1e8f981437 100644 --- a/test/functional/autocmd/termxx_spec.lua +++ b/test/functional/autocmd/termxx_spec.lua @@ -13,7 +13,7 @@ describe('autocmd TermClose', function() before_each(function() clear() nvim('set_option', 'shell', nvim_dir .. '/shell-test') - nvim('set_option', 'shellcmdflag', 'EXE') + command('set shellcmdflag=EXE shellredir= shellpipe= shellquote= shellxquote=') end) it('triggers when fast-exiting terminal job stops', function() @@ -90,6 +90,17 @@ describe('autocmd TermClose', function() retry(nil, nil, function() eq('3', eval('g:abuf')) end) feed('<c-c>:qa!<cr>') end) + + it('exposes v:event.status', function() + command('set shellcmdflag=EXIT') + command('autocmd TermClose * let g:status = v:event.status') + + command('terminal 0') + retry(nil, nil, function() eq(0, eval('g:status')) end) + + command('terminal 42') + retry(nil, nil, function() eq(42, eval('g:status')) end) + end) end) it('autocmd TermEnter, TermLeave', function() diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c index b95e563932..4196716799 100644 --- a/test/functional/fixtures/shell-test.c +++ b/test/functional/fixtures/shell-test.c @@ -19,7 +19,7 @@ static void flush_wait(void) static void help(void) { - puts("A simple implementation of a shell for testing termopen()."); + puts("Fake shell"); puts(""); puts("Usage:"); puts(" shell-test --help"); @@ -42,6 +42,8 @@ static void help(void) puts(" 96: foo bar"); puts(" shell-test INTERACT"); puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input."); + puts(" shell-test EXIT {code}"); + puts(" Exits immediately with exit code \"{code}\"."); } int main(int argc, char **argv) @@ -103,7 +105,6 @@ int main(int argc, char **argv) char input[256]; char cmd[100]; int arg; - int input_argc; while (1) { fprintf(stderr, "interact $ "); @@ -112,8 +113,7 @@ int main(int argc, char **argv) break; // EOF } - input_argc = sscanf(input, "%99s %d", cmd, &arg); - if(1 == input_argc) { + if(1 == sscanf(input, "%99s %d", cmd, &arg)) { arg = 0; } if (strcmp(cmd, "exit") == 0) { @@ -122,6 +122,15 @@ int main(int argc, char **argv) fprintf(stderr, "command not found: %s\n", cmd); } } + } else if (strcmp(argv[1], "EXIT") == 0) { + int code = 1; + if (argc >= 3) { + if (sscanf(argv[2], "%d", &code) != 1) { + fprintf(stderr, "Invalid exit code: %s\n", argv[2]); + return 2; + } + } + return code; } else { fprintf(stderr, "Unknown first argument: %s\n", argv[1]); return 3; diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 5974e8897f..92d802d62d 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -422,7 +422,7 @@ end -- Builds an argument list for use in clear(). -- ---@see clear() for parameters. +---@see clear() for parameters. function module.new_argv(...) local args = {unpack(module.nvim_argv)} table.insert(args, '--headless') @@ -573,7 +573,7 @@ function module.buf_lines(bufnr) return module.exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr) end ---@see buf_lines() +---@see buf_lines() function module.curbuf_contents() module.poke_eventloop() -- Before inspecting the buffer, do whatever. return table.concat(module.curbuf('get_lines', 0, -1, true), '\n') diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua new file mode 100644 index 0000000000..4f28f84c01 --- /dev/null +++ b/test/functional/lua/xdiff_spec.lua @@ -0,0 +1,112 @@ +local helpers = require('test.functional.helpers')(after_each) +local clear = helpers.clear +local exec_lua = helpers.exec_lua +local eq = helpers.eq +local pcall_err = helpers.pcall_err + +describe('xdiff bindings', function() + before_each(function() + clear() + end) + + describe('can diff text', function() + before_each(function() + exec_lua[[ + a1 = 'Hello\n' + b1 = 'Helli\n' + + a2 = 'Hello\nbye\nfoo\n' + b2 = 'Helli\nbye\nbar\nbaz\n' + ]] + end) + + it('with no callback', function() + + eq( + table.concat({ + '@@ -1 +1 @@', + '-Hello', + '+Helli', + '' + }, '\n'), + exec_lua("return vim.diff(a1, b1)") + ) + + eq( + table.concat({ + '@@ -1 +1 @@', + '-Hello', + '+Helli', + '@@ -3 +3,2 @@', + '-foo', + '+bar', + '+baz', + '' + }, '\n'), + exec_lua("return vim.diff(a2, b2)") + ) + + end) + + it('with callback', function() + exec_lua([[on_hunk = function(sa, ca, sb, cb) + exp[#exp+1] = {sa, ca, sb, cb} + end]]) + + eq({{1, 1, 1, 1}}, exec_lua[[ + exp = {} + assert(vim.diff(a1, b1, {on_hunk = on_hunk}) == nil) + return exp + ]]) + + eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, exec_lua[[ + exp = {} + assert(vim.diff(a2, b2, {on_hunk = on_hunk}) == nil) + return exp + ]]) + + -- gives higher precedence to on_hunk over result_type + eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, exec_lua[[ + exp = {} + assert(vim.diff(a2, b2, {on_hunk = on_hunk, result_type='indices'}) == nil) + return exp + ]]) + end) + + it('with error callback', function() + exec_lua([[on_hunk = function(sa, ca, sb, cb) + error('ERROR1') + end]]) + + eq([[Error executing lua: [string "<nvim>"]:0: error running function on_hunk: [string "<nvim>"]:0: ERROR1]], + pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]])) + end) + + it('with hunk_lines', function() + eq({{1, 1, 1, 1}}, + exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]])) + + eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, + exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]])) + end) + + end) + + it('can handle bad args', function() + eq([[Error executing lua: [string "<nvim>"]:0: Expected at least 2 arguments]], + pcall_err(exec_lua, [[vim.diff('a')]])) + + eq([[Error executing lua: [string "<nvim>"]:0: bad argument #1 to 'diff' (expected string)]], + pcall_err(exec_lua, [[vim.diff(1, 2)]])) + + eq([[Error executing lua: [string "<nvim>"]:0: bad argument #3 to 'diff' (expected table)]], + pcall_err(exec_lua, [[vim.diff('a', 'b', true)]])) + + eq([[Error executing lua: [string "<nvim>"]:0: unexpected key: bad_key]], + pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]])) + + eq([[Error executing lua: [string "<nvim>"]:0: on_hunk is not a function]], + pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]])) + + end) +end) diff --git a/test/functional/normal/K_spec.lua b/test/functional/normal/K_spec.lua index 174313d80e..40f36491e4 100644 --- a/test/functional/normal/K_spec.lua +++ b/test/functional/normal/K_spec.lua @@ -1,6 +1,6 @@ local helpers = require('test.functional.helpers')(after_each) -local eq, clear, eval, feed = - helpers.eq, helpers.clear, helpers.eval, helpers.feed +local eq, clear, eval, feed, retry = + helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.retry describe('K', function() local test_file = 'K_spec_out' @@ -31,7 +31,7 @@ describe('K', function() -- K on the text "K_spec_out" resolves to `!echo fnord >> K_spec_out`. feed('i'..test_file..'<ESC>K') - feed('<CR>') -- Press ENTER + retry(nil, nil, function() eq(1, eval('filereadable("'..test_file..'")')) end) eq({'fnord'}, eval("readfile('"..test_file.."')")) end) diff --git a/test/helpers.lua b/test/helpers.lua index 12d9f19187..469aee53f0 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -58,9 +58,9 @@ local check_logs_useless_lines = { --- Invokes `fn` and includes the tail of `logfile` in the error message if it --- fails. --- ---@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog' ---@param fn Function to invoke ---@param ... Function arguments +---@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog' +---@param fn Function to invoke +---@param ... Function arguments local function dumplog(logfile, fn, ...) -- module.validate({ -- logfile={logfile,'s',true}, @@ -102,8 +102,8 @@ end --- Asserts that `pat` matches one or more lines in the tail of $NVIM_LOG_FILE. --- ---@param pat (string) Lua pattern to search for in the log file. ---@param logfile (string, default=$NVIM_LOG_FILE) full path to log file. +---@param pat (string) Lua pattern to search for in the log file. +---@param logfile (string, default=$NVIM_LOG_FILE) full path to log file. function module.assert_log(pat, logfile) logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog' local nrlines = 10 |