aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.gitattributes1
-rw-r--r--.github/workflows/commitlint.config.js35
-rw-r--r--.github/workflows/commitlint.config_patch.js27
-rw-r--r--.github/workflows/commitlint.yml12
-rw-r--r--.github/workflows/labeler.yml16
-rw-r--r--CONTRIBUTING.md29
-rw-r--r--LICENSE1
-rw-r--r--MAINTAIN.md22
-rw-r--r--runtime/doc/diagnostic.txt58
-rw-r--r--runtime/doc/eval.txt49
-rw-r--r--runtime/doc/helphelp.txt12
-rw-r--r--runtime/doc/lsp.txt22
-rw-r--r--runtime/doc/lua.txt21
-rw-r--r--runtime/filetype.vim6
-rw-r--r--runtime/lua/vim/diagnostic.lua66
-rw-r--r--runtime/lua/vim/lsp.lua2
-rw-r--r--runtime/lua/vim/lsp/buf.lua125
-rw-r--r--runtime/lua/vim/lsp/codelens.lua16
-rw-r--r--runtime/lua/vim/lsp/handlers.lua46
-rw-r--r--runtime/lua/vim/lsp/protocol.lua4
-rw-r--r--runtime/lua/vim/lsp/rpc.lua46
-rw-r--r--runtime/lua/vim/lsp/util.lua11
-rw-r--r--runtime/lua/vim/ui.lua36
-rwxr-xr-xscripts/finddeclarations.pl50
-rwxr-xr-xscripts/gen_vimdoc.py3
-rw-r--r--scripts/lintcommit.lua2
-rwxr-xr-xscripts/release.sh4
-rwxr-xr-xscripts/vim-patch.sh43
-rw-r--r--src/cjson/fpconv.c211
-rw-r--r--src/cjson/fpconv.h22
-rw-r--r--src/cjson/lua_cjson.c1609
-rw-r--r--src/cjson/lua_cjson.h10
-rw-r--r--src/cjson/strbuf.c251
-rw-r--r--src/cjson/strbuf.h159
-rwxr-xr-xsrc/clint.py1
-rw-r--r--src/nvim/CMakeLists.txt19
-rw-r--r--src/nvim/api/buffer.c391
-rw-r--r--src/nvim/api/deprecated.c2
-rw-r--r--src/nvim/api/keysets.lua52
-rw-r--r--src/nvim/api/private/defs.h10
-rw-r--r--src/nvim/api/private/dispatch.c2
-rw-r--r--src/nvim/api/private/helpers.c471
-rw-r--r--src/nvim/api/private/helpers.h6
-rw-r--r--src/nvim/api/vim.c38
-rw-r--r--src/nvim/api/window.c2
-rw-r--r--src/nvim/autocmd.c27
-rw-r--r--src/nvim/buffer.c217
-rw-r--r--src/nvim/buffer_defs.h6
-rw-r--r--src/nvim/change.c23
-rw-r--r--src/nvim/charset.c16
-rw-r--r--src/nvim/cursor.c8
-rw-r--r--src/nvim/debugger.c24
-rw-r--r--src/nvim/decoration.c36
-rw-r--r--src/nvim/decoration.h8
-rw-r--r--src/nvim/diff.c64
-rw-r--r--src/nvim/edit.c22
-rw-r--r--src/nvim/eval.c14
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c157
-rw-r--r--src/nvim/eval/typval.c4
-rw-r--r--src/nvim/eval/userfunc.c20
-rw-r--r--src/nvim/event/stream.c2
-rw-r--r--src/nvim/ex_cmds.c20
-rw-r--r--src/nvim/ex_cmds2.c98
-rw-r--r--src/nvim/ex_docmd.c6
-rw-r--r--src/nvim/ex_getln.c50
-rw-r--r--src/nvim/extmark.c25
-rw-r--r--src/nvim/extmark_defs.h10
-rw-r--r--src/nvim/fileio.c106
-rw-r--r--src/nvim/fold.c4
-rw-r--r--src/nvim/generators/c_grammar.lua2
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua49
-rwxr-xr-xsrc/nvim/generators/gen_declarations.lua2
-rw-r--r--src/nvim/generators/gen_keysets.lua67
-rw-r--r--src/nvim/generators/hashy.lua122
-rw-r--r--src/nvim/getchar.c24
-rw-r--r--src/nvim/getchar.h2
-rw-r--r--src/nvim/hardcopy.c22
-rw-r--r--src/nvim/if_cscope.c447
-rw-r--r--src/nvim/lua/converter.c46
-rw-r--r--src/nvim/lua/executor.c4
-rw-r--r--src/nvim/lua/vim.lua3
-rw-r--r--src/nvim/lua/xdiff.c12
-rw-r--r--src/nvim/main.c29
-rw-r--r--src/nvim/map.c8
-rw-r--r--src/nvim/mbyte.c32
-rw-r--r--src/nvim/memory.c58
-rw-r--r--src/nvim/menu.c46
-rw-r--r--src/nvim/message.c2
-rw-r--r--src/nvim/misc1.c2
-rw-r--r--src/nvim/mouse.c17
-rw-r--r--src/nvim/move.c78
-rw-r--r--src/nvim/msgpack_rpc/channel.c14
-rw-r--r--src/nvim/msgpack_rpc/helpers.c71
-rw-r--r--src/nvim/normal.c9
-rw-r--r--src/nvim/option.c28
-rw-r--r--src/nvim/os/env.c8
-rw-r--r--src/nvim/os/fs.c8
-rw-r--r--src/nvim/os/pty_process_unix.c2
-rw-r--r--src/nvim/os/shell.c12
-rw-r--r--src/nvim/os/tty.c9
-rw-r--r--src/nvim/os/users.c10
-rw-r--r--src/nvim/plines.c32
-rw-r--r--src/nvim/popupmnu.c2
-rw-r--r--src/nvim/quickfix.c24
-rw-r--r--src/nvim/runtime.c377
-rw-r--r--src/nvim/runtime.h20
-rw-r--r--src/nvim/screen.c215
-rw-r--r--src/nvim/search.c44
-rw-r--r--src/nvim/sha256.c11
-rw-r--r--src/nvim/shada.c2820
-rw-r--r--src/nvim/sign.c937
-rw-r--r--src/nvim/spell.c1913
-rw-r--r--src/nvim/spellfile.c1761
-rw-r--r--src/nvim/state.c20
-rw-r--r--src/nvim/strings.c916
-rw-r--r--src/nvim/syntax.c10
-rw-r--r--src/nvim/tag.c1559
-rw-r--r--src/nvim/terminal.c666
-rw-r--r--src/nvim/testdir/test_filetype.vim3
-rw-r--r--src/nvim/testdir/test_functions.vim38
-rw-r--r--src/nvim/testdir/test_popup.vim4
-rw-r--r--src/nvim/testdir/test_startup.vim10
-rw-r--r--src/nvim/tui/tui.c10
-rw-r--r--src/nvim/ugrid.c9
-rw-r--r--src/nvim/ui.c72
-rw-r--r--src/nvim/ui_bridge.c27
-rw-r--r--src/nvim/ui_compositor.c61
-rw-r--r--src/nvim/undo.c626
-rw-r--r--src/nvim/version.c34
-rw-r--r--src/nvim/vim.h12
-rw-r--r--src/nvim/viml/parser/expressions.c10
-rw-r--r--src/nvim/window.c12
-rw-r--r--src/uncrustify.cfg85
-rw-r--r--src/xdiff/xdiffi.c3
-rw-r--r--src/xdiff/xemit.c3
-rw-r--r--src/xdiff/xhistogram.c3
-rw-r--r--src/xdiff/xpatience.c3
-rw-r--r--src/xdiff/xprepare.c3
-rw-r--r--src/xdiff/xutils.c3
-rw-r--r--test/config/paths.lua.in1
-rw-r--r--test/functional/api/command_spec.lua2
-rw-r--r--test/functional/api/keymap_spec.lua12
-rw-r--r--test/functional/api/vim_spec.lua19
-rw-r--r--test/functional/api/window_spec.lua26
-rw-r--r--test/functional/core/startup_spec.lua53
-rw-r--r--test/functional/editor/meta_key_spec.lua15
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua33
-rw-r--r--test/functional/fixtures/middle/filen.lua1
-rw-r--r--test/functional/fixtures/pack/foo/opt/funky/filen.lua12
-rw-r--r--test/functional/lua/diagnostic_spec.lua51
-rw-r--r--test/functional/lua/json_spec.lua133
-rw-r--r--test/functional/lua/ui_spec.lua46
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua28
-rw-r--r--test/functional/plugin/lsp_spec.lua192
-rw-r--r--test/functional/ui/decorations_spec.lua508
-rw-r--r--test/functional/ui/float_spec.lua316
-rw-r--r--test/functional/ui/mouse_spec.lua124
158 files changed, 12565 insertions, 7599 deletions
diff --git a/.gitattributes b/.gitattributes
index 1deb4dea49..e09a918303 100755
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,7 +1,6 @@
*.h linguist-language=C
src/nvim/testdir/test42.in diff
.github/ export-ignore
-ci/ export-ignore
.travis.yml export-ignore
codecov.yml export-ignore
.builds/ export-ignore
diff --git a/.github/workflows/commitlint.config.js b/.github/workflows/commitlint.config.js
deleted file mode 100644
index 5f10ffc6f4..0000000000
--- a/.github/workflows/commitlint.config.js
+++ /dev/null
@@ -1,35 +0,0 @@
-module.exports = {
- rules: {
- 'body-leading-blank': [1, 'always'],
- 'body-max-line-length': [2, 'always', 100],
- 'footer-leading-blank': [1, 'always'],
- 'footer-max-line-length': [2, 'always', 100],
- 'header-max-length': [2, 'always', 100],
- 'scope-case': [2, 'always', 'lower-case'],
- 'subject-case': [
- 2,
- 'never',
- ['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
- ],
- 'subject-empty': [2, 'never'],
- 'subject-full-stop': [2, 'never', '.'],
- 'type-case': [2, 'always', 'lower-case'],
- 'type-empty': [2, 'never'],
- 'type-enum': [
- 2,
- 'always',
- [
- 'build',
- 'chore',
- 'ci',
- 'docs',
- 'feat',
- 'fix',
- 'perf',
- 'refactor',
- 'revert',
- 'test',
- ],
- ],
- },
-};
diff --git a/.github/workflows/commitlint.config_patch.js b/.github/workflows/commitlint.config_patch.js
deleted file mode 100644
index ca398c45dc..0000000000
--- a/.github/workflows/commitlint.config_patch.js
+++ /dev/null
@@ -1,27 +0,0 @@
-module.exports = {
- parserPreset: {
- parserOpts: { headerPattern: /^([^\(\):]*)(?:\((.*)\))?!?:(.*)$/ }
- },
- rules: {
- 'body-leading-blank': [1, 'always'],
- 'body-max-line-length': [2, 'always', 100],
- 'footer-max-line-length': [2, 'always', 100],
- 'scope-case': [2, 'always', 'lower-case'],
- 'subject-case': [
- 2,
- 'never',
- ['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
- ],
- 'subject-empty': [2, 'never'],
- 'subject-full-stop': [2, 'never', '.'],
- 'type-case': [2, 'always', 'lower-case'],
- 'type-empty': [2, 'never'],
- 'type-enum': [
- 2,
- 'always',
- [
- 'vim-patch',
- ],
- ],
- },
-};
diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml
index 9ae138fbd7..4c9c526946 100644
--- a/.github/workflows/commitlint.yml
+++ b/.github/workflows/commitlint.yml
@@ -9,10 +9,8 @@ jobs:
- uses: actions/checkout@v2.3.1
with:
fetch-depth: 0
- - run: npm install --save-dev @commitlint/cli
- - run: |
- if [[ "$(gh pr view ${{ github.event.pull_request.number }} --json commits --jq '.[][0].messageHeadline')" == vim-patch* ]];then
- npx commitlint --from HEAD~1 --to HEAD --verbose --help-url https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages --config .github/workflows/commitlint.config_patch.js
- else
- npx commitlint --from HEAD~1 --to HEAD --verbose --help-url https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages --config .github/workflows/commitlint.config.js
- fi
+ - uses: rhysd/action-setup-vim@v1
+ with:
+ neovim: true
+ - run: gh pr checkout ${{ github.event.pull_request.number }}
+ - run: nvim --clean -es +"lua require('scripts.lintcommit').main({trace=true})"
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 67ad4c0552..c7a331c657 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -12,3 +12,19 @@ jobs:
- uses: actions/labeler@main
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ type-scope:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - uses: actions/checkout@v2.3.1
+ - run: gh pr checkout ${{ github.event.pull_request.number }}
+
+ # Extract type and try to add it as a label
+ - run: gh pr edit --add-label "$(echo "${{ github.event.pull_request.title }}" | sed -E 's|([[:alpha:]]+)(\(.*\))?:.*|\1|')" || true
+
+ # Extract scope and try to add it as a label
+ - run: gh pr edit --add-label "$(echo "${{ github.event.pull_request.title }}" | sed -E 's|[[:alpha:]]+\((.+)\):.*|\1|')" || true
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2a565574fa..fe3540f1f6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -161,7 +161,7 @@ see potential bugs found by [PVS Studio](https://www.viva64.com/en/pvs-studio/).
- Use this format for commit messages (where `{id}` is the PVS warning-id)):
```
- PVS/V{id}: {description}
+ fix(PVS/V{id}): {description}
```
- Search the Neovim commit history to find examples:
```
@@ -177,7 +177,7 @@ master build. To view the defects, just request access; you will be approved.
- Use this format for commit messages (where `{id}` is the CID (Coverity ID);
([example](https://github.com/neovim/neovim/pull/804))):
```
- coverity/{id}: {description}
+ fix(coverity/{id}): {description}
```
- Search the Neovim commit history to find examples:
```
@@ -217,13 +217,21 @@ You can lint a single file (but this will _not_ exclude legacy errors):
### Style
-The repo includes a `.clang-format` config file which (mostly) matches the
-[style-guide]. You can use `clang-format` to format code with the `gq`
-operator in Nvim:
-
- if !empty(findfile('.clang-format', ';'))
- setlocal formatprg=clang-format\ -style=file
- endif
+- Style rules are (mostly) defined by `src/uncrustify.cfg` which tries to match
+ the [style-guide]. To use the Nvim `gq` command with `uncrustify`:
+ ```
+ if !empty(findfile('src/uncrustify.cfg', ';'))
+ setlocal formatprg=uncrustify\ -q\ -l\ C\ -c\ src/uncrustify.cfg\ --no-backup
+ endif
+ ```
+ The required version of `uncrustify` is specified in `uncrustify.cfg`.
+- There is also `.clang-format` which has drifted from the [style-guide], but
+ is available for reference. To use the Nvim `gq` command with `clang-format`:
+ ```
+ if !empty(findfile('.clang-format', ';'))
+ setlocal formatprg=clang-format\ -style=file
+ endif
+ ```
### Navigate
@@ -263,7 +271,7 @@ as context, use the `-W` argument as well.
[1820]: https://github.com/neovim/neovim/pull/1820
[hub]: https://hub.github.com/
[conventional_commits]: https://www.conventionalcommits.org
-[style-guide]: http://neovim.io/develop/style-guide.xml
+[style-guide]: https://neovim.io/doc/user/dev_style.html#dev-style
[ASan]: http://clang.llvm.org/docs/AddressSanitizer.html
[run-tests]: https://github.com/neovim/neovim/blob/master/test/README.md#running-tests
[wiki-faq]: https://github.com/neovim/neovim/wiki/FAQ
@@ -278,3 +286,4 @@ as context, use the `-W` argument as well.
[wiki-contribute-help]: https://github.com/neovim/neovim/wiki/contribute-%3Ahelp
[pr-draft]: https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request
[pr-ready]: https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request
+[uncrustify]: https://formulae.brew.sh/formula/uncrustify
diff --git a/LICENSE b/LICENSE
index eabb27f5cd..c1b8286c4b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -199,6 +199,7 @@ The externally maintained libraries used by Neovim are:
- lua-compat: MIT license
- tree-sitter: MIT license
- xdiff: LGPL license
+ - lua-cjson: MIT license
====
diff --git a/MAINTAIN.md b/MAINTAIN.md
index 73578a8c5d..681ba91e3f 100644
--- a/MAINTAIN.md
+++ b/MAINTAIN.md
@@ -55,6 +55,28 @@ has a major bug:
- The [nightly job](https://github.com/neovim/bot-ci/blob/master/ci/nightly.sh)
will update the release assets based on the `stable` tag.
+Third-party dependencies
+--------------
+
+These "bundled" dependencies can be updated by bumping their versions in `third-party/CMakeLists.txt`:
+ - [Lua](https://www.lua.org/download.html)
+ - [LuaJIT](https://github.com/LuaJIT/LuaJIT)
+ - [Luv](https://github.com/luvit/luv)
+ - [libtermkey](https://github.com/neovim/libtermkey)
+ - [libuv](https://github.com/libuv/libuv)
+ - [libvterm](http://www.leonerd.org.uk/code/libvterm/)
+ - [lua-compat](https://github.com/keplerproject/lua-compat-5.3)
+ - [tree-sitter](https://github.com/tree-sitter/tree-sitter)
+
+These dependencies are "vendored" (inlined), we need to update the sources manually:
+ - [libmpack](https://github.com/libmpack/libmpack)
+ - [xdiff](https://github.com/git/git/tree/master/xdiff)
+ - [lua-cjson](https://github.com/openresty/lua-cjson)
+ - [Klib](https://github.com/attractivechaos/klib)
+
+We also maintain some forks, particularly for Windows, if we are waiting on upstream changes:
+https://github.com/neovim/neovim/wiki/Deps
+
See also
--------
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index 68e4353d5b..276571d042 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -187,6 +187,11 @@ can be customized using the following: >
sign define DiagnosticSignInfo text=I texthl=DiagnosticSignInfo linehl= numhl=
sign define DiagnosticSignHint text=H texthl=DiagnosticSignHint linehl= numhl=
+When the "severity_sort" option is set (see |vim.diagnostic.config()|) the
+priority of each sign depends on the severity of the associated diagnostic.
+Otherwise, all signs have the same priority (the value of the "priority"
+option in the "signs" table of |vim.diagnostic.config()| or 10 if unset).
+
==============================================================================
EVENTS *diagnostic-events*
@@ -196,7 +201,52 @@ DiagnosticsChanged After diagnostics have changed.
Example: >
autocmd User DiagnosticsChanged lua vim.diagnostic.setqflist({open = false })
<
-
+==============================================================================
+CUSTOMIZATION *diagnostic-config*
+
+If you need more customization over the way diagnostics are displayed than the
+built-in configuration options provide, you can override the display handler
+explicitly. For example, use the following to only show a sign for the highest
+severity diagnostic on a given line: >
+
+ -- Disable the default signs handler
+ vim.diagnostic.config({signs = false})
+
+ -- Create a namespace. This won't be used to add any diagnostics,
+ -- only to display them.
+ local ns = vim.api.nvim_create_namespace("my_namespace")
+
+ -- Create a reference to the original function
+ local orig_show = vim.diagnostic.show
+
+ local function set_signs(bufnr)
+ -- Get all diagnostics from the current buffer
+ local diagnostics = vim.diagnostic.get(bufnr)
+
+ -- Find the "worst" diagnostic per line
+ local max_severity_per_line = {}
+ for _, d in pairs(diagnostics) do
+ local m = max_severity_per_line[d.lnum]
+ if not m or d.severity < m.severity then
+ max_severity_per_line[d.lnum] = d
+ end
+ end
+
+ -- Show the filtered diagnostics using the custom namespace. Use the
+ -- reference to the original function to avoid a loop.
+ local filtered_diagnostics = vim.tbl_values(max_severity_per_line)
+ orig_show(ns, bufnr, filtered_diagnostics, {
+ virtual_text=false,
+ underline=false,
+ signs=true
+ })
+ end
+
+ function vim.diagnostic.show(namespace, bufnr, ...)
+ orig_show(namespace, bufnr, ...)
+ set_signs(bufnr)
+ end
+<
==============================================================================
Lua module: vim.diagnostic *diagnostic-api*
@@ -248,6 +298,12 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
• severity: Only show signs for diagnostics
matching the given severity
|diagnostic-severity|
+ • priority: (number, default 10) Base
+ priority to use for signs. When
+ {severity_sort} is used, the priority of
+ a sign is adjusted based on its severity.
+ Otherwise, all signs use the same
+ priority.
• update_in_insert: (default false) Update
diagnostics in Insert mode (if false,
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index ac02bdae32..d9ecdb40de 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2431,6 +2431,7 @@ getloclist({nr}) List list of location list items
getloclist({nr}, {what}) Dict get specific location list properties
getmarklist([{buf}]) List list of global/local marks
getmatches([{win}]) List list of current matches
+getmousepos() Dict last known mouse position
getpid() Number process ID of Vim
getpos({expr}) List position of cursor, mark, etc.
getqflist() List list of quickfix items
@@ -3418,6 +3419,8 @@ complete_info([{what}]) *complete_info()*
"" Not in completion mode
"keyword" Keyword completion |i_CTRL-X_CTRL-N|
"ctrl_x" Just pressed CTRL-X |i_CTRL-X|
+ "scroll" Scrolling with |i_CTRL-X_CTRL-E| or
+ |i_CTRL-X_CTRL-Y|
"whole_line" Whole lines |i_CTRL-X_CTRL-L|
"files" File names |i_CTRL-X_CTRL-F|
"tags" Tags |i_CTRL-X_CTRL-]|
@@ -4709,7 +4712,8 @@ getchar([expr]) *getchar()*
When the user clicks a mouse button, the mouse event will be
returned. The position can then be found in |v:mouse_col|,
|v:mouse_lnum|, |v:mouse_winid| and |v:mouse_win|.
- Mouse move events will be ignored.
+ |getmousepos()| can also be used. Mouse move events will be
+ ignored.
This example positions the mouse as it would normally happen: >
let c = getchar()
if c == "\<LeftMouse>" && v:mouse_win > 0
@@ -5099,6 +5103,35 @@ getmatches([{win}]) *getmatches()*
'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
:unlet m
<
+getmousepos() *getmousepos()*
+ Returns a Dictionary with the last known position of the
+ mouse. This can be used in a mapping for a mouse click. The
+ items are:
+ screenrow screen row
+ screencol screen column
+ winid Window ID of the click
+ winrow row inside "winid"
+ wincol column inside "winid"
+ line text line inside "winid"
+ column text column inside "winid"
+ All numbers are 1-based.
+
+ If not over a window, e.g. when in the command line, then only
+ "screenrow" and "screencol" are valid, the others are zero.
+
+ When on the status line below a window or the vertical
+ separater right of a window, the "line" and "column" values
+ are zero.
+
+ When the position is after the text then "column" is the
+ length of the text in bytes plus one.
+
+ If the mouse is over a focusable floating window then that
+ window is used.
+
+ When using |getchar()| the Vim variables |v:mouse_lnum|,
+ |v:mouse_col| and |v:mouse_winid| also provide these values.
+
*getpid()*
getpid() Return a Number which is the process ID of the Vim process.
This is a unique number, until Vim exits.
@@ -6832,29 +6865,31 @@ mode([expr]) Return a string that indicates the current mode.
niR Normal using |i_CTRL-O| in |Replace-mode|
niV Normal using |i_CTRL-O| in |Virtual-Replace-mode|
v Visual by character
+ vs Visual by character using |v_CTRL-O| in Select mode
V Visual by line
+ Vs Visual by line using |v_CTRL-O| in Select mode
CTRL-V Visual blockwise
+ CTRL-Vs Visual blockwise using |v_CTRL-O| in Select mode
s Select by character
S Select by line
CTRL-S Select blockwise
- vs Visual by character using |v_CTRL-O| from
- Select mode
- Vs Visual by line using |v_CTRL-O| from Select mode
- CTRL-Vs Visual blockwise using |v_CTRL-O| from Select mode
i Insert
ic Insert mode completion |compl-generic|
ix Insert mode |i_CTRL-X| completion
R Replace |R|
Rc Replace mode completion |compl-generic|
- Rv Virtual Replace |gR|
Rx Replace mode |i_CTRL-X| completion
+ Rv Virtual Replace |gR|
+ Rvc Virtual Replace mode completion |compl-generic|
+ Rvx Virtual Replace mode |i_CTRL-X| completion
c Command-line editing
cv Vim Ex mode |Q| or |gQ|
r Hit-enter prompt
rm The -- more -- prompt
- r? |:confirm| query of some sort
+ r? A |:confirm| query of some sort
! Shell or external command is executing
t Terminal mode: keys go to the job
+
This is useful in the 'statusline' option or when used
with |remote_expr()| In most other places it always returns
"c" or "n".
diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt
index 4a94701b2e..aaa2a35fe1 100644
--- a/runtime/doc/helphelp.txt
+++ b/runtime/doc/helphelp.txt
@@ -389,17 +389,5 @@ highlighting. So do these:
You can find the details in $VIMRUNTIME/syntax/help.vim
- *inclusion*
-Vim is for everybody, no matter race, gender or anything. Some people make a
-big deal about using "he" or "his" when referring to the user, thinking it
-means we assume the user is male. That is not the case, it's just a habit of
-writing help text, which quite often is many years old. Also, a lot of the
-text is written by contributors for whom English is not their first language.
-We do not make any assumptions about the gender of the user, no matter how the
-text is phrased. Some people have suggested using "they", but that is not
-regular English. We do not want to spend much time on this discussion. The
-goal is that the reader understands how Vim works, the exact wording is
-secondary.
-
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index c434f6db66..5b2a8d68b4 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -869,12 +869,17 @@ clear_references() *vim.lsp.buf.clear_references()*
Removes document highlights from current buffer.
code_action({context}) *vim.lsp.buf.code_action()*
- Selects a code action from the input list that is available at
- the current cursor position.
+ Selects a code action available at the current cursor
+ position.
Parameters: ~
- {context} (table, optional) Valid `CodeActionContext`
- object
+ {context} table|nil `CodeActionContext` of the LSP specification:
+ • diagnostics: (table|nil) LSP`Diagnostic[]` . Inferred from the current position if not
+ provided.
+ • only: (string|nil) LSP `CodeActionKind` used
+ to filter the code actions. Most language
+ servers support values like `refactor` or
+ `quickfix` .
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
@@ -1015,8 +1020,13 @@ range_code_action({context}, {start_pos}, {end_pos})
Performs |vim.lsp.buf.code_action()| for a given range.
Parameters: ~
- {context} (table, optional) Valid `CodeActionContext`
- object
+ {context} table|nil `CodeActionContext` of the LSP specification:
+ • diagnostics: (table|nil) LSP`Diagnostic[]` . Inferred from the current position if not
+ provided.
+ • only: (string|nil) LSP `CodeActionKind`
+ used to filter the code actions. Most
+ language servers support values like
+ `refactor` or `quickfix` .
{start_pos} ({number, number}, optional) mark-indexed
position. Defaults to the start of the last
visual selection.
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 4ceb123ffc..f6daa70b4c 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1650,4 +1650,25 @@ uri_to_fname({uri}) *vim.uri_to_fname()*
Return: ~
Filename
+
+==============================================================================
+Lua module: ui *lua-ui*
+
+select({items}, {opts}, {on_choice}) *vim.ui.select()*
+ Prompts the user to pick a single item from a collection of
+ entries
+
+ Parameters: ~
+ {items} table Arbitrary items
+ {opts} table Additional options
+ • prompt (string|nil) Text of the prompt.
+ Defaults to `Select one of:`
+ • format_item (function item -> text)
+ Function to format an individual item from
+ `items` . Defaults to `tostring` .
+ {on_choice} function ((item|nil, idx|nil) -> ()) Called
+ once the user made a choice. `idx` is the
+ 1-based index of `item` within `item` . `nil`
+ if the user aborted the dialog.
+
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index bc3965d4b6..322215e1de 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -872,6 +872,9 @@ au BufNewFile,BufRead *.json-patch setf json
" Jupyter Notebook is also json
au BufNewFile,BufRead *.ipynb setf json
+" Other files that look like json
+au BufNewFile,BufRead .babelrc,.eslintrc,.prettierrc,.firebaserc setf json
+
" JSONC
au BufNewFile,BufRead *.jsonc setf jsonc
@@ -1136,6 +1139,9 @@ au BufNewFile,BufRead Neomuttrc setf neomuttrc
" Netrc
au BufNewFile,BufRead .netrc setf netrc
+" Nginx
+au BufNewFile,BufRead *.nginx,nginx*.conf,*nginx.conf,*/etc/nginx/*,*/usr/local/nginx/conf/*,*/nginx/*.conf setf nginx
+
" Ninja file
au BufNewFile,BufRead *.ninja setf ninja
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 3f41ee5df8..c7c8c1878e 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -556,6 +556,9 @@ end
--- - signs: (default true) Use signs for diagnostics. Options:
--- * severity: Only show signs for diagnostics matching the given severity
--- |diagnostic-severity|
+--- * priority: (number, default 10) Base priority to use for signs. When
+--- {severity_sort} is used, the priority of a sign is adjusted based on
+--- its severity. Otherwise, all signs use the same priority.
--- - update_in_insert: (default false) Update diagnostics in Insert mode (if false,
--- diagnostics are updated on InsertLeave)
--- - severity_sort: (default false) Sort diagnostics by severity. This affects the order in
@@ -617,23 +620,22 @@ function M.set(namespace, bufnr, diagnostics, opts)
}
if vim.tbl_isempty(diagnostics) then
- return M.reset(namespace, bufnr)
- end
-
- if not diagnostic_cleanup[bufnr][namespace] then
- diagnostic_cleanup[bufnr][namespace] = true
-
- -- Clean up our data when the buffer unloads.
- vim.api.nvim_buf_attach(bufnr, false, {
- on_detach = function(_, b)
- clear_diagnostic_cache(b, namespace)
- diagnostic_cleanup[b][namespace] = nil
- end
- })
+ clear_diagnostic_cache(namespace, bufnr)
+ else
+ if not diagnostic_cleanup[bufnr][namespace] then
+ diagnostic_cleanup[bufnr][namespace] = true
+
+ -- Clean up our data when the buffer unloads.
+ vim.api.nvim_buf_attach(bufnr, false, {
+ on_detach = function(_, b)
+ clear_diagnostic_cache(b, namespace)
+ diagnostic_cleanup[b][namespace] = nil
+ end
+ })
+ end
+ set_diagnostic_cache(namespace, bufnr, diagnostics)
end
- set_diagnostic_cache(namespace, bufnr, diagnostics)
-
if vim.api.nvim_buf_is_loaded(bufnr) then
M.show(namespace, bufnr, diagnostics, opts)
elseif opts then
@@ -643,6 +645,13 @@ function M.set(namespace, bufnr, diagnostics, opts)
vim.api.nvim_command("doautocmd <nomodeline> User DiagnosticsChanged")
end
+--- Get current diagnostic namespaces.
+---
+---@return table A list of active diagnostic namespaces |vim.diagnostic|.
+function M.get_namespaces()
+ return vim.deepcopy(all_namespaces)
+end
+
--- Get current diagnostics.
---
---@param bufnr number|nil Buffer number to get diagnostics from. Use 0 for
@@ -806,16 +815,35 @@ function M._set_signs(namespace, bufnr, diagnostics, opts)
}
bufnr = get_bufnr(bufnr)
- opts = get_resolved_options({ signs = opts }, namespace, bufnr).signs
+ opts = get_resolved_options({ signs = opts }, namespace, bufnr)
- if opts and opts.severity then
- diagnostics = filter_by_severity(opts.severity, diagnostics)
+ if opts.signs and opts.signs.severity then
+ diagnostics = filter_by_severity(opts.signs.severity, diagnostics)
end
local ns = get_namespace(namespace)
define_default_signs()
+ -- 10 is the default sign priority when none is explicitly specified
+ local priority = opts.signs and opts.signs.priority or 10
+ local get_priority
+ if opts.severity_sort then
+ if type(opts.severity_sort) == "table" and opts.severity_sort.reverse then
+ get_priority = function(severity)
+ return priority + (severity - vim.diagnostic.severity.ERROR)
+ end
+ else
+ get_priority = function(severity)
+ return priority + (vim.diagnostic.severity.HINT - severity)
+ end
+ end
+ else
+ get_priority = function()
+ return priority
+ end
+ end
+
for _, diagnostic in ipairs(diagnostics) do
vim.fn.sign_place(
0,
@@ -823,7 +851,7 @@ function M._set_signs(namespace, bufnr, diagnostics, opts)
sign_highlight_map[diagnostic.severity],
bufnr,
{
- priority = opts and opts.priority,
+ priority = get_priority(diagnostic.severity),
lnum = diagnostic.lnum + 1
}
)
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index ae9a7ab513..c7a88a0993 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -830,7 +830,7 @@ function lsp.start_client(config)
rpc.request('initialize', initialize_params, function(init_err, result)
assert(not init_err, tostring(init_err))
assert(result, "server sent empty result")
- rpc.notify('initialized', {[vim.type_idx]=vim.types.dictionary})
+ rpc.notify('initialized', vim.empty_dict())
client.initialized = true
uninitialized_clients[client_id] = nil
client.workspaceFolders = initialize_params.workspaceFolders
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 054f7aee04..245f29943e 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -289,7 +289,6 @@ function M.references(context)
params.context = context or {
includeDeclaration = true;
}
- params[vim.type_idx] = vim.types.dictionary
request('textDocument/references', params)
end
@@ -451,6 +450,93 @@ function M.clear_references()
util.buf_clear_references()
end
+
+---@private
+--
+--- This is not public because the main extension point is
+--- vim.ui.select which can be overridden independently.
+---
+--- Can't call/use vim.lsp.handlers['textDocument/codeAction'] because it expects
+--- `(err, CodeAction[] | Command[], ctx)`, but we want to aggregate the results
+--- from multiple clients to have 1 single UI prompt for the user, yet we still
+--- need to be able to link a `CodeAction|Command` to the right client for
+--- `codeAction/resolve`
+local function on_code_action_results(results, ctx)
+ local action_tuples = {}
+ for client_id, result in pairs(results) do
+ for _, action in pairs(result.result or {}) do
+ table.insert(action_tuples, { client_id, action })
+ end
+ end
+ if #action_tuples == 0 then
+ vim.notify('No code actions available', vim.log.levels.INFO)
+ return
+ end
+
+ ---@private
+ local function apply_action(action, client)
+ if action.edit then
+ util.apply_workspace_edit(action.edit)
+ end
+ if action.command then
+ local command = type(action.command) == 'table' and action.command or action
+ local fn = vim.lsp.commands[command.command]
+ if fn then
+ local enriched_ctx = vim.deepcopy(ctx)
+ enriched_ctx.client_id = client.id
+ fn(command, ctx)
+ else
+ M.execute_command(command)
+ end
+ end
+ end
+
+ ---@private
+ local function on_user_choice(action_tuple)
+ if not action_tuple then
+ return
+ end
+ -- textDocument/codeAction can return either Command[] or CodeAction[]
+ --
+ -- CodeAction
+ -- ...
+ -- edit?: WorkspaceEdit -- <- must be applied before command
+ -- command?: Command
+ --
+ -- Command:
+ -- title: string
+ -- command: string
+ -- arguments?: any[]
+ --
+ local client = vim.lsp.get_client_by_id(action_tuple[1])
+ local action = action_tuple[2]
+ if not action.edit
+ and client
+ and type(client.resolved_capabilities.code_action) == 'table'
+ and client.resolved_capabilities.code_action.resolveProvider then
+
+ client.request('codeAction/resolve', action, function(err, resolved_action)
+ if err then
+ vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR)
+ return
+ end
+ apply_action(resolved_action, client)
+ end)
+ else
+ apply_action(action, client)
+ end
+ end
+
+ vim.ui.select(action_tuples, {
+ prompt = 'Code actions:',
+ format_item = function(action_tuple)
+ local title = action_tuple[2].title:gsub('\r\n', '\\r\\n')
+ return title:gsub('\n', '\\n')
+ end,
+ }, on_user_choice)
+end
+
+
--- Requests code actions from all clients and calls the handler exactly once
--- with all aggregated results
---@private
@@ -458,22 +544,28 @@ local function code_action_request(params)
local bufnr = vim.api.nvim_get_current_buf()
local method = 'textDocument/codeAction'
vim.lsp.buf_request_all(bufnr, method, params, function(results)
- local actions = {}
- for _, r in pairs(results) do
- vim.list_extend(actions, r.result or {})
- end
- vim.lsp.handlers[method](nil, actions, {bufnr=bufnr, method=method})
+ on_code_action_results(results, { bufnr = bufnr, method = method, params = params })
end)
end
---- Selects a code action from the input list that is available at the current
+--- Selects a code action available at the current
--- cursor position.
---
----@param context: (table, optional) Valid `CodeActionContext` object
+---@param context table|nil `CodeActionContext` of the LSP specification:
+--- - diagnostics: (table|nil)
+--- LSP `Diagnostic[]`. Inferred from the current
+--- position if not provided.
+--- - only: (string|nil)
+--- LSP `CodeActionKind` used to filter the code actions.
+--- Most language servers support values like `refactor`
+--- or `quickfix`.
---@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() }
+ context = context or {}
+ if not context.diagnostics then
+ context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
+ end
local params = util.make_range_params()
params.context = context
code_action_request(params)
@@ -481,14 +573,25 @@ end
--- Performs |vim.lsp.buf.code_action()| for a given range.
---
----@param context: (table, optional) Valid `CodeActionContext` object
+---
+---@param context table|nil `CodeActionContext` of the LSP specification:
+--- - diagnostics: (table|nil)
+--- LSP `Diagnostic[]`. Inferred from the current
+--- position if not provided.
+--- - only: (string|nil)
+--- LSP `CodeActionKind` used to filter the code actions.
+--- Most language servers support values like `refactor`
+--- or `quickfix`.
---@param 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.
---Defaults to the end of the last visual selection.
function M.range_code_action(context, start_pos, end_pos)
validate { context = { context, 't', true } }
- context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() }
+ context = context or {}
+ if not context.diagnostics then
+ context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
+ end
local params = util.make_given_range_params(start_pos, end_pos)
params.context = context
code_action_request(params)
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index 9cedb2f1db..20b203fe99 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -31,10 +31,24 @@ 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)
+ local command = lens.command
+ local fn = vim.lsp.commands[command.command]
+ if fn then
+ fn(command, { bufnr = bufnr, client_id = client_id })
+ return
+ end
-- Need to use the client that returned the lens → must not use buf_request
local client = vim.lsp.get_client_by_id(client_id)
assert(client, 'Client is required to execute lens, client_id=' .. client_id)
- client.request('workspace/executeCommand', lens.command, function(...)
+ local command_provider = client.server_capabilities.executeCommandProvider
+ local commands = type(command_provider) == 'table' and command_provider.commands or {}
+ if not vim.tbl_contains(commands, command.command) then
+ vim.notify(string.format(
+ "Language server does not support command `%s`. This command may require a client extension.", command.command),
+ vim.log.levels.WARN)
+ return
+ end
+ client.request('workspace/executeCommand', command, function(...)
local result = vim.lsp.handlers['workspace/executeCommand'](...)
M.refresh()
return result
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 624f8b5462..eff27807be 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -3,7 +3,6 @@ local protocol = require 'vim.lsp.protocol'
local util = require 'vim.lsp.util'
local vim = vim
local api = vim.api
-local buf = require 'vim.lsp.buf'
local M = {}
@@ -109,51 +108,6 @@ M['client/registerCapability'] = function(_, _, ctx)
return vim.NIL
end
---see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
-M['textDocument/codeAction'] = function(_, result, ctx)
- if result == nil or vim.tbl_isempty(result) then
- print("No code actions available")
- return
- end
-
- local option_strings = {"Code actions:"}
- for i, action in ipairs(result) do
- local title = action.title:gsub('\r\n', '\\r\\n')
- title = title:gsub('\n', '\\n')
- table.insert(option_strings, string.format("%d. %s", i, title))
- end
-
- local choice = vim.fn.inputlist(option_strings)
- if choice < 1 or choice > #result then
- return
- end
- local action = result[choice]
- -- textDocument/codeAction can return either Command[] or CodeAction[]
- --
- -- CodeAction
- -- ...
- -- edit?: WorkspaceEdit -- <- must be applied before command
- -- command?: Command
- --
- -- Command:
- -- title: string
- -- command: string
- -- arguments?: any[]
- --
- if action.edit then
- util.apply_workspace_edit(action.edit)
- end
- if action.command then
- local command = type(action.command) == 'table' and action.command or action
- local fn = vim.lsp.commands[command.command]
- if fn then
- fn(command, ctx)
- else
- buf.execute_command(command)
- end
- end
-end
-
--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
M['workspace/applyEdit'] = function(_, workspace_edit)
if not workspace_edit then return end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 27703b4503..b3aa8b934f 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -645,6 +645,10 @@ function protocol.make_client_capabilities()
end)();
};
};
+ dataSupport = true;
+ resolveSupport = {
+ properties = { 'edit', }
+ };
};
completion = {
dynamicRegistration = false;
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 7f31bbdf75..255eb65dfe 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -4,34 +4,6 @@ local log = require('vim.lsp.log')
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
---- Encodes to JSON.
----
----@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
- return result
- else
- return nil, result
- end
-end
----@private
---- Decodes from JSON.
----
----@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
- return result
- else
- return nil, result
- end
-end
-
---@private
--- Checks whether a given path exists and is a directory.
---@param filename (string) path to check
@@ -389,16 +361,13 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
--- 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()|
+ ---@param payload table
---@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing.
local function encode_and_send(payload)
local _ = log.debug() and log.debug("rpc.send", payload)
if handle == nil or handle:is_closing() then return false end
- -- TODO(ashkan) remove this once we have a Lua json_encode
- schedule(function()
- local encoded = assert(json_encode(payload))
- stdin:write(format_message_with_content_length(encoded))
- end)
+ local encoded = vim.json.encode(payload)
+ stdin:write(format_message_with_content_length(encoded))
return true
end
@@ -488,14 +457,15 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
---@private
local function handle_body(body)
- local decoded, err = json_decode(body)
- if not decoded then
- -- on_error(client_errors.INVALID_SERVER_JSON, err)
+ local ok, decoded = pcall(vim.json.decode, body)
+ if not ok then
+ on_error(client_errors.INVALID_SERVER_JSON, decoded)
return
end
local _ = log.debug() and log.debug("rpc.receive", decoded)
if type(decoded.method) == 'string' and decoded.id then
+ local err
-- Server Request
decoded.params = convert_NIL(decoded.params)
-- Schedule here so that the users functions don't trigger an error and
@@ -582,8 +552,6 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
on_error(client_errors.INVALID_SERVER_MESSAGE, decoded)
end
end
- -- TODO(ashkan) remove this once we have a Lua json_decode
- handle_body = schedule_wrap(handle_body)
local request_parser = coroutine.wrap(request_parser_loop)
request_parser()
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index e95f170427..fca956fb57 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -951,6 +951,11 @@ end
---@param width (number) window width (in character cells)
---@param height (number) window height (in character cells)
---@param opts (table, optional)
+--- - offset_x (number) offset to add to `col`
+--- - offset_y (number) offset to add to `row`
+--- - border (string or table) override `border`
+--- - focusable (string or table) override `focusable`
+--- - zindex (string or table) override `zindex`, defaults to 50
---@returns (table) Options
function M.make_floating_popup_options(width, height, opts)
validate {
@@ -975,7 +980,7 @@ function M.make_floating_popup_options(width, height, opts)
else
anchor = anchor..'S'
height = math.min(lines_above, height)
- row = -get_border_size(opts).height
+ row = 0
end
if vim.fn.wincol() + width + (opts.offset_x or 0) <= api.nvim_get_option('columns') then
@@ -1124,8 +1129,6 @@ end
--- - wrap_at character to wrap at for computing height
--- - max_width maximal width of floating window
--- - max_height maximal height of floating window
---- - pad_left number of columns to pad contents at left
---- - pad_right number of columns to pad contents at right
--- - pad_top number of lines to pad contents at top
--- - pad_bottom number of lines to pad contents at bottom
--- - separator insert separator after code block
@@ -1376,8 +1379,6 @@ end
--- - wrap_at character to wrap at for computing height when wrap is enabled
--- - max_width maximal width of floating window
--- - max_height maximal height of floating window
---- - pad_left number of columns to pad contents at left
---- - pad_right number of columns to pad contents at right
--- - pad_top number of lines to pad contents at top
--- - pad_bottom number of lines to pad contents at bottom
--- - focus_id if a popup with this id is opened, then focus it
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
new file mode 100644
index 0000000000..5eab20fc54
--- /dev/null
+++ b/runtime/lua/vim/ui.lua
@@ -0,0 +1,36 @@
+local M = {}
+
+--- Prompts the user to pick a single item from a collection of entries
+---
+---@param items table Arbitrary items
+---@param opts table Additional options
+--- - prompt (string|nil)
+--- Text of the prompt. Defaults to `Select one of:`
+--- - format_item (function item -> text)
+--- Function to format an
+--- individual item from `items`. Defaults to `tostring`.
+---@param on_choice function ((item|nil, idx|nil) -> ())
+--- Called once the user made a choice.
+--- `idx` is the 1-based index of `item` within `item`.
+--- `nil` if the user aborted the dialog.
+function M.select(items, opts, on_choice)
+ vim.validate {
+ items = { items, 'table', false },
+ on_choice = { on_choice, 'function', false },
+ }
+ opts = opts or {}
+ local choices = {opts.prompt or 'Select one of:'}
+ local format_item = opts.format_item or tostring
+ for i, item in pairs(items) do
+ table.insert(choices, string.format('%d: %s', i, format_item(item)))
+ end
+ local choice = vim.fn.inputlist(choices)
+ if choice < 1 or choice > #items then
+ on_choice(nil, nil)
+ else
+ on_choice(items[choice], choice)
+ end
+end
+
+
+return M
diff --git a/scripts/finddeclarations.pl b/scripts/finddeclarations.pl
deleted file mode 100755
index 1b1a57b9b7..0000000000
--- a/scripts/finddeclarations.pl
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-if ($ARGV[0] eq '--help') {
- print << "EOF";
-Usage:
-
- $0 definitions.c
-EOF
- exit;
-}
-
-my ($cfname, $sfname, $gfname, $cpp) = @ARGV;
-
-my $F;
-
-open $F, "<", $cfname;
-
-my $text = join "", <$F>;
-
-close $F;
-
-my $s = qr/(?>\s*)/aso;
-my $w = qr/(?>\w+)/aso;
-my $argname = qr/$w(?:\[(?>\w+)\])?/aso;
-my $type_regex = qr/(?:$w$s\**$s)+/aso;
-my $arg_regex = qr/(?:$type_regex$s$argname)/aso;
-
-while ($text =~ /
- (?<=\n) # Definition starts at the start of line
- $type_regex # Return type
- $s$w # Function name
- $s\($s
- (?:
- $arg_regex(?:$s,$s$arg_regex)*+
- ($s,$s\.\.\.)? # varargs function
- |void
- )?
- $s\)
- (?:$s FUNC_ATTR_$w(?:\((?>[^)]*)\))?)*+ # Optional attributes
- (?=$s;) # Ending semicolon
- /axsogp) {
- my $match = "${^MATCH}";
- my $s = "${^PREMATCH}";
- $s =~ s/[^\n]++//g;
- my $line = 1 + length $s;
- print "${cfname}:${line}: $match\n";
-}
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index 64ed8d61f6..36e01153f1 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -123,11 +123,13 @@ CONFIG = {
'vim.lua',
'shared.lua',
'uri.lua',
+ 'ui.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
os.path.join(base_dir, 'runtime/lua/vim/uri.lua'),
+ os.path.join(base_dir, 'runtime/lua/vim/ui.lua'),
]),
'file_patterns': '*.lua',
'fn_name_prefix': '',
@@ -141,6 +143,7 @@ CONFIG = {
# `shared` functions are exposed on the `vim` module.
'shared': 'vim',
'uri': 'vim',
+ 'ui': 'vim.ui',
},
'append_only': [
'shared.lua',
diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua
index 11ad8eb9ef..98f9da246c 100644
--- a/scripts/lintcommit.lua
+++ b/scripts/lintcommit.lua
@@ -91,7 +91,7 @@ local function validate_commit(commit_message)
-- Check that description doesn't end with a period
if vim.endswith(after_colon, ".") then
- return [[Description ends with a period (\".\").]]
+ return [[Description ends with a period (".").]]
end
-- Check that description has exactly one whitespace after colon, followed by
diff --git a/scripts/release.sh b/scripts/release.sh
index 4ec959d697..380503662d 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -80,8 +80,8 @@ _do_release_commit() {
_do_bump_commit() {
$__sed -i.bk 's/(NVIM_VERSION_PRERELEASE) ""/\1 "-dev"/' CMakeLists.txt
$__sed -i.bk 's/set\((NVIM_VERSION_PATCH) [[:digit:]]/set(\1 ?/' CMakeLists.txt
- rm CMakeLists.txt.bk
- rm runtime/nvim.appdata.xml.bk
+ rm -f CMakeLists.txt.bk
+ rm -f runtime/nvim.appdata.xml.bk
nvim +'/NVIM_VERSION' +1new +'exe "norm! iUpdate version numbers!!!"' \
-O CMakeLists.txt
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index f4b817dfff..d92480abb9 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -125,8 +125,12 @@ commit_message() {
}
find_git_remote() {
- git_remote=$(git remote -v \
- | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}')
+ local git_remote
+ if [[ "${1-}" == fork ]]; then
+ git_remote=$(git remote -v | awk '$2 !~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}')
+ else
+ git_remote=$(git remote -v | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}')
+ fi
if [[ -z "$git_remote" ]]; then
git_remote="origin"
fi
@@ -268,8 +272,8 @@ stage_patch() {
get_vimpatch "$1"
local try_apply="${2:-}"
- local git_remote
- git_remote="$(find_git_remote)"
+ local nvim_remote
+ nvim_remote="$(find_git_remote)"
local checked_out_branch
checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
@@ -277,16 +281,16 @@ stage_patch() {
msg_ok "Current branch '${checked_out_branch}' seems to be a vim-patch"
echo " branch; not creating a new branch."
else
- printf '\nFetching "%s/master".\n' "${git_remote}"
- output="$(git fetch "${git_remote}" master 2>&1)" &&
+ printf '\nFetching "%s/master".\n' "${nvim_remote}"
+ output="$(git fetch "${nvim_remote}" master 2>&1)" &&
msg_ok "${output}" ||
(msg_err "${output}"; false)
local nvim_branch="${BRANCH_PREFIX}${vim_version}"
echo
- echo "Creating new branch '${nvim_branch}' based on '${git_remote}/master'."
+ echo "Creating new branch '${nvim_branch}' based on '${nvim_remote}/master'."
cd "${NVIM_SOURCE_DIR}"
- output="$(git checkout -b "${nvim_branch}" "${git_remote}/master" 2>&1)" &&
+ output="$(git checkout -b "${nvim_branch}" "${nvim_remote}/master" 2>&1)" &&
msg_ok "${output}" ||
(msg_err "${output}"; false)
fi
@@ -362,13 +366,13 @@ submit_pr() {
exit 1
fi
- local git_remote
- git_remote="$(find_git_remote)"
+ local nvim_remote
+ nvim_remote="$(find_git_remote)"
local pr_body
- pr_body="$(git log --grep=vim-patch --reverse --format='#### %s%n%n%b%n' "${git_remote}"/master..HEAD)"
+ pr_body="$(git log --grep=vim-patch --reverse --format='#### %s%n%n%b%n' "${nvim_remote}"/master..HEAD)"
local patches
# Extract just the "vim-patch:X.Y.ZZZZ" or "vim-patch:sha" portion of each log
- patches=("$(git log --grep=vim-patch --reverse --format='%s' "${git_remote}"/master..HEAD | sed 's/: .*//')")
+ patches=("$(git log --grep=vim-patch --reverse --format='%s' "${nvim_remote}"/master..HEAD | sed 's/: .*//')")
# shellcheck disable=SC2206
patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
local pr_title="${patches[*]}" # Create space-separated string from array.
@@ -376,8 +380,19 @@ submit_pr() {
pr_title="$(printf 'vim-patch:%s' "${pr_title#,}")"
if [[ $push_first -ne 0 ]]; then
- echo "Pushing to 'origin/${checked_out_branch}'."
- output="$(git push origin "${checked_out_branch}" 2>&1)" &&
+ local push_remote
+ push_remote="$(git config --get branch."${checked_out_branch}".pushRemote || true)"
+ if [[ -z "$push_remote" ]]; then
+ push_remote="$(git config --get remote.pushDefault || true)"
+ if [[ -z "$push_remote" ]]; then
+ push_remote="$(git config --get branch."${checked_out_branch}".remote || true)"
+ if [[ -z "$push_remote" ]] || [[ "$push_remote" == "$nvim_remote" ]]; then
+ push_remote="$(find_git_remote fork)"
+ fi
+ fi
+ fi
+ echo "Pushing to '${push_remote}/${checked_out_branch}'."
+ output="$(git push "${push_remote}" "${checked_out_branch}" 2>&1)" &&
msg_ok "${output}" ||
(msg_err "${output}"; false)
diff --git a/src/cjson/fpconv.c b/src/cjson/fpconv.c
new file mode 100644
index 0000000000..b2f7a214c2
--- /dev/null
+++ b/src/cjson/fpconv.c
@@ -0,0 +1,211 @@
+/* fpconv - Floating point conversion routines
+ *
+ * Copyright (c) 2011-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
+ * with locale support will break when the decimal separator is a comma.
+ *
+ * fpconv_* will around these issues with a translation buffer if required.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "fpconv.h"
+
+/* Workaround for MSVC */
+#ifdef _MSC_VER
+#define inline __inline
+#define snprintf sprintf_s
+#endif
+
+/* Lua CJSON assumes the locale is the same for all threads within a
+ * process and doesn't change after initialisation.
+ *
+ * This avoids the need for per thread storage or expensive checks
+ * for call. */
+static char locale_decimal_point = '.';
+
+/* In theory multibyte decimal_points are possible, but
+ * Lua CJSON only supports UTF-8 and known locales only have
+ * single byte decimal points ([.,]).
+ *
+ * localconv() may not be thread safe (=>crash), and nl_langinfo() is
+ * not supported on some platforms. Use sprintf() instead - if the
+ * locale does change, at least Lua CJSON won't crash. */
+static void fpconv_update_locale(void)
+{
+ char buf[8];
+
+ snprintf(buf, sizeof(buf), "%g", 0.5);
+
+ /* Failing this test might imply the platform has a buggy dtoa
+ * implementation or wide characters */
+ if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
+ fprintf(stderr, "Error: wide characters found or printf() bug.");
+ abort();
+ }
+
+ locale_decimal_point = buf[1];
+}
+
+/* Check for a valid number character: [-+0-9a-yA-Y.]
+ * Eg: -0.6e+5, infinity, 0xF0.F0pF0
+ *
+ * Used to find the probable end of a number. It doesn't matter if
+ * invalid characters are counted - strtod() will find the valid
+ * number if it exists. The risk is that slightly more memory might
+ * be allocated before a parse error occurs. */
+static inline int valid_number_character(char ch)
+{
+ char lower_ch;
+
+ if ('0' <= ch && ch <= '9')
+ return 1;
+ if (ch == '-' || ch == '+' || ch == '.')
+ return 1;
+
+ /* Hex digits, exponent (e), base (p), "infinity",.. */
+ lower_ch = ch | 0x20;
+ if ('a' <= lower_ch && lower_ch <= 'y')
+ return 1;
+
+ return 0;
+}
+
+/* Calculate the size of the buffer required for a strtod locale
+ * conversion. */
+static int strtod_buffer_size(const char *s)
+{
+ const char *p = s;
+
+ while (valid_number_character(*p))
+ p++;
+
+ return p - s;
+}
+
+/* Similar to strtod(), but must be passed the current locale's decimal point
+ * character. Guaranteed to be called at the start of any valid number in a string */
+double fpconv_strtod(const char *nptr, char **endptr)
+{
+ char localbuf[FPCONV_G_FMT_BUFSIZE];
+ char *buf, *endbuf, *dp;
+ int buflen;
+ double value;
+
+ /* System strtod() is fine when decimal point is '.' */
+ if (locale_decimal_point == '.')
+ return strtod(nptr, endptr);
+
+ buflen = strtod_buffer_size(nptr);
+ if (!buflen) {
+ /* No valid characters found, standard strtod() return */
+ *endptr = (char *)nptr;
+ return 0;
+ }
+
+ /* Duplicate number into buffer */
+ if (buflen >= FPCONV_G_FMT_BUFSIZE) {
+ /* Handle unusually large numbers */
+ buf = malloc(buflen + 1);
+ if (!buf) {
+ fprintf(stderr, "Out of memory");
+ abort();
+ }
+ } else {
+ /* This is the common case.. */
+ buf = localbuf;
+ }
+ memcpy(buf, nptr, buflen);
+ buf[buflen] = 0;
+
+ /* Update decimal point character if found */
+ dp = strchr(buf, '.');
+ if (dp)
+ *dp = locale_decimal_point;
+
+ value = strtod(buf, &endbuf);
+ *endptr = (char *)&nptr[endbuf - buf];
+ if (buflen >= FPCONV_G_FMT_BUFSIZE)
+ free(buf);
+
+ return value;
+}
+
+/* "fmt" must point to a buffer of at least 6 characters */
+static void set_number_format(char *fmt, int precision)
+{
+ int d1, d2, i;
+
+ assert(1 <= precision && precision <= 16);
+
+ /* Create printf format (%.14g) from precision */
+ d1 = precision / 10;
+ d2 = precision % 10;
+ fmt[0] = '%';
+ fmt[1] = '.';
+ i = 2;
+ if (d1) {
+ fmt[i++] = '0' + d1;
+ }
+ fmt[i++] = '0' + d2;
+ fmt[i++] = 'g';
+ fmt[i] = 0;
+}
+
+/* Assumes there is always at least 32 characters available in the target buffer */
+int fpconv_g_fmt(char *str, double num, int precision)
+{
+ char buf[FPCONV_G_FMT_BUFSIZE];
+ char fmt[6];
+ int len;
+ char *b;
+
+ set_number_format(fmt, precision);
+
+ /* Pass through when decimal point character is dot. */
+ if (locale_decimal_point == '.')
+ return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num);
+
+ /* snprintf() to a buffer then translate for other decimal point characters */
+ len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num);
+
+ /* Copy into target location. Translate decimal point if required */
+ b = buf;
+ do {
+ *str++ = (*b == locale_decimal_point ? '.' : *b);
+ } while(*b++);
+
+ return len;
+}
+
+void fpconv_init()
+{
+ fpconv_update_locale();
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/fpconv.h b/src/cjson/fpconv.h
new file mode 100644
index 0000000000..6ac97808b6
--- /dev/null
+++ b/src/cjson/fpconv.h
@@ -0,0 +1,22 @@
+/* Lua CJSON floating point conversion routines */
+
+/* Buffer required to store the largest string representation of a double.
+ *
+ * Longest double printed with %.14g is 21 characters long:
+ * -1.7976931348623e+308 */
+# define FPCONV_G_FMT_BUFSIZE 32
+
+#ifdef USE_INTERNAL_FPCONV
+static inline void fpconv_init()
+{
+ /* Do nothing - not required */
+}
+#else
+extern void fpconv_init(void);
+#endif
+
+extern int fpconv_g_fmt(char*, double, int);
+extern double fpconv_strtod(const char*, char**);
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c
new file mode 100644
index 0000000000..92d07963bd
--- /dev/null
+++ b/src/cjson/lua_cjson.c
@@ -0,0 +1,1609 @@
+/* Lua CJSON - JSON support for Lua
+ *
+ * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Caveats:
+ * - JSON "null" values are represented as lightuserdata since Lua
+ * tables cannot contain "nil". Compare with cjson.null.
+ * - Invalid UTF-8 characters are not detected and will be passed
+ * untouched. If required, UTF-8 error checking should be done
+ * outside this library.
+ * - Javascript comments are not part of the JSON spec, and are not
+ * currently supported.
+ *
+ * Note: Decoding is slower than encoding. Lua spends significant
+ * time (30%) managing tables when parsing JSON since it is
+ * difficult to know object/array sizes ahead of time.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "nvim/lua/executor.h"
+
+#include "lua_cjson.h"
+#include "strbuf.h"
+#include "fpconv.h"
+
+#ifndef CJSON_MODNAME
+#define CJSON_MODNAME "cjson"
+#endif
+
+#ifndef CJSON_VERSION
+#define CJSON_VERSION "2.1.0.9"
+#endif
+
+#ifdef _MSC_VER
+#define snprintf sprintf_s
+
+#ifndef isnan
+#include <float.h>
+#define isnan(x) _isnan(x)
+#endif
+
+#endif
+
+/* Workaround for Solaris platforms missing isinf() */
+#if !defined(isinf) && (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF))
+#define isinf(x) (!isnan(x) && isnan((x) - (x)))
+#endif
+
+#define DEFAULT_SPARSE_CONVERT 0
+#define DEFAULT_SPARSE_RATIO 2
+#define DEFAULT_SPARSE_SAFE 10
+#define DEFAULT_ENCODE_MAX_DEPTH 1000
+#define DEFAULT_DECODE_MAX_DEPTH 1000
+#define DEFAULT_ENCODE_INVALID_NUMBERS 0
+#define DEFAULT_DECODE_INVALID_NUMBERS 1
+#define DEFAULT_ENCODE_KEEP_BUFFER 1
+#define DEFAULT_ENCODE_NUMBER_PRECISION 14
+#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 0
+#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
+#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
+
+#ifdef DISABLE_INVALID_NUMBERS
+#undef DEFAULT_DECODE_INVALID_NUMBERS
+#define DEFAULT_DECODE_INVALID_NUMBERS 0
+#endif
+
+#ifdef _MSC_VER
+/* Microsoft C compiler lacks strncasecmp and strcasecmp. */
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+#if LONG_MAX > ((1UL << 31) - 1)
+#define json_lightudata_mask(ludata) \
+ ((void *) ((uintptr_t) (ludata) & ((1UL << 47) - 1)))
+
+#else
+#define json_lightudata_mask(ludata) (ludata)
+#endif
+
+#if LUA_VERSION_NUM > 501
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+#endif
+
+static const char * const *json_empty_array;
+static const char * const *json_array;
+
+typedef enum {
+ T_OBJ_BEGIN,
+ T_OBJ_END,
+ T_ARR_BEGIN,
+ T_ARR_END,
+ T_STRING,
+ T_NUMBER,
+ T_BOOLEAN,
+ T_NULL,
+ T_COLON,
+ T_COMMA,
+ T_END,
+ T_WHITESPACE,
+ T_ERROR,
+ T_UNKNOWN
+} json_token_type_t;
+
+static const char *json_token_type_name[] = {
+ "T_OBJ_BEGIN",
+ "T_OBJ_END",
+ "T_ARR_BEGIN",
+ "T_ARR_END",
+ "T_STRING",
+ "T_NUMBER",
+ "T_BOOLEAN",
+ "T_NULL",
+ "T_COLON",
+ "T_COMMA",
+ "T_END",
+ "T_WHITESPACE",
+ "T_ERROR",
+ "T_UNKNOWN",
+ NULL
+};
+
+typedef struct {
+ json_token_type_t ch2token[256];
+ char escape2char[256]; /* Decoding */
+
+ /* encode_buf is only allocated and used when
+ * encode_keep_buffer is set */
+ strbuf_t encode_buf;
+
+ int encode_sparse_convert;
+ int encode_sparse_ratio;
+ int encode_sparse_safe;
+ int encode_max_depth;
+ int encode_invalid_numbers; /* 2 => Encode as "null" */
+ int encode_number_precision;
+ int encode_keep_buffer;
+ int encode_empty_table_as_object;
+ int encode_escape_forward_slash;
+
+ int decode_invalid_numbers;
+ int decode_max_depth;
+ int decode_array_with_array_mt;
+} json_config_t;
+
+typedef struct {
+ const char *data;
+ const char *ptr;
+ strbuf_t *tmp; /* Temporary storage for strings */
+ json_config_t *cfg;
+ int current_depth;
+} json_parse_t;
+
+typedef struct {
+ json_token_type_t type;
+ int index;
+ union {
+ const char *string;
+ double number;
+ int boolean;
+ } value;
+ int string_len;
+} json_token_t;
+
+static const char *char2escape[256] = {
+ "\\u0000", "\\u0001", "\\u0002", "\\u0003",
+ "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+ "\\b", "\\t", "\\n", "\\u000b",
+ "\\f", "\\r", "\\u000e", "\\u000f",
+ "\\u0010", "\\u0011", "\\u0012", "\\u0013",
+ "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+ "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+ "\\u001c", "\\u001d", "\\u001e", "\\u001f",
+ NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+/* ===== CONFIGURATION ===== */
+
+static json_config_t *json_fetch_config(lua_State *l)
+{
+ json_config_t *cfg;
+
+ cfg = lua_touserdata(l, lua_upvalueindex(1));
+ if (!cfg)
+ luaL_error(l, "BUG: Unable to fetch CJSON configuration");
+
+ return cfg;
+}
+
+/* Ensure the correct number of arguments have been provided.
+ * Pad with nil to allow other functions to simply check arg[i]
+ * to find whether an argument was provided */
+static json_config_t *json_arg_init(lua_State *l, int args)
+{
+ luaL_argcheck(l, lua_gettop(l) <= args, args + 1,
+ "found too many arguments");
+
+ while (lua_gettop(l) < args)
+ lua_pushnil(l);
+
+ return json_fetch_config(l);
+}
+
+/* Process integer options for configuration functions */
+static int json_integer_option(lua_State *l, int optindex, int *setting,
+ int min, int max)
+{
+ char errmsg[64];
+ int value;
+
+ if (!lua_isnil(l, optindex)) {
+ value = luaL_checkinteger(l, optindex);
+ snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max);
+ luaL_argcheck(l, min <= value && value <= max, 1, errmsg);
+ *setting = value;
+ }
+
+ lua_pushinteger(l, *setting);
+
+ return 1;
+}
+
+/* Process enumerated arguments for a configuration function */
+static int json_enum_option(lua_State *l, int optindex, int *setting,
+ const char **options, int bool_true)
+{
+ static const char *bool_options[] = { "off", "on", NULL };
+
+ if (!options) {
+ options = bool_options;
+ bool_true = 1;
+ }
+
+ if (!lua_isnil(l, optindex)) {
+ if (bool_true && lua_isboolean(l, optindex))
+ *setting = lua_toboolean(l, optindex) * bool_true;
+ else
+ *setting = luaL_checkoption(l, optindex, NULL, options);
+ }
+
+ if (bool_true && (*setting == 0 || *setting == bool_true))
+ lua_pushboolean(l, *setting);
+ else
+ lua_pushstring(l, options[*setting]);
+
+ return 1;
+}
+
+/* Configures handling of extremely sparse arrays:
+ * convert: Convert extremely sparse arrays into objects? Otherwise error.
+ * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio
+ * safe: Always use an array when the max index <= safe */
+static int json_cfg_encode_sparse_array(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 3);
+
+ json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1);
+ json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX);
+ json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX);
+
+ return 3;
+}
+
+/* Configures the maximum number of nested arrays/objects allowed when
+ * encoding */
+static int json_cfg_encode_max_depth(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX);
+}
+
+/* Configures the maximum number of nested arrays/objects allowed when
+ * encoding */
+static int json_cfg_decode_max_depth(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX);
+}
+
+/* Configures number precision when converting doubles to text */
+static int json_cfg_encode_number_precision(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 16);
+}
+
+/* Configures how to treat empty table when encode lua table */
+static int json_cfg_encode_empty_table_as_object(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_enum_option(l, 1, &cfg->encode_empty_table_as_object, NULL, 1);
+}
+
+/* Configures how to decode arrays */
+static int json_cfg_decode_array_with_array_mt(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ json_enum_option(l, 1, &cfg->decode_array_with_array_mt, NULL, 1);
+
+ return 1;
+}
+
+/* Configures JSON encoding buffer persistence */
+static int json_cfg_encode_keep_buffer(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+ int old_value;
+
+ old_value = cfg->encode_keep_buffer;
+
+ json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1);
+
+ /* Init / free the buffer if the setting has changed */
+ if (old_value ^ cfg->encode_keep_buffer) {
+ if (cfg->encode_keep_buffer)
+ strbuf_init(&cfg->encode_buf, 0);
+ else
+ strbuf_free(&cfg->encode_buf);
+ }
+
+ return 1;
+}
+
+#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV)
+void json_verify_invalid_number_setting(lua_State *l, int *setting)
+{
+ if (*setting == 1) {
+ *setting = 0;
+ luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported.");
+ }
+}
+#else
+#define json_verify_invalid_number_setting(l, s) do { } while(0)
+#endif
+
+static int json_cfg_encode_invalid_numbers(lua_State *l)
+{
+ static const char *options[] = { "off", "on", "null", NULL };
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1);
+
+ json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);
+
+ return 1;
+}
+
+static int json_cfg_decode_invalid_numbers(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1);
+
+ json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);
+
+ return 1;
+}
+
+static int json_cfg_encode_escape_forward_slash(lua_State *l)
+{
+ int ret;
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ ret = json_enum_option(l, 1, &cfg->encode_escape_forward_slash, NULL, 1);
+ if (cfg->encode_escape_forward_slash) {
+ char2escape['/'] = "\\/";
+ } else {
+ char2escape['/'] = NULL;
+ }
+ return ret;
+}
+
+static int json_destroy_config(lua_State *l)
+{
+ json_config_t *cfg;
+
+ cfg = lua_touserdata(l, 1);
+ if (cfg)
+ strbuf_free(&cfg->encode_buf);
+ cfg = NULL;
+
+ return 0;
+}
+
+static void json_create_config(lua_State *l)
+{
+ json_config_t *cfg;
+ int i;
+
+ cfg = lua_newuserdata(l, sizeof(*cfg));
+
+ /* Create GC method to clean up strbuf */
+ lua_newtable(l);
+ lua_pushcfunction(l, json_destroy_config);
+ lua_setfield(l, -2, "__gc");
+ lua_setmetatable(l, -2);
+
+ cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT;
+ cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO;
+ cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE;
+ cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH;
+ cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH;
+ cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS;
+ cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS;
+ cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER;
+ cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
+ cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT;
+ cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT;
+ cfg->encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH;
+
+#if DEFAULT_ENCODE_KEEP_BUFFER > 0
+ strbuf_init(&cfg->encode_buf, 0);
+#endif
+
+ /* Decoding init */
+
+ /* Tag all characters as an error */
+ for (i = 0; i < 256; i++)
+ cfg->ch2token[i] = T_ERROR;
+
+ /* Set tokens that require no further processing */
+ cfg->ch2token['{'] = T_OBJ_BEGIN;
+ cfg->ch2token['}'] = T_OBJ_END;
+ cfg->ch2token['['] = T_ARR_BEGIN;
+ cfg->ch2token[']'] = T_ARR_END;
+ cfg->ch2token[','] = T_COMMA;
+ cfg->ch2token[':'] = T_COLON;
+ cfg->ch2token['\0'] = T_END;
+ cfg->ch2token[' '] = T_WHITESPACE;
+ cfg->ch2token['\t'] = T_WHITESPACE;
+ cfg->ch2token['\n'] = T_WHITESPACE;
+ cfg->ch2token['\r'] = T_WHITESPACE;
+
+ /* Update characters that require further processing */
+ cfg->ch2token['f'] = T_UNKNOWN; /* false? */
+ cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */
+ cfg->ch2token['I'] = T_UNKNOWN;
+ cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */
+ cfg->ch2token['N'] = T_UNKNOWN;
+ cfg->ch2token['t'] = T_UNKNOWN; /* true? */
+ cfg->ch2token['"'] = T_UNKNOWN; /* string? */
+ cfg->ch2token['+'] = T_UNKNOWN; /* number? */
+ cfg->ch2token['-'] = T_UNKNOWN;
+ for (i = 0; i < 10; i++)
+ cfg->ch2token['0' + i] = T_UNKNOWN;
+
+ /* Lookup table for parsing escape characters */
+ for (i = 0; i < 256; i++)
+ cfg->escape2char[i] = 0; /* String error */
+ cfg->escape2char['"'] = '"';
+ cfg->escape2char['\\'] = '\\';
+ cfg->escape2char['/'] = '/';
+ cfg->escape2char['b'] = '\b';
+ cfg->escape2char['t'] = '\t';
+ cfg->escape2char['n'] = '\n';
+ cfg->escape2char['f'] = '\f';
+ cfg->escape2char['r'] = '\r';
+ cfg->escape2char['u'] = 'u'; /* Unicode parsing required */
+}
+
+/* ===== ENCODING ===== */
+
+static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex,
+ const char *reason)
+{
+ if (!cfg->encode_keep_buffer)
+ strbuf_free(json);
+ luaL_error(l, "Cannot serialise %s: %s",
+ lua_typename(l, lua_type(l, lindex)), reason);
+}
+
+/* json_append_string args:
+ * - lua_State
+ * - JSON strbuf
+ * - String (Lua stack index)
+ *
+ * Returns nothing. Doesn't remove string from Lua stack */
+static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
+{
+ const char *escstr;
+ unsigned i;
+ const char *str;
+ size_t len;
+
+ str = lua_tolstring(l, lindex, &len);
+
+ /* Worst case is len * 6 (all unicode escapes).
+ * This buffer is reused constantly for small strings
+ * If there are any excess pages, they won't be hit anyway.
+ * This gains ~5% speedup. */
+ strbuf_ensure_empty_length(json, len * 6 + 2);
+
+ strbuf_append_char_unsafe(json, '\"');
+ for (i = 0; i < len; i++) {
+ escstr = char2escape[(unsigned char)str[i]];
+ if (escstr)
+ strbuf_append_string(json, escstr);
+ else
+ strbuf_append_char_unsafe(json, str[i]);
+ }
+ strbuf_append_char_unsafe(json, '\"');
+}
+
+/* Find the size of the array on the top of the Lua stack
+ * -1 object (not a pure array)
+ * >=0 elements in array
+ */
+static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json)
+{
+ double k;
+ int max;
+ int items;
+
+ max = 0;
+ items = 0;
+
+ lua_pushnil(l);
+ /* table, startkey */
+ while (lua_next(l, -2) != 0) {
+ /* table, key, value */
+ if (lua_type(l, -2) == LUA_TNUMBER &&
+ (k = lua_tonumber(l, -2))) {
+ /* Integer >= 1 ? */
+ if (floor(k) == k && k >= 1) {
+ if (k > max)
+ max = k;
+ items++;
+ lua_pop(l, 1);
+ continue;
+ }
+ }
+
+ /* Must not be an array (non integer key) */
+ lua_pop(l, 2);
+ return -1;
+ }
+
+ /* Encode excessively sparse arrays as objects (if enabled) */
+ if (cfg->encode_sparse_ratio > 0 &&
+ max > items * cfg->encode_sparse_ratio &&
+ max > cfg->encode_sparse_safe) {
+ if (!cfg->encode_sparse_convert)
+ json_encode_exception(l, cfg, json, -1, "excessively sparse array");
+
+ return -1;
+ }
+
+ return max;
+}
+
+static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json)
+{
+ /* Ensure there are enough slots free to traverse a table (key,
+ * value) and push a string for a potential error message.
+ *
+ * Unlike "decode", the key and value are still on the stack when
+ * lua_checkstack() is called. Hence an extra slot for luaL_error()
+ * below is required just in case the next check to lua_checkstack()
+ * fails.
+ *
+ * While this won't cause a crash due to the EXTRA_STACK reserve
+ * slots, it would still be an improper use of the API. */
+ if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3))
+ return;
+
+ if (!cfg->encode_keep_buffer)
+ strbuf_free(json);
+
+ luaL_error(l, "Cannot serialise, excessive nesting (%d)",
+ current_depth);
+}
+
+static void json_append_data(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json);
+
+/* json_append_array args:
+ * - lua_State
+ * - JSON strbuf
+ * - Size of passwd Lua array (top of stack) */
+static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth,
+ strbuf_t *json, int array_length)
+{
+ int comma, i;
+
+ strbuf_append_char(json, '[');
+
+ comma = 0;
+ for (i = 1; i <= array_length; i++) {
+ if (comma)
+ strbuf_append_char(json, ',');
+ else
+ comma = 1;
+
+ lua_rawgeti(l, -1, i);
+ json_append_data(l, cfg, current_depth, json);
+ lua_pop(l, 1);
+ }
+
+ strbuf_append_char(json, ']');
+}
+
+static void json_append_number(lua_State *l, json_config_t *cfg,
+ strbuf_t *json, int lindex)
+{
+ double num = lua_tonumber(l, lindex);
+ int len;
+
+ if (cfg->encode_invalid_numbers == 0) {
+ /* Prevent encoding invalid numbers */
+ if (isinf(num) || isnan(num))
+ json_encode_exception(l, cfg, json, lindex,
+ "must not be NaN or Infinity");
+ } else if (cfg->encode_invalid_numbers == 1) {
+ /* Encode NaN/Infinity separately to ensure Javascript compatible
+ * values are used. */
+ if (isnan(num)) {
+ strbuf_append_mem(json, "NaN", 3);
+ return;
+ }
+ if (isinf(num)) {
+ if (num < 0)
+ strbuf_append_mem(json, "-Infinity", 9);
+ else
+ strbuf_append_mem(json, "Infinity", 8);
+ return;
+ }
+ } else {
+ /* Encode invalid numbers as "null" */
+ if (isinf(num) || isnan(num)) {
+ strbuf_append_mem(json, "null", 4);
+ return;
+ }
+ }
+
+ strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE);
+ len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision);
+ strbuf_extend_length(json, len);
+}
+
+static void json_append_object(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json)
+{
+ int comma, keytype;
+
+ /* Object */
+ strbuf_append_char(json, '{');
+
+ lua_pushnil(l);
+ /* table, startkey */
+ comma = 0;
+ while (lua_next(l, -2) != 0) {
+ if (comma)
+ strbuf_append_char(json, ',');
+ else
+ comma = 1;
+
+ /* table, key, value */
+ keytype = lua_type(l, -2);
+ if (keytype == LUA_TNUMBER) {
+ strbuf_append_char(json, '"');
+ json_append_number(l, cfg, json, -2);
+ strbuf_append_mem(json, "\":", 2);
+ } else if (keytype == LUA_TSTRING) {
+ json_append_string(l, json, -2);
+ strbuf_append_char(json, ':');
+ } else {
+ json_encode_exception(l, cfg, json, -2,
+ "table key must be a number or string");
+ /* never returns */
+ }
+
+ /* table, key, value */
+ json_append_data(l, cfg, current_depth, json);
+ lua_pop(l, 1);
+ /* table, key */
+ }
+
+ strbuf_append_char(json, '}');
+}
+
+/* Serialise Lua data into JSON string. */
+static void json_append_data(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json)
+{
+ int len;
+ int as_array = 0;
+ int as_empty_dict = 0;
+ int has_metatable;
+
+ switch (lua_type(l, -1)) {
+ case LUA_TSTRING:
+ json_append_string(l, json, -1);
+ break;
+ case LUA_TNUMBER:
+ json_append_number(l, cfg, json, -1);
+ break;
+ case LUA_TBOOLEAN:
+ if (lua_toboolean(l, -1))
+ strbuf_append_mem(json, "true", 4);
+ else
+ strbuf_append_mem(json, "false", 5);
+ break;
+ case LUA_TTABLE:
+ current_depth++;
+ json_check_encode_depth(l, cfg, current_depth, json);
+
+ has_metatable = lua_getmetatable(l, -1);
+
+ if (has_metatable) {
+
+ nlua_pushref(l, nlua_empty_dict_ref);
+ if (lua_rawequal(l, -2, -1)) {
+ as_empty_dict = true;
+ } else {
+ lua_pop(l, 1);
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ as_array = lua_rawequal(l, -1, -2);
+ }
+ lua_pop(l, 2);
+ }
+
+ if (as_array) {
+ len = lua_objlen(l, -1);
+ json_append_array(l, cfg, current_depth, json, len);
+ } else {
+ len = lua_array_length(l, cfg, json);
+
+ if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object && !as_empty_dict)) {
+ json_append_array(l, cfg, current_depth, json, len);
+ } else {
+ if (has_metatable) {
+ lua_getmetatable(l, -1);
+ lua_pushlightuserdata(l, json_lightudata_mask(
+ &json_empty_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ as_array = lua_rawequal(l, -1, -2);
+ lua_pop(l, 2); /* pop pointer + metatable */
+ if (as_array) {
+ json_append_array(l, cfg, current_depth, json, 0);
+ break;
+ }
+ }
+ json_append_object(l, cfg, current_depth, json);
+ }
+ }
+ break;
+ case LUA_TNIL:
+ strbuf_append_mem(json, "null", 4);
+ break;
+ case LUA_TLIGHTUSERDATA:
+ if (lua_touserdata(l, -1) == &json_array) {
+ json_append_array(l, cfg, current_depth, json, 0);
+ }
+ break;
+ case LUA_TUSERDATA:
+ nlua_pushref(l, nlua_nil_ref);
+ bool is_nil = lua_rawequal(l, -2, -1);
+ lua_pop(l, 1);
+ if (is_nil) {
+ strbuf_append_mem(json, "null", 4);
+ break;
+ } else {
+ FALLTHROUGH;
+ }
+ default:
+ /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD,
+ * and LUA_TLIGHTUSERDATA) cannot be serialised */
+ json_encode_exception(l, cfg, json, -1, "type not supported");
+ /* never returns */
+ }
+}
+
+static int json_encode(lua_State *l)
+{
+ json_config_t *cfg = json_fetch_config(l);
+ strbuf_t local_encode_buf;
+ strbuf_t *encode_buf;
+ char *json;
+ int len;
+
+ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+
+ if (!cfg->encode_keep_buffer) {
+ /* Use private buffer */
+ encode_buf = &local_encode_buf;
+ strbuf_init(encode_buf, 0);
+ } else {
+ /* Reuse existing buffer */
+ encode_buf = &cfg->encode_buf;
+ strbuf_reset(encode_buf);
+ }
+
+ json_append_data(l, cfg, 0, encode_buf);
+ json = strbuf_string(encode_buf, &len);
+
+ lua_pushlstring(l, json, len);
+
+ if (!cfg->encode_keep_buffer)
+ strbuf_free(encode_buf);
+
+ return 1;
+}
+
+/* ===== DECODING ===== */
+
+static void json_process_value(lua_State *l, json_parse_t *json,
+ json_token_t *token);
+
+static int hexdigit2int(char hex)
+{
+ if ('0' <= hex && hex <= '9')
+ return hex - '0';
+
+ /* Force lowercase */
+ hex |= 0x20;
+ if ('a' <= hex && hex <= 'f')
+ return 10 + hex - 'a';
+
+ return -1;
+}
+
+static int decode_hex4(const char *hex)
+{
+ int digit[4];
+ int i;
+
+ /* Convert ASCII hex digit to numeric digit
+ * Note: this returns an error for invalid hex digits, including
+ * NULL */
+ for (i = 0; i < 4; i++) {
+ digit[i] = hexdigit2int(hex[i]);
+ if (digit[i] < 0) {
+ return -1;
+ }
+ }
+
+ return (digit[0] << 12) +
+ (digit[1] << 8) +
+ (digit[2] << 4) +
+ digit[3];
+}
+
+/* Converts a Unicode codepoint to UTF-8.
+ * Returns UTF-8 string length, and up to 4 bytes in *utf8 */
+static int codepoint_to_utf8(char *utf8, int codepoint)
+{
+ /* 0xxxxxxx */
+ if (codepoint <= 0x7F) {
+ utf8[0] = codepoint;
+ return 1;
+ }
+
+ /* 110xxxxx 10xxxxxx */
+ if (codepoint <= 0x7FF) {
+ utf8[0] = (codepoint >> 6) | 0xC0;
+ utf8[1] = (codepoint & 0x3F) | 0x80;
+ return 2;
+ }
+
+ /* 1110xxxx 10xxxxxx 10xxxxxx */
+ if (codepoint <= 0xFFFF) {
+ utf8[0] = (codepoint >> 12) | 0xE0;
+ utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80;
+ utf8[2] = (codepoint & 0x3F) | 0x80;
+ return 3;
+ }
+
+ /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ if (codepoint <= 0x1FFFFF) {
+ utf8[0] = (codepoint >> 18) | 0xF0;
+ utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80;
+ utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80;
+ utf8[3] = (codepoint & 0x3F) | 0x80;
+ return 4;
+ }
+
+ return 0;
+}
+
+
+/* Called when index pointing to beginning of UTF-16 code escape: \uXXXX
+ * \u is guaranteed to exist, but the remaining hex characters may be
+ * missing.
+ * Translate to UTF-8 and append to temporary token string.
+ * Must advance index to the next character to be processed.
+ * Returns: 0 success
+ * -1 error
+ */
+static int json_append_unicode_escape(json_parse_t *json)
+{
+ char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */
+ int codepoint;
+ int surrogate_low;
+ int len;
+ int escape_len = 6;
+
+ /* Fetch UTF-16 code unit */
+ codepoint = decode_hex4(json->ptr + 2);
+ if (codepoint < 0)
+ return -1;
+
+ /* UTF-16 surrogate pairs take the following 2 byte form:
+ * 11011 x yyyyyyyyyy
+ * When x = 0: y is the high 10 bits of the codepoint
+ * x = 1: y is the low 10 bits of the codepoint
+ *
+ * Check for a surrogate pair (high or low) */
+ if ((codepoint & 0xF800) == 0xD800) {
+ /* Error if the 1st surrogate is not high */
+ if (codepoint & 0x400)
+ return -1;
+
+ /* Ensure the next code is a unicode escape */
+ if (*(json->ptr + escape_len) != '\\' ||
+ *(json->ptr + escape_len + 1) != 'u') {
+ return -1;
+ }
+
+ /* Fetch the next codepoint */
+ surrogate_low = decode_hex4(json->ptr + 2 + escape_len);
+ if (surrogate_low < 0)
+ return -1;
+
+ /* Error if the 2nd code is not a low surrogate */
+ if ((surrogate_low & 0xFC00) != 0xDC00)
+ return -1;
+
+ /* Calculate Unicode codepoint */
+ codepoint = (codepoint & 0x3FF) << 10;
+ surrogate_low &= 0x3FF;
+ codepoint = (codepoint | surrogate_low) + 0x10000;
+ escape_len = 12;
+ }
+
+ /* Convert codepoint to UTF-8 */
+ len = codepoint_to_utf8(utf8, codepoint);
+ if (!len)
+ return -1;
+
+ /* Append bytes and advance parse index */
+ strbuf_append_mem_unsafe(json->tmp, utf8, len);
+ json->ptr += escape_len;
+
+ return 0;
+}
+
+static void json_set_token_error(json_token_t *token, json_parse_t *json,
+ const char *errtype)
+{
+ token->type = T_ERROR;
+ token->index = json->ptr - json->data;
+ token->value.string = errtype;
+}
+
+static void json_next_string_token(json_parse_t *json, json_token_t *token)
+{
+ char *escape2char = json->cfg->escape2char;
+ char ch;
+
+ /* Caller must ensure a string is next */
+ assert(*json->ptr == '"');
+
+ /* Skip " */
+ json->ptr++;
+
+ /* json->tmp is the temporary strbuf used to accumulate the
+ * decoded string value.
+ * json->tmp is sized to handle JSON containing only a string value.
+ */
+ strbuf_reset(json->tmp);
+
+ while ((ch = *json->ptr) != '"') {
+ if (!ch) {
+ /* Premature end of the string */
+ json_set_token_error(token, json, "unexpected end of string");
+ return;
+ }
+
+ /* Handle escapes */
+ if (ch == '\\') {
+ /* Fetch escape character */
+ ch = *(json->ptr + 1);
+
+ /* Translate escape code and append to tmp string */
+ ch = escape2char[(unsigned char)ch];
+ if (ch == 'u') {
+ if (json_append_unicode_escape(json) == 0)
+ continue;
+
+ json_set_token_error(token, json,
+ "invalid unicode escape code");
+ return;
+ }
+ if (!ch) {
+ json_set_token_error(token, json, "invalid escape code");
+ return;
+ }
+
+ /* Skip '\' */
+ json->ptr++;
+ }
+ /* Append normal character or translated single character
+ * Unicode escapes are handled above */
+ strbuf_append_char_unsafe(json->tmp, ch);
+ json->ptr++;
+ }
+ json->ptr++; /* Eat final quote (") */
+
+ strbuf_ensure_null(json->tmp);
+
+ token->type = T_STRING;
+ token->value.string = strbuf_string(json->tmp, &token->string_len);
+}
+
+/* JSON numbers should take the following form:
+ * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)?
+ *
+ * json_next_number_token() uses strtod() which allows other forms:
+ * - numbers starting with '+'
+ * - NaN, -NaN, infinity, -infinity
+ * - hexadecimal numbers
+ * - numbers with leading zeros
+ *
+ * json_is_invalid_number() detects "numbers" which may pass strtod()'s
+ * error checking, but should not be allowed with strict JSON.
+ *
+ * json_is_invalid_number() may pass numbers which cause strtod()
+ * to generate an error.
+ */
+static int json_is_invalid_number(json_parse_t *json)
+{
+ const char *p = json->ptr;
+
+ /* Reject numbers starting with + */
+ if (*p == '+')
+ return 1;
+
+ /* Skip minus sign if it exists */
+ if (*p == '-')
+ p++;
+
+ /* Reject numbers starting with 0x, or leading zeros */
+ if (*p == '0') {
+ int ch2 = *(p + 1);
+
+ if ((ch2 | 0x20) == 'x' || /* Hex */
+ ('0' <= ch2 && ch2 <= '9')) /* Leading zero */
+ return 1;
+
+ return 0;
+ } else if (*p <= '9') {
+ return 0; /* Ordinary number */
+ }
+
+ /* Reject inf/nan */
+ if (!strncasecmp(p, "inf", 3))
+ return 1;
+ if (!strncasecmp(p, "nan", 3))
+ return 1;
+
+ /* Pass all other numbers which may still be invalid, but
+ * strtod() will catch them. */
+ return 0;
+}
+
+static void json_next_number_token(json_parse_t *json, json_token_t *token)
+{
+ char *endptr;
+
+ token->type = T_NUMBER;
+ token->value.number = fpconv_strtod(json->ptr, &endptr);
+ if (json->ptr == endptr)
+ json_set_token_error(token, json, "invalid number");
+ else
+ json->ptr = endptr; /* Skip the processed number */
+
+ return;
+}
+
+/* Fills in the token struct.
+ * T_STRING will return a pointer to the json_parse_t temporary string
+ * T_ERROR will leave the json->ptr pointer at the error.
+ */
+static void json_next_token(json_parse_t *json, json_token_t *token)
+{
+ const json_token_type_t *ch2token = json->cfg->ch2token;
+ int ch;
+
+ /* Eat whitespace. */
+ while (1) {
+ ch = (unsigned char)*(json->ptr);
+ token->type = ch2token[ch];
+ if (token->type != T_WHITESPACE)
+ break;
+ json->ptr++;
+ }
+
+ /* Store location of new token. Required when throwing errors
+ * for unexpected tokens (syntax errors). */
+ token->index = json->ptr - json->data;
+
+ /* Don't advance the pointer for an error or the end */
+ if (token->type == T_ERROR) {
+ json_set_token_error(token, json, "invalid token");
+ return;
+ }
+
+ if (token->type == T_END) {
+ return;
+ }
+
+ /* Found a known single character token, advance index and return */
+ if (token->type != T_UNKNOWN) {
+ json->ptr++;
+ return;
+ }
+
+ /* Process characters which triggered T_UNKNOWN
+ *
+ * Must use strncmp() to match the front of the JSON string.
+ * JSON identifier must be lowercase.
+ * When strict_numbers if disabled, either case is allowed for
+ * Infinity/NaN (since we are no longer following the spec..) */
+ if (ch == '"') {
+ json_next_string_token(json, token);
+ return;
+ } else if (ch == '-' || ('0' <= ch && ch <= '9')) {
+ if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) {
+ json_set_token_error(token, json, "invalid number");
+ return;
+ }
+ json_next_number_token(json, token);
+ return;
+ } else if (!strncmp(json->ptr, "true", 4)) {
+ token->type = T_BOOLEAN;
+ token->value.boolean = 1;
+ json->ptr += 4;
+ return;
+ } else if (!strncmp(json->ptr, "false", 5)) {
+ token->type = T_BOOLEAN;
+ token->value.boolean = 0;
+ json->ptr += 5;
+ return;
+ } else if (!strncmp(json->ptr, "null", 4)) {
+ token->type = T_NULL;
+ json->ptr += 4;
+ return;
+ } else if (json->cfg->decode_invalid_numbers &&
+ json_is_invalid_number(json)) {
+ /* When decode_invalid_numbers is enabled, only attempt to process
+ * numbers we know are invalid JSON (Inf, NaN, hex)
+ * This is required to generate an appropriate token error,
+ * otherwise all bad tokens will register as "invalid number"
+ */
+ json_next_number_token(json, token);
+ return;
+ }
+
+ /* Token starts with t/f/n but isn't recognised above. */
+ json_set_token_error(token, json, "invalid token");
+}
+
+/* This function does not return.
+ * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED.
+ * The only supported exception is the temporary parser string
+ * json->tmp struct.
+ * json and token should exist on the stack somewhere.
+ * luaL_error() will long_jmp and release the stack */
+static void json_throw_parse_error(lua_State *l, json_parse_t *json,
+ const char *exp, json_token_t *token)
+{
+ const char *found;
+
+ strbuf_free(json->tmp);
+
+ if (token->type == T_ERROR)
+ found = token->value.string;
+ else
+ found = json_token_type_name[token->type];
+
+ /* Note: token->index is 0 based, display starting from 1 */
+ luaL_error(l, "Expected %s but found %s at character %d",
+ exp, found, token->index + 1);
+}
+
+static inline void json_decode_ascend(json_parse_t *json)
+{
+ json->current_depth--;
+}
+
+static void json_decode_descend(lua_State *l, json_parse_t *json, int slots)
+{
+ json->current_depth++;
+
+ if (json->current_depth <= json->cfg->decode_max_depth &&
+ lua_checkstack(l, slots)) {
+ return;
+ }
+
+ strbuf_free(json->tmp);
+ luaL_error(l, "Found too many nested data structures (%d) at character %d",
+ json->current_depth, json->ptr - json->data);
+}
+
+static void json_parse_object_context(lua_State *l, json_parse_t *json)
+{
+ json_token_t token;
+
+ /* 3 slots required:
+ * .., table, key, value */
+ json_decode_descend(l, json, 3);
+
+ lua_newtable(l);
+
+ json_next_token(json, &token);
+
+ /* Handle empty objects */
+ if (token.type == T_OBJ_END) {
+ nlua_pushref(l, nlua_empty_dict_ref); \
+ lua_setmetatable(l, -2); \
+ json_decode_ascend(json);
+ return;
+ }
+
+ while (1) {
+ if (token.type != T_STRING)
+ json_throw_parse_error(l, json, "object key string", &token);
+
+ /* Push key */
+ lua_pushlstring(l, token.value.string, token.string_len);
+
+ json_next_token(json, &token);
+ if (token.type != T_COLON)
+ json_throw_parse_error(l, json, "colon", &token);
+
+ /* Fetch value */
+ json_next_token(json, &token);
+ json_process_value(l, json, &token);
+
+ /* Set key = value */
+ lua_rawset(l, -3);
+
+ json_next_token(json, &token);
+
+ if (token.type == T_OBJ_END) {
+ json_decode_ascend(json);
+ return;
+ }
+
+ if (token.type != T_COMMA)
+ json_throw_parse_error(l, json, "comma or object end", &token);
+
+ json_next_token(json, &token);
+ }
+}
+
+/* Handle the array context */
+static void json_parse_array_context(lua_State *l, json_parse_t *json)
+{
+ json_token_t token;
+ int i;
+
+ /* 2 slots required:
+ * .., table, value */
+ json_decode_descend(l, json, 2);
+
+ lua_newtable(l);
+
+ /* set array_mt on the table at the top of the stack */
+ if (json->cfg->decode_array_with_array_mt) {
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ lua_setmetatable(l, -2);
+ }
+
+ json_next_token(json, &token);
+
+ /* Handle empty arrays */
+ if (token.type == T_ARR_END) {
+ json_decode_ascend(json);
+ return;
+ }
+
+ for (i = 1; ; i++) {
+ json_process_value(l, json, &token);
+ lua_rawseti(l, -2, i); /* arr[i] = value */
+
+ json_next_token(json, &token);
+
+ if (token.type == T_ARR_END) {
+ json_decode_ascend(json);
+ return;
+ }
+
+ if (token.type != T_COMMA)
+ json_throw_parse_error(l, json, "comma or array end", &token);
+
+ json_next_token(json, &token);
+ }
+}
+
+/* Handle the "value" context */
+static void json_process_value(lua_State *l, json_parse_t *json,
+ json_token_t *token)
+{
+ switch (token->type) {
+ case T_STRING:
+ lua_pushlstring(l, token->value.string, token->string_len);
+ break;;
+ case T_NUMBER:
+ lua_pushnumber(l, token->value.number);
+ break;;
+ case T_BOOLEAN:
+ lua_pushboolean(l, token->value.boolean);
+ break;;
+ case T_OBJ_BEGIN:
+ json_parse_object_context(l, json);
+ break;;
+ case T_ARR_BEGIN:
+ json_parse_array_context(l, json);
+ break;;
+ case T_NULL:
+ nlua_pushref(l, nlua_nil_ref);
+ break;;
+ default:
+ json_throw_parse_error(l, json, "value", token);
+ }
+}
+
+static int json_decode(lua_State *l)
+{
+ json_parse_t json;
+ json_token_t token;
+ size_t json_len;
+
+ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+
+ json.cfg = json_fetch_config(l);
+ json.data = luaL_checklstring(l, 1, &json_len);
+ json.current_depth = 0;
+ json.ptr = json.data;
+
+ /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3)
+ *
+ * CJSON can support any simple data type, hence only the first
+ * character is guaranteed to be ASCII (at worst: '"'). This is
+ * still enough to detect whether the wrong encoding is in use. */
+ if (json_len >= 2 && (!json.data[0] || !json.data[1]))
+ luaL_error(l, "JSON parser does not support UTF-16 or UTF-32");
+
+ /* Ensure the temporary buffer can hold the entire string.
+ * This means we no longer need to do length checks since the decoded
+ * string must be smaller than the entire json string */
+ json.tmp = strbuf_new(json_len);
+
+ json_next_token(&json, &token);
+ json_process_value(l, &json, &token);
+
+ /* Ensure there is no more input left */
+ json_next_token(&json, &token);
+
+ if (token.type != T_END)
+ json_throw_parse_error(l, &json, "the end", &token);
+
+ strbuf_free(json.tmp);
+
+ return 1;
+}
+
+/* ===== INITIALISATION ===== */
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
+/* Compatibility for Lua 5.1 and older LuaJIT.
+ *
+ * compat_luaL_setfuncs() is used to create a module table where the functions
+ * have json_config_t as their first upvalue. Code borrowed from Lua 5.2
+ * source's luaL_setfuncs().
+ */
+static void compat_luaL_setfuncs(lua_State *l, const luaL_Reg *reg, int nup)
+{
+ int i;
+
+ luaL_checkstack(l, nup, "too many upvalues");
+ for (; reg->name != NULL; reg++) { /* fill the table with given functions */
+ for (i = 0; i < nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(l, -nup);
+ lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */
+ lua_setfield(l, -(nup + 2), reg->name);
+ }
+ lua_pop(l, nup); /* remove upvalues */
+}
+#else
+#define compat_luaL_setfuncs(L, reg, nup) luaL_setfuncs(L, reg, nup)
+#endif
+
+/* Call target function in protected mode with all supplied args.
+ * Assumes target function only returns a single non-nil value.
+ * Convert and return thrown errors as: nil, "error message" */
+static int json_protect_conversion(lua_State *l)
+{
+ int err;
+
+ /* Deliberately throw an error for invalid arguments */
+ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+
+ /* pcall() the function stored as upvalue(1) */
+ lua_pushvalue(l, lua_upvalueindex(1));
+ lua_insert(l, 1);
+ err = lua_pcall(l, 1, 1, 0);
+ if (!err)
+ return 1;
+
+ if (err == LUA_ERRRUN) {
+ lua_pushnil(l);
+ lua_insert(l, -2);
+ return 2;
+ }
+
+ /* Since we are not using a custom error handler, the only remaining
+ * errors are memory related */
+ return luaL_error(l, "Memory allocation error in CJSON protected call");
+}
+
+/* Return cjson module table */
+int lua_cjson_new(lua_State *l)
+{
+ luaL_Reg reg[] = {
+ { "encode", json_encode },
+ { "decode", json_decode },
+ { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object },
+ { "decode_array_with_array_mt", json_cfg_decode_array_with_array_mt },
+ { "encode_sparse_array", json_cfg_encode_sparse_array },
+ { "encode_max_depth", json_cfg_encode_max_depth },
+ { "decode_max_depth", json_cfg_decode_max_depth },
+ { "encode_number_precision", json_cfg_encode_number_precision },
+ { "encode_keep_buffer", json_cfg_encode_keep_buffer },
+ { "encode_invalid_numbers", json_cfg_encode_invalid_numbers },
+ { "decode_invalid_numbers", json_cfg_decode_invalid_numbers },
+ { "encode_escape_forward_slash", json_cfg_encode_escape_forward_slash },
+ { "new", lua_cjson_new },
+ { NULL, NULL }
+ };
+
+ /* Initialise number conversions */
+ fpconv_init();
+
+ /* Test if array metatables are in registry */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_empty_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ if (lua_isnil(l, -1)) {
+ /* Create array metatables.
+ *
+ * If multiple calls to lua_cjson_new() are made,
+ * this prevents overriding the tables at the given
+ * registry's index with a new one.
+ */
+ lua_pop(l, 1);
+
+ /* empty_array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_empty_array));
+ lua_newtable(l);
+ lua_rawset(l, LUA_REGISTRYINDEX);
+
+ /* array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_newtable(l);
+ lua_rawset(l, LUA_REGISTRYINDEX);
+ }
+
+ /* cjson module table */
+ lua_newtable(l);
+
+ /* Register functions with config data as upvalue */
+ json_create_config(l);
+ compat_luaL_setfuncs(l, reg, 1);
+
+ /* Set cjson.null */
+ nlua_pushref(l, nlua_nil_ref);
+ lua_setfield(l, -2, "null");
+
+ /* Set cjson.empty_array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_empty_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ lua_setfield(l, -2, "empty_array_mt");
+
+ /* Set cjson.array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ lua_setfield(l, -2, "array_mt");
+
+ /* Set cjson.empty_array */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_setfield(l, -2, "empty_array");
+
+ /* Set module name / version fields */
+ lua_pushliteral(l, CJSON_MODNAME);
+ lua_setfield(l, -2, "_NAME");
+ lua_pushliteral(l, CJSON_VERSION);
+ lua_setfield(l, -2, "_VERSION");
+
+ return 1;
+}
+
+/* Return cjson.safe module table */
+static int lua_cjson_safe_new(lua_State *l)
+{
+ const char *func[] = { "decode", "encode", NULL };
+ int i;
+
+ lua_cjson_new(l);
+
+ /* Fix new() method */
+ lua_pushcfunction(l, lua_cjson_safe_new);
+ lua_setfield(l, -2, "new");
+
+ for (i = 0; func[i]; i++) {
+ lua_getfield(l, -1, func[i]);
+ lua_pushcclosure(l, json_protect_conversion, 1);
+ lua_setfield(l, -2, func[i]);
+ }
+
+ return 1;
+}
+
+int luaopen_cjson(lua_State *l)
+{
+ lua_cjson_new(l);
+
+#ifdef ENABLE_CJSON_GLOBAL
+ /* Register a global "cjson" table. */
+ lua_pushvalue(l, -1);
+ lua_setglobal(l, CJSON_MODNAME);
+#endif
+
+ /* Return cjson table */
+ return 1;
+}
+
+int luaopen_cjson_safe(lua_State *l)
+{
+ lua_cjson_safe_new(l);
+
+ /* Return cjson.safe table */
+ return 1;
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/lua_cjson.h b/src/cjson/lua_cjson.h
new file mode 100644
index 0000000000..3f70b679be
--- /dev/null
+++ b/src/cjson/lua_cjson.h
@@ -0,0 +1,10 @@
+#ifndef CJSON_LUACJSON_H
+#define CJSON_LUACJSON_H
+
+#include "lua.h"
+
+int lua_cjson_new(lua_State *l);
+int luaopen_cjson(lua_State *l);
+int luaopen_cjson_safe(lua_State *l);
+
+#endif // CJSON_LUACJSON_H
diff --git a/src/cjson/strbuf.c b/src/cjson/strbuf.c
new file mode 100644
index 0000000000..f0f7f4b9a3
--- /dev/null
+++ b/src/cjson/strbuf.c
@@ -0,0 +1,251 @@
+/* strbuf - String buffer routines
+ *
+ * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "strbuf.h"
+
+static void die(const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ vfprintf(stderr, fmt, arg);
+ va_end(arg);
+ fprintf(stderr, "\n");
+
+ exit(-1);
+}
+
+void strbuf_init(strbuf_t *s, int len)
+{
+ int size;
+
+ if (len <= 0)
+ size = STRBUF_DEFAULT_SIZE;
+ else
+ size = len + 1; /* \0 terminator */
+
+ s->buf = NULL;
+ s->size = size;
+ s->length = 0;
+ s->increment = STRBUF_DEFAULT_INCREMENT;
+ s->dynamic = 0;
+ s->reallocs = 0;
+ s->debug = 0;
+
+ s->buf = malloc(size);
+ if (!s->buf)
+ die("Out of memory");
+
+ strbuf_ensure_null(s);
+}
+
+strbuf_t *strbuf_new(int len)
+{
+ strbuf_t *s;
+
+ s = malloc(sizeof(strbuf_t));
+ if (!s)
+ die("Out of memory");
+
+ strbuf_init(s, len);
+
+ /* Dynamic strbuf allocation / deallocation */
+ s->dynamic = 1;
+
+ return s;
+}
+
+void strbuf_set_increment(strbuf_t *s, int increment)
+{
+ /* Increment > 0: Linear buffer growth rate
+ * Increment < -1: Exponential buffer growth rate */
+ if (increment == 0 || increment == -1)
+ die("BUG: Invalid string increment");
+
+ s->increment = increment;
+}
+
+static inline void debug_stats(strbuf_t *s)
+{
+ if (s->debug) {
+ fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
+ (long)s, s->reallocs, s->length, s->size);
+ }
+}
+
+/* If strbuf_t has not been dynamically allocated, strbuf_free() can
+ * be called any number of times strbuf_init() */
+void strbuf_free(strbuf_t *s)
+{
+ debug_stats(s);
+
+ if (s->buf) {
+ free(s->buf);
+ s->buf = NULL;
+ }
+ if (s->dynamic)
+ free(s);
+}
+
+char *strbuf_free_to_string(strbuf_t *s, int *len)
+{
+ char *buf;
+
+ debug_stats(s);
+
+ strbuf_ensure_null(s);
+
+ buf = s->buf;
+ if (len)
+ *len = s->length;
+
+ if (s->dynamic)
+ free(s);
+
+ return buf;
+}
+
+static int calculate_new_size(strbuf_t *s, int len)
+{
+ int reqsize, newsize;
+
+ if (len <= 0)
+ die("BUG: Invalid strbuf length requested");
+
+ /* Ensure there is room for optional NULL termination */
+ reqsize = len + 1;
+
+ /* If the user has requested to shrink the buffer, do it exactly */
+ if (s->size > reqsize)
+ return reqsize;
+
+ newsize = s->size;
+ if (s->increment < 0) {
+ /* Exponential sizing */
+ while (newsize < reqsize)
+ newsize *= -s->increment;
+ } else {
+ /* Linear sizing */
+ newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
+ }
+
+ return newsize;
+}
+
+
+/* Ensure strbuf can handle a string length bytes long (ignoring NULL
+ * optional termination). */
+void strbuf_resize(strbuf_t *s, int len)
+{
+ int newsize;
+
+ newsize = calculate_new_size(s, len);
+
+ if (s->debug > 1) {
+ fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
+ (long)s, s->size, newsize);
+ }
+
+ s->size = newsize;
+ s->buf = realloc(s->buf, s->size);
+ if (!s->buf)
+ die("Out of memory");
+ s->reallocs++;
+}
+
+void strbuf_append_string(strbuf_t *s, const char *str)
+{
+ int space, i;
+
+ space = strbuf_empty_length(s);
+
+ for (i = 0; str[i]; i++) {
+ if (space < 1) {
+ strbuf_resize(s, s->length + 1);
+ space = strbuf_empty_length(s);
+ }
+
+ s->buf[s->length] = str[i];
+ s->length++;
+ space--;
+ }
+}
+
+/* strbuf_append_fmt() should only be used when an upper bound
+ * is known for the output string. */
+void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
+{
+ va_list arg;
+ int fmt_len;
+
+ strbuf_ensure_empty_length(s, len);
+
+ va_start(arg, fmt);
+ fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
+ va_end(arg);
+
+ if (fmt_len < 0)
+ die("BUG: Unable to convert number"); /* This should never happen.. */
+
+ s->length += fmt_len;
+}
+
+/* strbuf_append_fmt_retry() can be used when the there is no known
+ * upper bound for the output string. */
+void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
+{
+ va_list arg;
+ int fmt_len, try;
+ int empty_len;
+
+ /* If the first attempt to append fails, resize the buffer appropriately
+ * and try again */
+ for (try = 0; ; try++) {
+ va_start(arg, fmt);
+ /* Append the new formatted string */
+ /* fmt_len is the length of the string required, excluding the
+ * trailing NULL */
+ empty_len = strbuf_empty_length(s);
+ /* Add 1 since there is also space to store the terminating NULL. */
+ fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
+ va_end(arg);
+
+ if (fmt_len <= empty_len)
+ break; /* SUCCESS */
+ if (try > 0)
+ die("BUG: length of formatted string changed");
+
+ strbuf_resize(s, s->length + fmt_len);
+ }
+
+ s->length += fmt_len;
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/strbuf.h b/src/cjson/strbuf.h
new file mode 100644
index 0000000000..5df0b7bea3
--- /dev/null
+++ b/src/cjson/strbuf.h
@@ -0,0 +1,159 @@
+/* strbuf - String buffer routines
+ *
+ * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* Workaround for MSVC */
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
+/* Size: Total bytes allocated to *buf
+ * Length: String length, excluding optional NULL terminator.
+ * Increment: Allocation increments when resizing the string buffer.
+ * Dynamic: True if created via strbuf_new()
+ */
+
+typedef struct {
+ char *buf;
+ int size;
+ int length;
+ int increment;
+ int dynamic;
+ int reallocs;
+ int debug;
+} strbuf_t;
+
+#ifndef STRBUF_DEFAULT_SIZE
+#define STRBUF_DEFAULT_SIZE 1023
+#endif
+#ifndef STRBUF_DEFAULT_INCREMENT
+#define STRBUF_DEFAULT_INCREMENT -2
+#endif
+
+/* Initialise */
+extern strbuf_t *strbuf_new(int len);
+extern void strbuf_init(strbuf_t *s, int len);
+extern void strbuf_set_increment(strbuf_t *s, int increment);
+
+/* Release */
+extern void strbuf_free(strbuf_t *s);
+extern char *strbuf_free_to_string(strbuf_t *s, int *len);
+
+/* Management */
+extern void strbuf_resize(strbuf_t *s, int len);
+static int strbuf_empty_length(strbuf_t *s);
+static int strbuf_length(strbuf_t *s);
+static char *strbuf_string(strbuf_t *s, int *len);
+static void strbuf_ensure_empty_length(strbuf_t *s, int len);
+static char *strbuf_empty_ptr(strbuf_t *s);
+static void strbuf_extend_length(strbuf_t *s, int len);
+
+/* Update */
+extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
+extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
+static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
+extern void strbuf_append_string(strbuf_t *s, const char *str);
+static void strbuf_append_char(strbuf_t *s, const char c);
+static void strbuf_ensure_null(strbuf_t *s);
+
+/* Reset string for before use */
+static inline void strbuf_reset(strbuf_t *s)
+{
+ s->length = 0;
+}
+
+static inline int strbuf_allocated(strbuf_t *s)
+{
+ return s->buf != NULL;
+}
+
+/* Return bytes remaining in the string buffer
+ * Ensure there is space for a NULL terminator. */
+static inline int strbuf_empty_length(strbuf_t *s)
+{
+ return s->size - s->length - 1;
+}
+
+static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
+{
+ if (len > strbuf_empty_length(s))
+ strbuf_resize(s, s->length + len);
+}
+
+static inline char *strbuf_empty_ptr(strbuf_t *s)
+{
+ return s->buf + s->length;
+}
+
+static inline void strbuf_extend_length(strbuf_t *s, int len)
+{
+ s->length += len;
+}
+
+static inline int strbuf_length(strbuf_t *s)
+{
+ return s->length;
+}
+
+static inline void strbuf_append_char(strbuf_t *s, const char c)
+{
+ strbuf_ensure_empty_length(s, 1);
+ s->buf[s->length++] = c;
+}
+
+static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
+{
+ s->buf[s->length++] = c;
+}
+
+static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
+{
+ strbuf_ensure_empty_length(s, len);
+ memcpy(s->buf + s->length, c, len);
+ s->length += len;
+}
+
+static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
+{
+ memcpy(s->buf + s->length, c, len);
+ s->length += len;
+}
+
+static inline void strbuf_ensure_null(strbuf_t *s)
+{
+ s->buf[s->length] = 0;
+}
+
+static inline char *strbuf_string(strbuf_t *s, int *len)
+{
+ if (len)
+ *len = s->length;
+
+ return s->buf;
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/clint.py b/src/clint.py
index e7d76366b0..4b7bf002e6 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -2544,6 +2544,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
r'(?<!\bPMap)'
r'(?<!\bArrayOf)'
r'(?<!\bDictionaryOf)'
+ r'(?<!\bDict)'
r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)'
r' +'
r'-?(?:\*+|&)?(?:\w+|\+\+|--|\()', cast_line)
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 331ab16dd7..9c6eafa2df 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -27,6 +27,7 @@ set(BINARY_LIB_DIR ${PROJECT_BINARY_DIR}/lib/nvim/)
set(API_DISPATCH_GENERATOR ${GENERATOR_DIR}/gen_api_dispatch.lua)
set(API_UI_EVENTS_GENERATOR ${GENERATOR_DIR}/gen_api_ui_events.lua)
set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua)
+set(GENERATOR_HASHY ${GENERATOR_DIR}/hashy.lua)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.c)
@@ -42,12 +43,15 @@ set(GENERATED_UI_EVENTS_METADATA ${GENERATED_DIR}/api/private/ui_events_metadata
set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h)
set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h)
set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h)
+set(GENERATED_KEYSETS ${GENERATED_DIR}/keysets.generated.h)
+set(GENERATED_KEYSETS_DEFS ${GENERATED_DIR}/keysets_defs.generated.h)
set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h)
set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h)
set(GENERATED_OPTIONS ${GENERATED_DIR}/options.generated.h)
set(EX_CMDS_GENERATOR ${GENERATOR_DIR}/gen_ex_cmds.lua)
set(FUNCS_GENERATOR ${GENERATOR_DIR}/gen_eval.lua)
set(EVENTS_GENERATOR ${GENERATOR_DIR}/gen_events.lua)
+set(KEYSETS_GENERATOR ${GENERATOR_DIR}/gen_keysets.lua)
set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua)
set(UNICODE_TABLES_GENERATOR ${GENERATOR_DIR}/gen_unicode_tables.lua)
set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/unicode)
@@ -87,8 +91,8 @@ file(MAKE_DIRECTORY ${LINT_SUPPRESSES_ROOT}/src)
file(GLOB NVIM_SOURCES *.c)
file(GLOB NVIM_HEADERS *.h)
-file(GLOB EXTERNAL_SOURCES ../xdiff/*.c ../mpack/*.c)
-file(GLOB EXTERNAL_HEADERS ../xdiff/*.h ../mpack/*.h)
+file(GLOB EXTERNAL_SOURCES ../xdiff/*.c ../mpack/*.c ../cjson/*.c)
+file(GLOB EXTERNAL_HEADERS ../xdiff/*.h ../mpack/*.h ../cjson/*.h)
foreach(subdir
os
@@ -171,7 +175,7 @@ foreach(sfile ${CONV_SOURCES})
message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)")
endif()
endforeach()
-# xdiff, mpack: inlined external project, we don't maintain it. #9306
+# xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306
list(APPEND CONV_SOURCES ${EXTERNAL_SOURCES})
if(NOT MSVC)
@@ -261,6 +265,7 @@ foreach(sfile ${NVIM_SOURCES}
"${GENERATED_UI_EVENTS_CALL}"
"${GENERATED_UI_EVENTS_REMOTE}"
"${GENERATED_UI_EVENTS_BRIDGE}"
+ "${GENERATED_KEYSETS}"
)
get_filename_component(full_d ${sfile} PATH)
file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}")
@@ -364,12 +369,14 @@ add_custom_command(
list(APPEND NVIM_GENERATED_FOR_HEADERS
"${GENERATED_EX_CMDS_ENUM}"
"${GENERATED_EVENTS_ENUM}"
+ "${GENERATED_KEYSETS_DEFS}"
)
list(APPEND NVIM_GENERATED_FOR_SOURCES
"${GENERATED_API_DISPATCH}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_NAMES_MAP}"
+ "${GENERATED_KEYSETS}"
"${GENERATED_OPTIONS}"
"${GENERATED_UNICODE_TABLES}"
"${VIM_MODULE_FILE}"
@@ -404,6 +411,12 @@ add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
)
+add_custom_command(OUTPUT ${GENERATED_KEYSETS} ${GENERATED_KEYSETS_DEFS}
+ COMMAND ${LUA_PRG} ${KEYSETS_GENERATOR}
+ ${CMAKE_CURRENT_LIST_DIR} ${LUA_SHARED_MODULE_SOURCE} ${GENERATED_KEYSETS} ${GENERATED_KEYSETS_DEFS}
+ DEPENDS ${KEYSETS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/api/keysets.lua ${GENERATOR_HASHY}
+)
+
add_custom_command(OUTPUT ${GENERATED_OPTIONS}
COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR}
${CMAKE_CURRENT_LIST_DIR} ${GENERATED_OPTIONS}
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 8973f8fef6..34d7f6e32d 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -858,7 +858,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
/// @see |nvim_set_keymap()|
///
/// @param buffer Buffer handle, or 0 for current buffer
-void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, Dictionary opts,
+void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, Dict(keymap) *opts,
Error *err)
FUNC_API_SINCE(6)
{
@@ -874,8 +874,7 @@ void nvim_buf_del_keymap(Buffer buffer, String mode, String lhs, Error *err)
FUNC_API_SINCE(6)
{
String rhs = { .data = "", .size = 0 };
- Dictionary opts = ARRAY_DICT_INIT;
- modify_keymap(buffer, true, mode, lhs, rhs, opts, err);
+ modify_keymap(buffer, true, mode, lhs, rhs, NULL, err);
}
/// Gets a map of buffer-local |user-commands|.
@@ -885,22 +884,13 @@ void nvim_buf_del_keymap(Buffer buffer, String mode, String lhs, Error *err)
/// @param[out] err Error details, if any.
///
/// @returns Map of maps describing commands.
-Dictionary nvim_buf_get_commands(Buffer buffer, Dictionary opts, Error *err)
+Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error *err)
FUNC_API_SINCE(4)
{
bool global = (buffer == -1);
- bool builtin = false;
-
- for (size_t i = 0; i < opts.size; i++) {
- String k = opts.items[i].key;
- Object v = opts.items[i].value;
- if (!strequal("builtin", k.data)) {
- api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
- return (Dictionary)ARRAY_DICT_INIT;
- }
- if (strequal("builtin", k.data)) {
- builtin = v.data.boolean;
- }
+ bool builtin = api_object_to_bool(opts->builtin, "builtin", false, err);
+ if (ERROR_SET(err)) {
+ return (Dictionary)ARRAY_DICT_INIT;
}
if (global) {
@@ -1415,6 +1405,10 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// - end_col : ending col of the mark, 0-based exclusive.
/// - hl_group : name of the highlight group used to highlight
/// this mark.
+/// - hl_eol : when true, for a multiline highlight covering the
+/// EOL of a line, continue the highlight for the rest
+/// of the screen line (just like for diff and
+/// cursorline highlight).
/// - virt_text : virtual text to link to this mark.
/// A list of [text, highlight] tuples, each representing a
/// text chunk with specified highlight. `highlight` element
@@ -1442,10 +1436,28 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// default
/// - "combine": combine with background text color
/// - "blend": blend with background text color.
-/// - hl_eol : when true, for a multiline highlight covering the
-/// EOL of a line, continue the highlight for the rest
-/// of the screen line (just like for diff and
-/// cursorline highlight).
+///
+/// - virt_lines : virtual lines to add next to this mark
+/// This should be an array over lines, where each line in
+/// turn is an array over [text, highlight] tuples. In
+/// general, buffer and window options do not affect the
+/// display of the text. In particular 'wrap'
+/// and 'linebreak' options do not take effect, so
+/// the number of extra screen lines will always match
+/// the size of the array. However the 'tabstop' buffer
+/// option is still used for hard tabs. By default lines are
+/// placed below the buffer line containing the mark.
+///
+/// Note: currently virtual lines are limited to one block
+/// per buffer. Thus setting a new mark disables any previous
+/// `virt_lines` decoration. However plugins should not rely
+/// on this behaviour, as this limitation is planned to be
+/// removed.
+///
+/// - virt_lines_above: place virtual lines above instead.
+/// - virt_lines_leftcol: Place extmarks in the leftmost
+/// column of the window, bypassing
+/// sign and number columns.
///
/// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current
@@ -1463,7 +1475,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col,
- Dictionary opts, Error *err)
+ Dict(set_extmark) *opts, Error *err)
FUNC_API_SINCE(7)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1476,177 +1488,174 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
return 0;
}
- bool ephemeral = false;
uint64_t id = 0;
+ if (opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0) {
+ id = (uint64_t)opts->id.data.integer;
+ } else if (HAS_KEY(opts->id)) {
+ api_set_error(err, kErrorTypeValidation, "id is not a positive integer");
+ goto error;
+ }
+
int line2 = -1;
- Decoration decor = DECORATION_INIT;
+ if (opts->end_line.type == kObjectTypeInteger) {
+ Integer val = opts->end_line.data.integer;
+ if (val < 0 || val > buf->b_ml.ml_line_count) {
+ api_set_error(err, kErrorTypeValidation, "end_line value outside range");
+ goto error;
+ } else {
+ line2 = (int)val;
+ }
+ } else if (HAS_KEY(opts->end_line)) {
+ api_set_error(err, kErrorTypeValidation, "end_line is not an integer");
+ goto error;
+ }
+
colnr_T col2 = -1;
+ if (opts->end_col.type == kObjectTypeInteger) {
+ Integer val = opts->end_col.data.integer;
+ if (val < 0 || val > MAXCOL) {
+ api_set_error(err, kErrorTypeValidation, "end_col value outside range");
+ goto error;
+ } else {
+ col2 = (int)val;
+ }
+ } else if (HAS_KEY(opts->end_col)) {
+ api_set_error(err, kErrorTypeValidation, "end_col is not an integer");
+ goto error;
+ }
- bool right_gravity = true;
- bool end_right_gravity = false;
- bool end_gravity_set = false;
+ Decoration decor = DECORATION_INIT;
- for (size_t i = 0; i < opts.size; i++) {
- String k = opts.items[i].key;
- Object *v = &opts.items[i].value;
- if (strequal("id", k.data)) {
- if (v->type != kObjectTypeInteger || v->data.integer <= 0) {
- api_set_error(err, kErrorTypeValidation,
- "id is not a positive integer");
- goto error;
- }
+ if (HAS_KEY(opts->hl_group)) {
+ decor.hl_id = object_to_hl_id(opts->hl_group, "hl_group", err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ }
- id = (uint64_t)v->data.integer;
- } else if (strequal("end_line", k.data)) {
- if (v->type != kObjectTypeInteger) {
- api_set_error(err, kErrorTypeValidation,
- "end_line is not an integer");
- goto error;
- }
- if (v->data.integer < 0 || v->data.integer > buf->b_ml.ml_line_count) {
- api_set_error(err, kErrorTypeValidation,
- "end_line value outside range");
- goto error;
- }
+ if (opts->virt_text.type == kObjectTypeArray) {
+ decor.virt_text = parse_virt_text(opts->virt_text.data.array, err,
+ &decor.virt_text_width);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ } else if (HAS_KEY(opts->virt_text)) {
+ api_set_error(err, kErrorTypeValidation, "virt_text is not an Array");
+ goto error;
+ }
+
+ if (opts->virt_text_pos.type == kObjectTypeString) {
+ String str = opts->virt_text_pos.data.string;
+ if (strequal("eol", str.data)) {
+ decor.virt_text_pos = kVTEndOfLine;
+ } else if (strequal("overlay", str.data)) {
+ decor.virt_text_pos = kVTOverlay;
+ } else if (strequal("right_align", str.data)) {
+ decor.virt_text_pos = kVTRightAlign;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "virt_text_pos: invalid value");
+ goto error;
+ }
+ } else if (HAS_KEY(opts->virt_text_pos)) {
+ api_set_error(err, kErrorTypeValidation, "virt_text_pos is not a String");
+ goto error;
+ }
- line2 = (int)v->data.integer;
- } else if (strequal("end_col", k.data)) {
- if (v->type != kObjectTypeInteger) {
- api_set_error(err, kErrorTypeValidation,
- "end_col is not an integer");
- goto error;
- }
- if (v->data.integer < 0 || v->data.integer > MAXCOL) {
- api_set_error(err, kErrorTypeValidation,
- "end_col value outside range");
- goto error;
- }
+ if (opts->virt_text_win_col.type == kObjectTypeInteger) {
+ decor.col = (int)opts->virt_text_win_col.data.integer;
+ decor.virt_text_pos = kVTWinCol;
+ } else if (HAS_KEY(opts->virt_text_win_col)) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_win_col is not a Number of the correct size");
+ goto error;
+ }
- col2 = (colnr_T)v->data.integer;
- } else if (strequal("hl_group", k.data)) {
- String hl_group;
- switch (v->type) {
- case kObjectTypeString:
- hl_group = v->data.string;
- decor.hl_id = syn_check_group((char_u *)(hl_group.data),
- (int)hl_group.size);
- break;
- case kObjectTypeInteger:
- decor.hl_id = (int)v->data.integer;
- break;
- default:
- api_set_error(err, kErrorTypeValidation,
- "hl_group is not valid.");
- goto error;
- }
- } else if (strequal("virt_text", k.data)) {
- if (v->type != kObjectTypeArray) {
- api_set_error(err, kErrorTypeValidation,
- "virt_text is not an Array");
- goto error;
- }
- decor.virt_text = parse_virt_text(v->data.array, err,
- &decor.virt_text_width);
- if (ERROR_SET(err)) {
- goto error;
- }
- } else if (strequal("virt_text_pos", k.data)) {
- if (v->type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation,
- "virt_text_pos is not a String");
- goto error;
- }
- String str = v->data.string;
- if (strequal("eol", str.data)) {
- decor.virt_text_pos = kVTEndOfLine;
- } else if (strequal("overlay", str.data)) {
- decor.virt_text_pos = kVTOverlay;
- } else if (strequal("right_align", str.data)) {
- decor.virt_text_pos = kVTRightAlign;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "virt_text_pos: invalid value");
- goto error;
- }
- } else if (strequal("virt_text_win_col", k.data)) {
- if (v->type != kObjectTypeInteger) {
- api_set_error(err, kErrorTypeValidation,
- "virt_text_win_col is not a Number of the correct size");
- goto error;
- }
+#define OPTION_TO_BOOL(target, name, val) \
+ target = api_object_to_bool(opts-> name, #name, val, err); \
+ if (ERROR_SET(err)) { \
+ goto error; \
+ }
- decor.col = (int)v->data.integer;
- decor.virt_text_pos = kVTWinCol;
- } else if (strequal("virt_text_hide", k.data)) {
- decor.virt_text_hide = api_object_to_bool(*v,
- "virt_text_hide", false, err);
- if (ERROR_SET(err)) {
- goto error;
- }
- } else if (strequal("hl_eol", k.data)) {
- decor.hl_eol = api_object_to_bool(*v, "hl_eol", false, err);
- if (ERROR_SET(err)) {
- goto error;
- }
- } else if (strequal("hl_mode", k.data)) {
- if (v->type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation,
- "hl_mode is not a String");
- goto error;
- }
- String str = v->data.string;
- if (strequal("replace", str.data)) {
- decor.hl_mode = kHlModeReplace;
- } else if (strequal("combine", str.data)) {
- decor.hl_mode = kHlModeCombine;
- } else if (strequal("blend", str.data)) {
- decor.hl_mode = kHlModeBlend;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "virt_text_pos: invalid value");
+ OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false);
+ OPTION_TO_BOOL(decor.hl_eol, hl_eol, false);
+
+ if (opts->hl_mode.type == kObjectTypeString) {
+ String str = opts->hl_mode.data.string;
+ if (strequal("replace", str.data)) {
+ decor.hl_mode = kHlModeReplace;
+ } else if (strequal("combine", str.data)) {
+ decor.hl_mode = kHlModeCombine;
+ } else if (strequal("blend", str.data)) {
+ decor.hl_mode = kHlModeBlend;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_pos: invalid value");
+ goto error;
+ }
+ } else if (HAS_KEY(opts->hl_mode)) {
+ api_set_error(err, kErrorTypeValidation, "hl_mode is not a String");
+ goto error;
+ }
+
+ VirtLines virt_lines = KV_INITIAL_VALUE;
+ bool virt_lines_above = false;
+ bool virt_lines_leftcol = false;
+
+ if (opts->virt_lines.type == kObjectTypeArray) {
+ Array a = opts->virt_lines.data.array;
+ for (size_t j = 0; j < a.size; j++) {
+ if (a.items[j].type != kObjectTypeArray) {
+ api_set_error(err, kErrorTypeValidation, "virt_text_line item is not an Array");
goto error;
}
- } else if (strequal("ephemeral", k.data)) {
- ephemeral = api_object_to_bool(*v, "ephemeral", false, err);
+ int dummig;
+ VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig);
+ kv_push(virt_lines, jtem);
if (ERROR_SET(err)) {
goto error;
}
- } else if (strequal("priority", k.data)) {
- if (v->type != kObjectTypeInteger) {
- api_set_error(err, kErrorTypeValidation,
- "priority is not a Number of the correct size");
- goto error;
- }
+ }
+ } else if (HAS_KEY(opts->virt_lines)) {
+ api_set_error(err, kErrorTypeValidation, "virt_lines is not an Array");
+ goto error;
+ }
- if (v->data.integer < 0 || v->data.integer > UINT16_MAX) {
- api_set_error(err, kErrorTypeValidation,
- "priority is not a valid value");
- goto error;
- }
- decor.priority = (DecorPriority)v->data.integer;
- } else if (strequal("right_gravity", k.data)) {
- if (v->type != kObjectTypeBoolean) {
- api_set_error(err, kErrorTypeValidation,
- "right_gravity must be a boolean");
- goto error;
- }
- right_gravity = v->data.boolean;
- } else if (strequal("end_right_gravity", k.data)) {
- if (v->type != kObjectTypeBoolean) {
- api_set_error(err, kErrorTypeValidation,
- "end_right_gravity must be a boolean");
- goto error;
- }
- end_right_gravity = v->data.boolean;
- end_gravity_set = true;
- } else {
- api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ OPTION_TO_BOOL(virt_lines_above, virt_lines_above, false);
+ OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false);
+
+ if (opts->priority.type == kObjectTypeInteger) {
+ Integer val = opts->priority.data.integer;
+
+ if (val < 0 || val > UINT16_MAX) {
+ api_set_error(err, kErrorTypeValidation, "priority is not a valid value");
goto error;
}
+ decor.priority = (DecorPriority)val;
+ } else if (HAS_KEY(opts->priority)) {
+ api_set_error(err, kErrorTypeValidation, "priority is not a Number of the correct size");
+ goto error;
+ }
+
+ bool right_gravity = true;
+ OPTION_TO_BOOL(right_gravity, right_gravity, true);
+
+ // Only error out if they try to set end_right_gravity without
+ // setting end_col or end_line
+ if (line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)) {
+ api_set_error(err, kErrorTypeValidation,
+ "cannot set end_right_gravity without setting end_line or end_col");
+ goto error;
}
+ bool end_right_gravity = false;
+ OPTION_TO_BOOL(end_right_gravity, end_right_gravity, false);
+
size_t len = 0;
+
+ bool ephemeral = false;
+ OPTION_TO_BOOL(ephemeral, ephemeral, false);
+
if (line < 0 || line > buf->b_ml.ml_line_count) {
api_set_error(err, kErrorTypeValidation, "line value outside range");
return 0;
@@ -1661,15 +1670,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
return 0;
}
-
- // Only error out if they try to set end_right_gravity without
- // setting end_col or end_line
- if (line2 == -1 && col2 == -1 && end_gravity_set) {
- api_set_error(err, kErrorTypeValidation,
- "cannot set end_right_gravity "
- "without setting end_line or end_col");
- }
-
if (col2 >= 0) {
if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) {
len = ephemeral ? MAXCOL : STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false));
@@ -1688,15 +1688,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
col2 = 0;
}
- if (decor.virt_text_pos == kVTRightAlign) {
- decor.col = 0;
- for (size_t i = 0; i < kv_size(decor.virt_text); i++) {
- decor.col
- += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
- }
- }
-
-
Decoration *d = NULL;
if (ephemeral) {
@@ -1721,9 +1712,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer
goto error;
}
- id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
- line2, col2, d, right_gravity,
- end_right_gravity, kExtmarkNoUndo);
+ if (kv_size(virt_lines) && buf->b_virt_line_mark) {
+ mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL);
+ clear_virt_lines(buf, pos.row); // handles pos.row == -1
+ }
+
+ uint64_t mark = extmark_set(buf, (uint64_t)ns_id, &id, (int)line, (colnr_T)col,
+ line2, col2, d, right_gravity,
+ end_right_gravity, kExtmarkNoUndo);
+
+ if (kv_size(virt_lines)) {
+ buf->b_virt_lines = virt_lines;
+ buf->b_virt_line_mark = mark;
+ buf->b_virt_line_pos = -1;
+ buf->b_virt_line_above = virt_lines_above;
+ buf->b_virt_line_leftcol = virt_lines_leftcol;
+ redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count, line+1+(virt_lines_above?0:1)));
+ }
}
return (Integer)id;
@@ -1827,7 +1832,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In
end_line++;
}
- extmark_set(buf, ns, 0,
+ extmark_set(buf, ns, NULL,
(int)line, (colnr_T)col_start,
end_line, (colnr_T)col_end,
decor_hl(hl_id), true, false, kExtmarkNoUndo);
diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c
index 21b9db85c0..332fc0ba96 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -150,7 +150,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A
decor->virt_text = virt_text;
decor->virt_text_width = width;
- extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true,
+ extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, true,
false, kExtmarkNoUndo);
return src_id;
}
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
new file mode 100644
index 0000000000..76ce9e15ea
--- /dev/null
+++ b/src/nvim/api/keysets.lua
@@ -0,0 +1,52 @@
+return {
+ context = {
+ "types";
+ };
+ set_extmark = {
+ "id";
+ "end_line";
+ "end_col";
+ "hl_group";
+ "virt_text";
+ "virt_text_pos";
+ "virt_text_win_col";
+ "virt_text_hide";
+ "hl_eol";
+ "hl_mode";
+ "ephemeral";
+ "priority";
+ "right_gravity";
+ "end_right_gravity";
+ "virt_lines";
+ "virt_lines_above";
+ "virt_lines_leftcol";
+ };
+ keymap = {
+ "noremap";
+ "nowait";
+ "silent";
+ "script";
+ "expr";
+ "unique";
+ };
+ get_commands = {
+ "builtin";
+ };
+ float_config = {
+ "row";
+ "col";
+ "width";
+ "height";
+ "anchor";
+ "relative";
+ "win";
+ "bufpos";
+ "external";
+ "focusable";
+ "zindex";
+ "border";
+ "style";
+ "noautocmd";
+ };
+}
+
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index f0d48bf145..8346e01558 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -19,6 +19,7 @@
#ifdef INCLUDE_GENERATED_DECLARATIONS
# define ArrayOf(...) Array
# define DictionaryOf(...) Dictionary
+# define Dict(name) KeyDict_##name
#endif
// Basic types
@@ -129,5 +130,14 @@ struct key_value_pair {
Object value;
};
+typedef Object *(*field_hash)(void *retval, const char *str, size_t len);
+typedef struct {
+ char *str;
+ size_t ptr_off;
+} KeySetLink;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "keysets_defs.generated.h"
+#endif
#endif // NVIM_API_PRIVATE_DEFS_H
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c
index 38ce7ca78c..5e93ccce17 100644
--- a/src/nvim/api/private/dispatch.c
+++ b/src/nvim/api/private/dispatch.c
@@ -45,5 +45,5 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, size_t na
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "api/private/dispatch_wrappers.generated.h"
+# include "api/private/dispatch_wrappers.generated.h"
#endif
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 541793e528..24fac0a916 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <stddef.h>
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
@@ -814,7 +815,7 @@ Array string_to_array(const String input, bool crlf)
/// buffer, or -1 to signify global behavior ("all buffers")
/// @param is_unmap When true, removes the mapping that matches {lhs}.
void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String rhs,
- Dictionary opts, Error *err)
+ Dict(keymap) *opts, Error *err)
{
char *err_msg = NULL; // the error message to report, if any
char *err_arg = NULL; // argument for the error message format string
@@ -833,10 +834,21 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
return;
}
- MapArguments parsed_args;
- memset(&parsed_args, 0, sizeof(parsed_args));
- if (parse_keymap_opts(opts, &parsed_args, err)) {
- goto fail_and_free;
+ MapArguments parsed_args = MAP_ARGUMENTS_INIT;
+ if (opts) {
+#define KEY_TO_BOOL(name) \
+ parsed_args. name = api_object_to_bool(opts-> name, #name, false, err); \
+ if (ERROR_SET(err)) { \
+ goto fail_and_free; \
+ }
+
+ KEY_TO_BOOL(nowait);
+ KEY_TO_BOOL(noremap);
+ KEY_TO_BOOL(silent);
+ KEY_TO_BOOL(script);
+ KEY_TO_BOOL(expr);
+ KEY_TO_BOOL(unique);
+#undef KEY_TO_BOOL
}
parsed_args.buffer = !global;
@@ -947,95 +959,6 @@ fail_and_free:
return;
}
-/// Read in the given opts, setting corresponding flags in `out`.
-///
-/// @param opts A dictionary passed to @ref nvim_set_keymap or
-/// @ref nvim_buf_set_keymap.
-/// @param[out] out MapArguments object in which to set parsed
-/// |:map-arguments| flags.
-/// @param[out] err Error details, if any.
-///
-/// @returns Zero on success, nonzero on failure.
-Integer parse_keymap_opts(Dictionary opts, MapArguments *out, Error *err)
-{
- char *err_msg = NULL; // the error message to report, if any
- char *err_arg = NULL; // argument for the error message format string
- ErrorType err_type = kErrorTypeNone;
-
- out->buffer = false;
- out->nowait = false;
- out->silent = false;
- out->script = false;
- out->expr = false;
- out->unique = false;
-
- for (size_t i = 0; i < opts.size; i++) {
- KeyValuePair *key_and_val = &opts.items[i];
- char *optname = key_and_val->key.data;
-
- if (key_and_val->value.type != kObjectTypeBoolean) {
- err_msg = "Gave non-boolean value for an opt: %s";
- err_arg = optname;
- err_type = kErrorTypeValidation;
- goto fail_with_message;
- }
-
- bool was_valid_opt = false;
- switch (optname[0]) {
- // note: strncmp up to and including the null terminator, so that
- // "nowaitFoobar" won't match against "nowait"
-
- // don't recognize 'buffer' as a key; user shouldn't provide <buffer>
- // when calling nvim_set_keymap or nvim_buf_set_keymap, since it can be
- // inferred from which function they called
- case 'n':
- if (STRNCMP(optname, "noremap", 8) == 0) {
- was_valid_opt = true;
- out->noremap = key_and_val->value.data.boolean;
- } else if (STRNCMP(optname, "nowait", 7) == 0) {
- was_valid_opt = true;
- out->nowait = key_and_val->value.data.boolean;
- }
- break;
- case 's':
- if (STRNCMP(optname, "silent", 7) == 0) {
- was_valid_opt = true;
- out->silent = key_and_val->value.data.boolean;
- } else if (STRNCMP(optname, "script", 7) == 0) {
- was_valid_opt = true;
- out->script = key_and_val->value.data.boolean;
- }
- break;
- case 'e':
- if (STRNCMP(optname, "expr", 5) == 0) {
- was_valid_opt = true;
- out->expr = key_and_val->value.data.boolean;
- }
- break;
- case 'u':
- if (STRNCMP(optname, "unique", 7) == 0) {
- was_valid_opt = true;
- out->unique = key_and_val->value.data.boolean;
- }
- break;
- default:
- break;
- } // switch
- if (!was_valid_opt) {
- err_msg = "Invalid key: %s";
- err_arg = optname;
- err_type = kErrorTypeValidation;
- goto fail_with_message;
- }
- } // for
-
- return 0;
-
-fail_with_message:
- api_set_error(err, err_type, err_msg, err_arg);
- return 1;
-}
-
/// Collects `n` buffer lines into array `l`, optionally replacing newlines
/// with NUL.
///
@@ -1413,8 +1336,10 @@ static void set_option_value_for(char *key, int numval, char *stringval, int opt
switch (opt_type)
{
case SREQ_WIN:
- if (switch_win(&save_curwin, &save_curtab, (win_T *)from,
- win_find_tabpage((win_T *)from), false) == FAIL) {
+ if (switch_win_noblock(&save_curwin, &save_curtab, (win_T *)from,
+ win_find_tabpage((win_T *)from), true)
+ == FAIL) {
+ restore_win_noblock(save_curwin, save_curtab, true);
if (try_end(err)) {
return;
}
@@ -1424,7 +1349,7 @@ static void set_option_value_for(char *key, int numval, char *stringval, int opt
return;
}
set_option_value_err(key, numval, stringval, opt_flags, err);
- restore_win(save_curwin, save_curtab, true);
+ restore_win_noblock(save_curwin, save_curtab, true);
break;
case SREQ_BUF:
aucmd_prepbuf(&aco, (buf_T *)from);
@@ -1625,7 +1550,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width)
}
}
- char *text = transstr(str.size > 0 ? str.data : ""); // allocates
+ char *text = transstr(str.size > 0 ? str.data : "", false); // allocates
w += (int)mb_string2cells((char_u *)text);
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
@@ -1877,213 +1802,227 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
}
}
-bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, bool new_win,
+bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, bool reconf, bool new_win,
Error *err)
{
- // TODO(bfredl): use a get/has_key interface instead and get rid of extra
- // flags
- bool has_row = false, has_col = false, has_relative = false;
- bool has_external = false, has_window = false;
- bool has_width = false, has_height = false;
- bool has_bufpos = false;
-
- for (size_t i = 0; i < config.size; i++) {
- char *key = config.items[i].key.data;
- Object val = config.items[i].value;
- if (!strcmp(key, "row")) {
- has_row = true;
- if (val.type == kObjectTypeInteger) {
- fconfig->row = (double)val.data.integer;
- } else if (val.type == kObjectTypeFloat) {
- fconfig->row = val.data.floating;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'row' key must be Integer or Float");
- return false;
- }
- } else if (!strcmp(key, "col")) {
- has_col = true;
- if (val.type == kObjectTypeInteger) {
- fconfig->col = (double)val.data.integer;
- } else if (val.type == kObjectTypeFloat) {
- fconfig->col = val.data.floating;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'col' key must be Integer or Float");
- return false;
- }
- } else if (strequal(key, "width")) {
- has_width = true;
- if (val.type == kObjectTypeInteger && val.data.integer > 0) {
- fconfig->width = (int)val.data.integer;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'width' key must be a positive Integer");
+ bool has_relative = false, relative_is_win = false;
+ if (config->relative.type == kObjectTypeString) {
+ // ignore empty string, to match nvim_win_get_config
+ if (config->relative.data.string.size > 0) {
+ if (!parse_float_relative(config->relative.data.string, &fconfig->relative)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key");
return false;
}
- } else if (strequal(key, "height")) {
- has_height = true;
- if (val.type == kObjectTypeInteger && val.data.integer > 0) {
- fconfig->height = (int)val.data.integer;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "'height' key must be a positive Integer");
- return false;
- }
- } else if (!strcmp(key, "anchor")) {
- if (val.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation,
- "'anchor' key must be String");
- return false;
- }
- if (!parse_float_anchor(val.data.string, &fconfig->anchor)) {
- api_set_error(err, kErrorTypeValidation,
- "Invalid value of 'anchor' key");
- return false;
- }
- } else if (!strcmp(key, "relative")) {
- if (val.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation,
- "'relative' key must be String");
- return false;
- }
- // ignore empty string, to match nvim_win_get_config
- if (val.data.string.size > 0) {
- has_relative = true;
- if (!parse_float_relative(val.data.string, &fconfig->relative)) {
- api_set_error(err, kErrorTypeValidation,
- "Invalid value of 'relative' key");
- return false;
- }
- }
- } else if (!strcmp(key, "win")) {
- has_window = true;
- if (val.type != kObjectTypeInteger
- && val.type != kObjectTypeWindow) {
- api_set_error(err, kErrorTypeValidation,
- "'win' key must be Integer or Window");
- return false;
- }
- fconfig->window = (Window)val.data.integer;
- } else if (!strcmp(key, "bufpos")) {
- if (val.type != kObjectTypeArray) {
- api_set_error(err, kErrorTypeValidation,
- "'bufpos' key must be Array");
- return false;
- }
- if (!parse_float_bufpos(val.data.array, &fconfig->bufpos)) {
- api_set_error(err, kErrorTypeValidation,
- "Invalid value of 'bufpos' key");
- return false;
- }
- has_bufpos = true;
- } else if (!strcmp(key, "external")) {
- has_external = fconfig->external
- = api_object_to_bool(val, "'external' key", false, err);
- if (ERROR_SET(err)) {
- return false;
- }
- } else if (!strcmp(key, "focusable")) {
- fconfig->focusable
- = api_object_to_bool(val, "'focusable' key", true, err);
- if (ERROR_SET(err)) {
- return false;
- }
- } else if (strequal(key, "zindex")) {
- if (val.type == kObjectTypeInteger && val.data.integer > 0) {
- fconfig->zindex = (int)val.data.integer;
- } else {
+
+ if (!(HAS_KEY(config->row) && HAS_KEY(config->col)) && !HAS_KEY(config->bufpos)) {
api_set_error(err, kErrorTypeValidation,
- "'zindex' key must be a positive Integer");
+ "'relative' requires 'row'/'col' or 'bufpos'");
return false;
}
- } else if (!strcmp(key, "border")) {
- parse_border_style(val, fconfig, err);
- if (ERROR_SET(err)) {
- return false;
+
+ has_relative = true;
+ fconfig->external = false;
+ if (fconfig->relative == kFloatRelativeWindow) {
+ relative_is_win = true;
+ fconfig->bufpos.lnum = -1;
}
- } else if (!strcmp(key, "style")) {
- if (val.type != kObjectTypeString) {
- api_set_error(err, kErrorTypeValidation,
- "'style' key must be String");
+ }
+ } else if (HAS_KEY(config->relative)) {
+ api_set_error(err, kErrorTypeValidation, "'relative' key must be String");
+ return false;
+ }
+
+ if (config->anchor.type == kObjectTypeString) {
+ if (!parse_float_anchor(config->anchor.data.string, &fconfig->anchor)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key");
+ return false;
+ }
+ } else if (HAS_KEY(config->anchor)) {
+ api_set_error(err, kErrorTypeValidation, "'anchor' key must be String");
+ return false;
+ }
+
+ if (HAS_KEY(config->row)) {
+ if (!has_relative) {
+ api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'");
+ return false;
+ } else if (config->row.type == kObjectTypeInteger) {
+ fconfig->row = (double)config->row.data.integer;
+ } else if (config->row.type == kObjectTypeFloat) {
+ fconfig->row = config->row.data.floating;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "'row' key must be Integer or Float");
+ return false;
+ }
+ }
+
+ if (HAS_KEY(config->col)) {
+ if (!has_relative) {
+ api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'");
+ return false;
+ } else if (config->col.type == kObjectTypeInteger) {
+ fconfig->col = (double)config->col.data.integer;
+ } else if (config->col.type == kObjectTypeFloat) {
+ fconfig->col = config->col.data.floating;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "'col' key must be Integer or Float");
+ return false;
+ }
+ }
+
+ if (HAS_KEY(config->bufpos)) {
+ if (!has_relative) {
+ api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'");
+ return false;
+ } else if (config->bufpos.type == kObjectTypeArray) {
+ if (!parse_float_bufpos(config->bufpos.data.array, &fconfig->bufpos)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key");
return false;
}
- if (val.data.string.data[0] == NUL) {
- fconfig->style = kWinStyleUnused;
- } else if (striequal(val.data.string.data, "minimal")) {
- fconfig->style = kWinStyleMinimal;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "Invalid value of 'style' key");
+
+ if (!HAS_KEY(config->row)) {
+ fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1;
}
- } else if (strequal(key, "noautocmd") && new_win) {
- fconfig->noautocmd
- = api_object_to_bool(val, "'noautocmd' key", false, err);
- if (ERROR_SET(err)) {
- return false;
+ if (!HAS_KEY(config->col)) {
+ fconfig->col = 0;
}
} else {
- api_set_error(err, kErrorTypeValidation,
- "Invalid key '%s'", key);
+ api_set_error(err, kErrorTypeValidation, "'bufpos' key must be Array");
return false;
}
}
- if (has_window && !(has_relative
- && fconfig->relative == kFloatRelativeWindow)) {
- api_set_error(err, kErrorTypeValidation,
- "'win' key is only valid with relative='win'");
+ if (config->width.type == kObjectTypeInteger && config->width.data.integer > 0) {
+ fconfig->width = (int)config->width.data.integer;
+ } else if (HAS_KEY(config->width)) {
+ api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer");
+ return false;
+ } else if (!reconf) {
+ api_set_error(err, kErrorTypeValidation, "Must specify 'width'");
return false;
}
- if ((has_relative && fconfig->relative == kFloatRelativeWindow)
- && (!has_window || fconfig->window == 0)) {
- fconfig->window = curwin->handle;
+ if (config->height.type == kObjectTypeInteger && config->height.data.integer > 0) {
+ fconfig->height = (int)config->height.data.integer;
+ } else if (HAS_KEY(config->height)) {
+ api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer");
+ return false;
+ } else if (!reconf) {
+ api_set_error(err, kErrorTypeValidation, "Must specify 'height'");
+ return false;
}
- if (has_window && !has_bufpos) {
- fconfig->bufpos.lnum = -1;
+ if (relative_is_win) {
+ fconfig->window = curwin->handle;
+ if (config->win.type == kObjectTypeInteger || config->win.type == kObjectTypeWindow) {
+ if (config->win.data.integer > 0) {
+ fconfig->window = (Window)config->win.data.integer;
+ }
+ } else if (HAS_KEY(config->win)) {
+ api_set_error(err, kErrorTypeValidation, "'win' key must be Integer or Window");
+ return false;
+ }
+ } else {
+ if (HAS_KEY(config->win)) {
+ api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win'");
+ return false;
+ }
}
- if (has_bufpos) {
- if (!has_row) {
- fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1;
- has_row = true;
+ if (HAS_KEY(config->external)) {
+ fconfig->external = api_object_to_bool(config->external, "'external' key", false, err);
+ if (ERROR_SET(err)) {
+ return false;
}
- if (!has_col) {
- fconfig->col = 0;
- has_col = true;
+ if (has_relative && fconfig->external) {
+ api_set_error(err, kErrorTypeValidation,
+ "Only one of 'relative' and 'external' must be used");
+ return false;
+ }
+ if (fconfig->external && !ui_has(kUIMultigrid)) {
+ api_set_error(err, kErrorTypeValidation,
+ "UI doesn't support external windows");
+ return false;
}
}
- if (has_relative && has_external) {
- api_set_error(err, kErrorTypeValidation,
- "Only one of 'relative' and 'external' must be used");
- return false;
- } else if (!reconf && !has_relative && !has_external) {
+ if (!reconf && (!has_relative && !fconfig->external)) {
api_set_error(err, kErrorTypeValidation,
"One of 'relative' and 'external' must be used");
return false;
- } else if (has_relative) {
- fconfig->external = false;
}
- if (!reconf && !(has_height && has_width)) {
- api_set_error(err, kErrorTypeValidation,
- "Must specify 'width' and 'height'");
- return false;
+
+ if (HAS_KEY(config->focusable)) {
+ fconfig->focusable = api_object_to_bool(config->focusable, "'focusable' key", false, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
}
- if (fconfig->external && !ui_has(kUIMultigrid)) {
- api_set_error(err, kErrorTypeValidation,
- "UI doesn't support external windows");
+ if (config->zindex.type == kObjectTypeInteger && config->zindex.data.integer > 0) {
+ fconfig->zindex = (int)config->zindex.data.integer;
+ } else if (HAS_KEY(config->zindex)) {
+ api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer");
return false;
}
- if (has_relative != has_row || has_row != has_col) {
- api_set_error(err, kErrorTypeValidation,
- "'relative' requires 'row'/'col' or 'bufpos'");
+ if (HAS_KEY(config->border)) {
+ parse_border_style(config->border, fconfig, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
+ }
+
+ if (config->style.type == kObjectTypeString) {
+ if (config->style.data.string.data[0] == NUL) {
+ fconfig->style = kWinStyleUnused;
+ } else if (striequal(config->style.data.string.data, "minimal")) {
+ fconfig->style = kWinStyleMinimal;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key");
+ }
+ } else if (HAS_KEY(config->style)) {
+ api_set_error(err, kErrorTypeValidation, "'style' key must be String");
return false;
}
+
+ if (HAS_KEY(config->noautocmd)) {
+ if (!new_win) {
+ api_set_error(err, kErrorTypeValidation, "Invalid key: 'noautocmd'");
+ return false;
+ }
+ fconfig->noautocmd = api_object_to_bool(config->noautocmd, "'noautocmd' key", false, err);
+ if (ERROR_SET(err)) {
+ return false;
+ }
+ }
+
return true;
}
+
+bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err)
+{
+ for (size_t i = 0; i < dict.size; i++) {
+ String k = dict.items[i].key;
+ Object *field = hashy(rv, k.data, k.size);
+ if (!field) {
+ api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s'", (int)k.size, k.data);
+ return false;
+ }
+
+ *field = dict.items[i].value;
+ }
+
+ return true;
+}
+
+void api_free_keydict(void *dict, KeySetLink *table)
+{
+ for (size_t i = 0; table[i].str; i++) {
+ api_free_object(*(Object *)((char *)dict + table[i].ptr_off));
+ }
+}
+
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index ecce6afa26..2cdd80bffe 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -59,6 +59,9 @@
#define NIL ((Object)OBJECT_INIT)
#define NULL_STRING ((String)STRING_INIT)
+// currently treat key=vim.NIL as if the key was missing
+#define HAS_KEY(o) ((o).type != kObjectTypeNil)
+
#define PUT(dict, k, v) \
kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v }))
@@ -138,6 +141,9 @@ typedef struct {
} while (0)
#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "keysets.h.generated.h"
# include "api/private/helpers.h.generated.h"
#endif
+
+
#endif // NVIM_API_PRIVATE_HELPERS_H
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 3be45d0cf7..f80d605d9a 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -1360,7 +1360,9 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// - `bufpos`: Places float relative to buffer text (only when
/// relative="win"). Takes a tuple of zero-indexed [line, column].
/// `row` and `col` if given are applied relative to this
-/// position, else they default to `row=1` and `col=0`
+/// position, else they default to:
+/// - `row=1` and `col=0` if `anchor` is "NW" or "NE"
+/// - `row=0` and `col=0` if `anchor` is "SW" or "SE"
/// (thus like a tooltip near the buffer text).
/// - `row`: Row position in units of "screen cell height", may be fractional.
/// - `col`: Column position in units of "screen cell width", may be
@@ -1422,7 +1424,7 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// @param[out] err Error details, if any
///
/// @return Window handle, or 0 on error
-Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, Error *err)
+Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err)
FUNC_API_SINCE(6)
FUNC_API_CHECK_TEXTLOCK
{
@@ -1437,13 +1439,14 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, Error *err
if (enter) {
win_enter(wp, false);
}
+ // autocmds in win_enter or win_set_buf below may close the window
+ if (win_valid(wp) && buffer > 0) {
+ win_set_buf(wp->handle, buffer, fconfig.noautocmd, err);
+ }
if (!win_valid(wp)) {
api_set_error(err, kErrorTypeException, "Window was closed immediately");
return 0;
}
- if (buffer > 0) {
- win_set_buf(wp->handle, buffer, fconfig.noautocmd, err);
- }
if (fconfig.style == kWinStyleMinimal) {
win_set_minimal_style(wp);
@@ -1758,24 +1761,15 @@ Dictionary nvim_get_color_map(void)
/// @param[out] err Error details, if any
///
/// @return map of global |context|.
-Dictionary nvim_get_context(Dictionary opts, Error *err)
+Dictionary nvim_get_context(Dict(context) *opts, Error *err)
FUNC_API_SINCE(6)
{
Array types = ARRAY_DICT_INIT;
- for (size_t i = 0; i < opts.size; i++) {
- String k = opts.items[i].key;
- Object v = opts.items[i].value;
- if (strequal("types", k.data)) {
- if (v.type != kObjectTypeArray) {
- api_set_error(err, kErrorTypeValidation, "invalid value for key: %s",
- k.data);
- return (Dictionary)ARRAY_DICT_INIT;
- }
- types = v.data.array;
- } else {
- api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
- return (Dictionary)ARRAY_DICT_INIT;
- }
+ if (opts->types.type == kObjectTypeArray) {
+ types = opts->types.data.array;
+ } else if (opts->types.type != kObjectTypeNil) {
+ api_set_error(err, kErrorTypeValidation, "invalid value for key: types");
+ return (Dictionary)ARRAY_DICT_INIT;
}
int int_types = types.size > 0 ? 0 : kCtxAll;
@@ -1885,7 +1879,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode)
/// as keys excluding |<buffer>| but including |noremap|.
/// Values are Booleans. Unknown key is an error.
/// @param[out] err Error details, if any.
-void nvim_set_keymap(String mode, String lhs, String rhs, Dictionary opts, Error *err)
+void nvim_set_keymap(String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err)
FUNC_API_SINCE(6)
{
modify_keymap(-1, false, mode, lhs, rhs, opts, err);
@@ -1911,7 +1905,7 @@ void nvim_del_keymap(String mode, String lhs, Error *err)
/// @param[out] err Error details, if any.
///
/// @returns Map of maps describing commands.
-Dictionary nvim_get_commands(Dictionary opts, Error *err)
+Dictionary nvim_get_commands(Dict(get_commands) *opts, Error *err)
FUNC_API_SINCE(4)
{
return nvim_buf_get_commands(-1, opts, err);
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 99ba297111..95eae1af2d 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -385,7 +385,7 @@ Boolean nvim_win_is_valid(Window window)
/// @param config Map defining the window configuration,
/// see |nvim_open_win()|
/// @param[out] err Error details, if any
-void nvim_win_set_config(Window window, Dictionary config, Error *err)
+void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
FUNC_API_SINCE(6)
{
win_T *win = find_window_by_handle(window, err);
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 4c502b53d4..d991b88131 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -24,8 +24,8 @@
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "auevents_name_map.generated.h"
-#include "autocmd.c.generated.h"
+# include "auevents_name_map.generated.h"
+# include "autocmd.c.generated.h"
#endif
//
@@ -199,7 +199,7 @@ static void au_cleanup(void)
}
// Loop over all events.
- for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ for (event = (event_T)0; (int)event < NUM_EVENTS;
event = (event_T)((int)event + 1)) {
// Loop over all autocommand patterns.
prev_ap = &(first_autopat[(int)event]);
@@ -266,7 +266,7 @@ void aubuflocal_remove(buf_T *buf)
}
// invalidate buflocals looping through events
- for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ for (event = (event_T)0; (int)event < NUM_EVENTS;
event = (event_T)((int)event + 1)) {
// loop over all autocommand patterns
for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
@@ -321,7 +321,7 @@ static void au_del_group(char_u *name)
AutoPat *ap;
int in_use = false;
- for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
+ for (event = (event_T)0; (int)event < NUM_EVENTS;
event = (event_T)((int)event + 1)) {
for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
if (ap->group == i && ap->pat != NULL) {
@@ -475,7 +475,7 @@ static char_u *find_end_event(char_u *arg, int have_group)
pat = arg + 1;
} else {
for (pat = arg; *pat && *pat != '|' && !ascii_iswhite(*pat); pat = p) {
- if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS) {
+ if ((int)event_name2nr(pat, &p) >= NUM_EVENTS) {
if (have_group) {
EMSG2(_("E216: No such event: %s"), pat);
} else {
@@ -701,7 +701,7 @@ void do_autocmd(char_u *arg_in, int forceit)
if (!forceit && *cmd != NUL) {
EMSG(_(e_cannot_define_autocommands_for_all_events));
} else {
- for (event_T event = (event_T)0; event < (int)NUM_EVENTS;
+ for (event_T event = (event_T)0; event < NUM_EVENTS;
event = (event_T)(event + 1)) {
if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group)
== FAIL) {
@@ -956,10 +956,11 @@ static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, c
return OK;
}
-// Implementation of ":doautocmd [group] event [fname]".
-// Return OK for success, FAIL for failure;
-int do_doautocmd(char_u *arg, bool do_msg, // give message for no matching autocmds?
- bool *did_something)
+/// Implementation of ":doautocmd [group] event [fname]".
+/// Return OK for success, FAIL for failure;
+///
+/// @param do_msg give message for no matching autocmds?
+int do_doautocmd(char_u *arg, bool do_msg, bool *did_something)
{
char_u *fname;
int nothing_done = true;
@@ -1916,8 +1917,8 @@ char_u *get_augroup_name(expand_T *xp, int idx)
return (char_u *)AUGROUP_NAME(idx);
}
-char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd // true for :doauto*, false for :autocmd
- )
+/// @param doautocmd true for :doauto*, false for :autocmd
+char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd)
{
char_u *p;
int group;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index c58eb1610e..20dd94622f 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -65,6 +65,7 @@
#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
@@ -98,13 +99,15 @@ typedef enum {
kBffInitChangedtick = 2,
} BufFreeFlags;
-// Read data from buffer for retrying.
-static int read_buffer(int read_stdin, // read file from stdin, otherwise fifo
- exarg_T *eap, // for forced 'ff' and 'fenc' or NULL
- int flags) // extra flags for readfile()
+/// Read data from buffer for retrying.
+///
+/// @param read_stdin read file from stdin, otherwise fifo
+/// @param eap for forced 'ff' and 'fenc' or NULL
+/// @param flags extra flags for readfile()
+static int read_buffer(int read_stdin, exarg_T *eap, int flags)
{
- int retval = OK;
- linenr_T line_count;
+ int retval = OK;
+ linenr_T line_count;
//
// Read from the buffer which the text is already filled in and append at
@@ -114,7 +117,7 @@ static int read_buffer(int read_stdin, // read file from stdin, otherwis
line_count = curbuf->b_ml.ml_line_count;
retval = readfile(read_stdin ? NULL : curbuf->b_ffname,
read_stdin ? NULL : curbuf->b_fname,
- (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
+ line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
flags | READ_BUFFER);
if (retval == OK) {
// Delete the binary lines.
@@ -146,16 +149,18 @@ static int read_buffer(int read_stdin, // read file from stdin, otherwis
return retval;
}
-// Open current buffer, that is: open the memfile and read the file into
-// memory.
-// Return FAIL for failure, OK otherwise.
-int open_buffer(int read_stdin, // read file from stdin
- exarg_T *eap, // for forced 'ff' and 'fenc' or NULL
- int flags // extra flags for readfile()
- )
+/// Open current buffer, that is: open the memfile and read the file into
+/// memory.
+///
+/// @param read_stdin read file from stdin
+/// @param eap for forced 'ff' and 'fenc' or NULL
+/// @param flags extra flags for readfile()
+///
+/// @return FAIL for failure, OK otherwise.
+int open_buffer(int read_stdin, exarg_T *eap, int flags)
{
int retval = OK;
- bufref_T old_curbuf;
+ bufref_T old_curbuf;
long old_tw = curbuf->b_p_tw;
int read_fifo = false;
@@ -816,6 +821,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf, (char_u *)"*"); // delete any signs
extmark_free_all(buf); // delete any extmarks
+ clear_virt_lines(buf, -1);
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
@@ -939,23 +945,22 @@ void handle_swap_exists(bufref_T *old_curbuf)
swap_exists_action = SEA_NONE; // -V519
}
-/*
- * do_bufdel() - delete or unload buffer(s)
- *
- * addr_count == 0: ":bdel" - delete current buffer
- * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
- * buffer "end_bnr", then any other arguments.
- * addr_count == 2: ":N,N bdel" - delete buffers in range
- *
- * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
- * DOBUF_DEL (":bdel")
- *
- * Returns error message or NULL
- */
-char_u *do_bufdel(int command, char_u *arg, // pointer to extra arguments
- int addr_count, int start_bnr, // first buffer number in a range
- int end_bnr, // buffer nr or last buffer nr in a range
- int forceit)
+/// do_bufdel() - delete or unload buffer(s)
+///
+/// addr_count == 0: ":bdel" - delete current buffer
+/// addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
+/// buffer "end_bnr", then any other arguments.
+/// addr_count == 2: ":N,N bdel" - delete buffers in range
+///
+/// command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
+/// DOBUF_DEL (":bdel")
+///
+/// @param arg pointer to extra arguments
+/// @param start_bnr first buffer number in a range
+/// @param end_bnr buffer nr or last buffer nr in a range
+///
+/// @return error message or NULL
+char_u *do_bufdel(int command, char_u *arg, int addr_count, int start_bnr, int end_bnr, int forceit)
{
int do_current = 0; // delete current buffer?
int deleted = 0; // number of buffers deleted
@@ -1097,26 +1102,26 @@ static int empty_curbuf(int close_others, int forceit, int action)
return retval;
}
-/*
- * Implementation of the commands for the buffer list.
- *
- * action == DOBUF_GOTO go to specified buffer
- * action == DOBUF_SPLIT split window and go to specified buffer
- * action == DOBUF_UNLOAD unload specified buffer(s)
- * action == DOBUF_DEL delete specified buffer(s) from buffer list
- * action == DOBUF_WIPE delete specified buffer(s) really
- *
- * start == DOBUF_CURRENT go to "count" buffer from current buffer
- * start == DOBUF_FIRST go to "count" buffer from first buffer
- * start == DOBUF_LAST go to "count" buffer from last buffer
- * start == DOBUF_MOD go to "count" modified buffer from current buffer
- *
- * Return FAIL or OK.
- */
-int do_buffer(int action, int start, int dir, // FORWARD or BACKWARD
- int count, // buffer number or number of buffers
- int forceit // true for :...!
- )
+
+/// Implementation of the commands for the buffer list.
+///
+/// action == DOBUF_GOTO go to specified buffer
+/// action == DOBUF_SPLIT split window and go to specified buffer
+/// action == DOBUF_UNLOAD unload specified buffer(s)
+/// action == DOBUF_DEL delete specified buffer(s) from buffer list
+/// action == DOBUF_WIPE delete specified buffer(s) really
+///
+/// start == DOBUF_CURRENT go to "count" buffer from current buffer
+/// start == DOBUF_FIRST go to "count" buffer from first buffer
+/// start == DOBUF_LAST go to "count" buffer from last buffer
+/// start == DOBUF_MOD go to "count" modified buffer from current buffer
+///
+/// @param dir FORWARD or BACKWARD
+/// @param count buffer number or number of buffers
+/// @param forceit true for :...!
+///
+/// @return FAIL or OK.
+int do_buffer(int action, int start, int dir, int count, int forceit)
{
buf_T *buf;
buf_T *bp;
@@ -2154,11 +2159,13 @@ static buf_T *buflist_findname_file_id(char_u *ffname, FileID *file_id, bool fil
/// Find file in buffer list by a regexp pattern.
/// Return fnum of the found buffer.
/// Return < 0 for error.
-int buflist_findpat(const char_u *pattern, const char_u *pattern_end, // pointer to first char after pattern
- bool unlisted, // find unlisted buffers
- bool diffmode, // find diff-mode buffers only
- bool curtab_only // find buffers in current tab only
- )
+///
+/// @param pattern_end pointer to first char after pattern
+/// @param unlisted find unlisted buffers
+/// @param diffmode find diff-mode buffers only
+/// @param curtab_only find buffers in current tab only
+int buflist_findpat(const char_u *pattern, const char_u *pattern_end, bool unlisted, bool diffmode,
+ bool curtab_only)
FUNC_ATTR_NONNULL_ARG(1)
{
int match = -1;
@@ -2466,14 +2473,14 @@ buf_T *buflist_findnr(int nr)
return handle_get_buffer((handle_T)nr);
}
-/*
- * Get name of file 'n' in the buffer list.
- * When the file has no name an empty string is returned.
- * home_replace() is used to shorten the file name (used for marks).
- * Returns a pointer to allocated memory, of NULL when failed.
- */
-char_u *buflist_nr2name(int n, int fullname, int helptail // for help buffers return tail only
- )
+/// Get name of file 'n' in the buffer list.
+/// When the file has no name an empty string is returned.
+/// home_replace() is used to shorten the file name (used for marks).
+///
+/// @param helptail for help buffers return tail only
+///
+/// @return a pointer to allocated memory, of NULL when failed.
+char_u *buflist_nr2name(int n, int fullname, int helptail)
{
buf_T *buf;
@@ -2800,13 +2807,14 @@ int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum)
return OK;
}
-// Set the file name for "buf" to "ffname_arg", short file name to
-// "sfname_arg".
-// The file name with the full path is also remembered, for when :cd is used.
-// Returns FAIL for failure (file name already in use by other buffer)
-// OK otherwise.
-int setfname(buf_T *buf, char_u *ffname_arg, char_u *sfname_arg, bool message // give message when buffer already exists
- )
+/// Set the file name for "buf" to "ffname_arg", short file name to
+/// "sfname_arg".
+/// The file name with the full path is also remembered, for when :cd is used.
+///
+/// @param message give message when buffer already exists
+///
+/// @return FAIL for failure (file name already in use by other buffer) OK otherwise.
+int setfname(buf_T *buf, char_u *ffname_arg, char_u *sfname_arg, bool message)
{
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
@@ -2934,12 +2942,11 @@ buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum)
return buf;
}
-/*
- * Get alternate file name for current window.
- * Return NULL if there isn't any, and give error message if requested.
- */
-char_u *getaltfname(bool errmsg // give error message
- )
+/// Get alternate file name for current window.
+/// Return NULL if there isn't any, and give error message if requested.
+///
+/// @param errmsg give error message
+char_u *getaltfname(bool errmsg)
{
char_u *fname;
linenr_T dummy;
@@ -3078,11 +3085,10 @@ static bool buf_same_file_id(buf_T *buf, FileID *file_id)
return buf->file_id_valid && os_fileid_equal(&(buf->file_id), file_id);
}
-/*
- * Print info about the current buffer.
- */
-void fileinfo(int fullname, // when non-zero print full path
- int shorthelp, int dont_truncate)
+/// Print info about the current buffer.
+///
+/// @param fullname when non-zero print full path
+void fileinfo(int fullname, int shorthelp, int dont_truncate)
{
char_u *name;
int n;
@@ -3258,7 +3264,7 @@ void maketitle(void)
buf_p += MIN(size, SPACE_FOR_FNAME);
} else {
buf_p += transstr_buf((const char *)path_tail(curbuf->b_fname),
- buf_p, SPACE_FOR_FNAME + 1);
+ buf_p, SPACE_FOR_FNAME + 1, true);
}
switch (bufIsChanged(curbuf)
@@ -3307,7 +3313,7 @@ void maketitle(void)
// room for the server name. When there is no room (very long
// file name) use (...).
if ((size_t)(buf_p - buf) < SPACE_FOR_DIR) {
- char *const tbuf = transstr(buf_p);
+ char *const tbuf = transstr(buf_p, true);
const size_t free_space = SPACE_FOR_DIR - (size_t)(buf_p - buf) + 1;
const size_t dir_len = xstrlcpy(buf_p, tbuf, free_space);
buf_p += MIN(dir_len, free_space - 1);
@@ -3423,14 +3429,14 @@ void resettitle(void)
ui_flush();
}
-# if defined(EXITFREE)
+#if defined(EXITFREE)
void free_titles(void)
{
xfree(lasttitle);
xfree(lasticon);
}
-# endif
+#endif
/// Enumeration specifying the valid numeric bases that can
/// be used when printing numbers in the status line.
@@ -4653,7 +4659,7 @@ void get_rel_pos(win_T *wp, char_u *buf, int buflen)
long below; // number of lines below window
above = wp->w_topline - 1;
- above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
+ above += win_get_fill(wp, wp->w_topline) - wp->w_topfill;
if (wp->w_topline == 1 && wp->w_topfill >= 1) {
// All buffer lines are displayed and there is an indication
// of filler lines, that can be considered seeing all lines.
@@ -4751,12 +4757,11 @@ char_u *alist_name(aentry_T *aep)
return bp->b_fname;
}
-/*
- * do_arg_all(): Open up to 'count' windows, one for each argument.
- */
-void do_arg_all(int count, int forceit, // hide buffers in current windows
- int keep_tabs // keep current tabs, for ":tab drop file"
- )
+/// do_arg_all(): Open up to 'count' windows, one for each argument.
+///
+/// @param forceit hide buffers in current windows
+/// @param keep_tabs keep current tabs, for ":tab drop file"
+void do_arg_all(int count, int forceit, int keep_tabs)
{
char_u *opened; // Array of weight for which args are open:
// 0: not opened
@@ -5254,12 +5259,11 @@ void do_modelines(int flags)
entered--;
}
-/*
- * chk_modeline() - check a single line for a mode string
- * Return FAIL if an error encountered.
- */
-static int chk_modeline(linenr_T lnum, int flags // Same as for do_modelines().
- )
+/// chk_modeline() - check a single line for a mode string
+/// Return FAIL if an error encountered.
+///
+/// @param flags Same as for do_modelines().
+static int chk_modeline(linenr_T lnum, int flags)
{
char_u *s;
char_u *e;
@@ -5631,13 +5635,12 @@ bool buf_contents_changed(buf_T *buf)
return differ;
}
-/*
- * Wipe out a buffer and decrement the last buffer number if it was used for
- * this buffer. Call this to wipe out a temp buffer that does not contain any
- * marks.
- */
-void wipe_buffer(buf_T *buf, bool aucmd // When true trigger autocommands.
- )
+/// Wipe out a buffer and decrement the last buffer number if it was used for
+/// this buffer. Call this to wipe out a temp buffer that does not contain any
+/// marks.
+///
+/// @param aucmd When true trigger autocommands.
+void wipe_buffer(buf_T *buf, bool aucmd)
{
if (!aucmd) {
// Don't trigger BufDelete autocommands here.
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index ba2bcd7223..0264a60117 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -868,6 +868,12 @@ struct file_buffer {
Map(uint64_t, ExtmarkItem) b_extmark_index[1];
Map(uint64_t, ExtmarkNs) b_extmark_ns[1]; // extmark namespaces
+ VirtLines b_virt_lines;
+ uint64_t b_virt_line_mark;
+ int b_virt_line_pos;
+ bool b_virt_line_above;
+ bool b_virt_line_leftcol;
+
// array of channel_id:s which have asked to receive updates for this
// buffer.
kvec_t(uint64_t) update_channels;
diff --git a/src/nvim/change.c b/src/nvim/change.c
index ccceb0e320..4ac5edeaa9 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -461,15 +461,15 @@ void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra)
/// When only inserting lines, "lnum" and "lnume" are equal.
/// Takes care of calling changed() and updating b_mod_*.
/// Careful: may trigger autocommands that reload the buffer.
-void changed_lines(linenr_T lnum, // first line with change
- colnr_T col, // column in first line with change
- linenr_T lnume, // line below last changed line
- long xtra, // number of extra lines (negative when deleting)
- bool do_buf_event // some callers like undo/redo call changed_lines()
- // and then increment changedtick *again*. This flag
- // allows these callers to send the nvim_buf_lines_event
- // events after they're done modifying changedtick.
- )
+///
+/// @param lnum first line with change
+/// @param col column in first line with change
+/// @param lnume line below last changed line
+/// @param xtra number of extra lines (negative when deleting)
+/// @param do_buf_event some callers like undo/redo call changed_lines() and
+/// then increment changedtick *again*. This flag allows these callers to send
+/// the nvim_buf_lines_event events after they're done modifying changedtick.
+void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra, bool do_buf_event)
{
changed_lines_buf(curbuf, lnum, lnume, xtra);
@@ -950,9 +950,10 @@ int copy_indent(int size, char_u *src)
/// "second_line_indent": indent for after ^^D in Insert mode or if flag
/// OPENLINE_COM_LIST
///
+/// @param dir FORWARD or BACKWARD
+///
/// @return true on success, false on failure
-int open_line(int dir, // FORWARD or BACKWARD
- int flags, int second_line_indent)
+int open_line(int dir, int flags, int second_line_indent)
{
char_u *next_line = NULL; // copy of the next line
char_u *p_extra = NULL; // what goes to next line
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 0ad7dddd33..f899ebf57c 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -310,7 +310,7 @@ void trans_characters(char_u *buf, int bufsize)
///
/// @return number of bytes needed to hold a translation of `s`, NUL byte not
/// included.
-size_t transstr_len(const char *const s)
+size_t transstr_len(const char *const s, bool untab)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
const char *p = s;
@@ -331,6 +331,9 @@ size_t transstr_len(const char *const s)
}
}
p += l;
+ } else if (*p == TAB && !untab) {
+ len += 1;
+ p++;
} else {
const int b2c_l = byte2cells((uint8_t)(*p++));
// Illegal byte sequence may occupy up to 4 characters.
@@ -346,9 +349,10 @@ size_t transstr_len(const char *const s)
/// @param[out] buf Buffer to which result should be saved.
/// @param[in] len Buffer length. Resulting string may not occupy more then
/// len - 1 bytes (one for trailing NUL byte).
+/// @param[in] untab remove tab characters
///
/// @return length of the resulting string, without the NUL byte.
-size_t transstr_buf(const char *const s, char *const buf, const size_t len)
+size_t transstr_buf(const char *const s, char *const buf, const size_t len, bool untab)
FUNC_ATTR_NONNULL_ALL
{
const char *p = s;
@@ -379,6 +383,8 @@ size_t transstr_buf(const char *const s, char *const buf, const size_t len)
}
}
p += l;
+ } else if (*p == TAB && !untab) {
+ *buf_p++ = *p++;
} else {
const char *const tb = (const char *)transchar_byte((uint8_t)(*p++));
const size_t tb_len = strlen(tb);
@@ -401,14 +407,14 @@ size_t transstr_buf(const char *const s, char *const buf, const size_t len)
/// @param[in] s String to replace characters from.
///
/// @return [allocated] translated string
-char *transstr(const char *const s)
+char *transstr(const char *const s, bool untab)
FUNC_ATTR_NONNULL_RET
{
// Compute the length of the result, taking account of unprintable
// multi-byte characters.
- const size_t len = transstr_len((const char *)s) + 1;
+ const size_t len = transstr_len((const char *)s, untab) + 1;
char *const buf = xmalloc(len);
- transstr_buf(s, buf, len);
+ transstr_buf(s, buf, len, untab);
return buf;
}
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 2eced03c03..e334fd166e 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -93,10 +93,10 @@ int coladvance(colnr_T wcol)
return rc;
}
-static int coladvance2(pos_T *pos, bool addspaces, // change the text to achieve our goal?
- bool finetune, // change char offset for the exact column
- colnr_T wcol_arg // column to move to (can be negative)
- )
+/// @param addspaces change the text to achieve our goal?
+/// @param finetune change char offset for the exact column
+/// @param wcol_arg column to move to (can be negative)
+static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_arg)
{
colnr_T wcol = wcol_arg;
int idx;
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c
index a5dd4cd485..58b1d9ce7f 100644
--- a/src/nvim/debugger.c
+++ b/src/nvim/debugger.c
@@ -398,7 +398,7 @@ void dbg_check_breakpoint(exarg_T *eap)
// replace K_SNR with "<SNR>"
if (debug_breakpoint_name[0] == K_SPECIAL
&& debug_breakpoint_name[1] == KS_EXTRA
- && debug_breakpoint_name[2] == (int)KE_SNR) {
+ && debug_breakpoint_name[2] == KE_SNR) {
p = (char_u *)"<SNR>";
} else {
p = (char_u *)"";
@@ -718,10 +718,11 @@ void ex_breaklist(exarg_T *eap)
/// Find a breakpoint for a function or sourced file.
/// Returns line number at which to break; zero when no matching breakpoint.
-linenr_T dbg_find_breakpoint(bool file, // true for a file, false for a function
- char_u *fname, // file or function name
- linenr_T after // after this line number
- )
+///
+/// @param file true for a file, false for a function
+/// @param fname file or function name
+/// @param after after this line number
+linenr_T dbg_find_breakpoint(bool file, char_u *fname, linenr_T after)
{
return debuggy_find(file, fname, after, &dbg_breakp, NULL);
}
@@ -738,12 +739,13 @@ bool has_profiling(bool file, char_u *fname, bool *fp)
}
/// Common code for dbg_find_breakpoint() and has_profiling().
-static linenr_T debuggy_find(bool file, // true for a file, false for a function
- char_u *fname, // file or function name
- linenr_T after, // after this line number
- garray_T *gap, // either &dbg_breakp or &prof_ga
- bool *fp // if not NULL: return forceit
- )
+///
+/// @param file true for a file, false for a function
+/// @param fname file or function name
+/// @param after after this line number
+/// @param gap either &dbg_breakp or &prof_ga
+/// @param fp if not NULL: return forceit
+static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T *gap, bool *fp)
{
struct debuggy *bp;
linenr_T lnum = 0;
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 0f21b47261..4e80528c74 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -37,7 +37,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
decor->priority = DECOR_PRIORITY_BASE;
// TODO(bfredl): if decoration had blocky mode, we could avoid this loop
- for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
+ for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum++) {
int end_off = 0;
if (pos_start.lnum < lnum && lnum < pos_end.lnum) {
// TODO(bfredl): This is quite ad-hoc, but the space between |num| and
@@ -59,7 +59,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start
hl_start = pos_start.col + offset;
hl_end = pos_end.col + offset;
}
- (void)extmark_set(buf, (uint64_t)src_id, 0,
+ (void)extmark_set(buf, (uint64_t)src_id, NULL,
(int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end,
decor, true, false, kExtmarkNoUndo);
}
@@ -412,3 +412,35 @@ void decor_free_all_mem(void)
}
kv_destroy(decor_providers);
}
+
+
+int decor_virtual_lines(win_T *wp, linenr_T lnum)
+{
+ buf_T *buf = wp->w_buffer;
+ if (!buf->b_virt_line_mark) {
+ return 0;
+ }
+ if (buf->b_virt_line_pos < 0) {
+ mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL);
+ if (pos.row < 0) {
+ buf->b_virt_line_mark = 0;
+ }
+ buf->b_virt_line_pos = pos.row + (buf->b_virt_line_above ? 0 : 1);
+ }
+
+ return (lnum-1 == buf->b_virt_line_pos) ? (int)kv_size(buf->b_virt_lines) : 0;
+}
+
+void clear_virt_lines(buf_T *buf, int row)
+{
+ if (row > -1) {
+ redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count,
+ row+1+(buf->b_virt_line_above?0:1)));
+ }
+ for (size_t i = 0; i < kv_size(buf->b_virt_lines); i++) {
+ clear_virttext(&kv_A(buf->b_virt_lines, i));
+ }
+ kv_destroy(buf->b_virt_lines); // re-initializes
+ buf->b_virt_line_pos = -1;
+ buf->b_virt_line_mark = 0;
+}
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 28dabeeada..35f5af87ed 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -7,14 +7,6 @@
// actual Decoration data is in extmark_defs.h
-typedef struct {
- char *text;
- int hl_id;
-} VirtTextChunk;
-
-typedef kvec_t(VirtTextChunk) VirtText;
-#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
-
typedef uint16_t DecorPriority;
#define DECOR_PRIORITY_BASE 0x1000
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 1d70145209..5c43b2498e 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -73,21 +73,21 @@ static TriState diff_a_works = kNone;
// used for diff input
typedef struct {
char_u *din_fname; // used for external diff
- mmfile_t din_mmfile; // used for internal diff
+ mmfile_t din_mmfile; // used for internal diff
} diffin_T;
// used for diff result
typedef struct {
char_u *dout_fname; // used for external diff
- garray_T dout_ga; // used for internal diff
+ garray_T dout_ga; // used for internal diff
} diffout_T;
// two diff inputs and one result
typedef struct {
- diffin_T dio_orig; // original file input
- diffin_T dio_new; // new file input
- diffout_T dio_diff; // diff result
- int dio_internal; // using internal diff
+ diffin_T dio_orig; // original file input
+ diffin_T dio_new; // new file input
+ diffout_T dio_diff; // diff result
+ int dio_internal; // using internal diff
} diffio_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -702,9 +702,9 @@ static void clear_diffout(diffout_T *dout)
/// @return FAIL for failure.
static int diff_write_buffer(buf_T *buf, diffin_T *din)
{
- linenr_T lnum;
+ linenr_T lnum;
char_u *s;
- long len = 0;
+ long len = 0;
char_u *ptr;
// xdiff requires one big block of memory with all the text.
@@ -732,7 +732,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
for (s = ml_get_buf(buf, lnum, false); *s != NUL; ) {
if (diff_flags & DIFF_ICASE) {
- char_u cbuf[MB_MAXBYTES + 1];
+ char_u cbuf[MB_MAXBYTES + 1];
// xdiff doesn't support ignoring case, fold-case the text.
int c = PTR2CHAR(s);
@@ -787,10 +787,10 @@ static int diff_write(buf_T *buf, diffin_T *din)
/// @param dio
/// @param idx_orig
/// @param eap can be NULL
-static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap)
+static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap)
{
buf_T *buf;
- int idx_new;
+ int idx_new;
if (dio->dio_internal) {
ga_init(&dio->dio_diff.dout_ga, sizeof(char *), 1000);
@@ -928,7 +928,7 @@ void ex_diffupdate(exarg_T *eap)
}
// Only use the internal method if it did not fail for one of the buffers.
- diffio_T diffio;
+ diffio_T diffio;
memset(&diffio, 0, sizeof(diffio));
diffio.dio_internal = diff_internal() && !diff_internal_failed();
@@ -1044,9 +1044,9 @@ static int check_external_diff(diffio_T *diffio)
///
static int diff_file_internal(diffio_T *diffio)
{
- xpparam_t param;
- xdemitconf_t emit_cfg;
- xdemitcb_t emit_cb;
+ xpparam_t param;
+ xdemitconf_t emit_cfg;
+ xdemitcb_t emit_cb;
memset(&param, 0, sizeof(param));
memset(&emit_cfg, 0, sizeof(emit_cfg));
@@ -1985,26 +1985,6 @@ static int diff_cmp(char_u *s1, char_u *s2)
return 0;
}
-/// Return the number of filler lines above "lnum".
-///
-/// @param wp
-/// @param lnum
-///
-/// @return Number of filler lines above lnum
-int diff_check_fill(win_T *wp, linenr_T lnum)
-{
- // be quick when there are no filler lines
- if (!(diff_flags & DIFF_FILLER)) {
- return 0;
- }
- int n = diff_check(wp, lnum);
-
- if (n <= 0) {
- return 0;
- }
- return n;
-}
-
/// Set the topline of "towin" to match the position in "fromwin", so that they
/// show the same diff'ed lines.
///
@@ -2030,6 +2010,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin)
}
towin->w_topfill = 0;
+
// search for a change that includes "lnum" in the list of diffblocks.
for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) {
if (lnum <= dp->df_lnum[fromidx] + dp->df_count[fromidx]) {
@@ -2255,6 +2236,13 @@ bool diffopt_closeoff(void)
return (diff_flags & DIFF_CLOSE_OFF) != 0;
}
+// Return true if 'diffopt' contains "filler".
+bool diffopt_filler(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return (diff_flags & DIFF_FILLER) != 0;
+}
+
/// Find the difference within a changed line.
///
/// @param wp window whose current buffer to check
@@ -3033,8 +3021,8 @@ static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, li
long *count_new)
{
char_u *p;
- long f1, l1, f2, l2;
- int difftype;
+ long f1, l1, f2, l2;
+ int difftype;
// The line must be one of three formats:
// change: {first}[,{last}]c{first}[,{last}]
@@ -3088,7 +3076,7 @@ static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_ori
linenr_T *lnum_new, long *count_new)
{
char_u *p;
- long oldline, oldcount, newline, newcount;
+ long oldline, oldcount, newline, newcount;
// Parse unified diff hunk header:
// @@ -oldline,oldcount +newline,newcount @@
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 20dc3cd06b..5ac733285d 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -116,7 +116,7 @@ static char *ctrl_x_msgs[] =
static char *ctrl_x_mode_names[] = {
"keyword",
"ctrl_x",
- "unknown", // CTRL_X_SCROLL
+ "scroll",
"whole_line",
"files",
"tags",
@@ -147,7 +147,7 @@ struct compl_S {
compl_T *cp_prev;
char_u *cp_str; // matched text
char_u *(cp_text[CPT_COUNT]); // text for the menu
- typval_T cp_user_data;
+ typval_T cp_user_data;
char_u *cp_fname; // file containing the match, allocated when
// cp_flags has CP_FREE_FNAME
int cp_flags; // CP_ values
@@ -3329,7 +3329,7 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
// Return Insert completion mode name string
static char_u *ins_compl_mode(void)
{
- if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || compl_started) {
+ if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || ctrl_x_mode == CTRL_X_SCROLL || compl_started) {
return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
}
return (char_u *)"";
@@ -3344,12 +3344,10 @@ static char_u *ins_compl_mode(void)
*/
static int ins_compl_bs(void)
{
- char_u *line;
- char_u *p;
-
- line = get_cursor_line_ptr();
- p = line + curwin->w_cursor.col;
+ char_u *line = get_cursor_line_ptr();
+ char_u *p = line + curwin->w_cursor.col;
MB_PTR_BACK(line, p);
+ ptrdiff_t p_off = p - line;
// Stop completion when the whole word was deleted. For Omni completion
// allow the word to be deleted, we won't match everything.
@@ -3369,8 +3367,12 @@ static int ins_compl_bs(void)
ins_compl_restart();
}
+ // ins_compl_restart() calls update_screen(0) which may invalidate the pointer
+ // TODO(bfredl): get rid of random update_screen() calls deep inside completion logic
+ line = get_cursor_line_ptr();
+
xfree(compl_leader);
- compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
+ compl_leader = vim_strnsave(line + compl_col, (int)p_off - compl_col);
ins_compl_new_leader();
if (compl_shown_match != NULL) {
// Make sure current match is not a hidden item.
@@ -5679,7 +5681,7 @@ static void insert_special(int c, int allow_modmask, int ctrlv)
* stop and defer processing to the "normal" mechanism.
* '0' and '^' are special, because they can be followed by CTRL-D.
*/
-# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
+#define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
#define WHITECHAR(cc) ( \
ascii_iswhite(cc) \
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 0b73d6b37f..768b82b464 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -5848,8 +5848,8 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate)
{
char_u *name;
char_u *string = NULL;
- int len;
- int cc;
+ int len;
+ int cc;
++*arg;
name = *arg;
@@ -6299,9 +6299,9 @@ int assert_fails(typval_T *argvars)
FUNC_ATTR_NONNULL_ALL
{
const char *const cmd = tv_get_string_chk(&argvars[0]);
- garray_T ga;
+ garray_T ga;
int ret = 0;
- int save_trylevel = trylevel;
+ int save_trylevel = trylevel;
// trylevel must be zero for a ":throw" command to be considered failed
trylevel = 0;
@@ -7345,7 +7345,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
const char *line = NULL;
list_T *l = NULL;
listitem_T *li = NULL;
- long added = 0;
+ long added = 0;
linenr_T append_lnum;
buf_T *curbuf_save = NULL;
win_T *curwin_save = NULL;
@@ -8807,9 +8807,9 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg)
char_u *newval = xmalloc(newval_len);
if (eap->force_bin == FORCE_BIN) {
- sprintf((char *)newval, " ++bin");
+ snprintf((char *)newval, newval_len, " ++bin");
} else if (eap->force_bin == FORCE_NOBIN) {
- sprintf((char *)newval, " ++nobin");
+ snprintf((char *)newval, newval_len, " ++nobin");
} else {
*newval = NUL;
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 762d741fb7..c6ac27b269 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -162,6 +162,7 @@ return {
getloclist={args={1, 2}},
getmarklist={args={0, 1}},
getmatches={args={0, 1}},
+ getmousepos={},
getpid={},
getpos={args=1},
getqflist={args={0, 1}},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index ff91f13444..5569d74413 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -80,16 +80,16 @@ KHASH_MAP_INIT_STR(functions, VimLFuncDef)
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/funcs.c.generated.h"
-#ifdef _MSC_VER
+# ifdef _MSC_VER
// This prevents MSVC from replacing the functions with intrinsics,
// and causing errors when trying to get their addresses in funcs.generated.h
-#pragma function(ceil)
-#pragma function(floor)
-#endif
+# pragma function(ceil)
+# pragma function(floor)
+# endif
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
-#include "funcs.generated.h"
+# include "funcs.generated.h"
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
#endif
@@ -248,7 +248,7 @@ static int non_zero_arg(typval_T *argvars)
static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
float_T f;
- float_T (*function)(float_T) = (float_T (*)(float_T))fptr;
+ float_T (*function)(float_T) = (float_T (*)(float_T)) fptr;
rettv->v_type = VAR_FLOAT;
if (tv_get_float_chk(argvars, &f)) {
@@ -1802,7 +1802,7 @@ static void f_did_filetype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
+ rettv->vval.v_number = MAX(0, diff_check(curwin, tv_get_lnum(argvars)));
}
/*
@@ -2695,13 +2695,13 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T foldstart;
- linenr_T foldend;
+ linenr_T foldstart;
+ linenr_T foldend;
char_u *dashes;
- linenr_T lnum;
+ linenr_T lnum;
char_u *s;
char_u *r;
- int len;
+ int len;
char *txt;
rettv->v_type = VAR_STRING;
@@ -3310,10 +3310,10 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char_u *pat;
- expand_T xpc;
- bool filtered = false;
- int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
- | WILD_NO_BEEP;
+ expand_T xpc;
+ bool filtered = false;
+ int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
+ | WILD_NO_BEEP;
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "type must be a string");
@@ -3750,6 +3750,59 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "getmousepos()" function
+void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ dict_T *d;
+ win_T *wp;
+ int row = mouse_row;
+ int col = mouse_col;
+ int grid = mouse_grid;
+ varnumber_T winid = 0;
+ varnumber_T winrow = 0;
+ varnumber_T wincol = 0;
+ linenr_T line = 0;
+ varnumber_T column = 0;
+
+ tv_dict_alloc_ret(rettv);
+ d = rettv->vval.v_dict;
+
+ tv_dict_add_nr(d, S_LEN("screenrow"), (varnumber_T)mouse_row + 1);
+ tv_dict_add_nr(d, S_LEN("screencol"), (varnumber_T)mouse_col + 1);
+
+ wp = mouse_find_win(&grid, &row, &col);
+ if (wp != NULL) {
+ int height = wp->w_height + wp->w_status_height;
+ // The height is adjusted by 1 when there is a bottom border. This is not
+ // necessary for a top border since `row` starts at -1 in that case.
+ if (row < height + wp->w_border_adj[2]) {
+ winid = wp->handle;
+ winrow = row + 1 + wp->w_border_adj[0]; // Adjust by 1 for top border
+ wincol = col + 1 + wp->w_border_adj[3]; // Adjust by 1 for left border
+ if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) {
+ char_u *p;
+ int count;
+
+ mouse_comp_pos(wp, &row, &col, &line);
+
+ // limit to text length plus one
+ p = ml_get_buf(wp->w_buffer, line, false);
+ count = (int)STRLEN(p);
+ if (col > count) {
+ col = count;
+ }
+
+ column = col + 1;
+ }
+ }
+ }
+ tv_dict_add_nr(d, S_LEN("winid"), winid);
+ tv_dict_add_nr(d, S_LEN("winrow"), winrow);
+ tv_dict_add_nr(d, S_LEN("wincol"), wincol);
+ tv_dict_add_nr(d, S_LEN("line"), (varnumber_T)line);
+ tv_dict_add_nr(d, S_LEN("column"), column);
+}
+
/*
* "getpid()" function
*/
@@ -4113,8 +4166,8 @@ static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
//
static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
{
- int dir;
- int height = wp->w_height;
+ int dir;
+ int height = wp->w_height;
win_T *oldwin = curwin;
if (wp == targetwin) {
@@ -4153,7 +4206,7 @@ static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
win_T *wp;
win_T *targetwin;
- int flags = 0, size = 0;
+ int flags = 0, size = 0;
wp = find_win_by_nr_or_id(&argvars[0]);
targetwin = find_win_by_nr_or_id(&argvars[1]);
@@ -5968,7 +6021,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
const SomeMatchType type)
{
char_u *str = NULL;
- long len = 0;
+ long len = 0;
char_u *expr = NULL;
regmatch_T regmatch;
char_u *save_cpo;
@@ -7250,17 +7303,17 @@ static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
buf[1] = NUL;
colnr_T reglen = 0;
switch (get_reg_type(regname, &reglen)) {
- case kMTLineWise:
- buf[0] = 'V';
- break;
- case kMTCharWise:
- buf[0] = 'v';
- break;
- case kMTBlockWise:
- vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1);
- break;
- case kMTUnknown:
- abort();
+ case kMTLineWise:
+ buf[0] = 'V';
+ break;
+ case kMTCharWise:
+ buf[0] = 'v';
+ break;
+ case kMTBlockWise:
+ vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1);
+ break;
+ case kMTUnknown:
+ abort();
}
tv_dict_add_str(dict, S_LEN("regtype"), buf);
@@ -9056,7 +9109,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
pos_T pos;
int fnum;
- colnr_T curswant = -1;
+ colnr_T curswant = -1;
rettv->vval.v_number = -1;
const char *const name = tv_get_string_chk(argvars);
@@ -9100,25 +9153,25 @@ static int get_yank_type(char_u **const pp, MotionType *const yank_type, long *c
{
char_u *stropt = *pp;
switch (*stropt) {
- case 'v':
- case 'c': // character-wise selection
- *yank_type = kMTCharWise;
- break;
- case 'V':
- case 'l': // line-wise selection
- *yank_type = kMTLineWise;
- break;
- case 'b':
- case Ctrl_V: // block-wise selection
- *yank_type = kMTBlockWise;
- if (ascii_isdigit(stropt[1])) {
- stropt++;
- *block_len = getdigits_long(&stropt, false, 0) - 1;
- stropt--;
- }
- break;
- default:
- return FAIL;
+ case 'v':
+ case 'c': // character-wise selection
+ *yank_type = kMTCharWise;
+ break;
+ case 'V':
+ case 'l': // line-wise selection
+ *yank_type = kMTLineWise;
+ break;
+ case 'b':
+ case Ctrl_V: // block-wise selection
+ *yank_type = kMTBlockWise;
+ if (ascii_isdigit(stropt[1])) {
+ stropt++;
+ *block_len = getdigits_long(&stropt, false, 0) - 1;
+ stropt--;
+ }
+ break;
+ default:
+ return FAIL;
}
*pp = stropt;
return OK;
@@ -9319,7 +9372,7 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static char *e_invact2 = N_("E962: Invalid action: '%s'");
win_T *wp;
dict_T *d;
- int action = 'r';
+ int action = 'r';
rettv->vval.v_number = -1;
@@ -10801,7 +10854,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]));
+ rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]), true);
}
/*
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 3bc4ec9381..075b50a366 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -100,7 +100,7 @@ void list_write_log(const char *const fname)
}
}
-#ifdef EXITFREE
+# ifdef EXITFREE
/// Free list log
void list_free_log(void)
{
@@ -110,7 +110,7 @@ void list_free_log(void)
chunk = list_log_first;
}
}
-#endif
+# endif
#endif
//{{{2 List item
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 77297f9ffa..657777d7db 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -39,7 +39,7 @@
#define FC_CFUNC 0x800 // C function extension
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "eval/userfunc.c.generated.h"
+# include "eval/userfunc.c.generated.h"
#endif
hashtab_T func_hashtab;
@@ -68,11 +68,11 @@ void func_init(void)
static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, int *varargs,
garray_T *default_args, bool skip)
{
- bool mustend = false;
+ bool mustend = false;
char_u *arg = *argp;
char_u *p = arg;
- int c;
- int i;
+ int c;
+ int i;
if (newargs != NULL) {
ga_init(newargs, (int)sizeof(char_u *), 3);
@@ -205,8 +205,8 @@ static void register_closure(ufunc_T *fp)
/// Get a name for a lambda. Returned in static memory.
char_u *get_lambda_name(void)
{
- static char_u name[30];
- static int lambda_no = 0;
+ static char_u name[30];
+ static int lambda_no = 0;
snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
return name;
@@ -217,16 +217,16 @@ char_u *get_lambda_name(void)
/// @return OK or FAIL. Returns NOTDONE for dict or {expr}.
int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
{
- garray_T newargs = GA_EMPTY_INIT_VALUE;
+ garray_T newargs = GA_EMPTY_INIT_VALUE;
garray_T *pnewargs;
ufunc_T *fp = NULL;
partial_T *pt = NULL;
- int varargs;
- int ret;
+ int varargs;
+ int ret;
char_u *start = skipwhite(*arg + 1);
char_u *s, *e;
bool *old_eval_lavars = eval_lavars_used;
- bool eval_lavars = false;
+ bool eval_lavars = false;
// First, check if this is a lambda expression. "->" must exists.
ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 8569b92d56..b34fd73d52 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -20,7 +20,7 @@
// For compatibility with libuv < 1.19.0 (tested on 1.18.0)
#if UV_VERSION_MINOR < 19
-#define uv_stream_get_write_queue_size(stream) stream->write_queue_size
+# define uv_stream_get_write_queue_size(stream) stream->write_queue_size
#endif
/// Sets the stream associated with `fd` to "blocking" mode.
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index f8186c000e..bbc1dd9717 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -1800,7 +1800,7 @@ int do_write(exarg_T *eap)
int retval = FAIL;
char_u *free_fname = NULL;
buf_T *alt_buf = NULL;
- int name_was_missing;
+ int name_was_missing;
if (not_writing()) { // check 'write' option
return FAIL;
@@ -2294,8 +2294,8 @@ int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T new
char_u *new_name = NULL;
bool did_set_swapcommand = false;
buf_T *buf;
- bufref_T bufref;
- bufref_T old_curbuf;
+ bufref_T bufref;
+ bufref_T old_curbuf;
char_u *free_fname = NULL;
int retval = FAIL;
long n;
@@ -3078,7 +3078,7 @@ void ex_change(exarg_T *eap)
void ex_z(exarg_T *eap)
{
char_u *x;
- int64_t bigness;
+ int64_t bigness;
char_u *kind;
int minus = 0;
linenr_T start, end, curs, i;
@@ -5549,8 +5549,9 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
if (add_help_tags
|| path_full_compare((char_u *)"$VIMRUNTIME/doc",
dir, false, true) == kEqualFiles) {
- s = xmalloc(18 + STRLEN(tagfname));
- sprintf((char *)s, "help-tags\t%s\t1\n", tagfname);
+ size_t s_len = 18 + STRLEN(tagfname);
+ s = xmalloc(s_len);
+ snprintf((char *)s, s_len, "help-tags\t%s\t1\n", tagfname);
GA_APPEND(char_u *, &ga, s);
}
@@ -5611,10 +5612,11 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
&& (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL
|| s[1] == '\0')) {
*p2 = '\0';
- ++p1;
- s = xmalloc((p2 - p1) + STRLEN(fname) + 2);
+ p1++;
+ size_t s_len= (p2 - p1) + STRLEN(fname) + 2;
+ s = xmalloc(s_len);
GA_APPEND(char_u *, &ga, s);
- sprintf((char *)s, "%s\t%s", p1, fname);
+ snprintf((char *)s, s_len, "%s\t%s", p1, fname);
// find next '*'
p2 = vim_strchr(p2 + 1, '*');
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 1a576bd891..46b86fbc84 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -109,7 +109,7 @@ struct source_cookie {
vimconv_T conv; ///< type of conversion
};
-# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
+#define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds2.c.generated.h"
@@ -317,7 +317,7 @@ static void profile_reset(void)
}
// Reset functions.
- size_t n = func_hashtab.ht_used;
+ size_t n = func_hashtab.ht_used;
hashitem_T *hi = func_hashtab.ht_array;
for (; n > (size_t)0; hi++) {
@@ -1703,8 +1703,8 @@ void init_pyxversion(void)
static int requires_py_version(char_u *filename)
{
FILE *file;
- int requires_py_version = 0;
- int i, lines;
+ int requires_py_version = 0;
+ int i, lines;
lines = (int)p_mls;
if (lines < 0) {
@@ -2340,7 +2340,7 @@ void ex_scriptnames(exarg_T *eap)
}
}
-# if defined(BACKSLASH_IN_FILENAME)
+#if defined(BACKSLASH_IN_FILENAME)
/// Fix slashes in the list of script names for 'shellslash'.
void scriptnames_slash_adjust(void)
{
@@ -2351,7 +2351,7 @@ void scriptnames_slash_adjust(void)
}
}
-# endif
+#endif
/// Get a pointer to a script name. Used for ":verbose set".
/// Message appended to "Last set from "
@@ -2388,7 +2388,7 @@ char_u *get_scriptname(LastSet last_set, bool *should_free)
}
}
-# if defined(EXITFREE)
+#if defined(EXITFREE)
void free_scriptnames(void)
{
profile_reset();
@@ -2396,7 +2396,7 @@ void free_scriptnames(void)
# define FREE_SCRIPTNAME(item) xfree((item)->sn_name)
GA_DEEP_CLEAR(&script_items, scriptitem_T, FREE_SCRIPTNAME);
}
-# endif
+#endif
linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie)
{
@@ -2786,17 +2786,17 @@ char *get_mess_lang(void)
{
char *p;
-# ifdef HAVE_GET_LOCALE_VAL
-# if defined(LC_MESSAGES)
+#ifdef HAVE_GET_LOCALE_VAL
+# if defined(LC_MESSAGES)
p = get_locale_val(LC_MESSAGES);
-# else
+# else
// This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
// may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
// and LC_MONETARY may be set differently for a Japanese working in the
// US.
p = get_locale_val(LC_COLLATE);
-# endif
-# else
+# endif
+#else
p = os_getenv("LC_ALL");
if (!is_valid_mess_lang(p)) {
p = os_getenv("LC_MESSAGES");
@@ -2804,7 +2804,7 @@ char *get_mess_lang(void)
p = os_getenv("LANG");
}
}
-# endif
+#endif
return is_valid_mess_lang(p) ? p : NULL;
}
@@ -2842,37 +2842,37 @@ void set_lang_var(void)
{
const char *loc;
-# ifdef HAVE_GET_LOCALE_VAL
+#ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_CTYPE);
-# else
+#else
// setlocale() not supported: use the default value
loc = "C";
-# endif
+#endif
set_vim_var_string(VV_CTYPE, loc, -1);
// When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
// back to LC_CTYPE if it's empty.
-# ifdef HAVE_WORKING_LIBINTL
+#ifdef HAVE_WORKING_LIBINTL
loc = (char *)get_mess_env();
-# elif defined(LC_MESSAGES)
+#elif defined(LC_MESSAGES)
loc = get_locale_val(LC_MESSAGES);
-# else
+#else
// In Windows LC_MESSAGES is not defined fallback to LC_CTYPE
loc = get_locale_val(LC_CTYPE);
-# endif
+#endif
set_vim_var_string(VV_LANG, loc, -1);
-# ifdef HAVE_GET_LOCALE_VAL
+#ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_TIME);
-# endif
+#endif
set_vim_var_string(VV_LC_TIME, loc, -1);
-# ifdef HAVE_GET_LOCALE_VAL
+#ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_COLLATE);
-# else
+#else
// setlocale() not supported: use the default value
loc = "C";
-# endif
+#endif
set_vim_var_string(VV_COLLATE, loc, -1);
}
@@ -2889,11 +2889,11 @@ void ex_language(exarg_T *eap)
char_u *name;
int what = LC_ALL;
char *whatstr = "";
-#ifdef LC_MESSAGES
-# define VIM_LC_MESSAGES LC_MESSAGES
-#else
-# define VIM_LC_MESSAGES 6789
-#endif
+# ifdef LC_MESSAGES
+# define VIM_LC_MESSAGES LC_MESSAGES
+# else
+# define VIM_LC_MESSAGES 6789
+# endif
name = eap->arg;
@@ -2922,43 +2922,43 @@ void ex_language(exarg_T *eap)
}
if (*name == NUL) {
-#ifdef HAVE_WORKING_LIBINTL
+# ifdef HAVE_WORKING_LIBINTL
if (what == VIM_LC_MESSAGES) {
p = get_mess_env();
} else {
-#endif
+# endif
p = (char_u *)setlocale(what, NULL);
-#ifdef HAVE_WORKING_LIBINTL
+# ifdef HAVE_WORKING_LIBINTL
}
-#endif
+# endif
if (p == NULL || *p == NUL) {
p = (char_u *)"Unknown";
}
smsg(_("Current %slanguage: \"%s\""), whatstr, p);
} else {
-#ifndef LC_MESSAGES
+# ifndef LC_MESSAGES
if (what == VIM_LC_MESSAGES) {
loc = "";
} else {
-#endif
+# endif
loc = setlocale(what, (char *)name);
-#ifdef LC_NUMERIC
+# ifdef LC_NUMERIC
// Make sure strtod() uses a decimal point, not a comma.
setlocale(LC_NUMERIC, "C");
-#endif
-#ifndef LC_MESSAGES
+# endif
+# ifndef LC_MESSAGES
}
-#endif
+# endif
if (loc == NULL) {
EMSG2(_("E197: Cannot set language to \"%s\""), name);
} else {
-#ifdef HAVE_NL_MSG_CAT_CNTR
+# ifdef HAVE_NL_MSG_CAT_CNTR
// Need to do this for GNU gettext, otherwise cached translations
// will be used again.
extern int _nl_msg_cat_cntr;
_nl_msg_cat_cntr++;
-#endif
+# endif
// Reset $LC_ALL, otherwise it would overrule everything.
os_setenv("LC_ALL", "", 1);
@@ -2987,7 +2987,7 @@ void ex_language(exarg_T *eap)
static char_u **locales = NULL; // Array of all available locales
-#ifndef WIN32
+# ifndef WIN32
static bool did_init_locales = false;
/// Return an array of strings for all available locales + NULL for the
@@ -3022,20 +3022,20 @@ static char_u **find_locales(void)
((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
return (char_u **)locales_ga.ga_data;
}
-#endif
+# endif
/// Lazy initialization of all available locales.
static void init_locales(void)
{
-#ifndef WIN32
+# ifndef WIN32
if (!did_init_locales) {
did_init_locales = true;
locales = find_locales();
}
-#endif
+# endif
}
-# if defined(EXITFREE)
+# if defined(EXITFREE)
void free_locales(void)
{
int i;
@@ -3047,7 +3047,7 @@ void free_locales(void)
}
}
-# endif
+# endif
/// Function given to ExpandGeneric() to obtain the possible arguments of the
/// ":language" command.
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 68dd039278..dff3b4223b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -99,7 +99,7 @@ static garray_T ucmds = { 0, 0, sizeof(ucmd_T), 4, NULL };
#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i])
// Whether a command index indicates a user command.
-# define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
+#define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
// Struct for storing a line inside a while/for loop
typedef struct {
@@ -5637,7 +5637,7 @@ static void ex_command(exarg_T *eap)
uint32_t argt = 0;
long def = -1;
int flags = 0;
- int compl = EXPAND_NOTHING;
+ int compl = EXPAND_NOTHING;
char_u *compl_arg = NULL;
cmd_addr_T addr_type_arg = ADDR_NONE;
int has_attr = (eap->arg[0] == '-');
@@ -6949,7 +6949,7 @@ static void ex_goto(exarg_T *eap)
*/
void alist_clear(alist_T *al)
{
-# define FREE_AENTRY_FNAME(arg) xfree(arg->ae_fname)
+#define FREE_AENTRY_FNAME(arg) xfree(arg->ae_fname)
GA_DEEP_CLEAR(&al->al_ga, aentry_T, FREE_AENTRY_FNAME);
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index ddf60eac18..a9990df58f 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -140,25 +140,25 @@ static unsigned last_prompt_id = 0;
// Struct to store the viewstate during 'incsearch' highlighting.
typedef struct {
- colnr_T vs_curswant;
- colnr_T vs_leftcol;
- linenr_T vs_topline;
- int vs_topfill;
- linenr_T vs_botline;
- int vs_empty_rows;
+ colnr_T vs_curswant;
+ colnr_T vs_leftcol;
+ linenr_T vs_topline;
+ int vs_topfill;
+ linenr_T vs_botline;
+ int vs_empty_rows;
} viewstate_T;
// Struct to store the state of 'incsearch' highlighting.
typedef struct {
- pos_T search_start; // where 'incsearch' starts searching
- pos_T save_cursor;
+ pos_T search_start; // where 'incsearch' starts searching
+ pos_T save_cursor;
viewstate_T init_viewstate;
viewstate_T old_viewstate;
- pos_T match_start;
- pos_T match_end;
- bool did_incsearch;
- bool incsearch_postponed;
- int magic_save;
+ pos_T match_start;
+ pos_T match_end;
+ bool did_incsearch;
+ bool incsearch_postponed;
+ int magic_save;
} incsearch_state_T;
typedef struct command_line_state {
@@ -178,8 +178,8 @@ typedef struct command_line_state {
int did_wild_list; // did wild_list() recently
int wim_index; // index in wim_flags[]
int res;
- int save_msg_scroll;
- int save_State; // remember State when called
+ int save_msg_scroll;
+ int save_State; // remember State when called
char_u *save_p_icm;
int some_key_typed; // one of the keys was typed
// mouse drag and release events are ignored, unless they are
@@ -383,7 +383,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
// Don't do 'hlsearch' highlighting if the pattern matches everything.
if (!use_last_pat) {
char_u c = *end;
- int empty;
+ int empty;
*end = NUL;
empty = empty_pattern(p);
@@ -1502,7 +1502,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_
ui_busy_start();
ui_flush();
- pos_T t;
+ pos_T t;
char_u *pat;
int search_flags = SEARCH_NOOF;
char_u save;
@@ -2570,13 +2570,13 @@ static void realloc_cmdbuff(int len)
static char_u *arshape_buf = NULL;
-# if defined(EXITFREE)
+#if defined(EXITFREE)
void free_arshape_buf(void)
{
xfree(arshape_buf);
}
-# endif
+#endif
enum { MAX_CB_ERRORS = 1 };
@@ -4111,7 +4111,7 @@ char *vim_strsave_fnameescape(const char *const fname, const bool shell FUNC_ATT
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
#ifdef BACKSLASH_IN_FILENAME
-#define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<"
+# define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<"
char_u buf[sizeof(PATH_ESC_CHARS)];
int j = 0;
@@ -4125,8 +4125,8 @@ char *vim_strsave_fnameescape(const char *const fname, const bool shell FUNC_ATT
char *p = (char *)vim_strsave_escaped((const char_u *)fname,
(const char_u *)buf);
#else
-#define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
-#define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
+# define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
+# define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
char *p =
(char *)vim_strsave_escaped((const char_u *)fname, (shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS));
if (shell && csh_like_shell()) {
@@ -5272,7 +5272,7 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)
{
char_u *e;
- garray_T ga;
+ garray_T ga;
char_u *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp, num_file,
file);
@@ -6250,8 +6250,8 @@ int hist_type2char(int type)
static int open_cmdwin(void)
{
struct cmdline_info save_ccline;
- bufref_T old_curbuf;
- bufref_T bufref;
+ bufref_T old_curbuf;
+ bufref_T bufref;
win_T *old_curwin = curwin;
win_T *wp;
int i;
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 819b8ad3dc..cf01c305d7 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -56,8 +56,8 @@ static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
/// Create or update an extmark
///
/// must not be used during iteration!
-/// @returns the mark id
-uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id, int row, colnr_T col, int end_row,
+/// @returns the internal mark id
+uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t *idp, int row, colnr_T col, int end_row,
colnr_T end_col, Decoration *decor, bool right_gravity, bool end_right_gravity,
ExtmarkOp op)
{
@@ -65,6 +65,7 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id, int row, colnr_T c
assert(ns != NULL);
mtpos_t old_pos;
uint64_t mark = 0;
+ uint64_t id = idp ? *idp : 0;
if (id == 0) {
id = ns->free_id++;
@@ -118,7 +119,11 @@ revised:
if (decor) {
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
}
- return id;
+
+ if (idp) {
+ *idp = id;
+ }
+ return mark;
}
static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col)
@@ -169,6 +174,10 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
decor_free(item.decor);
}
+ if (mark == buf->b_virt_line_mark) {
+ clear_virt_lines(buf, pos.row);
+ }
+
map_del(uint64_t, uint64_t)(ns->map, id);
map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark);
@@ -227,6 +236,9 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_r
}
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
+ if (start_id == buf->b_virt_line_mark) {
+ clear_virt_lines(buf, mark.row);
+ }
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
start_id);
@@ -496,6 +508,7 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
kExtmarkNoUndo);
}
}
+ curbuf->b_virt_line_pos = -1;
}
@@ -574,7 +587,8 @@ void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t
int old_row, colnr_T old_col, bcount_t old_byte, int new_row,
colnr_T new_col, bcount_t new_byte, ExtmarkOp undo)
{
- curbuf->deleted_bytes2 = 0;
+ buf->deleted_bytes2 = 0;
+ buf->b_virt_line_pos = -1;
buf_updates_send_splice(buf, start_row, start_col, start_byte,
old_row, old_col, old_byte,
new_row, new_col, new_byte);
@@ -665,7 +679,8 @@ void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, bcount_t
int extent_row, colnr_T extent_col, bcount_t extent_byte, int new_row,
colnr_T new_col, bcount_t new_byte, ExtmarkOp undo)
{
- curbuf->deleted_bytes2 = 0;
+ buf->deleted_bytes2 = 0;
+ buf->b_virt_line_pos = -1;
// TODO(bfredl): this is not synced to the buffer state inside the callback.
// But unless we make the undo implementation smarter, this is not ensured
// anyway.
diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h
index b5d91382ec..2da4f3dc00 100644
--- a/src/nvim/extmark_defs.h
+++ b/src/nvim/extmark_defs.h
@@ -6,6 +6,16 @@
typedef struct Decoration Decoration;
+typedef struct {
+ char *text;
+ int hl_id;
+} VirtTextChunk;
+
+typedef kvec_t(VirtTextChunk) VirtText;
+#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
+typedef kvec_t(VirtText) VirtLines;
+
+
typedef struct
{
uint64_t ns_id;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 31af47999b..f5a4efc371 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -65,7 +65,7 @@
// For compatibility with libuv < 1.20.0 (tested on 1.18.0)
#ifndef UV_FS_COPYFILE_FICLONE
-#define UV_FS_COPYFILE_FICLONE 0
+# define UV_FS_COPYFILE_FICLONE 0
#endif
#define HAS_BW_FLAGS
@@ -105,9 +105,9 @@ struct bw_info {
int bw_conv_error; // set for conversion error
linenr_T bw_conv_error_lnum; // first line with error or zero
linenr_T bw_start_lnum; // line number at start of buffer
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
iconv_t bw_iconv_fd; // descriptor for iconv() or -1
-# endif
+#endif
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -233,11 +233,11 @@ int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_ski
char_u *fenc_next = NULL; // next item in 'fencs' or NULL
bool advance_fenc = false;
long real_size = 0;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1
bool did_iconv = false; // true when iconv() failed and trying
// 'charconvert' next
-# endif
+#endif
bool converted = false; // true if conversion done
bool notconverted = false; // true if conversion wanted but it wasn't possible
char_u conv_rest[CONV_RESTLEN];
@@ -373,10 +373,10 @@ int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_ski
if (perm >= 0 && !S_ISREG(perm) // not a regular file ...
&& !S_ISFIFO(perm) // ... or fifo
&& !S_ISSOCK(perm) // ... or socket
-# ifdef OPEN_CHR_FILES
+#ifdef OPEN_CHR_FILES
&& !(S_ISCHR(perm) && is_dev_fd_file(fname))
// ... or a character special file named /dev/fd/<n>
-# endif
+#endif
) {
if (S_ISDIR(perm)) {
filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
@@ -493,11 +493,11 @@ int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_ski
} else {
filemess(curbuf, sfname, (char_u *)(
(fd == UV_EFBIG) ? _("[File too big]") :
-# if defined(UNIX) && defined(EOVERFLOW)
+#if defined(UNIX) && defined(EOVERFLOW)
// libuv only returns -errno in Unix and in Windows open() does not
// set EOVERFLOW
(fd == -EOVERFLOW) ? _("[File too big]") :
-# endif
+#endif
_("[Permission Denied]")), 0);
curbuf->b_p_ro = TRUE; // must use "w!" now
}
@@ -768,13 +768,13 @@ retry:
}
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
// aborted conversion with iconv(), close the descriptor
iconv_close(iconv_fd);
iconv_fd = (iconv_t)-1;
}
-# endif
+#endif
if (advance_fenc) {
/*
@@ -833,13 +833,13 @@ retry:
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
// Try using iconv() if we can't convert internally.
if (fio_flags == 0
&& !did_iconv) {
iconv_fd = (iconv_t)my_iconv_open((char_u *)"utf-8", fenc);
}
-# endif
+#endif
/*
* Use the 'charconvert' expression when conversion is required
@@ -847,13 +847,13 @@ retry:
*/
if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
&& !read_fifo
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
&& iconv_fd == (iconv_t)-1
-# endif
+#endif
) {
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
did_iconv = false;
-# endif
+#endif
/* Skip conversion when it's already done (retry for wrong
* "fileformat"). */
if (tmpname == NULL) {
@@ -872,9 +872,9 @@ retry:
}
} else {
if (fio_flags == 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
&& iconv_fd == (iconv_t)-1
-# endif
+#endif
) {
/* Conversion wanted but we can't.
* Try the next conversion in 'fileencodings' */
@@ -960,11 +960,11 @@ retry:
* ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
* multiple of 4 */
real_size = (int)size;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
size = size / ICONV_MULT;
} else {
-# endif
+#endif
if (fio_flags & FIO_LATIN1) {
size = size / 2;
} else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) {
@@ -974,9 +974,9 @@ retry:
} else if (fio_flags == FIO_UCSBOM) {
size = size / ICONV_MULT; // worst case
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
}
-# endif
+#endif
if (conv_restlen > 0) {
// Insert unconverted bytes from previous line.
memmove(ptr, conv_rest, conv_restlen); // -V614
@@ -1055,9 +1055,9 @@ retry:
// When we did a conversion report an error.
if (fio_flags != 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
|| iconv_fd != (iconv_t)-1
-# endif
+#endif
) {
if (can_retry) {
goto rewind_retry;
@@ -1081,9 +1081,9 @@ retry:
* leave the UTF8 checking code to do it, as it
* works slightly differently. */
if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
|| iconv_fd != (iconv_t)-1
-# endif
+#endif
)) {
while (conv_restlen > 0) {
*(--ptr) = bad_char_behavior;
@@ -1091,12 +1091,12 @@ retry:
}
}
fio_flags = 0; // don't convert this
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
iconv_fd = (iconv_t)-1;
}
-# endif
+#endif
}
}
}
@@ -1165,7 +1165,7 @@ retry:
break;
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
/*
* Attempt conversion of the read bytes to 'encoding' using
@@ -1223,7 +1223,7 @@ retry:
memmove(line_start, buffer, (size_t)linerest);
size = ((char_u *)top - ptr);
}
-# endif
+#endif
if (fio_flags != 0) {
unsigned int u8c;
@@ -1441,12 +1441,12 @@ retry:
if (can_retry && !incomplete_tail) {
break;
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
// When we did a conversion report an error.
if (iconv_fd != (iconv_t)-1 && conv_error == 0) {
conv_error = readfile_linenr(linecnt, ptr, p);
}
-# endif
+#endif
// Remember the first linenr with an illegal byte
if (conv_error == 0 && illegal_byte == 0) {
illegal_byte = readfile_linenr(linecnt, ptr, p);
@@ -1469,17 +1469,17 @@ retry:
// Detected a UTF-8 error.
rewind_retry:
// Retry reading with another conversion.
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) {
// iconv() failed, try 'charconvert'
did_iconv = true;
} else {
-# endif
+#endif
// use next item from 'fileencodings'
advance_fenc = true;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
}
-# endif
+#endif
file_rewind = true;
goto retry;
}
@@ -1700,11 +1700,11 @@ failed:
if (fenc_alloced) {
xfree(fenc);
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
}
-# endif
+#endif
if (!read_buffer && !read_stdin) {
close(fd); // errors are ignored
@@ -2280,9 +2280,9 @@ int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_
write_info.bw_conv_error = FALSE;
write_info.bw_conv_error_lnum = 0;
write_info.bw_restlen = 0;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
write_info.bw_iconv_fd = (iconv_t)-1;
-# endif
+#endif
/* After writing a file changedtick changes but we don't want to display
* the line. */
@@ -2690,7 +2690,7 @@ int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_
if (fd < 0) { // can't write in directory
backup_copy = TRUE;
} else {
-# ifdef UNIX
+#ifdef UNIX
os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
if (!os_fileinfo((char *)IObuff, &file_info)
|| file_info.stat.st_uid != file_info_old.stat.st_uid
@@ -2698,7 +2698,7 @@ int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_
|| (long)file_info.stat.st_mode != perm) {
backup_copy = TRUE;
}
-# endif
+#endif
/* Close the file before removing it, on MS-Windows we
* can't delete an open file. */
close(fd);
@@ -2711,7 +2711,7 @@ int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_
* Break symlinks and/or hardlinks if we've been asked to.
*/
if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) {
-# ifdef UNIX
+#ifdef UNIX
bool file_info_link_ok = os_fileinfo_link((char *)fname, &file_info);
// Symlinks.
@@ -2728,7 +2728,7 @@ int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_
|| os_fileinfo_id_equal(&file_info, &file_info_old))) {
backup_copy = FALSE;
}
-# endif
+#endif
}
// make sure we have a valid backup extension to use
@@ -3085,7 +3085,7 @@ nobackup:
if (converted && wb_flags == 0) {
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
// Use iconv() conversion when conversion is needed and it's not done
// internally.
write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, (char_u *)"utf-8");
@@ -3098,7 +3098,7 @@ nobackup:
}
write_info.bw_first = TRUE;
} else
-# endif
+#endif
/*
* When the file needs to be converted with 'charconvert' after
@@ -3114,9 +3114,9 @@ nobackup:
}
}
if (converted && wb_flags == 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
&& write_info.bw_iconv_fd == (iconv_t)-1
-# endif
+#endif
&& wfname == fname) {
if (!forceit) {
SET_ERRMSG(_("E213: Cannot convert (add ! to write without conversion)"));
@@ -3644,12 +3644,12 @@ nofail:
}
xfree(fenc_tofree);
xfree(write_info.bw_conv_buf);
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (write_info.bw_iconv_fd != (iconv_t)-1) {
iconv_close(write_info.bw_iconv_fd);
write_info.bw_iconv_fd = (iconv_t)-1;
}
-# endif
+#endif
#ifdef HAVE_ACL
mch_free_acl(acl);
#endif
@@ -4034,7 +4034,7 @@ static int buf_write_bytes(struct bw_info *ip)
}
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (ip->bw_iconv_fd != (iconv_t)-1) {
const char *from;
size_t fromlen;
@@ -4096,7 +4096,7 @@ static int buf_write_bytes(struct bw_info *ip)
buf = ip->bw_conv_buf;
len = (int)((char_u *)to - ip->bw_conv_buf);
}
-# endif
+#endif
}
if (ip->bw_fd < 0) {
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 7a017702ee..06b8049176 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1414,7 +1414,7 @@ static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
*/
void deleteFoldRecurse(buf_T *bp, garray_T *gap)
{
-# define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(bp, &((fd)->fd_nested))
+#define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(bp, &((fd)->fd_nested))
GA_DEEP_CLEAR(gap, fold_T, DELETE_FOLD_NESTED);
}
@@ -1875,7 +1875,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin
}
}
if (*p != NUL) {
- p = (char_u *)transstr((const char *)text);
+ p = (char_u *)transstr((const char *)text, true);
xfree(text);
text = p;
}
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index c9ab0cf709..a5f76e1c6a 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -17,7 +17,7 @@ local fill = ws ^ 0
local c_comment = P('//') * (not_nl ^ 0)
local c_preproc = P('#') * (not_nl ^ 0)
local typed_container =
- (P('ArrayOf(') + P('DictionaryOf(')) * ((any - P(')')) ^ 1) * P(')')
+ (P('ArrayOf(') + P('DictionaryOf(') + P('Dict(')) * ((any - P(')')) ^ 1) * P(')')
local c_id = (
typed_container +
(letter * (alpha ^ 0))
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 99d80cdebc..6ed2e5dab8 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -152,6 +152,8 @@ for _,f in ipairs(functions) do
for i,param in ipairs(f.parameters) do
if param[1] == "DictionaryOf(LuaRef)" then
param = {"Dictionary", param[2]}
+ elseif startswith(param[1], "Dict(") then
+ param = {"Dictionary", param[2]}
end
f_exported.parameters[i] = param
end
@@ -173,7 +175,10 @@ local output = io.open(dispatch_outputf, 'wb')
local function real_type(type)
local rv = type
- if c_grammar.typed_container:match(rv) then
+ local rmatch = string.match(type, "Dict%(([_%w]+)%)")
+ if rmatch then
+ return "KeyDict_"..rmatch
+ elseif c_grammar.typed_container:match(rv) then
if rv:match('Array') then
rv = 'Array'
else
@@ -209,8 +214,9 @@ for i = 1, #functions do
-- Declare/initialize variables that will hold converted arguments
for j = 1, #fn.parameters do
local param = fn.parameters[j]
+ local rt = real_type(param[1])
local converted = 'arg_'..j
- output:write('\n '..param[1]..' '..converted..';')
+ output:write('\n '..rt..' '..converted..';')
end
output:write('\n')
output:write('\n if (args.size != '..#fn.parameters..') {')
@@ -225,7 +231,24 @@ for i = 1, #functions do
param = fn.parameters[j]
converted = 'arg_'..j
local rt = real_type(param[1])
- if rt ~= 'Object' then
+ if rt == 'Object' then
+ output:write('\n '..converted..' = args.items['..(j - 1)..'];\n')
+ elseif rt:match('^KeyDict_') then
+ converted = '&' .. converted
+ output:write('\n if (args.items['..(j - 1)..'].type == kObjectTypeDictionary) {') --luacheck: ignore 631
+ output:write('\n memset('..converted..', 0, sizeof(*'..converted..'));') -- TODO: neeeee
+ output:write('\n if (!api_dict_to_keydict('..converted..', '..rt..'_get_field, args.items['..(j - 1)..'].data.dictionary, error)) {')
+ output:write('\n goto cleanup;')
+ output:write('\n }')
+ output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeArray && args.items['..(j - 1)..'].data.array.size == 0) {') --luacheck: ignore 631
+ output:write('\n memset('..converted..', 0, sizeof(*'..converted..'));')
+
+ output:write('\n } else {')
+ output:write('\n api_set_error(error, kErrorTypeException, \
+ "Wrong type for argument '..j..' when calling '..fn.name..', expecting '..param[1]..'");')
+ output:write('\n goto cleanup;')
+ output:write('\n }\n')
+ else
if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') then
-- Buffer, Window, and Tabpage have a specific type, but are stored in integer
output:write('\n if (args.items['..
@@ -257,10 +280,7 @@ for i = 1, #functions do
"Wrong type for argument '..j..' when calling '..fn.name..', expecting '..param[1]..'");')
output:write('\n goto cleanup;')
output:write('\n }\n')
- else
- output:write('\n '..converted..' = args.items['..(j - 1)..'];\n')
end
-
args[#args + 1] = converted
end
@@ -423,13 +443,24 @@ local function process_function(fn)
if param[1] == "DictionaryOf(LuaRef)" then
extra = "true, "
end
+ local errshift = 0
+ if string.match(param_type, '^KeyDict_') then
+ write_shifted_output(output, string.format([[
+ %s %s = { 0 }; nlua_pop_keydict(lstate, &%s, %s_get_field, %s&err);]], param_type, cparam, cparam, param_type, extra))
+ cparam = '&'..cparam
+ errshift = 1 -- free incomplete dict on error
+ else
+ write_shifted_output(output, string.format([[
+ const %s %s = nlua_pop_%s(lstate, %s&err);]], param[1], cparam, param_type, extra))
+ end
+
write_shifted_output(output, string.format([[
- const %s %s = nlua_pop_%s(lstate, %s&err);
if (ERROR_SET(&err)) {
goto exit_%u;
}
- ]], param[1], cparam, param_type, extra, #fn.parameters - j))
+
+ ]], #fn.parameters - j + errshift))
free_code[#free_code + 1] = ('api_free_%s(%s);'):format(
lc_param_type, cparam)
cparams = cparam .. ', ' .. cparams
@@ -446,7 +477,7 @@ local function process_function(fn)
for i = 1, #free_code do
local rev_i = #free_code - i + 1
local code = free_code[rev_i]
- if i == 1 then
+ if i == 1 and not string.match(real_type(fn.parameters[1][1]), '^KeyDict_') then
free_at_exit_code = free_at_exit_code .. ('\n %s'):format(code)
else
free_at_exit_code = free_at_exit_code .. ('\n exit_%u:\n %s'):format(
diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua
index 0782c8115d..97491679a4 100755
--- a/src/nvim/generators/gen_declarations.lua
+++ b/src/nvim/generators/gen_declarations.lua
@@ -60,7 +60,7 @@ local right_word = concat(
)
local word = branch(
concat(
- branch(lit('ArrayOf('), lit('DictionaryOf(')), -- typed container macro
+ branch(lit('ArrayOf('), lit('DictionaryOf('), lit('Dict(')), -- typed container macro
one_or_more(any_character - lit(')')),
lit(')')
),
diff --git a/src/nvim/generators/gen_keysets.lua b/src/nvim/generators/gen_keysets.lua
new file mode 100644
index 0000000000..63ef202fe1
--- /dev/null
+++ b/src/nvim/generators/gen_keysets.lua
@@ -0,0 +1,67 @@
+
+local nvimsrcdir = arg[1]
+local shared_file = arg[2]
+local funcs_file = arg[3]
+local defs_file = arg[4]
+
+_G.vim = loadfile(shared_file)()
+
+if nvimsrcdir == '--help' then
+ print([[
+Usage:
+ lua gen_keyset.lua TODOFIXUPDATETHIS
+
+Will generate build/src/nvim/auto/keyset.generated.h with definition of functions
+static const array.
+]])
+ os.exit(0)
+end
+
+
+package.path = nvimsrcdir .. '/?.lua;' .. package.path
+local hashy = require'generators.hashy'
+
+local funcspipe = io.open(funcs_file, 'wb')
+local defspipe = io.open(defs_file, 'wb')
+
+local keysets = require'api.keysets'
+
+for name, keys in pairs(keysets) do
+ local neworder, hashfun = hashy.hashy_hash(name, keys, function (idx)
+ return name.."_table["..idx.."].str"
+ end)
+
+ defspipe:write("typedef struct {\n")
+ for _, key in ipairs(neworder) do
+ defspipe:write(" Object "..key..";\n")
+ end
+ defspipe:write("} KeyDict_"..name..";\n\n")
+
+ defspipe:write("extern KeySetLink "..name.."_table[];\n")
+
+ funcspipe:write("KeySetLink "..name.."_table[] = {\n")
+ for _, key in ipairs(neworder) do
+ funcspipe:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..key..")},\n")
+ end
+ funcspipe:write(' {NULL, 0},\n')
+ funcspipe:write("};\n\n")
+
+ funcspipe:write(hashfun)
+
+ funcspipe:write([[
+Object *KeyDict_]]..name..[[_get_field(void *retval, const char *str, size_t len)
+{
+ int hash = ]]..name..[[_hash(str, len);
+ if (hash == -1) {
+ return NULL;
+ }
+
+ return (Object *)((char *)retval + ]]..name..[[_table[hash].ptr_off);
+}
+
+]])
+ defspipe:write("#define api_free_keydict_"..name.."(x) api_free_keydict(x, "..name.."_table)\n")
+end
+
+funcspipe:close()
+defspipe:close()
diff --git a/src/nvim/generators/hashy.lua b/src/nvim/generators/hashy.lua
new file mode 100644
index 0000000000..fac24c810a
--- /dev/null
+++ b/src/nvim/generators/hashy.lua
@@ -0,0 +1,122 @@
+-- HASHY McHASHFACE
+
+local M = {}
+_G.d = M
+
+
+local function setdefault(table, key)
+ local val = table[key]
+ if val == nil then
+ val = {}
+ table[key] = val
+ end
+ return val
+end
+
+function M.build_pos_hash(strings)
+ local len_buckets = {}
+ local maxlen = 0
+ for _,s in ipairs(strings) do
+ table.insert(setdefault(len_buckets, #s),s)
+ if #s > maxlen then maxlen = #s end
+ end
+
+ local len_pos_buckets = {}
+ local worst_buck_size = 0
+
+ for len = 1,maxlen do
+ local strs = len_buckets[len]
+ if strs then
+ -- the best position so far generates `best_bucket`
+ -- with `minsize` worst case collisions
+ local bestpos, minsize, best_bucket = nil, #strs*2, nil
+ for pos = 1,len do
+ local try_bucket = {}
+ for _,str in ipairs(strs) do
+ local poschar = string.sub(str, pos, pos)
+ table.insert(setdefault(try_bucket, poschar), str)
+ end
+ local maxsize = 1
+ for _,pos_strs in pairs(try_bucket) do
+ maxsize = math.max(maxsize, #pos_strs)
+ end
+ if maxsize < minsize then
+ bestpos = pos
+ minsize = maxsize
+ best_bucket = try_bucket
+ end
+ end
+ len_pos_buckets[len] = {bestpos, best_bucket}
+ worst_buck_size = math.max(worst_buck_size, minsize)
+ end
+ end
+ return len_pos_buckets, maxlen, worst_buck_size
+end
+
+function M.switcher(put, tab, maxlen, worst_buck_size)
+ local neworder = {}
+ put " switch (len) {\n"
+ local bucky = worst_buck_size > 1
+ for len = 1,maxlen do
+ local vals = tab[len]
+ if vals then
+ put(" case "..len..": ")
+ local pos, posbuck = unpack(vals)
+ local keys = vim.tbl_keys(posbuck)
+ if #keys > 1 then
+ table.sort(keys)
+ put("switch (str["..(pos-1).."]) {\n")
+ for _,c in ipairs(keys) do
+ local buck = posbuck[c]
+ local startidx = #neworder
+ vim.list_extend(neworder, buck)
+ local endidx = #neworder
+ put(" case '"..c.."': ")
+ put("low = "..startidx.."; ")
+ if bucky then put("high = "..endidx.."; ") end
+ put "break;\n"
+ end
+ put " default: break;\n"
+ put " }\n "
+ else
+ local startidx = #neworder
+ table.insert(neworder, posbuck[keys[1]][1])
+ local endidx = #neworder
+ put("low = "..startidx.."; ")
+ if bucky then put("high = "..endidx.."; ") end
+ end
+ put " break;\n"
+ end
+ end
+ put " default: break;\n"
+ put " }\n"
+ return neworder
+end
+
+function M.hashy_hash(name, strings, access)
+ local stats = {}
+ local put = function(str) table.insert(stats, str) end
+ local len_pos_buckets, maxlen, worst_buck_size = M.build_pos_hash(strings)
+ put("int "..name.."_hash(const char *str, size_t len)\n{\n")
+ if worst_buck_size > 1 then
+ put(" int low = 0, high = 0;\n")
+ else
+ put(" int low = -1;\n")
+ end
+ local neworder = M.switcher(put, len_pos_buckets, maxlen, worst_buck_size)
+ if worst_buck_size > 1 then
+ error [[ not implemented yet ]] -- TODO(bfredl)
+ else
+ put [[
+ if (low < 0) {
+ return -1;
+ }
+ ]]
+ put("if(memcmp(str, "..access("low")..", len)) {\n return -1;\n }\n")
+ put " return low;\n"
+ put "}\n\n"
+ end
+ return neworder, table.concat(stats)
+end
+
+return M
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index beb4ff4da6..15acd73aa5 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -1000,6 +1000,18 @@ void ins_char_typebuf(int c)
buf[3] = NUL;
} else {
buf[utf_char2bytes(c, buf)] = NUL;
+ char_u *p = buf;
+ while (*p) {
+ if ((uint8_t)(*p) == CSI || (uint8_t)(*p) == K_SPECIAL) {
+ bool is_csi = (uint8_t)(*p) == CSI;
+ memmove(p + 3, p + 1, STRLEN(p + 1) + 1);
+ *p++ = K_SPECIAL;
+ *p++ = is_csi ? KS_EXTRA : KS_SPECIAL;
+ *p++ = is_csi ? KE_CSI : KE_FILLER;
+ } else {
+ p++;
+ }
+ }
}
(void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
}
@@ -1558,7 +1570,7 @@ int vgetc(void)
// a CSI (0x9B),
// of a K_SPECIAL - KS_EXTRA - KE_CSI, which is CSI too.
c = vgetorpeek(true);
- if (vgetorpeek(true) == (int)KE_CSI && c == KS_EXTRA) {
+ if (vgetorpeek(true) == KE_CSI && c == KS_EXTRA) {
buf[i] = CSI;
}
}
@@ -1573,9 +1585,9 @@ int vgetc(void)
if (!no_mapping && KeyTyped
&& (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) {
mod_mask = 0;
- stuffcharReadbuff(c);
- u_sync(false);
- c = ESC;
+ ins_char_typebuf(c);
+ ins_char_typebuf(ESC);
+ continue;
}
break;
@@ -1934,7 +1946,7 @@ static int vgetorpeek(bool advance)
&& (mp->m_keys[0] != K_SPECIAL
|| mp->m_keys[1] != KS_EXTRA
|| mp->m_keys[2]
- != (int)KE_SNR)) {
+ != KE_SNR)) {
continue;
}
/*
@@ -2216,7 +2228,7 @@ static int vgetorpeek(bool advance)
if (!ascii_iswhite(ptr[col])) {
curwin->w_wcol = vcol;
}
- vcol += lbr_chartabsize(ptr, ptr + col, (colnr_T)vcol);
+ vcol += lbr_chartabsize(ptr, ptr + col, vcol);
col += utfc_ptr2len(ptr + col);
}
curwin->w_wrow = curwin->w_cline_row
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index f0b52079aa..83fa00977f 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -56,6 +56,8 @@ struct map_arguments {
size_t orig_rhs_len;
};
typedef struct map_arguments MapArguments;
+#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \
+ { 0 }, 0, NULL, 0, false, NULL, 0 }
#define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code
#define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 125108ee78..9d9ffa550a 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -140,13 +140,13 @@ static uint32_t curr_bg;
static uint32_t curr_fg;
static int page_count;
-# define OPT_MBFONT_USECOURIER 0
-# define OPT_MBFONT_ASCII 1
-# define OPT_MBFONT_REGULAR 2
-# define OPT_MBFONT_BOLD 3
-# define OPT_MBFONT_OBLIQUE 4
-# define OPT_MBFONT_BOLDOBLIQUE 5
-# define OPT_MBFONT_NUM_OPTIONS 6
+#define OPT_MBFONT_USECOURIER 0
+#define OPT_MBFONT_ASCII 1
+#define OPT_MBFONT_REGULAR 2
+#define OPT_MBFONT_BOLD 3
+#define OPT_MBFONT_OBLIQUE 4
+#define OPT_MBFONT_BOLDOBLIQUE 5
+#define OPT_MBFONT_NUM_OPTIONS 6
static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] =
{
@@ -643,12 +643,8 @@ void ex_hardcopy(exarg_T *eap)
* PS.)
*/
if (mch_print_init(&settings,
- curbuf->b_fname == NULL
- ? (char_u *)buf_spname(curbuf)
- : curbuf->b_sfname == NULL
- ? curbuf->b_fname
- : curbuf->b_sfname,
- eap->forceit) == FAIL) {
+ curbuf->b_fname == NULL ? buf_spname(curbuf) : curbuf->b_sfname ==
+ NULL ? curbuf->b_fname : curbuf->b_sfname, eap->forceit) == FAIL) {
return;
}
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 31615e744a..76dcb58236 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -9,31 +9,29 @@
* might be a few lines of code that look similar to what Nvi has.
*/
-#include <stdbool.h>
-
#include <assert.h>
#include <errno.h>
-#include <inttypes.h>
#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
-#include "nvim/buffer.h"
#include "nvim/ascii.h"
-#include "nvim/if_cscope.h"
+#include "nvim/buffer.h"
#include "nvim/charset.h"
+#include "nvim/event/stream.h"
#include "nvim/fileio.h"
-#include "nvim/message.h"
+#include "nvim/if_cscope.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
-#include "nvim/event/stream.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
#if defined(UNIX)
# include <sys/wait.h>
#endif
@@ -90,19 +88,20 @@ char_u *get_cscope_name(expand_T *xp, int idx)
// Complete with sub-commands of ":cscope":
// add, find, help, kill, reset, show
return (char_u *)cs_cmds[idx].name;
- case EXP_SCSCOPE_SUBCMD:
- {
+ case EXP_SCSCOPE_SUBCMD: {
// Complete with sub-commands of ":scscope": same sub-commands as
// ":cscope" but skip commands which don't support split windows
int i;
- for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++)
- if (cs_cmds[i].cansplit)
- if (current_idx++ == idx)
+ for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++) {
+ if (cs_cmds[i].cansplit) {
+ if (current_idx++ == idx) {
break;
+ }
+ }
+ }
return (char_u *)cs_cmds[i].name;
}
- case EXP_CSCOPE_FIND:
- {
+ case EXP_CSCOPE_FIND: {
const char *query_type[] =
{
"a", "c", "d", "e", "f", "g", "i", "s", "t", NULL
@@ -114,8 +113,7 @@ char_u *get_cscope_name(expand_T *xp, int idx)
// redundant.
return (char_u *)query_type[idx];
}
- case EXP_CSCOPE_KILL:
- {
+ case EXP_CSCOPE_KILL: {
static char connection[5];
// ":cscope kill" accepts connection numbers or partial names of
@@ -124,8 +122,9 @@ char_u *get_cscope_name(expand_T *xp, int idx)
// connections.
size_t i;
for (i = 0, current_idx = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname == NULL)
+ if (csinfo[i].fname == NULL) {
continue;
+ }
if (current_idx++ == idx) {
vim_snprintf(connection, sizeof(connection), "%zu", i);
return (char_u *)connection;
@@ -172,11 +171,9 @@ void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx)
/// Find the command, print help if invalid, and then call the corresponding
/// command function.
-static void
-do_cscope_general(
- exarg_T *eap,
- int make_split // whether to split window
-)
+///
+/// @param make_split whether to split window
+static void do_cscope_general(exarg_T *eap, int make_split)
{
cscmd_T *cmdp;
@@ -187,8 +184,7 @@ do_cscope_general(
if (make_split) {
if (!cmdp->cansplit) {
- (void)MSG_PUTS(_(
- "This cscope command does not support splitting the window.\n"));
+ (void)MSG_PUTS(_("This cscope command does not support splitting the window.\n"));
return;
}
postponed_split = -1;
@@ -228,14 +224,16 @@ void ex_cstag(exarg_T *eap)
case 0:
if (cs_check_for_connections()) {
ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
- FALSE, *eap->cmdlinep);
+ FALSE, *eap->cmdlinep);
if (ret == FALSE) {
cs_free_tags();
- if (msg_col)
+ if (msg_col) {
msg_putchar('\n');
+ }
- if (cs_check_for_tags())
+ if (cs_check_for_tags()) {
ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
+ }
}
} else if (cs_check_for_tags()) {
ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
@@ -245,21 +243,24 @@ void ex_cstag(exarg_T *eap)
if (cs_check_for_tags()) {
ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE);
if (ret == FALSE) {
- if (msg_col)
+ if (msg_col) {
msg_putchar('\n');
+ }
if (cs_check_for_connections()) {
ret = cs_find_common("g", (char *)(eap->arg), eap->forceit,
- FALSE, FALSE, *eap->cmdlinep);
- if (ret == FALSE)
+ FALSE, FALSE, *eap->cmdlinep);
+ if (ret == FALSE) {
cs_free_tags();
+ }
}
}
} else if (cs_check_for_connections()) {
ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE,
- FALSE, *eap->cmdlinep);
- if (ret == FALSE)
+ FALSE, *eap->cmdlinep);
+ if (ret == FALSE) {
cs_free_tags();
+ }
}
break;
default:
@@ -306,29 +307,29 @@ void cs_print_tags(void)
/*
* "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
*
- * Checks for the existence of a |cscope| connection. If no
- * parameters are specified, then the function returns:
+ * Checks for the existence of a |cscope| connection. If no
+ * parameters are specified, then the function returns:
*
- * 0, if cscope was not available (not compiled in), or if there
- * are no cscope connections; or
- * 1, if there is at least one cscope connection.
+ * 0, if cscope was not available (not compiled in), or if there
+ * are no cscope connections; or
+ * 1, if there is at least one cscope connection.
*
- * If parameters are specified, then the value of {num}
- * determines how existence of a cscope connection is checked:
+ * If parameters are specified, then the value of {num}
+ * determines how existence of a cscope connection is checked:
*
- * {num} Description of existence check
- * ----- ------------------------------
- * 0 Same as no parameters (e.g., "cscope_connection()").
- * 1 Ignore {prepend}, and use partial string matches for
- * {dbpath}.
- * 2 Ignore {prepend}, and use exact string matches for
- * {dbpath}.
- * 3 Use {prepend}, use partial string matches for both
- * {dbpath} and {prepend}.
- * 4 Use {prepend}, use exact string matches for both
- * {dbpath} and {prepend}.
+ * {num} Description of existence check
+ * ----- ------------------------------
+ * 0 Same as no parameters (e.g., "cscope_connection()").
+ * 1 Ignore {prepend}, and use partial string matches for
+ * {dbpath}.
+ * 2 Ignore {prepend}, and use exact string matches for
+ * {dbpath}.
+ * 3 Use {prepend}, use partial string matches for both
+ * {dbpath} and {prepend}.
+ * 4 Use {prepend}, use exact string matches for both
+ * {dbpath} and {prepend}.
*
- * Note: All string comparisons are case sensitive!
+ * Note: All string comparisons are case sensitive!
*/
bool cs_connection(int num, char_u *dbpath, char_u *ppath)
{
@@ -393,8 +394,9 @@ static int cs_add(exarg_T *eap)
cs_usage_msg(Add);
return CSCOPE_FAILURE;
}
- if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL)
+ if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL) {
flags = strtok((char *)NULL, (const char *)" ");
+ }
return cs_add_common(fname, ppath, flags);
}
@@ -413,18 +415,16 @@ static void cs_stat_emsg(char *fname)
/// The common routine to add a new cscope connection. Called by
/// cs_add() and cs_reset(). I really don't like to do this, but this
/// routine uses a number of goto statements.
-static int
-cs_add_common(
- char *arg1, // filename - may contain environment variables
- char *arg2, // prepend path - may contain environment variables
- char *flags
-)
+///
+/// @param arg1 filename - may contain environment variables
+/// @param arg2 prepend path - may contain environment variables
+static int cs_add_common(char *arg1, char *arg2, char *flags)
{
- char *fname = NULL;
- char *fname2 = NULL;
- char *ppath = NULL;
+ char *fname = NULL;
+ char *fname2 = NULL;
+ char *ppath = NULL;
size_t usedlen = 0;
- char_u *fbuf = NULL;
+ char_u *fbuf = NULL;
// get the filename (arg1), expand it, and try to stat it
fname = xmalloc(MAXPATHL + 1);
@@ -443,8 +443,9 @@ cs_add_common(
bool file_info_ok = os_fileinfo(fname, &file_info);
if (!file_info_ok) {
staterr:
- if (p_csverbose)
+ if (p_csverbose) {
cs_stat_emsg(fname);
+ }
goto add_err;
}
@@ -465,31 +466,32 @@ staterr:
while (fname[strlen(fname)-1] == '/'
) {
fname[strlen(fname)-1] = '\0';
- if (fname[0] == '\0')
+ if (fname[0] == '\0') {
break;
+ }
}
- if (fname[0] == '\0')
+ if (fname[0] == '\0') {
(void)sprintf(fname2, "/%s", CSCOPE_DBFILE);
- else
+ } else {
(void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE);
+ }
file_info_ok = os_fileinfo(fname2, &file_info);
if (!file_info_ok) {
- if (p_csverbose)
+ if (p_csverbose) {
cs_stat_emsg(fname2);
+ }
goto add_err;
}
i = cs_insert_filelist(fname2, ppath, flags, &file_info);
- }
- else if (S_ISREG(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode))
- {
+ } else if (S_ISREG(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode)) {
i = cs_insert_filelist(fname, ppath, flags, &file_info);
} else {
- if (p_csverbose)
- (void)EMSG2(
- _("E564: %s is not a directory or a valid cscope database"),
- fname);
+ if (p_csverbose) {
+ (void)EMSG2(_("E564: %s is not a directory or a valid cscope database"),
+ fname);
+ }
goto add_err;
}
@@ -538,15 +540,15 @@ static size_t cs_cnt_connections(void)
size_t cnt = 0;
for (size_t i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname != NULL)
+ if (csinfo[i].fname != NULL) {
cnt++;
+ }
}
return cnt;
}
-static void cs_reading_emsg(
- size_t idx // connection index
-)
+/// @param idx connection index
+static void cs_reading_emsg(size_t idx)
{
EMSGU(_("E262: error reading cscope connection %" PRIu64), idx);
}
@@ -582,7 +584,7 @@ static int cs_cnt_matches(size_t idx)
// Accept "\S*cscope: X lines", also matches "mlcscope".
// Bail out for the "Unable to search" error.
if (strstr((const char *)buf, "Unable to search database") != NULL) {
- break;
+ break;
}
if ((stok = strtok(buf, (const char *)" ")) == NULL) {
continue;
@@ -591,18 +593,21 @@ static int cs_cnt_matches(size_t idx)
continue;
}
- if ((stok = strtok(NULL, (const char *)" ")) == NULL)
+ if ((stok = strtok(NULL, (const char *)" ")) == NULL) {
continue;
+ }
nlines = atoi(stok);
if (nlines < 0) {
nlines = 0;
break;
}
- if ((stok = strtok(NULL, (const char *)" ")) == NULL)
+ if ((stok = strtok(NULL, (const char *)" ")) == NULL) {
continue;
- if (strncmp((const char *)stok, "lines", 5))
+ }
+ if (strncmp((const char *)stok, "lines", 5)) {
continue;
+ }
break;
}
@@ -620,31 +625,40 @@ static char *cs_create_cmd(char *csoption, char *pattern)
char *pat;
switch (csoption[0]) {
- case '0': case 's':
+ case '0':
+ case 's':
search = 0;
break;
- case '1': case 'g':
+ case '1':
+ case 'g':
search = 1;
break;
- case '2': case 'd':
+ case '2':
+ case 'd':
search = 2;
break;
- case '3': case 'c':
+ case '3':
+ case 'c':
search = 3;
break;
- case '4': case 't':
+ case '4':
+ case 't':
search = 4;
break;
- case '6': case 'e':
+ case '6':
+ case 'e':
search = 6;
break;
- case '7': case 'f':
+ case '7':
+ case 'f':
search = 7;
break;
- case '8': case 'i':
+ case '8':
+ case 'i':
search = 8;
break;
- case '9': case 'a':
+ case '9':
+ case 'a':
search = 9;
break;
default:
@@ -656,9 +670,11 @@ static char *cs_create_cmd(char *csoption, char *pattern)
// Skip white space before the patter, except for text and pattern search,
// they may want to use the leading white space.
pat = pattern;
- if (search != 4 && search != 6)
- while (ascii_iswhite(*pat))
+ if (search != 4 && search != 6) {
+ while (ascii_iswhite(*pat)) {
++pat;
+ }
+ }
cmd = xmalloc(strlen(pat) + 2);
@@ -675,7 +691,7 @@ static int cs_create_connection(size_t i)
#ifdef UNIX
int to_cs[2], from_cs[2];
#endif
- char *prog, *cmd, *ppath = NULL;
+ char *prog, *cmd, *ppath = NULL;
#if defined(UNIX)
/*
@@ -686,14 +702,18 @@ static int cs_create_connection(size_t i)
if (pipe(to_cs) < 0 || pipe(from_cs) < 0) {
(void)EMSG(_("E566: Could not create cscope pipes"));
err_closing:
- if (to_cs[0] != -1)
+ if (to_cs[0] != -1) {
(void)close(to_cs[0]);
- if (to_cs[1] != -1)
+ }
+ if (to_cs[1] != -1) {
(void)close(to_cs[1]);
- if (from_cs[0] != -1)
+ }
+ if (from_cs[0] != -1) {
(void)close(from_cs[0]);
- if (from_cs[1] != -1)
+ }
+ if (from_cs[1] != -1) {
(void)close(from_cs[1]);
+ }
return CSCOPE_FAILURE;
}
@@ -759,8 +779,9 @@ err_closing:
len += strlen(ppath);
}
- if (csinfo[i].flags)
+ if (csinfo[i].flags) {
len += strlen(csinfo[i].flags);
+ }
cmd = xmalloc(len);
@@ -779,10 +800,10 @@ err_closing:
(void)strcat(cmd, " ");
(void)strcat(cmd, csinfo[i].flags);
}
-# ifdef UNIX
+#ifdef UNIX
// on Win32 we still need prog
xfree(prog);
-# endif
+#endif
xfree(ppath);
#if defined(UNIX)
@@ -791,12 +812,14 @@ err_closing:
# if defined(HAVE_SETSID)
(void)setsid();
# else
- if (setpgid(0, 0) == -1)
+ if (setpgid(0, 0) == -1) {
PERROR(_("cs_create_connection setpgid failed"));
+ }
# endif
# endif
- if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1)
+ if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1) {
PERROR(_("cs_create_connection exec failed"));
+ }
exit(127);
// NOTREACHED
@@ -827,7 +850,7 @@ err_closing:
si.hStdError = stdout_wr;
si.hStdInput = stdin_rd;
created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
- NULL, NULL, &si, &pi);
+ NULL, NULL, &si, &pi);
xfree(prog);
xfree(cmd);
@@ -888,9 +911,11 @@ static int cs_find(exarg_T *eap)
* Let's replace the NULs written by strtok() with spaces - we need the
* spaces to correctly display the quickfix/location list window's title.
*/
- for (int i = 0; i < eap_arg_len; ++i)
- if (NUL == eap->arg[i])
+ for (int i = 0; i < eap_arg_len; ++i) {
+ if (NUL == eap->arg[i]) {
eap->arg[i] = ' ';
+ }
+ }
return cs_find_common(opt, pat, eap->forceit, true,
eap->cmdidx == CMD_lcscope, *eap->cmdlinep);
@@ -898,8 +923,8 @@ static int cs_find(exarg_T *eap)
/// Common code for cscope find, shared by cs_find() and ex_cstag().
-static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
- int use_ll, char_u *cmdline)
+static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int use_ll,
+ char_u *cmdline)
{
char *cmd;
int *nummatches;
@@ -966,8 +991,9 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
// create the actual command to send to cscope
cmd = cs_create_cmd(opt, pat);
- if (cmd == NULL)
+ if (cmd == NULL) {
return FALSE;
+ }
nummatches = xmalloc(sizeof(int) * csinfo_size);
@@ -978,8 +1004,9 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
}
totmatches = 0;
for (size_t i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL)
+ if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL) {
continue;
+ }
// send cmd to cscope
(void)fprintf(csinfo[i].to_fp, "%s\n", cmd);
@@ -987,11 +1014,13 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
nummatches[i] = cs_cnt_matches(i);
- if (nummatches[i] > -1)
+ if (nummatches[i] > -1) {
totmatches += (size_t)nummatches[i];
+ }
- if (nummatches[i] == 0)
+ if (nummatches[i] == 0) {
(void)cs_read_prompt(i);
+ }
}
xfree(cmd);
@@ -1014,10 +1043,10 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
if (qfpos != NULL && *qfpos != '0') {
// Fill error list.
- FILE *f;
- char_u *tmp = vim_tempname();
- qf_info_T *qi = NULL;
- win_T *wp = NULL;
+ FILE *f;
+ char_u *tmp = vim_tempname();
+ qf_info_T *qi = NULL;
+ win_T *wp = NULL;
f = os_fopen((char *)tmp, "w");
if (f == NULL) {
@@ -1039,14 +1068,15 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
}
apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope",
- curbuf->b_fname, TRUE, curbuf);
- if (use_ll)
+ curbuf->b_fname, TRUE, curbuf);
+ if (use_ll) {
/*
* In the location list window, use the displayed location
* list. Otherwise, use the location list for the window.
*/
qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
? wp->w_llist_ref : wp->w_llist;
+ }
qf_jump(qi, 0, 0, forceit);
}
}
@@ -1059,11 +1089,11 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
size_t matched = 0;
// read output
- cs_fill_results((char *)pat, totmatches, nummatches, &matches,
- &contexts, &matched);
+ cs_fill_results(pat, totmatches, nummatches, &matches, &contexts, &matched);
xfree(nummatches);
- if (matches == NULL)
+ if (matches == NULL) {
return FALSE;
+ }
(void)cs_manage_matches(matches, contexts, matched, Store);
@@ -1086,10 +1116,10 @@ static int cs_help(exarg_T *eap)
space_cnt = 0;
}
(void)smsg(_("%-5s: %s%*s (Usage: %s)"),
- cmdp->name,
- help, space_cnt, " ",
- cmdp->usage);
- if (strcmp(cmdp->name, "find") == 0)
+ cmdp->name,
+ help, space_cnt, " ",
+ cmdp->usage);
+ if (strcmp(cmdp->name, "find") == 0) {
MSG_PUTS(_("\n"
" a: Find assignments to this symbol\n"
" c: Find functions calling this function\n"
@@ -1100,6 +1130,7 @@ static int cs_help(exarg_T *eap)
" i: Find files #including this file\n"
" s: Find this C symbol\n"
" t: Find this text string\n"));
+ }
cmdp++;
}
@@ -1121,8 +1152,7 @@ static void clear_csinfo(size_t i)
}
/// Insert a new cscope database filename into the filelist.
-static int cs_insert_filelist(char *fname, char *ppath, char *flags,
- FileInfo *file_info)
+static int cs_insert_filelist(char *fname, char *ppath, char *flags, FileInfo *file_info)
{
size_t i = 0;
bool empty_found = false;
@@ -1130,8 +1160,9 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
for (size_t j = 0; j < csinfo_size; j++) {
if (csinfo[j].fname != NULL
&& os_fileid_equal_fileinfo(&(csinfo[j].file_id), file_info)) {
- if (p_csverbose)
+ if (p_csverbose) {
(void)EMSG(_("E568: duplicate cscope database not added"));
+ }
return CSCOPE_FAILURE;
}
@@ -1154,8 +1185,9 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
csinfo_size *= 2;
csinfo = xrealloc(csinfo, sizeof(csinfo_T)*csinfo_size);
}
- for (size_t j = csinfo_size/2; j < csinfo_size; j++)
+ for (size_t j = csinfo_size/2; j < csinfo_size; j++) {
clear_csinfo(j);
+ }
}
csinfo[i].fname = xmalloc(strlen(fname) + 1);
@@ -1165,14 +1197,16 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
if (ppath != NULL) {
csinfo[i].ppath = xmalloc(strlen(ppath) + 1);
(void)strcpy(csinfo[i].ppath, (const char *)ppath);
- } else
+ } else {
csinfo[i].ppath = NULL;
+ }
if (flags != NULL) {
csinfo[i].flags = xmalloc(strlen(flags) + 1);
(void)strcpy(csinfo[i].flags, (const char *)flags);
- } else
+ } else {
csinfo[i].flags = NULL;
+ }
os_fileinfo_id(file_info, &(csinfo[i].file_id));
assert(i <= INT_MAX);
@@ -1181,25 +1215,28 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags,
/// Find cscope command in command table.
-static cscmd_T * cs_lookup_cmd(exarg_T *eap)
+static cscmd_T *cs_lookup_cmd(exarg_T *eap)
{
cscmd_T *cmdp;
char *stok;
size_t len;
- if (eap->arg == NULL)
+ if (eap->arg == NULL) {
return NULL;
+ }
// Store length of eap->arg before it gets modified by strtok().
eap_arg_len = (int)STRLEN(eap->arg);
- if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL)
+ if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL) {
return NULL;
+ }
len = strlen(stok);
for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp) {
- if (strncmp((const char *)(stok), cmdp->name, len) == 0)
+ if (strncmp((const char *)(stok), cmdp->name, len) == 0) {
return cmdp;
+ }
}
return NULL;
}
@@ -1224,21 +1261,23 @@ static int cs_kill(exarg_T *eap)
|| (strlen(stok) < 3 && stok[0] == '-'
&& ascii_isdigit((int)(stok[1])))) {
num = atoi(stok);
- if (num == -1)
+ if (num == -1) {
killall = true;
- else if (num >= 0) {
+ } else if (num >= 0) {
i = (size_t)num;
} else { // All negative values besides -1 are invalid.
- if (p_csverbose)
+ if (p_csverbose) {
(void)EMSG2(_("E261: cscope connection %s not found"), stok);
+ }
return CSCOPE_FAILURE;
}
} else {
// Else it must be part of a name. We will try to find a match
// within all the names in the csinfo data structure
for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok))
+ if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok)) {
break;
+ }
}
}
@@ -1250,8 +1289,9 @@ static int cs_kill(exarg_T *eap)
} else {
if (killall) {
for (i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname)
+ if (csinfo[i].fname) {
cs_kill_execute(i, csinfo[i].fname);
+ }
}
} else {
cs_kill_execute((size_t)i, stok);
@@ -1263,10 +1303,10 @@ static int cs_kill(exarg_T *eap)
/// Actually kills a specific cscope connection.
-static void cs_kill_execute(
- size_t i, // cscope table index
- char *cname // cscope database name
-)
+///
+/// @param i cscope table index
+/// @param cname cscope database name
+static void cs_kill_execute(size_t i, char *cname)
{
if (p_csverbose) {
msg_clr_eos();
@@ -1293,8 +1333,7 @@ static void cs_kill_execute(
/// Besides, even if this particular case didn't happen, the search pattern
/// would still have to be modified to escape all the special regular expression
/// characters to comply with ctags formatting.
-static char *cs_make_vim_style_matches(char *fname, char *slno, char *search,
- char *tagstr)
+static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, char *tagstr)
{
// vim style is ctags:
//
@@ -1339,8 +1378,7 @@ static char *cs_make_vim_style_matches(char *fname, char *slno, char *search,
/// Free: frees up everything and resets
///
/// Print: prints the tags
-static char *cs_manage_matches(char **matches, char **contexts,
- size_t totmatches, mcmd_e cmd)
+static char *cs_manage_matches(char **matches, char **contexts, size_t totmatches, mcmd_e cmd)
{
static char **mp = NULL;
static char **cp = NULL;
@@ -1352,16 +1390,18 @@ static char *cs_manage_matches(char **matches, char **contexts,
case Store:
assert(matches != NULL);
assert(totmatches > 0);
- if (mp != NULL || cp != NULL)
+ if (mp != NULL || cp != NULL) {
(void)cs_manage_matches(NULL, NULL, 0, Free);
+ }
mp = matches;
cp = contexts;
cnt = totmatches;
next = 0;
break;
case Get:
- if (next >= cnt)
+ if (next >= cnt) {
return NULL;
+ }
p = mp[next];
next++;
@@ -1370,8 +1410,9 @@ static char *cs_manage_matches(char **matches, char **contexts,
if (mp != NULL) {
while (cnt--) {
xfree(mp[cnt]);
- if (cp != NULL)
+ if (cp != NULL) {
xfree(cp[cnt]);
+ }
}
xfree(mp);
xfree(cp);
@@ -1396,8 +1437,8 @@ static char *cs_manage_matches(char **matches, char **contexts,
/// Parse cscope output.
-static char *cs_parse_results(size_t cnumber, char *buf, int bufsize,
- char **context, char **linenumber, char **search)
+static char *cs_parse_results(size_t cnumber, char *buf, int bufsize, char **context,
+ char **linenumber, char **search)
{
int ch;
char *p;
@@ -1421,8 +1462,9 @@ retry:
// If the line's too long for the buffer, discard it.
if ((p = strchr(buf, '\n')) == NULL) {
- while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n')
+ while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n') {
;
+ }
return NULL;
}
*p = '\0';
@@ -1430,14 +1472,18 @@ retry:
/*
* cscope output is in the following format:
*
- * <filename> <context> <line number> <pattern>
+ * <filename> <context> <line number> <pattern>
*/
- if ((name = strtok((char *)buf, (const char *)" ")) == NULL)
+ char *saveptr = NULL;
+ if ((name = os_strtok(buf, (const char *)" ", &saveptr)) == NULL) {
return NULL;
- if ((*context = strtok(NULL, (const char *)" ")) == NULL)
+ }
+ if ((*context = os_strtok(NULL, (const char *)" ", &saveptr)) == NULL) {
return NULL;
- if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL)
+ }
+ if ((*linenumber = os_strtok(NULL, (const char *)" ", &saveptr)) == NULL) {
return NULL;
+ }
*search = *linenumber + strlen(*linenumber) + 1; // +1 to skip \0
// --- nvi ---
@@ -1463,25 +1509,29 @@ static void cs_file_results(FILE *f, int *nummatches_a)
char *buf = xmalloc(CSREAD_BUFSIZE);
for (size_t i = 0; i < csinfo_size; i++) {
- if (nummatches_a[i] < 1)
+ if (nummatches_a[i] < 1) {
continue;
+ }
for (int j = 0; j < nummatches_a[i]; j++) {
if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
- &slno, &search)) == NULL)
+ &slno, &search)) == NULL) {
continue;
+ }
context = xmalloc(strlen(cntx) + 5);
- if (strcmp(cntx, "<global>")==0)
+ if (strcmp(cntx, "<global>")==0) {
strcpy(context, "<<global>>");
- else
+ } else {
sprintf(context, "<<%s>>", cntx);
+ }
- if (search == NULL)
+ if (search == NULL) {
fprintf(f, "%s\t%s\t%s\n", fullname, slno, context);
- else
+ } else {
fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search);
+ }
xfree(context);
xfree(fullname);
@@ -1495,9 +1545,8 @@ static void cs_file_results(FILE *f, int *nummatches_a)
/// Get parsed cscope output and calls cs_make_vim_style_matches to convert
/// into ctags format.
/// When there are no matches sets "*matches_p" to NULL.
-static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a,
- char ***matches_p, char ***cntxts_p,
- size_t *matched)
+static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, char ***matches_p,
+ char ***cntxts_p, size_t *matched)
{
char *buf;
char *search, *slno;
@@ -1514,22 +1563,24 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a,
cntxts = xmalloc(sizeof(char *) * (size_t)totmatches);
for (size_t i = 0; i < csinfo_size; i++) {
- if (nummatches_a[i] < 1)
+ if (nummatches_a[i] < 1) {
continue;
+ }
for (int j = 0; j < nummatches_a[i]; j++) {
if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx,
- &slno, &search)) == NULL)
+ &slno, &search)) == NULL) {
continue;
+ }
matches[totsofar] = cs_make_vim_style_matches(fullname, slno, search,
tagstr);
xfree(fullname);
- if (strcmp(cntx, "<global>") == 0)
+ if (strcmp(cntx, "<global>") == 0) {
cntxts[totsofar] = NULL;
- else {
+ } else {
cntxts[totsofar] = xstrdup(cntx);
}
@@ -1691,9 +1742,9 @@ static void cs_print_tags_priv(char **matches, char **cntxts,
static int cs_read_prompt(size_t i)
{
int ch;
- char *buf = NULL; // buffer for possible error message from cscope
+ char *buf = NULL; // buffer for possible error message from cscope
size_t bufpos = 0;
- char *cs_emsg = _("E609: Cscope error: %s");
+ char *cs_emsg = _("E609: Cscope error: %s");
size_t cs_emsg_len = strlen(cs_emsg);
static char *eprompt = "Press the RETURN key to continue:";
size_t epromptlen = strlen(eprompt);
@@ -1886,10 +1937,12 @@ static void cs_release_csp(size_t i, bool freefnpp)
}
#endif
- if (csinfo[i].fr_fp != NULL)
+ if (csinfo[i].fr_fp != NULL) {
(void)fclose(csinfo[i].fr_fp);
- if (csinfo[i].to_fp != NULL)
+ }
+ if (csinfo[i].to_fp != NULL) {
(void)fclose(csinfo[i].to_fp);
+ }
if (freefnpp) {
xfree(csinfo[i].fname);
@@ -1904,11 +1957,12 @@ static void cs_release_csp(size_t i, bool freefnpp)
/// Calls cs_kill on all cscope connections then reinits.
static int cs_reset(exarg_T *eap)
{
- char **dblist = NULL, **pplist = NULL, **fllist = NULL;
+ char **dblist = NULL, **pplist = NULL, **fllist = NULL;
char buf[25]; // for snprintf " (#%zu)"
- if (csinfo_size == 0)
+ if (csinfo_size == 0) {
return CSCOPE_SUCCESS;
+ }
// malloc our db and ppath list
dblist = xmalloc(csinfo_size * sizeof(char *));
@@ -1919,8 +1973,9 @@ static int cs_reset(exarg_T *eap)
dblist[i] = csinfo[i].fname;
pplist[i] = csinfo[i].ppath;
fllist[i] = csinfo[i].flags;
- if (csinfo[i].fname != NULL)
+ if (csinfo[i].fname != NULL) {
cs_release_csp(i, FALSE);
+ }
}
// rebuild the cscope connection list
@@ -1959,8 +2014,8 @@ static int cs_reset(exarg_T *eap)
/// Contrast this with my development system (Digital Unix), which does.
static char *cs_resolve_file(size_t i, char *name)
{
- char *fullname;
- char_u *csdir = NULL;
+ char *fullname;
+ char_u *csdir = NULL;
/*
* Ppath is freed when we destroy the cscope connection.
@@ -1975,8 +2030,8 @@ static char *cs_resolve_file(size_t i, char *name)
// path in path resolution.
csdir = xmalloc(MAXPATHL);
STRLCPY(csdir, csinfo[i].fname,
- path_tail((char_u *)csinfo[i].fname)
- - (char_u *)csinfo[i].fname + 1);
+ path_tail((char_u *)csinfo[i].fname)
+ - (char_u *)csinfo[i].fname + 1);
len += STRLEN(csdir);
}
@@ -1985,8 +2040,7 @@ static char *cs_resolve_file(size_t i, char *name)
// happens, you are screwed up and need to fix how you're using cscope.
if (csinfo[i].ppath != NULL
&& (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0)
- && (name[0] != '/')
- ) {
+ && (name[0] != '/')) {
fullname = xmalloc(len);
(void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name);
} else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL) {
@@ -2005,15 +2059,15 @@ static char *cs_resolve_file(size_t i, char *name)
/// Show all cscope connections.
static int cs_show(exarg_T *eap)
{
- if (cs_cnt_connections() == 0)
+ if (cs_cnt_connections() == 0) {
MSG_PUTS(_("no cscope connections\n"));
- else {
- MSG_PUTS_ATTR(
- _(" # pid database name prepend path\n"),
- HL_ATTR(HLF_T));
+ } else {
+ MSG_PUTS_ATTR(_(" # pid database name prepend path\n"),
+ HL_ATTR(HLF_T));
for (size_t i = 0; i < csinfo_size; i++) {
- if (csinfo[i].fname == NULL)
+ if (csinfo[i].fname == NULL) {
continue;
+ }
if (csinfo[i].ppath != NULL) {
(void)smsg("%2zu %-5" PRId64 " %-34s %-32s", i,
@@ -2033,8 +2087,9 @@ static int cs_show(exarg_T *eap)
/// Only called when VIM exits to quit any cscope sessions.
void cs_end(void)
{
- for (size_t i = 0; i < csinfo_size; i++)
+ for (size_t i = 0; i < csinfo_size; i++) {
cs_release_csp(i, true);
+ }
xfree(csinfo);
csinfo_size = 0;
}
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 07c53299fa..fd4cfc4c31 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -755,7 +755,7 @@ void nlua_push_Array(lua_State *lstate, const Array array, bool special)
FUNC_ATTR_NONNULL_ALL \
{ \
lua_pushnumber(lstate, (lua_Number)(item)); \
-}
+ }
GENERATE_INDEX_FUNCTION(Buffer)
GENERATE_INDEX_FUNCTION(Window)
@@ -1126,9 +1126,9 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
size_t len;
const char *s = lua_tolstring(lstate, -1, &len);
*cur.obj = STRING_OBJ(((String) {
- .data = xmemdupz(s, len),
- .size = len,
- }));
+ .data = xmemdupz(s, len),
+ .size = len,
+ }));
break;
}
case LUA_TNUMBER: {
@@ -1147,10 +1147,10 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
switch (table_props.type) {
case kObjectTypeArray:
*cur.obj = ARRAY_OBJ(((Array) {
- .items = NULL,
- .size = 0,
- .capacity = 0,
- }));
+ .items = NULL,
+ .size = 0,
+ .capacity = 0,
+ }));
if (table_props.maxidx != 0) {
cur.obj->data.array.items =
xcalloc(table_props.maxidx,
@@ -1162,10 +1162,10 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
break;
case kObjectTypeDictionary:
*cur.obj = DICTIONARY_OBJ(((Dictionary) {
- .items = NULL,
- .size = 0,
- .capacity = 0,
- }));
+ .items = NULL,
+ .size = 0,
+ .capacity = 0,
+ }));
if (table_props.string_keys_num != 0) {
cur.obj->data.dictionary.items =
xcalloc(table_props.string_keys_num,
@@ -1299,3 +1299,25 @@ void nlua_init_types(lua_State *const lstate)
lua_rawset(lstate, -3);
}
+
+
+void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err)
+{
+ lua_pushnil(L); // [dict, nil]
+ while (lua_next(L, -2)) {
+ // [dict, key, value]
+ size_t len;
+ const char *s = lua_tolstring(L, -2, &len);
+ Object *field = hashy(retval, s, len);
+ if (!field) {
+ api_set_error(err, kErrorTypeValidation, "invalid key: %.*s", (int)len, s);
+ lua_pop(L, 3); // []
+ return;
+ }
+
+ *field = nlua_pop_Object(L, true, err);
+ }
+ // [dict]
+ lua_pop(L, 1);
+ // []
+}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 8c7dc90111..3f93bb9a09 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -5,6 +5,7 @@
#include <lua.h>
#include <lualib.h>
+#include "cjson/lua_cjson.h"
#include "luv/luv.h"
#include "mpack/lmpack.h"
#include "nvim/api/private/defs.h"
@@ -531,6 +532,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_xdl_diff);
lua_setfield(lstate, -2, "diff");
+ lua_cjson_new(lstate);
+ lua_setfield(lstate, -2, "json");
+
lua_setglobal(lstate, "vim");
{
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index ba124c41ad..7a209f2d79 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -108,6 +108,9 @@ setmetatable(vim, {
elseif key == 'diagnostic' then
t.diagnostic = require('vim.diagnostic')
return t.diagnostic
+ elseif key == 'ui' then
+ t.ui = require('vim.ui')
+ return t.ui
end
end
})
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
index b89807b9f1..3955fbe72c 100644
--- a/src/nvim/lua/xdiff.c
+++ b/src/nvim/lua/xdiff.c
@@ -53,8 +53,8 @@ static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
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)
+ // src/xdiff/xemit.c:284
+ // src/xdiff/xutils.c:(356,368)
if (count_a > 0) {
start_a += 1;
}
@@ -83,8 +83,8 @@ static int hunk_locations_cb(long start_a, long count_a, long start_b, long coun
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)
+ // src/xdiff/xemit.c:284
+ // src/xdiff/xutils.c:(356,368)
if (count_a > 0) {
start_a += 1;
}
@@ -265,8 +265,8 @@ int nlua_xdl_diff(lua_State *lstate)
Error err = ERROR_INIT;
xdemitconf_t cfg;
- xpparam_t params;
- xdemitcb_t ecb;
+ xpparam_t params;
+ xdemitcb_t ecb;
memset(&cfg, 0, sizeof(cfg));
memset(&params, 0, sizeof(params));
diff --git a/src/nvim/main.c b/src/nvim/main.c
index d977589ad7..f801351d2d 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -1306,35 +1306,6 @@ static void set_window_layout(mparm_T *paramp)
}
}
-/*
- * Read all the plugin files.
- * Only when compiled with +eval, since most plugins need it.
- */
-static void load_plugins(void)
-{
- if (p_lpl) {
- char_u *rtp_copy = NULL;
- char_u *const plugin_pattern_vim = (char_u *)"plugin/**/*.vim"; // NOLINT
- char_u *const plugin_pattern_lua = (char_u *)"plugin/**/*.lua"; // NOLINT
-
- // don't use source_runtime() yet so we can check for :packloadall below
- source_in_path(p_rtp, plugin_pattern_vim, DIP_ALL | DIP_NOAFTER);
- source_in_path(p_rtp, plugin_pattern_lua, DIP_ALL | DIP_NOAFTER);
- TIME_MSG("loading rtp plugins");
- xfree(rtp_copy);
-
- // Only source "start" packages if not done already with a :packloadall
- // command.
- if (!did_source_packages) {
- load_start_packages();
- }
- TIME_MSG("loading packages");
-
- source_runtime(plugin_pattern_vim, DIP_ALL | DIP_AFTER);
- source_runtime(plugin_pattern_lua, DIP_ALL | DIP_AFTER);
- TIME_MSG("loading after plugins");
- }
-}
/*
* "-q errorfile": Load the error file now.
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 1c986a4fa4..20d5570e8c 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -36,11 +36,11 @@
#if defined(ARCH_64)
-#define ptr_t_hash(key) uint64_t_hash((uint64_t)key)
-#define ptr_t_eq(a, b) uint64_t_eq((uint64_t)a, (uint64_t)b)
+# define ptr_t_hash(key) uint64_t_hash((uint64_t)key)
+# define ptr_t_eq(a, b) uint64_t_eq((uint64_t)a, (uint64_t)b)
#elif defined(ARCH_32)
-#define ptr_t_hash(key) uint32_t_hash((uint32_t)key)
-#define ptr_t_eq(a, b) uint32_t_eq((uint32_t)a, (uint32_t)b)
+# define ptr_t_hash(key) uint32_t_hash((uint32_t)key)
+# define ptr_t_eq(a, b) uint32_t_eq((uint32_t)a, (uint32_t)b)
#endif
#define INITIALIZER(T, U) T##_##U##_initializer
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index fe4ec9f96c..253ddfc253 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -1395,9 +1395,9 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1, size_t n2
}
#ifdef WIN32
-#ifndef CP_UTF8
-# define CP_UTF8 65001 // magic number from winnls.h
-#endif
+# ifndef CP_UTF8
+# define CP_UTF8 65001 // magic number from winnls.h
+# endif
/// Converts string from UTF-8 to UTF-16.
///
@@ -2208,13 +2208,13 @@ char_u *enc_locale(void)
char buf[50];
const char *s;
-# ifdef HAVE_NL_LANGINFO_CODESET
+#ifdef HAVE_NL_LANGINFO_CODESET
if (!(s = nl_langinfo(CODESET)) || *s == NUL)
-# endif
+#endif
{
-# if defined(HAVE_LOCALE_H)
+#if defined(HAVE_LOCALE_H)
if (!(s = setlocale(LC_CTYPE, NULL)) || *s == NUL)
-# endif
+#endif
{
if ((s = os_getenv("LC_ALL"))) {
if ((s = os_getenv("LC_CTYPE"))) {
@@ -2265,7 +2265,7 @@ enc_locale_copy_enc:
return enc_canonize((char_u *)buf);
}
-# if defined(HAVE_ICONV)
+#if defined(HAVE_ICONV)
/*
@@ -2277,7 +2277,7 @@ enc_locale_copy_enc:
void *my_iconv_open(char_u *to, char_u *from)
{
iconv_t fd;
-#define ICONV_TESTLEN 400
+# define ICONV_TESTLEN 400
char_u tobuf[ICONV_TESTLEN];
char *p;
size_t tolen;
@@ -2395,7 +2395,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen
return result;
}
-# endif // HAVE_ICONV
+#endif // HAVE_ICONV
@@ -2425,11 +2425,11 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, c
int to_is_utf8;
// Reset to no conversion.
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1) {
iconv_close(vcp->vc_fd);
}
-# endif
+#endif
*vcp = (vimconv_T)MBYTE_NONE_CONV;
// No conversion when one of the names is empty or they are equal.
@@ -2466,7 +2466,7 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, c
// Internal utf-8 -> latin9 conversion.
vcp->vc_type = CONV_TO_LATIN9;
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
else { // NOLINT(readability/braces)
// Use iconv() for conversion.
vcp->vc_fd = (iconv_t)my_iconv_open(to_is_utf8 ? (char_u *)"utf-8" : to,
@@ -2476,7 +2476,7 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, c
vcp->vc_factor = 4; // could be longer too...
}
}
-# endif
+#endif
if (vcp->vc_type == CONV_NONE) {
return FAIL;
}
@@ -2644,11 +2644,11 @@ char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp
}
break;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
case CONV_ICONV: // conversion with vcp->vc_fd
retval = iconv_string(vcp, ptr, len, unconvlenp, lenp);
break;
-# endif
+#endif
}
return retval;
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 0f5f4c1e40..5e6c6a8189 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -526,35 +526,35 @@ void time_to_bytes(time_t time_, uint8_t buf[8])
#if defined(EXITFREE)
-#include "nvim/buffer.h"
-#include "nvim/charset.h"
-#include "nvim/diff.h"
-#include "nvim/edit.h"
-#include "nvim/eval/typval.h"
-#include "nvim/ex_cmds.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/ex_getln.h"
-#include "nvim/file_search.h"
-#include "nvim/fileio.h"
-#include "nvim/fold.h"
-#include "nvim/getchar.h"
-#include "nvim/mark.h"
-#include "nvim/mbyte.h"
-#include "nvim/memline.h"
-#include "nvim/move.h"
-#include "nvim/ops.h"
-#include "nvim/option.h"
-#include "nvim/os/os.h"
-#include "nvim/os_unix.h"
-#include "nvim/path.h"
-#include "nvim/quickfix.h"
-#include "nvim/regexp.h"
-#include "nvim/screen.h"
-#include "nvim/search.h"
-#include "nvim/spell.h"
-#include "nvim/syntax.h"
-#include "nvim/tag.h"
-#include "nvim/window.h"
+# include "nvim/buffer.h"
+# include "nvim/charset.h"
+# include "nvim/diff.h"
+# include "nvim/edit.h"
+# include "nvim/eval/typval.h"
+# include "nvim/ex_cmds.h"
+# include "nvim/ex_docmd.h"
+# include "nvim/ex_getln.h"
+# include "nvim/file_search.h"
+# include "nvim/fileio.h"
+# include "nvim/fold.h"
+# include "nvim/getchar.h"
+# include "nvim/mark.h"
+# include "nvim/mbyte.h"
+# include "nvim/memline.h"
+# include "nvim/move.h"
+# include "nvim/ops.h"
+# include "nvim/option.h"
+# include "nvim/os/os.h"
+# include "nvim/os_unix.h"
+# include "nvim/path.h"
+# include "nvim/quickfix.h"
+# include "nvim/regexp.h"
+# include "nvim/screen.h"
+# include "nvim/search.h"
+# include "nvim/spell.h"
+# include "nvim/syntax.h"
+# include "nvim/tag.h"
+# include "nvim/window.h"
/*
* Free everything that we allocated.
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 2b1a250604..de8503f9d0 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -64,7 +64,7 @@ static vimmenu_T **get_root_menu(const char_u *const name)
/// @param eap Ex command arguments
void ex_menu(exarg_T *eap)
{
- char_u *menu_path;
+ char *menu_path;
int modes;
char_u *map_to; // command mapped to the menu entry
int noremap;
@@ -166,7 +166,7 @@ void ex_menu(exarg_T *eap)
}
- menu_path = arg;
+ menu_path = (char *)arg;
if (*menu_path == '.') {
EMSG2(_(e_invarg2), menu_path);
goto theend;
@@ -178,25 +178,25 @@ void ex_menu(exarg_T *eap)
* If there is only a menu name, display menus with that name.
*/
if (*map_to == NUL && !unmenu && enable == kNone) {
- show_menus(menu_path, modes);
+ show_menus((char_u *)menu_path, modes);
goto theend;
} else if (*map_to != NUL && (unmenu || enable != kNone)) {
EMSG(_(e_trailing));
goto theend;
}
- vimmenu_T **root_menu_ptr = get_root_menu(menu_path);
+ vimmenu_T **root_menu_ptr = get_root_menu((char_u *)menu_path);
if (enable != kNone) {
// Change sensitivity of the menu.
// For the PopUp menu, remove a menu for each mode separately.
// Careful: menu_enable_recurse() changes menu_path.
if (STRCMP(menu_path, "*") == 0) { // meaning: do all menus
- menu_path = (char_u *)"";
+ menu_path = "";
}
if (menu_is_popup(menu_path)) {
- for (i = 0; i < MENU_INDEX_TIP; ++i) {
+ for (i = 0; i < MENU_INDEX_TIP; i++) {
if (modes & (1 << i)) {
p = popup_mode_name(menu_path, i);
menu_enable_recurse(*root_menu_ptr, p, MENU_ALL_MODES, enable);
@@ -204,20 +204,20 @@ void ex_menu(exarg_T *eap)
}
}
}
- menu_enable_recurse(*root_menu_ptr, menu_path, modes, enable);
+ menu_enable_recurse(*root_menu_ptr, (char_u *)menu_path, modes, enable);
} else if (unmenu) {
/*
* Delete menu(s).
*/
if (STRCMP(menu_path, "*") == 0) { // meaning: remove all menus
- menu_path = (char_u *)"";
+ menu_path = "";
}
/*
* For the PopUp menu, remove a menu for each mode separately.
*/
if (menu_is_popup(menu_path)) {
- for (i = 0; i < MENU_INDEX_TIP; ++i) {
+ for (i = 0; i < MENU_INDEX_TIP; i++) {
if (modes & (1 << i)) {
p = popup_mode_name(menu_path, i);
remove_menu(root_menu_ptr, p, MENU_ALL_MODES, true);
@@ -227,7 +227,7 @@ void ex_menu(exarg_T *eap)
}
// Careful: remove_menu() changes menu_path
- remove_menu(root_menu_ptr, menu_path, modes, false);
+ remove_menu(root_menu_ptr, (char_u *)menu_path, modes, false);
} else {
/*
* Add menu(s).
@@ -245,13 +245,13 @@ void ex_menu(exarg_T *eap)
menuarg.modes = modes;
menuarg.noremap[0] = noremap;
menuarg.silent[0] = silent;
- add_menu_path(menu_path, &menuarg, pri_tab, map_to);
+ add_menu_path((char_u *)menu_path, &menuarg, pri_tab, map_to);
/*
* For the PopUp menu, add a menu for each mode separately.
*/
if (menu_is_popup(menu_path)) {
- for (i = 0; i < MENU_INDEX_TIP; ++i) {
+ for (i = 0; i < MENU_INDEX_TIP; i++) {
if (modes & (1 << i)) {
p = popup_mode_name(menu_path, i);
// Include all modes, to make ":amenu" work
@@ -1273,12 +1273,12 @@ int get_menu_cmd_modes(const char *cmd, bool forceit, int *noremap, int *unmenu)
* Modify a menu name starting with "PopUp" to include the mode character.
* Returns the name in allocated memory.
*/
-static char_u *popup_mode_name(char_u *name, int idx)
+static char_u *popup_mode_name(char *name, int idx)
{
size_t len = STRLEN(name);
assert(len >= 4);
- char_u *p = vim_strnsave(name, len + 1);
+ char_u *p = vim_strnsave((char_u *)name, len + 1);
memmove(p + 6, p + 5, len - 4);
p[5] = menu_mode_chars[idx];
@@ -1337,14 +1337,14 @@ static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext)
bool menu_is_menubar(const char_u *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- return !menu_is_popup(name)
+ return !menu_is_popup((char *)name)
&& !menu_is_toolbar(name)
&& !menu_is_winbar(name)
&& *name != MNU_HIDDEN_CHAR;
}
// Return true if "name" is a popup menu name.
-bool menu_is_popup(const char_u *const name)
+bool menu_is_popup(const char *const name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
return STRNCMP(name, "PopUp", 5) == 0;
@@ -1374,7 +1374,7 @@ int menu_is_separator(char_u *name)
static int menu_is_hidden(char_u *name)
{
return (name[0] == MNU_HIDDEN_CHAR)
- || (menu_is_popup(name) && name[5] != NUL);
+ || (menu_is_popup((char *)name) && name[5] != NUL);
}
// Execute "menu". Use by ":emenu" and the window toolbar.
@@ -1383,25 +1383,25 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
FUNC_ATTR_NONNULL_ARG(2)
{
int idx = -1;
- char_u *mode;
+ char *mode;
// Use the Insert mode entry when returning to Insert mode.
if (((State & INSERT) || restart_edit) && !current_sctx.sc_sid) {
- mode = (char_u *)"Insert";
+ mode = "Insert";
idx = MENU_INDEX_INSERT;
} else if (State & CMDLINE) {
- mode = (char_u *)"Command";
+ mode = "Command";
idx = MENU_INDEX_CMDLINE;
} else if (get_real_state() & VISUAL) {
/* Detect real visual mode -- if we are really in visual mode we
* don't need to do any guesswork to figure out what the selection
* is. Just execute the visual binding for the menu. */
- mode = (char_u *)"Visual";
+ mode = "Visual";
idx = MENU_INDEX_VISUAL;
} else if (eap != NULL && eap->addr_count) {
pos_T tpos;
- mode = (char_u *)"Visual";
+ mode = "Visual";
idx = MENU_INDEX_VISUAL;
/* GEDDES: This is not perfect - but it is a
@@ -1442,7 +1442,7 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
}
if (idx == -1 || eap == NULL) {
- mode = (char_u *)"Normal";
+ mode = "Normal";
idx = MENU_INDEX_NORMAL;
}
diff --git a/src/nvim/message.c b/src/nvim/message.c
index f9fe7774f6..ed673b52d3 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -762,7 +762,7 @@ bool emsgf_multiline(const char *const fmt, ...)
va_list ap;
- static char errbuf[MULTILINE_BUFSIZE];
+ static char errbuf[MULTILINE_BUFSIZE];
if (emsg_not_now()) {
return true;
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 2166631767..2dfe5df325 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -874,7 +874,7 @@ void preserve_exit(void)
*/
#ifndef BREAKCHECK_SKIP
-# define BREAKCHECK_SKIP 1000
+# define BREAKCHECK_SKIP 1000
#endif
static int breakcheck_count = 0;
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index b65d87e617..cf463fd40a 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -241,7 +241,7 @@ retnomove:
if (row < 0) {
count = 0;
for (first = true; curwin->w_topline > 1; ) {
- if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) {
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
count++;
} else {
count += plines_win(curwin, curwin->w_topline - 1, true);
@@ -251,8 +251,8 @@ retnomove:
}
first = false;
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
- if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) {
- ++curwin->w_topfill;
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
+ curwin->w_topfill++;
} else {
--curwin->w_topline;
curwin->w_topfill = 0;
@@ -283,11 +283,10 @@ retnomove:
}
if (curwin->w_topfill > 0) {
- --curwin->w_topfill;
+ curwin->w_topfill--;
} else {
- ++curwin->w_topline;
- curwin->w_topfill =
- diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topline++;
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
}
}
check_topfill(curwin, false);
@@ -373,12 +372,12 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
while (row > 0) {
// Don't include filler lines in "count"
- if (win->w_p_diff
+ if (win_may_fill(win)
&& !hasFoldingWin(win, lnum, NULL, NULL, true, NULL)) {
if (lnum == win->w_topline) {
row -= win->w_topfill;
} else {
- row -= diff_check_fill(win, lnum);
+ row -= win_get_fill(win, lnum);
}
count = plines_win_nofill(win, lnum, true);
} else {
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 3a5b2fb211..c4f8e81fa3 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -197,7 +197,7 @@ void update_topline(win_T *wp)
}
}
// Check if there are more filler lines than allowed.
- if (!check_topline && wp->w_topfill > diff_check_fill(wp, wp->w_topline)) {
+ if (!check_topline && wp->w_topfill > win_get_fill(wp, wp->w_topline)) {
check_topline = true;
}
@@ -582,8 +582,7 @@ static void curs_rows(win_T *wp)
--i; // hold at inserted lines
}
}
- if (valid
- && (lnum != wp->w_topline || !wp->w_p_diff)) {
+ if (valid && (lnum != wp->w_topline || !win_may_fill(wp))) {
lnum = wp->w_lines[i].wl_lastlnum + 1;
// Cursor inside folded lines, don't count this row
if (lnum > wp->w_cursor.lnum) {
@@ -795,7 +794,7 @@ void curs_columns(win_T *wp, int may_scroll)
// column
char_u *const sbr = get_showbreak_value(wp);
if (*sbr && *get_cursor_pos_ptr() == NUL
- && wp->w_wcol == (int)vim_strsize(sbr)) {
+ && wp->w_wcol == vim_strsize(sbr)) {
wp->w_wcol = 0;
}
}
@@ -854,7 +853,7 @@ void curs_columns(win_T *wp, int may_scroll)
if (wp->w_cursor.lnum == wp->w_topline) {
wp->w_wrow += wp->w_topfill;
} else {
- wp->w_wrow += diff_check_fill(wp, wp->w_cursor.lnum);
+ wp->w_wrow += win_get_fill(wp, wp->w_cursor.lnum);
}
prev_skipcol = wp->w_skipcol;
@@ -992,7 +991,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp,
if ((local && existing_row) || visible_row) {
colnr_T off;
colnr_T col;
- int width;
+ int width;
getvcol(wp, pos, &scol, &ccol, &ecol);
@@ -1041,7 +1040,7 @@ bool scrolldown(long line_count, int byfold)
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
validate_cursor(); // w_wrow needs to be valid
while (line_count-- > 0) {
- if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)
&& curwin->w_topfill < curwin->w_height_inner - 1) {
curwin->w_topfill++;
done++;
@@ -1122,7 +1121,7 @@ bool scrollup(long line_count, int byfold)
linenr_T botline = curwin->w_botline;
if ((byfold && hasAnyFolding(curwin))
- || curwin->w_p_diff) {
+ || win_may_fill(curwin)) {
// count each sequence of folded lines as one logical line
linenr_T lnum = curwin->w_topline;
while (line_count--) {
@@ -1135,8 +1134,8 @@ bool scrollup(long line_count, int byfold)
if (lnum >= curbuf->b_ml.ml_line_count) {
break;
}
- ++lnum;
- curwin->w_topfill = diff_check_fill(curwin, lnum);
+ lnum++;
+ curwin->w_topfill = win_get_fill(curwin, lnum);
}
}
// approximate w_botline
@@ -1207,7 +1206,7 @@ static void max_topfill(void)
if (n >= curwin->w_height_inner) {
curwin->w_topfill = 0;
} else {
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
if (curwin->w_topfill + n > curwin->w_height_inner) {
curwin->w_topfill = curwin->w_height_inner - n;
}
@@ -1220,8 +1219,7 @@ static void max_topfill(void)
*/
void scrolldown_clamp(void)
{
- int can_fill = (curwin->w_topfill
- < diff_check_fill(curwin, curwin->w_topline));
+ int can_fill = (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline));
if (curwin->w_topline <= 1
&& !can_fill) {
@@ -1302,7 +1300,7 @@ void scrollup_clamp(void)
*/
static void topline_back(win_T *wp, lineoff_T *lp)
{
- if (lp->fill < diff_check_fill(wp, lp->lnum)) {
+ if (lp->fill < win_get_fill(wp, lp->lnum)) {
// Add a filler line
lp->fill++;
lp->height = 1;
@@ -1328,7 +1326,7 @@ static void topline_back(win_T *wp, lineoff_T *lp)
*/
static void botline_forw(win_T *wp, lineoff_T *lp)
{
- if (lp->fill < diff_check_fill(wp, lp->lnum + 1)) {
+ if (lp->fill < win_get_fill(wp, lp->lnum + 1)) {
// Add a filler line.
lp->fill++;
lp->height = 1;
@@ -1355,8 +1353,8 @@ static void botline_forw(win_T *wp, lineoff_T *lp)
static void botline_topline(lineoff_T *lp)
{
if (lp->fill > 0) {
- ++lp->lnum;
- lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
+ lp->lnum++;
+ lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1;
}
}
@@ -1368,8 +1366,8 @@ static void botline_topline(lineoff_T *lp)
static void topline_botline(lineoff_T *lp)
{
if (lp->fill > 0) {
- lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
- --lp->lnum;
+ lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1;
+ lp->lnum--;
}
}
@@ -1417,7 +1415,7 @@ void scroll_cursor_top(int min_scroll, int always)
// "used" already contains the number of filler lines above, don't add it
// again.
// Hide filler lines above cursor line by adding them to "extra".
- int extra = diff_check_fill(curwin, curwin->w_cursor.lnum);
+ int extra = win_get_fill(curwin, curwin->w_cursor.lnum);
/*
* Check if the lines from "top" to "bot" fit in the window. If they do,
@@ -1475,7 +1473,7 @@ void scroll_cursor_top(int min_scroll, int always)
if (curwin->w_topline > curwin->w_cursor.lnum) {
curwin->w_topline = curwin->w_cursor.lnum;
}
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
if (curwin->w_topfill > 0 && extra > off) {
curwin->w_topfill -= extra - off;
if (curwin->w_topfill < 0) {
@@ -1505,7 +1503,7 @@ void set_empty_rows(win_T *wp, int used)
} else {
wp->w_empty_rows = wp->w_height_inner - used;
if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) {
- wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
+ wp->w_filler_rows = win_get_fill(wp, wp->w_botline);
if (wp->w_empty_rows > wp->w_filler_rows) {
wp->w_empty_rows -= wp->w_filler_rows;
} else {
@@ -1531,10 +1529,10 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
lineoff_T boff;
int fill_below_window;
linenr_T old_topline = curwin->w_topline;
- int old_topfill = curwin->w_topfill;
+ int old_topfill = curwin->w_topfill;
linenr_T old_botline = curwin->w_botline;
- int old_valid = curwin->w_valid;
- int old_empty_rows = curwin->w_empty_rows;
+ int old_valid = curwin->w_valid;
+ int old_empty_rows = curwin->w_empty_rows;
linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
long so = get_scrolloff_value(curwin);
@@ -1590,7 +1588,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
}
loff.fill = 0;
boff.fill = 0;
- fill_below_window = diff_check_fill(curwin, curwin->w_botline)
+ fill_below_window = win_get_fill(curwin, curwin->w_botline)
- curwin->w_filler_rows;
while (loff.lnum > 1) {
@@ -1835,7 +1833,7 @@ void cursor_correct(void)
// Count filler lines below this line as context.
if (topline < botline) {
- above += diff_check_fill(curwin, topline + 1);
+ above += win_get_fill(curwin, topline + 1);
}
++topline;
}
@@ -1889,9 +1887,7 @@ int onepage(Direction dir, long count)
? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so)
&& curwin->w_botline > curbuf->b_ml.ml_line_count)
: (curwin->w_topline == 1
- && curwin->w_topfill ==
- diff_check_fill(curwin, curwin->w_topline)
- )) {
+ && curwin->w_topfill == win_get_fill(curwin, curwin->w_topline))) {
beep_flush();
retval = FAIL;
break;
@@ -1919,7 +1915,7 @@ int onepage(Direction dir, long count)
/* For the overlap, start with the line just below the window
* and go upwards. */
loff.lnum = curwin->w_botline;
- loff.fill = diff_check_fill(curwin, loff.lnum)
+ loff.fill = win_get_fill(curwin, loff.lnum)
- curwin->w_filler_rows;
get_scroll_overlap(&loff, -1);
curwin->w_topline = loff.lnum;
@@ -1956,8 +1952,7 @@ int onepage(Direction dir, long count)
* line at the bottom of the window. Make sure this results in
* the same line as before doing CTRL-F. */
loff.lnum = curwin->w_topline - 1;
- loff.fill = diff_check_fill(curwin, loff.lnum + 1)
- - curwin->w_topfill;
+ loff.fill = win_get_fill(curwin, loff.lnum + 1) - curwin->w_topfill;
get_scroll_overlap(&loff, 1);
if (loff.lnum >= curbuf->b_ml.ml_line_count) {
@@ -2000,8 +1995,7 @@ int onepage(Direction dir, long count)
/* First try using the maximum number of filler lines. If
* that's not enough, backup one line. */
loff.fill = curwin->w_topfill;
- if (curwin->w_topfill < diff_check_fill(curwin,
- curwin->w_topline)) {
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
max_topfill();
}
if (curwin->w_topfill == loff.fill) {
@@ -2146,8 +2140,8 @@ void halfpage(bool flag, linenr_T Prenum)
break;
}
(void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
- ++curwin->w_topline;
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topline++;
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
++curwin->w_cursor.lnum;
@@ -2158,11 +2152,9 @@ void halfpage(bool flag, linenr_T Prenum)
curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
scrolled += i;
- /*
- * Correct w_botline for changed w_topline.
- * Won't work when there are filler lines.
- */
- if (curwin->w_p_diff) {
+ // Correct w_botline for changed w_topline.
+ // Won't work when there are filler lines.
+ if (win_may_fill(curwin)) {
curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
} else {
room += i;
@@ -2197,7 +2189,7 @@ void halfpage(bool flag, linenr_T Prenum)
* scroll the text down
*/
while (n > 0 && curwin->w_topline > 1) {
- if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline)) {
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
i = 1;
n--;
curwin->w_topfill++;
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 813f21407c..a1a1f0f8c0 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -33,8 +33,8 @@
#include "nvim/vim.h"
#if MIN_LOG_LEVEL > DEBUG_LOG_LEVEL
-#define log_client_msg(...)
-#define log_server_msg(...)
+# define log_client_msg(...)
+# define log_server_msg(...)
#endif
static PMap(cstr_t) event_strings = MAP_INIT;
@@ -699,14 +699,14 @@ const char *rpc_client_name(Channel *chan)
}
#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
-#define REQ "[request] "
-#define RES "[response] "
-#define NOT "[notify] "
-#define ERR "[error] "
+# define REQ "[request] "
+# define RES "[response] "
+# define NOT "[notify] "
+# define ERR "[error] "
// Cannot define array with negative offsets, so this one is needed to be added
// to MSGPACK_UNPACK_\* values.
-#define MUR_OFF 2
+# define MUR_OFF 2
static const char *const msgpack_error_messages[] = {
[MSGPACK_UNPACK_EXTRA_BYTES + MUR_OFF] = "extra bytes found",
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 0bc58fffba..549016e751 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -15,6 +15,7 @@
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "keysets.generated.h"
# include "msgpack_rpc/helpers.c.generated.h"
#endif
@@ -47,17 +48,15 @@ static msgpack_sbuffer sbuffer;
} \
\
static void msgpack_rpc_from_##lt(Integer o, msgpack_packer *res) \
-/* uncrustify:indent-off */ \
FUNC_ATTR_NONNULL_ARG(2) \
-/* uncrustify:indent-on */ \
{ \
- msgpack_packer pac; \
- msgpack_packer_init(&pac, &sbuffer, msgpack_sbuffer_write); \
- msgpack_pack_int64(&pac, (handle_T)o); \
- msgpack_pack_ext(res, sbuffer.size, \
- kObjectType##t - EXT_OBJECT_TYPE_SHIFT); \
- msgpack_pack_ext_body(res, sbuffer.data, sbuffer.size); \
- msgpack_sbuffer_clear(&sbuffer); \
+ msgpack_packer pac; \
+ msgpack_packer_init(&pac, &sbuffer, msgpack_sbuffer_write); \
+ msgpack_pack_int64(&pac, (handle_T)o); \
+ msgpack_pack_ext(res, sbuffer.size, \
+ kObjectType##t - EXT_OBJECT_TYPE_SHIFT); \
+ msgpack_pack_ext_body(res, sbuffer.data, sbuffer.size); \
+ msgpack_sbuffer_clear(&sbuffer); \
}
void msgpack_rpc_helpers_init(void)
@@ -90,11 +89,11 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
kvec_withinit_t(MPToAPIObjectStackItem, 2) stack = KV_INITIAL_VALUE;
kvi_init(stack);
kvi_push(stack, ((MPToAPIObjectStackItem) {
- .mobj = obj,
- .aobj = arg,
- .container = false,
- .idx = 0,
- }));
+ .mobj = obj,
+ .aobj = arg,
+ .container = false,
+ .idx = 0,
+ }));
while (ret && kv_size(stack)) {
MPToAPIObjectStackItem cur = kv_last(stack);
if (!cur.container) {
@@ -154,19 +153,19 @@ case type: { \
cur.idx++;
kv_last(stack) = cur;
kvi_push(stack, ((MPToAPIObjectStackItem) {
- .mobj = &cur.mobj->via.array.ptr[idx],
- .aobj = &cur.aobj->data.array.items[idx],
- .container = false,
- }));
+ .mobj = &cur.mobj->via.array.ptr[idx],
+ .aobj = &cur.aobj->data.array.items[idx],
+ .container = false,
+ }));
}
} else {
*cur.aobj = ARRAY_OBJ(((Array) {
- .size = size,
- .capacity = size,
- .items = (size > 0
+ .size = size,
+ .capacity = size,
+ .items = (size > 0
? xcalloc(size, sizeof(*cur.aobj->data.array.items))
: NULL),
- }));
+ }));
cur.container = true;
kv_last(stack) = cur;
}
@@ -207,20 +206,20 @@ case type: { \
}
if (ret) {
kvi_push(stack, ((MPToAPIObjectStackItem) {
- .mobj = &cur.mobj->via.map.ptr[idx].val,
- .aobj = &cur.aobj->data.dictionary.items[idx].value,
- .container = false,
- }));
+ .mobj = &cur.mobj->via.map.ptr[idx].val,
+ .aobj = &cur.aobj->data.dictionary.items[idx].value,
+ .container = false,
+ }));
}
}
} else {
*cur.aobj = DICTIONARY_OBJ(((Dictionary) {
- .size = size,
- .capacity = size,
- .items = (size > 0
+ .size = size,
+ .capacity = size,
+ .items = (size > 0
? xcalloc(size, sizeof(*cur.aobj->data.dictionary.items))
: NULL),
- }));
+ }));
cur.container = true;
kv_last(stack) = cur;
}
@@ -412,9 +411,9 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
cur.idx++;
kv_last(stack) = cur;
kvi_push(stack, ((APIToMPObjectStackItem) {
- .aobj = &cur.aobj->data.array.items[idx],
- .container = false,
- }));
+ .aobj = &cur.aobj->data.array.items[idx],
+ .container = false,
+ }));
}
} else {
msgpack_pack_array(res, size);
@@ -435,9 +434,9 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key,
res);
kvi_push(stack, ((APIToMPObjectStackItem) {
- .aobj = &cur.aobj->data.dictionary.items[idx].value,
- .container = false,
- }));
+ .aobj = &cur.aobj->data.dictionary.items[idx].value,
+ .container = false,
+ }));
}
} else {
msgpack_pack_map(res, size);
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index b8a62a8fea..493c704f42 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -3372,7 +3372,7 @@ static void may_clear_cmdline(void)
}
// Routines for displaying a partly typed command
-# define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
+#define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
static char_u showcmd_buf[SHOWCMD_BUFLEN];
static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; // For push_showcmd()
static bool showcmd_is_clear = true;
@@ -5261,16 +5261,15 @@ static void nv_scroll(cmdarg_T *cap)
} else {
if (cap->cmdchar == 'M') {
// Don't count filler lines above the window.
- used -= diff_check_fill(curwin, curwin->w_topline)
+ used -= win_get_fill(curwin, curwin->w_topline)
- curwin->w_topfill;
validate_botline(curwin); // make sure w_empty_rows is valid
half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2;
for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; n++) {
// Count half he number of filler lines to be "below this
// line" and half to be "above the next line".
- if (n > 0 && used + diff_check_fill(curwin, curwin->w_topline
- + n) / 2 >= half) {
- --n;
+ if (n > 0 && used + win_get_fill(curwin, curwin->w_topline + n) / 2 >= half) {
+ n--;
break;
}
used += plines_win(curwin, curwin->w_topline + n, true);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 310f382db7..5646a62cd4 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -374,11 +374,11 @@ void set_init_1(bool clean_arg)
* temp files.
*/
{
-# ifdef UNIX
+#ifdef UNIX
static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" };
-# else
+#else
static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" };
-# endif
+#endif
garray_T ga;
opt_idx = findoption("backupskip");
@@ -386,16 +386,16 @@ void set_init_1(bool clean_arg)
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
bool mustfree = true;
char *p;
-# ifdef UNIX
+#ifdef UNIX
if (*names[n] == NUL) {
-# ifdef __APPLE__
+# ifdef __APPLE__
p = "/private/tmp";
-# else
+# else
p = "/tmp";
-# endif
+# endif
mustfree = false;
} else
-# endif
+#endif
{
p = vim_getenv(names[n]);
}
@@ -2397,6 +2397,8 @@ static char_u *did_set_string_option(int opt_idx, char_u **varp, bool new_value_
os_setenv("VIMRUNTIME", "", 1);
didset_vimruntime = false;
}
+ } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath'
+ runtime_search_path_invalidate();
} else if (varp == &curwin->w_p_culopt
|| gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK) {
@@ -3439,7 +3441,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
struct chars_tab {
int *cp; ///< char value
char *name; ///< char id
- int def; ///< default value
+ int def; ///< default value
};
struct chars_tab *tab;
@@ -5829,10 +5831,10 @@ static char_u *get_varp(vimoption_T *p)
return (char_u *)&(curbuf->b_p_cms);
case PV_CPT:
return (char_u *)&(curbuf->b_p_cpt);
-# ifdef BACKSLASH_IN_FILENAME
+#ifdef BACKSLASH_IN_FILENAME
case PV_CSL:
return (char_u *)&(curbuf->b_p_csl);
-# endif
+#endif
case PV_CFU:
return (char_u *)&(curbuf->b_p_cfu);
case PV_OFU:
@@ -6177,9 +6179,9 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inf = p_inf;
buf->b_p_swf = cmdmod.noswapfile ? false : p_swf;
buf->b_p_cpt = vim_strsave(p_cpt);
-# ifdef BACKSLASH_IN_FILENAME
+#ifdef BACKSLASH_IN_FILENAME
buf->b_p_csl = vim_strsave(p_csl);
-# endif
+#endif
buf->b_p_cfu = vim_strsave(p_cfu);
buf->b_p_ofu = vim_strsave(p_ofu);
buf->b_p_tfu = vim_strsave(p_tfu);
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index f239c9e1ec..0f363ecfc3 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -22,15 +22,15 @@
#include "nvim/vim.h"
#ifdef WIN32
-#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
+# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
#endif
#ifdef HAVE__NSGETENVIRON
-#include <crt_externs.h>
+# include <crt_externs.h>
#endif
#ifdef HAVE_SYS_UTSNAME_H
-#include <sys/utsname.h>
+# include <sys/utsname.h>
#endif
// Because `uv_os_getenv` requires allocating, we must manage a map to maintain
@@ -1161,7 +1161,7 @@ char_u *home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
/// Function given to ExpandGeneric() to obtain an environment variable name.
char_u *get_env_name(expand_T *xp, int idx)
{
-# define ENVNAMELEN 100
+#define ENVNAMELEN 100
// this static buffer is needed to avoid a memory leak in ExpandGeneric
static char_u name[ENVNAMELEN];
assert(idx >= 0);
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index d50d68c99e..bbf70a4830 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -29,7 +29,7 @@
#include "nvim/strings.h"
#ifdef WIN32
-#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
+# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -1226,12 +1226,12 @@ char *os_resolve_shortcut(const char *fname)
goto shortcut_errorw;
}
-# if 0 // This makes Vim wait a long time if the target does not exist.
+# if 0 // This makes Vim wait a long time if the target does not exist.
hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI);
if (hr != S_OK) {
goto shortcut_errorw;
}
-# endif
+# endif
// Get the path to the link target.
ZeroMemory(wsz, MAX_PATH * sizeof(wchar_t));
@@ -1262,7 +1262,7 @@ shortcut_end:
return rfname;
}
-#define is_path_sep(c) ((c) == L'\\' || (c) == L'/')
+# define is_path_sep(c) ((c) == L'\\' || (c) == L'/')
/// Returns true if the path contains a reparse point (junction or symbolic
/// link). Otherwise false in returned.
bool os_is_reparse_point_include(const char *path)
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index d94de2e397..24ecf5c24f 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -157,7 +157,7 @@ static void init_child(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
#if defined(HAVE__NSGETENVIRON)
-#define environ (*_NSGetEnviron())
+# define environ (*_NSGetEnviron())
#else
extern char **environ;
#endif
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index f0d446b4c5..2bff65b241 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -873,10 +873,10 @@ static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *dat
/// Returns the previous decision if size=0.
static bool out_data_decide_throttle(size_t size)
{
- static uint64_t started = 0; // Start time of the current throttle.
- static size_t received = 0; // Bytes observed since last throttle.
- static size_t visit = 0; // "Pulse" count of the current throttle.
- static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
+ static uint64_t started = 0; // Start time of the current throttle.
+ static size_t received = 0; // Bytes observed since last throttle.
+ static size_t visit = 0; // "Pulse" count of the current throttle.
+ static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
if (!size) {
bool previous_decision = (visit > 0);
@@ -933,8 +933,8 @@ static bool out_data_decide_throttle(size_t size)
static void out_data_ring(char *output, size_t size)
{
#define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2)
- static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
- static size_t last_skipped_len = 0;
+ static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
+ static size_t last_skipped_len = 0;
assert(output != NULL || (size == 0 || size == SIZE_MAX));
diff --git a/src/nvim/os/tty.c b/src/nvim/os/tty.c
index c80ef99084..126b1b0044 100644
--- a/src/nvim/os/tty.c
+++ b/src/nvim/os/tty.c
@@ -23,15 +23,6 @@
/// @param out_fd stdout file descriptor
void os_tty_guess_term(const char **term, int out_fd)
{
- bool winpty = (os_getenv("NVIM") != NULL);
-
- if (winpty) {
- // Force TERM=win32con when running in winpty.
- *term = "win32con";
- uv_tty_set_vterm_state(UV_TTY_UNSUPPORTED);
- return;
- }
-
bool conemu_ansi = strequal(os_getenv("ConEmuANSI"), "ON");
bool vtp = false;
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index 2687c66f24..fd7ead68da 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -43,7 +43,7 @@ int os_get_usernames(garray_T *users)
}
ga_init(users, sizeof(char *), 20);
-# if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
+#if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
{
struct passwd *pw;
@@ -53,7 +53,7 @@ int os_get_usernames(garray_T *users)
}
endpwent();
}
-# elif defined(WIN32)
+#elif defined(WIN32)
{
DWORD nusers = 0, ntotal = 0, i;
PUSER_INFO_0 uinfo;
@@ -73,8 +73,8 @@ int os_get_usernames(garray_T *users)
NetApiBufferFree(uinfo);
}
}
-# endif
-# if defined(HAVE_GETPWNAM)
+#endif
+#if defined(HAVE_GETPWNAM)
{
const char *user_env = os_getenv("USER");
@@ -104,7 +104,7 @@ int os_get_usernames(garray_T *users)
}
}
}
-# endif
+#endif
return OK;
}
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index 28138af13c..5b0418ed92 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -13,6 +13,7 @@
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/decoration.h"
#include "nvim/diff.h"
#include "nvim/fold.h"
#include "nvim/func_attr.h"
@@ -41,7 +42,34 @@ int plines_win(win_T *wp, linenr_T lnum, bool winheight)
{
// Check for filler lines above this buffer line. When folded the result
// is one line anyway.
- return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum);
+ return plines_win_nofill(wp, lnum, winheight) + win_get_fill(wp, lnum);
+}
+
+
+/// Return the number of filler lines above "lnum".
+///
+/// @param wp
+/// @param lnum
+///
+/// @return Number of filler lines above lnum
+int win_get_fill(win_T *wp, linenr_T lnum)
+{
+ int virt_lines = decor_virtual_lines(wp, lnum);
+
+ // be quick when there are no filler lines
+ if (diffopt_filler()) {
+ int n = diff_check(wp, lnum);
+
+ if (n > 0) {
+ return virt_lines+n;
+ }
+ }
+ return virt_lines;
+}
+
+bool win_may_fill(win_T *wp)
+{
+ return (wp->w_p_diff && diffopt_filler()) || wp->w_buffer->b_virt_line_mark;
}
/// @param winheight when true limit to window height
@@ -107,7 +135,7 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column)
{
// Check for filler lines above this buffer line. When folded the result
// is one line anyway.
- int lines = diff_check_fill(wp, lnum);
+ int lines = win_get_fill(wp, lnum);
if (!wp->w_p_wrap) {
return lines + 1;
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index aeb2c8c44a..606c03f838 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -514,7 +514,7 @@ void pum_redraw(void)
char_u saved = *p;
*p = NUL;
- st = (char_u *)transstr((const char *)s);
+ st = (char_u *)transstr((const char *)s, true);
*p = saved;
if (pum_rl) {
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index d0bd63e6ca..eb0ba874f4 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -93,7 +93,7 @@ typedef enum
/// information and entries can be added later using setqflist()/setloclist().
typedef struct qf_list_S {
unsigned qf_id; ///< Unique identifier for this list
- qfltype_T qfl_type;
+ qfltype_T qfl_type;
qfline_T *qf_start; ///< pointer to the first error
qfline_T *qf_last; ///< pointer to the last error
qfline_T *qf_ptr; ///< pointer to the current error
@@ -103,7 +103,7 @@ typedef struct qf_list_S {
char_u *qf_title; ///< title derived from the command that created
///< the error list or set by setqflist
typval_T *qf_ctx; ///< context set by setqflist/setloclist
- Callback qftf_cb; ///< 'quickfixtextfunc' callback function
+ Callback qftf_cb; ///< 'quickfixtextfunc' callback function
struct dir_stack_T *qf_dir_stack;
char_u *qf_directory;
@@ -201,13 +201,13 @@ typedef struct {
size_t errmsglen;
long lnum;
long end_lnum;
- int col;
+ int col;
int end_col;
bool use_viscol;
char_u *pattern;
- int enr;
+ int enr;
char_u type;
- bool valid;
+ bool valid;
} qffields_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -244,7 +244,7 @@ static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
// Looking up a buffer can be slow if there are many. Remember the last one
// to make this a lot faster if there are multiple matches in the same file.
static char_u *qf_last_bufname = NULL;
-static bufref_T qf_last_bufref = { NULL, 0, 0 };
+static bufref_T qf_last_bufref = { NULL, 0, 0 };
static char *e_current_quickfix_list_was_changed =
N_("E925: Current quickfix list was changed");
@@ -913,7 +913,7 @@ static int qf_parse_line(qf_list_T *qfl, char_u *linebuf, size_t linelen, efm_T
qffields_T *fields)
{
efm_T *fmt_ptr;
- int idx = 0;
+ int idx = 0;
char_u *tail = NULL;
int status;
@@ -3115,8 +3115,8 @@ void qf_list(exarg_T *eap)
int idx1 = 1;
int idx2 = -1;
char_u *arg = eap->arg;
- int all = eap->forceit; // if not :cl!, only show
- // recognised errors
+ int all = eap->forceit; // if not :cl!, only show
+ // recognised errors
qf_info_T *qi;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
@@ -6448,7 +6448,7 @@ static int qf_setprop_items_from_lines(qf_info_T *qi, int qf_idx, const dict_T *
{
char_u *errorformat = p_efm;
dictitem_T *efm_di;
- int retval = FAIL;
+ int retval = FAIL;
// Use the user supplied errorformat settings (if present)
if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
@@ -6491,7 +6491,7 @@ static int qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, const dictitem_T *di)
FUNC_ATTR_NONNULL_ALL
{
- int newidx;
+ int newidx;
// If the specified index is '$', then use the last entry
if (di->di_tv.v_type == VAR_STRING
@@ -6537,7 +6537,7 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char
{
qf_list_T *qfl;
dictitem_T *di;
- int retval = FAIL;
+ int retval = FAIL;
bool newlist = action == ' ' || qf_stack_empty(qi);
int qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
if (qf_idx == INVALID_QFIDX) { // List not found
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index cbd1e081b3..e1669a8c19 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -5,6 +5,7 @@
///
/// Management of runtime files (including packages)
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
@@ -20,6 +21,9 @@
# include "runtime.c.generated.h"
#endif
+static bool runtime_search_path_valid = false;
+static int *runtime_search_path_ref = NULL;
+static RuntimeSearchPath runtime_search_path;
/// ":runtime [what] {name}"
void ex_runtime(exarg_T *eap)
@@ -89,8 +93,7 @@ int do_in_path(char_u *path, char_u *name, int flags, DoInRuntimepathCB callback
// Skip after or non-after directories.
if (flags & (DIP_NOAFTER | DIP_AFTER)) {
- bool is_after = buflen >= 5
- && STRCMP(buf + buflen - 5, "after") == 0;
+ bool is_after = path_is_after(buf, buflen);
if ((is_after && (flags & DIP_NOAFTER))
|| (!is_after && (flags & DIP_AFTER))) {
@@ -155,6 +158,115 @@ int do_in_path(char_u *path, char_u *name, int flags, DoInRuntimepathCB callback
return did_one ? OK : FAIL;
}
+/// Find the file "name" in all directories in "path" and invoke
+/// "callback(fname, cookie)".
+/// "name" can contain wildcards.
+/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
+/// When "flags" has DIP_DIR: find directories instead of files.
+/// When "flags" has DIP_ERR: give an error message if there is no match.
+///
+/// return FAIL when no file could be sourced, OK otherwise.
+int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void *cookie)
+{
+ runtime_search_path_validate();
+ char_u *tail;
+ int num_files;
+ char_u **files;
+ int i;
+ bool did_one = false;
+
+ char_u buf[MAXPATHL];
+
+ if (p_verbose > 10 && name != NULL) {
+ verbose_enter();
+ smsg(_("Searching for \"%s\" in runtime path"), (char *)name);
+ verbose_leave();
+ }
+
+ RuntimeSearchPath path = runtime_search_path;
+ int ref = 0;
+ if (runtime_search_path_ref == NULL) {
+ // cached path was unreferenced. keep a ref to
+ // prevent runtime_search_path() to freeing it too early
+ ref++;
+ runtime_search_path_ref = &ref;
+ }
+
+ // Loop over all entries in cached path
+ for (size_t j = 0; j < kv_size(path); j++) {
+ SearchPathItem item = kv_A(path, j);
+ size_t buflen = strlen(item.path);
+
+ // Skip after or non-after directories.
+ if (flags & (DIP_NOAFTER | DIP_AFTER)) {
+ if ((item.after && (flags & DIP_NOAFTER))
+ || (!item.after && (flags & DIP_AFTER))) {
+ continue;
+ }
+ }
+
+ if (name == NULL) {
+ (*callback)((char_u *)item.path, cookie);
+ did_one = true;
+ } else if (buflen + STRLEN(name) + 2 < MAXPATHL) {
+ STRCPY(buf, item.path);
+ add_pathsep((char *)buf);
+ tail = buf + STRLEN(buf);
+
+ // Loop over all patterns in "name"
+ char_u *np = name;
+ while (*np != NUL && ((flags & DIP_ALL) || !did_one)) {
+ // Append the pattern from "name" to buf[].
+ assert(MAXPATHL >= (tail - buf));
+ copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)),
+ "\t ");
+
+ if (p_verbose > 10) {
+ verbose_enter();
+ smsg(_("Searching for \"%s\""), buf);
+ verbose_leave();
+ }
+
+ int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE)
+ | (flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0;
+
+ // Expand wildcards, invoke the callback for each match.
+ char_u *(pat[]) = { buf };
+ if (gen_expand_wildcards(1, pat, &num_files, &files, ew_flags) == OK) {
+ for (i = 0; i < num_files; i++) {
+ (*callback)(files[i], cookie);
+ did_one = true;
+ if (!(flags & DIP_ALL)) {
+ break;
+ }
+ }
+ FreeWild(num_files, files);
+ }
+ }
+ }
+ }
+
+ if (!did_one && name != NULL) {
+ if (flags & DIP_ERR) {
+ EMSG3(_(e_dirnotf), "runtime path", name);
+ } else if (p_verbose > 0) {
+ verbose_enter();
+ smsg(_("not found in runtime path: \"%s\""), name);
+ verbose_leave();
+ }
+ }
+
+ if (ref) {
+ if (runtime_search_path_ref == &ref) {
+ runtime_search_path_ref = NULL;
+ } else {
+ runtime_search_path_free(path);
+ }
+ }
+
+
+ return did_one ? OK : FAIL;
+}
/// Find "name" in "path". When found, invoke the callback function for
/// it: callback(fname, "cookie")
/// When "flags" has DIP_ALL repeat for all matches, otherwise only the first
@@ -167,13 +279,6 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB c
void *cookie)
{
int done = FAIL;
- if (!(flags & (DIP_NOAFTER | DIP_AFTER))) {
- done = do_in_path_and_pp(path, name, flags | DIP_NOAFTER, callback, cookie);
- if (done == OK && !(flags & DIP_ALL)) {
- return done;
- }
- flags |= DIP_AFTER;
- }
if ((flags & DIP_NORTP) == 0) {
done |= do_in_path(path, (name && !*name) ? NULL : name, flags, callback, cookie);
@@ -227,10 +332,182 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB c
return done;
}
+static void push_path(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used,
+ char *entry, bool after)
+{
+ handle_T h = map_get(String, handle_T)(rtp_used, cstr_as_string((char *)entry));
+ if (h == 0) {
+ char *allocated = xstrdup(entry);
+ map_put(String, handle_T)(rtp_used, cstr_as_string(allocated), 1);
+ kv_push(*search_path, ((SearchPathItem){ allocated, after }));
+ }
+}
+
+static void expand_rtp_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used,
+ char *entry, bool after)
+{
+ if (map_get(String, handle_T)(rtp_used, cstr_as_string(entry))) {
+ return;
+ }
+
+ if (!*entry) {
+ push_path(search_path, rtp_used, entry, after);
+ }
+
+ int num_files;
+ char_u **files;
+ char_u *(pat[]) = { (char_u *)entry };
+ if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) {
+ for (int i = 0; i < num_files; i++) {
+ push_path(search_path, rtp_used, (char *)files[i], after);
+ }
+ FreeWild(num_files, files);
+ }
+}
+
+static void expand_pack_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used,
+ CharVec *after_path, char_u *pack_entry)
+{
+ static char buf[MAXPATHL];
+ char *(start_pat[]) = { "/pack/*/start/*", "/start/*" }; // NOLINT
+ for (int i = 0; i < 2; i++) {
+ if (STRLEN(pack_entry) + STRLEN(start_pat[i]) + 1 > MAXPATHL) {
+ continue;
+ }
+ xstrlcpy(buf, (char *)pack_entry, MAXPATHL);
+ xstrlcat(buf, start_pat[i], sizeof buf);
+ expand_rtp_entry(search_path, rtp_used, buf, false);
+ size_t after_size = STRLEN(buf)+7;
+ char *after = xmallocz(after_size);
+ xstrlcpy(after, buf, after_size);
+ xstrlcat(after, "/after", after_size);
+ kv_push(*after_path, after);
+ }
+}
+
+static bool path_is_after(char_u *buf, size_t buflen)
+{
+ // NOTE: we only consider dirs exactly matching "after" to be an AFTER dir.
+ // vim8 considers all dirs like "foo/bar_after", "Xafter" etc, as an
+ // "after" dir in SOME codepaths not not in ALL codepaths.
+ return buflen >= 5
+ && (!(buflen >= 6) || vim_ispathsep(buf[buflen-6]))
+ && STRCMP(buf + buflen - 5, "after") == 0;
+}
+
+RuntimeSearchPath runtime_search_path_build(void)
+{
+ kvec_t(String) pack_entries = KV_INITIAL_VALUE;
+ // TODO(bfredl): these should just be sets, when Set(String) is do merge to
+ // master.
+ Map(String, handle_T) pack_used = MAP_INIT;
+ Map(String, handle_T) rtp_used = MAP_INIT;
+ RuntimeSearchPath search_path = KV_INITIAL_VALUE;
+ CharVec after_path = KV_INITIAL_VALUE;
+
+ static char_u buf[MAXPATHL];
+ for (char *entry = (char *)p_pp; *entry != NUL; ) {
+ char *cur_entry = entry;
+ copy_option_part((char_u **)&entry, buf, MAXPATHL, ",");
+
+ String the_entry = { .data = cur_entry, .size = STRLEN(buf) };
+
+ kv_push(pack_entries, the_entry);
+ map_put(String, handle_T)(&pack_used, the_entry, 0);
+ }
+
+
+ char *rtp_entry;
+ for (rtp_entry = (char *)p_rtp; *rtp_entry != NUL; ) {
+ char *cur_entry = rtp_entry;
+ copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ",");
+ size_t buflen = STRLEN(buf);
+
+ if (path_is_after(buf, buflen)) {
+ rtp_entry = cur_entry;
+ break;
+ }
+
+ // fact: &rtp entries can contain wild chars
+ expand_rtp_entry(&search_path, &rtp_used, (char *)buf, false);
+
+ handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string((char *)buf), false);
+ if (h) {
+ (*h)++;
+ expand_pack_entry(&search_path, &rtp_used, &after_path, buf);
+ }
+ }
+
+ for (size_t i = 0; i < kv_size(pack_entries); i++) {
+ handle_T h = map_get(String, handle_T)(&pack_used, kv_A(pack_entries, i));
+ if (h == 0) {
+ expand_pack_entry(&search_path, &rtp_used, &after_path, (char_u *)kv_A(pack_entries, i).data);
+ }
+ }
+
+ // "after" packages
+ for (size_t i = 0; i < kv_size(after_path); i++) {
+ expand_rtp_entry(&search_path, &rtp_used, kv_A(after_path, i), true);
+ xfree(kv_A(after_path, i));
+ }
+
+ // "after" dirs in rtp
+ for (; *rtp_entry != NUL;) {
+ copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ",");
+ expand_rtp_entry(&search_path, &rtp_used, (char *)buf, path_is_after(buf, STRLEN(buf)));
+ }
+
+ // strings are not owned
+ kv_destroy(pack_entries);
+ kv_destroy(after_path);
+ map_destroy(String, handle_T)(&pack_used);
+ map_destroy(String, handle_T)(&rtp_used);
+
+ return search_path;
+}
+
+void runtime_search_path_invalidate(void)
+{
+ runtime_search_path_valid = false;
+}
+
+void runtime_search_path_free(RuntimeSearchPath path)
+{
+ for (size_t j = 0; j < kv_size(path); j++) {
+ SearchPathItem item = kv_A(path, j);
+ xfree(item.path);
+ }
+ kv_destroy(path);
+}
+
+void runtime_search_path_validate(void)
+{
+ if (!runtime_search_path_valid) {
+ if (!runtime_search_path_ref) {
+ runtime_search_path_free(runtime_search_path);
+ }
+ runtime_search_path = runtime_search_path_build();
+ runtime_search_path_valid = true;
+ runtime_search_path_ref = NULL; // initially unowned
+ }
+}
+
+
+
/// Just like do_in_path_and_pp(), using 'runtimepath' for "path".
int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback, void *cookie)
{
- return do_in_path_and_pp(p_rtp, name, flags | DIP_START, callback, cookie);
+ int success = FAIL;
+ if (!(flags & DIP_NORTP)) {
+ success |= do_in_cached_path((name && !*name) ? NULL : name, flags, callback, cookie);
+ flags = (flags & ~DIP_START) | DIP_NORTP;
+ }
+ // TODO(bfredl): we could integrate disabled OPT dirs into the cached path
+ // which would effectivize ":packadd myoptpack" as well
+ if ((flags & (DIP_START|DIP_OPT)) && (success == FAIL || (flags & DIP_ALL))) {
+ success |= do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
+ }
+ return success;
}
/// Source the file "name" from all directories in 'runtimepath'.
@@ -240,8 +517,7 @@ int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback, void
/// return FAIL when no file could be sourced, OK otherwise.
int source_runtime(char_u *name, int flags)
{
- flags |= (flags & DIP_NORTP) ? 0 : DIP_START;
- return source_in_path(p_rtp, name, flags);
+ return do_in_runtimepath(name, flags, source_callback, NULL);
}
/// Just like source_runtime(), but use "path" instead of 'runtimepath'.
@@ -266,7 +542,10 @@ static void source_all_matches(char_u *pat)
}
/// Add the package directory to 'runtimepath'
-static int add_pack_dir_to_rtp(char_u *fname)
+///
+/// @param fname the package path
+/// @param is_pack whether the added dir is a "pack/*/start/*/" style package
+static int add_pack_dir_to_rtp(char_u *fname, bool is_pack)
{
char_u *p4, *p3, *p2, *p1, *p;
char_u *buf = NULL;
@@ -344,7 +623,7 @@ static int add_pack_dir_to_rtp(char_u *fname)
// check if rtp/pack/name/start/name/after exists
afterdir = concat_fnames((char *)fname, "after", true);
size_t afterlen = 0;
- if (os_isdir((char_u *)afterdir)) {
+ if (is_pack ? pack_has_entries((char_u *)afterdir) : os_isdir((char_u *)afterdir)) {
afterlen = strlen(afterdir) + 1; // add one for comma
}
@@ -465,7 +744,7 @@ static void add_pack_plugin(bool opt, char_u *fname, void *cookie)
xfree(buf);
if (!found) {
// directory is not yet in 'runtimepath', add it
- if (add_pack_dir_to_rtp(fname) == FAIL) {
+ if (add_pack_dir_to_rtp(fname, false) == FAIL) {
return;
}
}
@@ -486,6 +765,41 @@ 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, NULL, DIP_ALL + DIP_DIR, add_pack_start_dir, NULL);
+}
+
+static bool pack_has_entries(char_u *buf)
+{
+ int num_files;
+ char_u **files;
+ char_u *(pat[]) = { (char_u *)buf };
+ if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) {
+ FreeWild(num_files, files);
+ }
+ return num_files > 0;
+}
+
+static void add_pack_start_dir(char_u *fname, void *cookie)
+{
+ static char_u buf[MAXPATHL];
+ char *(start_pat[]) = { "/start/*", "/pack/*/start/*" }; // NOLINT
+ for (int i = 0; i < 2; i++) {
+ if (STRLEN(fname) + STRLEN(start_pat[i]) + 1 > MAXPATHL) {
+ continue;
+ }
+ xstrlcpy((char *)buf, (char *)fname, MAXPATHL);
+ xstrlcat((char *)buf, start_pat[i], sizeof buf);
+ if (pack_has_entries(buf)) {
+ add_pack_dir_to_rtp(buf, true);
+ }
+ }
+}
+
+
/// Load plugins from all packages in the "start" directory.
void load_start_packages(void)
{
@@ -504,10 +818,43 @@ void ex_packloadall(exarg_T *eap)
// First do a round to add all directories to 'runtimepath', then load
// the plugins. This allows for plugins to use an autoload directory
// of another plugin.
+ add_pack_start_dirs();
load_start_packages();
}
}
+/// Read all the plugin files at startup
+void load_plugins(void)
+{
+ if (p_lpl) {
+ char_u *rtp_copy = p_rtp;
+ char_u *const plugin_pattern_vim = (char_u *)"plugin/**/*.vim"; // NOLINT
+ char_u *const plugin_pattern_lua = (char_u *)"plugin/**/*.lua"; // NOLINT
+
+ if (!did_source_packages) {
+ rtp_copy = vim_strsave(p_rtp);
+ add_pack_start_dirs();
+ }
+
+ // don't use source_runtime() yet so we can check for :packloadall below
+ source_in_path(rtp_copy, plugin_pattern_vim, DIP_ALL | DIP_NOAFTER);
+ source_in_path(rtp_copy, plugin_pattern_lua, DIP_ALL | DIP_NOAFTER);
+ TIME_MSG("loading rtp plugins");
+
+ // Only source "start" packages if not done already with a :packloadall
+ // command.
+ if (!did_source_packages) {
+ xfree(rtp_copy);
+ load_start_packages();
+ }
+ TIME_MSG("loading packages");
+
+ source_runtime(plugin_pattern_vim, DIP_ALL | DIP_AFTER);
+ source_runtime(plugin_pattern_lua, DIP_ALL | DIP_AFTER);
+ TIME_MSG("loading after plugins");
+ }
+}
+
/// ":packadd[!] {name}"
void ex_packadd(exarg_T *eap)
{
diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h
index b40c2b670e..db31ae4e1e 100644
--- a/src/nvim/runtime.h
+++ b/src/nvim/runtime.h
@@ -7,10 +7,30 @@
typedef void (*DoInRuntimepathCB)(char_u *, void *);
+typedef struct {
+ char *path;
+ bool after;
+} SearchPathItem;
+
+typedef kvec_t(SearchPathItem) RuntimeSearchPath;
+typedef kvec_t(char *) CharVec;
+
// last argument for do_source()
#define DOSO_NONE 0
#define DOSO_VIMRC 1 // loading vimrc file
+// Used for flags in do_in_path()
+#define DIP_ALL 0x01 // all matches, not just the first one
+#define DIP_DIR 0x02 // find directories instead of files
+#define DIP_ERR 0x04 // give an error message when none found
+#define DIP_START 0x08 // also use "start" directory in 'packpath'
+#define DIP_OPT 0x10 // also use "opt" directory in 'packpath'
+#define DIP_NORTP 0x20 // do not use 'runtimepath'
+#define DIP_NOAFTER 0x40 // skip "after" directories
+#define DIP_AFTER 0x80 // only use "after" directories
+#define DIP_LUA 0x100 // also use ".lua" files
+#define DIP_DIRFILE 0x200 // find both files and directories
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "runtime.h.generated.h"
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 79e960fe8b..fcd8fb1118 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1003,8 +1003,7 @@ static void win_update(win_T *wp, Providers *providers)
i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1);
// insert extra lines for previously invisible filler lines
if (wp->w_lines[0].wl_lnum != wp->w_topline) {
- i += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
- - wp->w_old_topfill;
+ i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill;
}
if (i != 0 && i < wp->w_grid.Rows - 2) { // less than a screen off
// Try to insert the correct number of lines.
@@ -1067,7 +1066,7 @@ static void win_update(win_T *wp, Providers *providers)
if (wp->w_lines[0].wl_lnum == wp->w_topline) {
row += wp->w_old_topfill;
} else {
- row += diff_check_fill(wp, wp->w_topline);
+ row += win_get_fill(wp, wp->w_topline);
}
// ... but don't delete new filler lines.
row -= wp->w_topfill;
@@ -1101,12 +1100,12 @@ static void win_update(win_T *wp, Providers *providers)
break;
}
}
- /* Correct the first entry for filler lines at the top
- * when it won't get updated below. */
- if (wp->w_p_diff && bot_start > 0) {
- wp->w_lines[0].wl_size =
- plines_win_nofill(wp, wp->w_topline, true)
- + wp->w_topfill;
+
+ // Correct the first entry for filler lines at the top
+ // when it won't get updated below.
+ if (win_may_fill(wp) && bot_start > 0) {
+ wp->w_lines[0].wl_size = (plines_win_nofill(wp, wp->w_topline, true)
+ + wp->w_topfill);
}
}
}
@@ -1564,7 +1563,7 @@ static void win_update(win_T *wp, Providers *providers)
&& lnum > wp->w_topline
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
&& srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
- && diff_check_fill(wp, lnum) == 0) {
+ && win_get_fill(wp, lnum) == 0) {
// This line is not going to fit. Don't draw anything here,
// will draw "@ " lines below.
row = wp->w_grid.Rows + 1;
@@ -1664,7 +1663,7 @@ static void win_update(win_T *wp, Providers *providers)
* Don't overwrite it, it can be edited.
*/
wp->w_botline = lnum + 1;
- } else if (diff_check_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
+ } else if (win_get_fill(wp, lnum) >= wp->w_grid.Rows - srow) {
// Window ends in filler lines.
wp->w_botline = lnum;
wp->w_filler_rows = wp->w_grid.Rows - srow;
@@ -1691,7 +1690,7 @@ static void win_update(win_T *wp, Providers *providers)
} else {
if (eof) { // we hit the end of the file
wp->w_botline = buf->b_ml.ml_line_count + 1;
- j = diff_check_fill(wp, wp->w_botline);
+ j = win_get_fill(wp, wp->w_botline);
if (j > 0 && !wp->w_botfill) {
// Display filler text below last line. win_line() will check
// for ml_line_count+1 and only draw filler lines
@@ -1866,7 +1865,7 @@ static int compute_foldcolumn(win_T *wp, int col)
/// Put a single char from an UTF-8 buffer into a line buffer.
///
/// Handles composing chars and arabic shaping state.
-static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
+static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, bool rl, int vcol)
{
const char_u *p = (char_u *)s->p;
int cells = utf_ptr2cells(p);
@@ -1876,7 +1875,13 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
return -1;
}
u8c = utfc_ptr2char(p, u8cc);
- if (*p < 0x80 && u8cc[0] == 0) {
+ if (*p == TAB) {
+ cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
+ for (int c = 0; c < cells; c++) {
+ schar_from_ascii(dest[c], ' ');
+ }
+ goto done;
+ } else if (*p < 0x80 && u8cc[0] == 0) {
schar_from_ascii(dest[0], *p);
s->prev_c = u8c;
} else {
@@ -1909,6 +1914,7 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
if (cells > 1) {
dest[1][0] = 0;
}
+done:
s->p += c_len;
return cells;
}
@@ -2055,7 +2061,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
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
+#define SPWORDLEN 150
char_u nextline[SPWORDLEN * 2]; // text with start of the next line
int nextlinecol = 0; // column where nextline[] starts
int nextline_idx = 0; /* index in nextline[] where next line
@@ -2118,12 +2124,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
// draw_state: items that are drawn in sequence:
#define WL_START 0 // nothing done yet
-# define WL_CMDLINE WL_START + 1 // cmdline window column
-# define WL_FOLD WL_CMDLINE + 1 // 'foldcolumn'
-# define WL_SIGN WL_FOLD + 1 // column for signs
+#define WL_CMDLINE WL_START + 1 // cmdline window column
+#define WL_FOLD WL_CMDLINE + 1 // 'foldcolumn'
+#define WL_SIGN WL_FOLD + 1 // column for signs
#define WL_NR WL_SIGN + 1 // line number
-# define WL_BRI WL_NR + 1 // 'breakindent'
-# define WL_SBR WL_BRI + 1 // 'showbreak' or 'diff'
+#define WL_BRI WL_NR + 1 // 'breakindent'
+#define WL_SBR WL_BRI + 1 // 'showbreak' or 'diff'
#define WL_LINE WL_SBR + 1 // text in the line
int draw_state = WL_START; // what to draw next
@@ -2138,8 +2144,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
int did_wcol = false;
int match_conc = 0; ///< cchar for match functions
int old_boguscols = 0;
-# define VCOL_HLC (vcol - vcol_off)
-# define FIX_FOR_BOGUSCOLS \
+#define VCOL_HLC (vcol - vcol_off)
+#define FIX_FOR_BOGUSCOLS \
{ \
n_extra += vcol_off; \
vcol -= vcol_off; \
@@ -2366,8 +2372,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
filler_lines = 0;
area_highlighting = true;
}
+ int virtual_lines = decor_virtual_lines(wp, lnum);
+ filler_lines += virtual_lines;
if (lnum == wp->w_topline) {
filler_lines = wp->w_topfill;
+ virtual_lines = MIN(virtual_lines, filler_lines);
}
filler_todo = filler_lines;
@@ -2895,7 +2904,18 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (draw_state == WL_SBR - 1 && n_extra == 0) {
draw_state = WL_SBR;
- if (filler_todo > 0) {
+ if (filler_todo > filler_lines - virtual_lines) {
+ // TODO(bfredl): check this doesn't inhibit TUI-style
+ // clear-to-end-of-line.
+ c_extra = ' ';
+ c_final = NUL;
+ if (wp->w_p_rl) {
+ n_extra = col + 1;
+ } else {
+ n_extra = grid->Columns - col;
+ }
+ char_attr = 0;
+ } else if (filler_todo > 0) {
// draw "deleted" diff line(s)
if (char2cells(wp->w_p_fcs_chars.diff) > 1) {
c_extra = '-';
@@ -3667,8 +3687,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
n_extra = tab_len;
} else {
char_u *p;
- int i;
- int saved_nextra = n_extra;
+ int i;
+ int saved_nextra = n_extra;
if (vcol_off > 0) {
// there are characters to conceal
@@ -4402,7 +4422,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
&& !wp->w_p_rl; // Not right-to-left.
int draw_col = col - boguscols;
- draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
+ if (filler_todo > 0) {
+ int index = filler_todo - (filler_lines - virtual_lines);
+ if (index > 0) {
+ int fpos = kv_size(buf->b_virt_lines) - index;
+ assert(fpos >= 0);
+ int offset = buf->b_virt_line_leftcol ? 0 : win_col_offset;
+ draw_virt_text_item(buf, offset, kv_A(buf->b_virt_lines, fpos),
+ kHlModeReplace, grid->Columns, offset);
+ }
+ } else {
+ draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
+ }
+
grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
@@ -4485,67 +4517,80 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
bool do_eol = state->eol_col > -1;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange *item = &kv_A(state->active, i);
- if (item->start_row == state->row && kv_size(item->decor.virt_text)) {
- if (item->win_col == -1) {
- if (item->decor.virt_text_pos == kVTRightAlign) {
- right_pos -= item->decor.virt_text_width;
- item->win_col = right_pos;
- } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
- item->win_col = state->eol_col;
- state->eol_col += item->decor.virt_text_width;
- } else if (item->decor.virt_text_pos == kVTWinCol) {
- item->win_col = MAX(item->decor.col+col_off, 0);
- }
- }
- if (item->win_col < 0) {
- continue;
- }
- VirtText vt = item->decor.virt_text;
- HlMode hl_mode = item->decor.hl_mode;
- LineState s = LINE_STATE("");
- int virt_attr = 0;
- int col = item->win_col;
- size_t virt_pos = 0;
- item->win_col = -2; // deactivate
-
- while (col < max_col) {
- if (!*s.p) {
- if (virt_pos >= kv_size(vt)) {
- break;
- }
- virt_attr = 0;
- do {
- s.p = kv_A(vt, virt_pos).text;
- int hl_id = kv_A(vt, virt_pos).hl_id;
- virt_attr = hl_combine_attr(virt_attr,
- hl_id > 0 ? syn_id2attr(hl_id) : 0);
- virt_pos++;
- } while (!s.p && virt_pos < kv_size(vt));
- if (!s.p) {
- break;
- }
- }
- int attr;
- bool through = false;
- if (hl_mode == kHlModeCombine) {
- attr = hl_combine_attr(linebuf_attr[col], virt_attr);
- } else if (hl_mode == kHlModeBlend) {
- through = (*s.p == ' ');
- attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
- } else {
- attr = virt_attr;
- }
- schar_T dummy[2];
- int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
- max_col-col, false);
- linebuf_attr[col++] = attr;
- if (cells > 1) {
- linebuf_attr[col++] = attr;
- }
+ if (!(item->start_row == state->row && kv_size(item->decor.virt_text))) {
+ continue;
+ }
+ if (item->win_col == -1) {
+ if (item->decor.virt_text_pos == kVTRightAlign) {
+ right_pos -= item->decor.virt_text_width;
+ item->win_col = right_pos;
+ } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
+ item->win_col = state->eol_col;
+ } else if (item->decor.virt_text_pos == kVTWinCol) {
+ item->win_col = MAX(item->decor.col+col_off, 0);
+ }
+ }
+ if (item->win_col < 0) {
+ continue;
+ }
+
+ int col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text,
+ item->decor.hl_mode, max_col, item->win_col-col_off);
+ item->win_col = -2; // deactivate
+ if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
+ state->eol_col = col+1;
+ }
+
+ *end_col = MAX(*end_col, col);
+ }
+}
+
+static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
+ int vcol)
+{
+ LineState s = LINE_STATE("");
+ int virt_attr = 0;
+ size_t virt_pos = 0;
+
+ while (col < max_col) {
+ if (!*s.p) {
+ if (virt_pos >= kv_size(vt)) {
+ break;
+ }
+ virt_attr = 0;
+ do {
+ s.p = kv_A(vt, virt_pos).text;
+ int hl_id = kv_A(vt, virt_pos).hl_id;
+ virt_attr = hl_combine_attr(virt_attr,
+ hl_id > 0 ? syn_id2attr(hl_id) : 0);
+ virt_pos++;
+ } while (!s.p && virt_pos < kv_size(vt));
+ if (!s.p) {
+ break;
}
- *end_col = MAX(*end_col, col);
}
+ int attr;
+ bool through = false;
+ if (hl_mode == kHlModeCombine) {
+ attr = hl_combine_attr(linebuf_attr[col], virt_attr);
+ } else if (hl_mode == kHlModeBlend) {
+ through = (*s.p == ' ');
+ attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
+ } else {
+ attr = virt_attr;
+ }
+ schar_T dummy[2];
+ int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
+ max_col-col, false, vcol);
+ // if we failed to emit a char, we still need to advance
+ cells = MAX(cells, 1);
+
+ for (int c = 0; c < cells; c++) {
+ linebuf_attr[col++] = attr;
+ }
+ vcol += cells;
}
+ return col;
}
/// Determine if dedicated window grid should be used or the default_grid
@@ -5489,7 +5534,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
ewp->w_p_crb = p_crb_save;
// Make all characters printable.
- p = (char_u *)transstr((const char *)buf);
+ p = (char_u *)transstr((const char *)buf, true);
len = STRLCPY(buf, p, sizeof(buf));
len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
xfree(p);
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 4be2402f1d..3d30932d69 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1046,8 +1046,8 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
char_u *strcopy = NULL;
char_u *ps;
char_u *msgbuf = NULL;
- size_t len;
- bool has_offset = false;
+ size_t len;
+ bool has_offset = false;
/*
* A line offset is not remembered, this is vi compatible.
@@ -1182,8 +1182,8 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
if ((options & SEARCH_ECHO) && messaging() && !msg_silent
&& (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) {
char_u *trunc;
- char_u off_buf[40];
- size_t off_len = 0;
+ char_u off_buf[40];
+ size_t off_len = 0;
// Compute msg_row early.
msg_start();
@@ -2459,7 +2459,7 @@ int findsent(Direction dir, long count)
{
pos_T pos, tpos;
int c;
- int (*func)(pos_T *);
+ int (*func)(pos_T *);
bool noskip = false; // do not skip blanks
pos = curwin->w_cursor;
@@ -4474,7 +4474,7 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh
update_search_stat(dirc, pos, cursor_pos, &stat, recompute, maxcount,
timeout);
if (stat.cur > 0) {
- char t[SEARCH_STAT_BUF_LEN];
+ char t[SEARCH_STAT_BUF_LEN];
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
if (stat.incomplete == 1) {
@@ -4534,19 +4534,19 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh
static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchstat_T *stat,
bool recompute, int maxcount, long timeout)
{
- int save_ws = p_ws;
- bool wraparound = false;
- pos_T p = (*pos);
- static pos_T lastpos = { 0, 0, 0 };
- static int cur = 0;
- static int cnt = 0;
- static bool exact_match = false;
- static int incomplete = 0;
- static int last_maxcount = SEARCH_STAT_DEF_MAX_COUNT;
- static int chgtick = 0;
+ int save_ws = p_ws;
+ bool wraparound = false;
+ pos_T p = (*pos);
+ static pos_T lastpos = { 0, 0, 0 };
+ static int cur = 0;
+ static int cnt = 0;
+ static bool exact_match = false;
+ static int incomplete = 0;
+ static int last_maxcount = SEARCH_STAT_DEF_MAX_COUNT;
+ static int chgtick = 0;
static char_u *lastpat = NULL;
static buf_T *lbuf = NULL;
- proftime_T start;
+ proftime_T start;
memset(stat, 0, sizeof(searchstat_T));
@@ -4636,12 +4636,12 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst
// "searchcount()" function
void f_searchcount(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- pos_T pos = curwin->w_cursor;
+ pos_T pos = curwin->w_cursor;
char_u *pattern = NULL;
- int maxcount = SEARCH_STAT_DEF_MAX_COUNT;
- long timeout = SEARCH_STAT_DEF_TIMEOUT;
- bool recompute = true;
- searchstat_T stat;
+ int maxcount = SEARCH_STAT_DEF_MAX_COUNT;
+ long timeout = SEARCH_STAT_DEF_TIMEOUT;
+ bool recompute = true;
+ searchstat_T stat;
tv_dict_alloc_ret(rettv);
diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c
index a2378cc202..9d6a2f2c41 100644
--- a/src/nvim/sha256.c
+++ b/src/nvim/sha256.c
@@ -51,8 +51,7 @@ void sha256_start(context_sha256_T *ctx)
ctx->state[7] = 0x5BE0CD19;
}
-static void sha256_process(context_sha256_T *ctx,
- const char_u data[SHA256_BUFFER_SIZE])
+static void sha256_process(context_sha256_T *ctx, const char_u data[SHA256_BUFFER_SIZE])
{
uint32_t temp1, temp2, W[SHA256_BUFFER_SIZE];
uint32_t A, B, C, D, E, F, G, H;
@@ -88,7 +87,7 @@ static void sha256_process(context_sha256_T *ctx,
#define R(t) \
(W[t] = S1(W[t - 2]) + W[t - 7] + \
- S0(W[t - 15]) + W[t - 16])
+ S0(W[t - 15]) + W[t - 16])
#define P(a, b, c, d, e, f, g, h, x, K) { \
temp1 = h + S3(e) + F1(e, f, g) + K + x; \
@@ -188,7 +187,7 @@ void sha256_update(context_sha256_T *ctx, const char_u *input, size_t length)
uint32_t left = ctx->total[0] & (SHA256_BUFFER_SIZE-1); // left < buf size
- ctx->total[0] += (uint32_t) length;
+ ctx->total[0] += (uint32_t)length;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < length) {
@@ -262,8 +261,8 @@ void sha256_finish(context_sha256_T *ctx, char_u digest[SHA256_SUM_SIZE])
///
/// @returns hex digest of "buf[buf_len]" in a static array.
/// if "salt" is not NULL also do "salt[salt_len]".
-const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len,
- const uint8_t *restrict salt, size_t salt_len)
+const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uint8_t *restrict salt,
+ size_t salt_len)
{
char_u sha256sum[SHA256_SUM_SIZE];
static char hexit[SHA256_BUFFER_SIZE + 1]; // buf size + NULL
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 7d277fe5c8..bf245bec51 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -1,51 +1,50 @@
// 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 <stdlib.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-#include <inttypes.h>
-#include <errno.h>
#include <assert.h>
-
+#include <errno.h>
+#include <inttypes.h>
#include <msgpack.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
#include <uv.h>
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/vim.h"
-#include "nvim/pos.h"
-#include "nvim/ascii.h"
-#include "nvim/shada.h"
-#include "nvim/message.h"
-#include "nvim/globals.h"
-#include "nvim/memory.h"
-#include "nvim/mark.h"
-#include "nvim/macros.h"
-#include "nvim/ops.h"
-#include "nvim/garray.h"
-#include "nvim/option.h"
-#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
+#include "nvim/eval/decode.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/search.h"
-#include "nvim/regexp.h"
-#include "nvim/eval/typval.h"
-#include "nvim/version.h"
-#include "nvim/path.h"
#include "nvim/fileio.h"
-#include "nvim/os/fileio.h"
-#include "nvim/strings.h"
-#include "nvim/quickfix.h"
-#include "nvim/eval/encode.h"
-#include "nvim/eval/decode.h"
+#include "nvim/garray.h"
+#include "nvim/globals.h"
#include "nvim/lib/khash.h"
#include "nvim/lib/kvec.h"
+#include "nvim/macros.h"
+#include "nvim/mark.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
+#include "nvim/path.h"
+#include "nvim/pos.h"
+#include "nvim/quickfix.h"
+#include "nvim/regexp.h"
+#include "nvim/search.h"
+#include "nvim/shada.h"
+#include "nvim/strings.h"
+#include "nvim/version.h"
+#include "nvim/vim.h"
#ifdef HAVE_BE64TOH
# define _BSD_SOURCE 1
@@ -67,24 +66,24 @@ KHASH_MAP_INIT_STR(fnamebufs, buf_T *)
KHASH_SET_INIT_STR(strset)
#define copy_option_part(src, dest, ...) \
- ((char *) copy_option_part((char_u **) src, (char_u *) dest, __VA_ARGS__))
+ ((char *)copy_option_part((char_u **)src, (char_u *)dest, __VA_ARGS__))
#define find_shada_parameter(...) \
- ((const char *) find_shada_parameter(__VA_ARGS__))
+ ((const char *)find_shada_parameter(__VA_ARGS__))
#define home_replace_save(a, b) \
- ((char *)home_replace_save(a, (char_u *)b))
+ ((char *)home_replace_save(a, (char_u *)b))
#define home_replace(a, b, c, d, e) \
- home_replace(a, (char_u *)b, (char_u *)c, d, e)
+ home_replace(a, (char_u *)b, (char_u *)c, d, e)
#define vim_rename(a, b) \
- (vim_rename((char_u *)a, (char_u *)b))
+ (vim_rename((char_u *)a, (char_u *)b))
#define mb_strnicmp(a, b, c) \
- (mb_strnicmp((char_u *)a, (char_u *)b, c))
+ (mb_strnicmp((char_u *)a, (char_u *)b, c))
#define path_try_shorten_fname(b) \
- ((char *)path_try_shorten_fname((char_u *)b))
+ ((char *)path_try_shorten_fname((char_u *)b))
#define buflist_new(ffname, sfname, ...) \
- (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
-#define os_isdir(f) (os_isdir((char_u *) f))
-#define regtilde(s, m) ((char *) regtilde((char_u *) s, m))
-#define path_tail_with_sep(f) ((char *) path_tail_with_sep((char_u *)f))
+ (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
+#define os_isdir(f) (os_isdir((char_u *)f))
+#define regtilde(s, m) ((char *)regtilde((char_u *)s, m))
+#define path_tail_with_sep(f) ((char *)path_tail_with_sep((char_u *)f))
#define SEARCH_KEY_MAGIC "sm"
#define SEARCH_KEY_SMARTCASE "sc"
@@ -172,7 +171,7 @@ typedef enum {
kSDItemBufferList = 9, ///< Buffer list.
kSDItemLocalMark = 10, ///< Buffer-local mark.
kSDItemChange = 11, ///< Item from buffer change list.
-#define SHADA_LAST_ENTRY ((uint64_t) kSDItemChange)
+#define SHADA_LAST_ENTRY ((uint64_t)kSDItemChange)
} ShadaEntryType;
/// Possible results when reading ShaDa file
@@ -202,11 +201,11 @@ enum SRNIFlags {
kSDReadHeader = (1 << kSDItemHeader), ///< Determines whether header should
///< be read (it is usually ignored).
kSDReadUndisableableData = (
- (1 << kSDItemSearchPattern)
- | (1 << kSDItemSubString)
- | (1 << kSDItemJump)), ///< Data reading which cannot be disabled by
- ///< &shada or other options except for disabling
- ///< reading ShaDa as a whole.
+ (1 << kSDItemSearchPattern)
+ | (1 << kSDItemSubString)
+ | (1 << kSDItemJump)), ///< Data reading which cannot be disabled by
+ ///< &shada or other options except for disabling
+ ///< reading ShaDa as a whole.
kSDReadRegisters = (1 << kSDItemRegister), ///< Determines whether registers
///< should be read (may only be
///< disabled when writing, but
@@ -434,13 +433,13 @@ typedef struct sd_write_def {
#endif
#define DEF_SDE(name, attr, ...) \
- [kSDItem##name] = { \
- .timestamp = 0, \
- .type = kSDItem##name, \
- .data = { \
- .attr = { __VA_ARGS__ } \
- } \
- }
+ [kSDItem##name] = { \
+ .timestamp = 0, \
+ .type = kSDItem##name, \
+ .data = { \
+ .attr = { __VA_ARGS__ } \
+ } \
+ }
#define DEFAULT_POS { 1, 0, 0 }
static const pos_T default_pos = DEFAULT_POS;
static const ShadaEntry sd_default_values[] = {
@@ -475,9 +474,9 @@ static const ShadaEntry sd_default_values[] = {
DEF_SDE(Variable, global_var,
.name = NULL,
.value = {
- .v_type = VAR_UNKNOWN,
- .vval = { .v_string = NULL }
- },
+ .v_type = VAR_UNKNOWN,
+ .vval = { .v_string = NULL }
+ },
.additional_elements = NULL),
DEF_SDE(GlobalMark, filemark,
.name = '"',
@@ -533,17 +532,16 @@ static inline void hmll_init(HMLList *const hmll, const size_t size)
///
/// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`).
#define HMLL_FORALL(hmll, cur_entry, code) \
- for (HMLListEntry *cur_entry = (hmll)->first; cur_entry != NULL; \
- cur_entry = cur_entry->next) { \
- code \
- } \
+ for (HMLListEntry *cur_entry = (hmll)->first; cur_entry != NULL; \
+ cur_entry = cur_entry->next) { \
+ code \
+ } \
/// Remove entry from the linked list
///
/// @param hmll List to remove from.
/// @param hmll_entry Entry to remove.
-static inline void hmll_remove(HMLList *const hmll,
- HMLListEntry *const hmll_entry)
+static inline void hmll_remove(HMLList *const hmll, HMLListEntry *const hmll_entry)
FUNC_ATTR_NONNULL_ALL
{
if (hmll_entry == hmll->last_free_entry - 1) {
@@ -580,9 +578,7 @@ static inline void hmll_remove(HMLList *const hmll,
/// to insert at the first entry.
/// @param[in] data Data to insert.
/// @param[in] can_free_entry True if data can be freed.
-static inline void hmll_insert(HMLList *const hmll,
- HMLListEntry *hmll_entry,
- const ShadaEntry data,
+static inline void hmll_insert(HMLList *const hmll, HMLListEntry *hmll_entry, const ShadaEntry data,
const bool can_free_entry)
FUNC_ATTR_NONNULL_ARG(1)
{
@@ -595,11 +591,11 @@ static inline void hmll_insert(HMLList *const hmll,
}
HMLListEntry *target_entry;
if (hmll->free_entry == NULL) {
- assert((size_t) (hmll->last_free_entry - hmll->entries)
+ assert((size_t)(hmll->last_free_entry - hmll->entries)
== hmll->num_entries);
target_entry = hmll->last_free_entry++;
} else {
- assert((size_t) (hmll->last_free_entry - hmll->entries) - 1
+ assert((size_t)(hmll->last_free_entry - hmll->entries) - 1
== hmll->num_entries);
target_entry = hmll->free_entry;
hmll->free_entry = NULL;
@@ -637,10 +633,10 @@ static inline void hmll_insert(HMLList *const hmll,
///
/// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`).
#define HMLL_ITER_BACK(hmll, cur_entry, code) \
- for (cur_entry = (hmll)->last; cur_entry != NULL; \
- cur_entry = cur_entry->prev) { \
- code \
- }
+ for (cur_entry = (hmll)->last; cur_entry != NULL; \
+ cur_entry = cur_entry->prev) { \
+ code \
+ }
/// Free linked list
///
@@ -655,8 +651,7 @@ static inline void hmll_dealloc(HMLList *const hmll)
/// Wrapper for reading from file descriptors
///
/// @return -1 or number of bytes read.
-static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest,
- const size_t size)
+static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size);
@@ -678,14 +673,13 @@ static int read_char(ShaDaReadDef *const sd_reader)
if (read_bytes != 1) {
return EOF;
}
- return (int) ret;
+ return (int)ret;
}
/// Wrapper for writing to file descriptors
///
/// @return -1 or number of bytes written.
-static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer,
- const void *const dest,
+static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer, const void *const dest,
const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -720,8 +714,7 @@ static void close_sd_writer(ShaDaWriteDef *const sd_writer)
///
/// @return FAIL in case of failure, OK in case of success. May set
/// sd_reader->eof or sd_reader->error.
-static int sd_reader_skip_read(ShaDaReadDef *const sd_reader,
- const size_t offset)
+static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset);
@@ -749,8 +742,7 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader,
///
/// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or
/// kSDReadStatusSuccess.
-static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
- const size_t offset)
+static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_t offset)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (sd_reader->skip(sd_reader, offset) != OK) {
@@ -762,7 +754,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
emsgf(_(RCERR "Error while reading ShaDa file: "
"last entry specified that it occupies %" PRIu64 " bytes, "
"but file ended earlier"),
- (uint64_t) offset);
+ (uint64_t)offset);
return kSDReadStatusNotShaDa;
}
abort();
@@ -776,8 +768,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
/// @param[out] sd_reader Location where reader structure will be saved.
///
/// @return libuv error in case of error, 0 otherwise.
-static int open_shada_file_for_reading(const char *const fname,
- ShaDaReadDef *sd_reader)
+static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int error;
@@ -819,7 +810,7 @@ static void close_file(void *cookie)
static inline bool in_bufset(const khash_t(bufset) *const set, const buf_T *buf)
FUNC_ATTR_PURE
{
- return kh_get(bufset, set, (uintptr_t) buf) != kh_end(set);
+ return kh_get(bufset, set, (uintptr_t)buf) != kh_end(set);
}
/// Check whether string is in the given set
@@ -837,7 +828,7 @@ static inline bool in_strset(const khash_t(strset) *const set, char *str)
/// Msgpack callback for writing to ShaDaWriteDef*
static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
{
- ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *) data;
+ ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *)data;
ptrdiff_t written_bytes = sd_writer->write(sd_writer, buf, len);
if (written_bytes == -1) {
emsgf(_(SERR "System error while writing ShaDa file: %s"),
@@ -910,10 +901,8 @@ static int shada_read_file(const char *const file, const int flags)
/// @param[out] hist Location where iteration results should be saved.
///
/// @return Next iteration state.
-static const void *shada_hist_iter(const void *const iter,
- const uint8_t history_type,
- const bool zero,
- ShadaEntry *const hist)
+static const void *shada_hist_iter(const void *const iter, const uint8_t history_type,
+ const bool zero, ShadaEntry *const hist)
FUNC_ATTR_NONNULL_ARG(4) FUNC_ATTR_WARN_UNUSED_RESULT
{
histentry_T hist_he;
@@ -927,9 +916,9 @@ static const void *shada_hist_iter(const void *const iter,
.data = {
.history_item = {
.histtype = history_type,
- .string = (char *) hist_he.hisstr,
- .sep = (char) (history_type == HIST_SEARCH
- ? (char) hist_he.hisstr[STRLEN(hist_he.hisstr) + 1]
+ .string = (char *)hist_he.hisstr,
+ .sep = (char)(history_type == HIST_SEARCH
+ ? (char)hist_he.hisstr[STRLEN(hist_he.hisstr) + 1]
: 0),
.additional_elements = hist_he.additional_elements,
}
@@ -954,8 +943,8 @@ static const void *shada_hist_iter(const void *const iter,
/// be used. Must be true only if inserting
/// entry from current Neovim history.
/// @param[in] can_free_entry True if entry can be freed.
-static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
- const bool do_iter, const bool can_free_entry)
+static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry, const bool do_iter,
+ const bool can_free_entry)
FUNC_ATTR_NONNULL_ALL
{
if (do_iter) {
@@ -1008,11 +997,8 @@ static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
/// @param[in] do_merge Prepare structure for merging elements.
/// @param[in] reading If true, then merger is reading history for use
/// in Neovim.
-static inline void hms_init(HistoryMergerState *const hms_p,
- const uint8_t history_type,
- const size_t num_elements,
- const bool do_merge,
- const bool reading)
+static inline void hms_init(HistoryMergerState *const hms_p, const uint8_t history_type,
+ const size_t num_elements, const bool do_merge, const bool reading)
FUNC_ATTR_NONNULL_ALL
{
hmll_init(&hms_p->hmll, num_elements);
@@ -1027,8 +1013,7 @@ static inline void hms_init(HistoryMergerState *const hms_p,
///
/// @param[in,out] hms_p Merger structure into which history should be
/// inserted.
-static inline void hms_insert_whole_neovim_history(
- HistoryMergerState *const hms_p)
+static inline void hms_insert_whole_neovim_history(HistoryMergerState *const hms_p)
FUNC_ATTR_NONNULL_ALL
{
while (hms_p->last_hist_entry.type != kSDItemMissing) {
@@ -1048,21 +1033,20 @@ static inline void hms_insert_whole_neovim_history(
/// @param[out] new_hisidx New last history entry index.
/// @param[out] new_hisnum Amount of history items in merger structure.
static inline void hms_to_he_array(const HistoryMergerState *const hms_p,
- histentry_T *const hist_array,
- int *const new_hisidx,
+ histentry_T *const hist_array, int *const new_hisidx,
int *const new_hisnum)
FUNC_ATTR_NONNULL_ALL
{
histentry_T *hist = hist_array;
HMLL_FORALL(&hms_p->hmll, cur_entry, {
hist->timestamp = cur_entry->data.timestamp;
- hist->hisnum = (int) (hist - hist_array) + 1;
- hist->hisstr = (char_u *) cur_entry->data.data.history_item.string;
+ hist->hisnum = (int)(hist - hist_array) + 1;
+ hist->hisstr = (char_u *)cur_entry->data.data.history_item.string;
hist->additional_elements =
- cur_entry->data.data.history_item.additional_elements;
+ cur_entry->data.data.history_item.additional_elements;
hist++;
})
- *new_hisnum = (int) (hist - hist_array);
+ *new_hisnum = (int)(hist - hist_array);
*new_hisidx = *new_hisnum - 1;
}
@@ -1083,7 +1067,7 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p)
///
/// @return for cycle header. Use `HMS_ITER(hms_p, cur_entry) {body}`.
#define HMS_ITER(hms_p, cur_entry, code) \
- HMLL_FORALL(&((hms_p)->hmll), cur_entry, code)
+ HMLL_FORALL(&((hms_p)->hmll), cur_entry, code)
/// Find buffer for given buffer name (cached)
///
@@ -1091,8 +1075,7 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p)
/// @param[in] fname File name to find.
///
/// @return Pointer to the buffer or NULL.
-static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs,
- const char *const fname)
+static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs, const char *const fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int kh_ret;
@@ -1123,7 +1106,7 @@ static inline bool marks_equal(const pos_T a, const pos_T b)
entry, fname_cond, free_func, fin_func, \
idxadj_func, afterfree_func) \
do { \
- const int jl_len = (int) jumps_size; \
+ const int jl_len = (int)jumps_size; \
int i; \
for (i = jl_len; i > 0; i--) { \
const jumps_type jl_entry = jumps[i - 1]; \
@@ -1140,17 +1123,17 @@ static inline bool marks_equal(const pos_T a, const pos_T b)
free_func(jumps[0]); \
i--; \
if (i > 0) { \
- memmove(&jumps[0], &jumps[1], sizeof(jumps[1]) * (size_t) i); \
+ memmove(&jumps[0], &jumps[1], sizeof(jumps[1]) * (size_t)i); \
} \
} else if (i != jl_len) { \
memmove(&jumps[i + 1], &jumps[i], \
- sizeof(jumps[0]) * (size_t) (jl_len - i)); \
+ sizeof(jumps[0]) * (size_t)(jl_len - i)); \
} \
} else if (i == 0) { \
if (jl_len == JUMPLISTSIZE) { \
i = -1; \
} else if (jl_len > 0) { \
- memmove(&jumps[1], &jumps[0], sizeof(jumps[0]) * (size_t) jl_len); \
+ memmove(&jumps[1], &jumps[0], sizeof(jumps[0]) * (size_t)jl_len); \
} \
} \
if (i != -1) { \
@@ -1177,8 +1160,8 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
const bool get_old_files = (flags & (kShaDaGetOldfiles | kShaDaForceit)
&& (force || tv_list_len(oldfiles_list) == 0));
const bool want_marks = flags & kShaDaWantMarks;
- const unsigned srni_flags = (unsigned) (
- (flags & kShaDaWantInfo
+ const unsigned srni_flags = (unsigned)(
+ (flags & kShaDaWantInfo
? (kSDReadUndisableableData
| kSDReadRegisters
| kSDReadGlobalMarks
@@ -1190,11 +1173,11 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
&& ARGCOUNT == 0
? kSDReadBufferList
: 0))
- : 0)
- | (want_marks && get_shada_parameter('\'') > 0
+ : 0)
+ | (want_marks && get_shada_parameter('\'') > 0
? kSDReadLocalMarks | kSDReadChanges
: 0)
- | (get_old_files
+ | (get_old_files
? kSDReadLocalMarks
: 0));
if (srni_flags == 0) {
@@ -1204,7 +1187,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
HistoryMergerState hms[HIST_COUNT];
if (srni_flags & kSDReadHistory) {
for (uint8_t i = 0; i < HIST_COUNT; i++) {
- hms_init(&hms[i], i, (size_t) p_hi, true, true);
+ hms_init(&hms[i], i, (size_t)p_hi, true, true);
}
}
ShadaEntry cur_entry;
@@ -1219,253 +1202,237 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
while ((srni_ret = shada_read_next_item(sd_reader, &cur_entry, srni_flags, 0))
!= kSDReadStatusFinished) {
switch (srni_ret) {
- case kSDReadStatusSuccess: {
- break;
- }
- case kSDReadStatusFinished: {
- // Should be handled by the while condition.
- abort();
- }
- case kSDReadStatusNotShaDa:
- case kSDReadStatusReadError: {
- goto shada_read_main_cycle_end;
- }
- case kSDReadStatusMalformed: {
- continue;
- }
+ case kSDReadStatusSuccess:
+ break;
+ case kSDReadStatusFinished:
+ // Should be handled by the while condition.
+ abort();
+ case kSDReadStatusNotShaDa:
+ case kSDReadStatusReadError:
+ goto shada_read_main_cycle_end;
+ case kSDReadStatusMalformed:
+ continue;
}
switch (cur_entry.type) {
- case kSDItemMissing: {
- abort();
- }
- case kSDItemUnknown: {
- break;
- }
- case kSDItemHeader: {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- case kSDItemSearchPattern: {
- if (!force) {
- SearchPattern pat;
- (cur_entry.data.search_pattern.is_substitute_pattern
+ case kSDItemMissing:
+ abort();
+ case kSDItemUnknown:
+ break;
+ case kSDItemHeader:
+ shada_free_shada_entry(&cur_entry);
+ break;
+ case kSDItemSearchPattern:
+ if (!force) {
+ SearchPattern pat;
+ (cur_entry.data.search_pattern.is_substitute_pattern
? &get_substitute_pattern
: &get_search_pattern)(&pat);
- if (pat.pat != NULL && pat.timestamp >= cur_entry.timestamp) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
+ if (pat.pat != NULL && pat.timestamp >= cur_entry.timestamp) {
+ shada_free_shada_entry(&cur_entry);
+ break;
}
- (cur_entry.data.search_pattern.is_substitute_pattern
+ }
+ (cur_entry.data.search_pattern.is_substitute_pattern
? &set_substitute_pattern
: &set_search_pattern)((SearchPattern) {
- .magic = cur_entry.data.search_pattern.magic,
- .no_scs = !cur_entry.data.search_pattern.smartcase,
- .off = {
- .dir = cur_entry.data.search_pattern.search_backward ? '?' : '/',
- .line = cur_entry.data.search_pattern.has_line_offset,
- .end = cur_entry.data.search_pattern.place_cursor_at_end,
- .off = cur_entry.data.search_pattern.offset,
- },
- .pat = (char_u *) cur_entry.data.search_pattern.pat,
- .additional_data = cur_entry.data.search_pattern.additional_data,
- .timestamp = cur_entry.timestamp,
- });
- if (cur_entry.data.search_pattern.is_last_used) {
- set_last_used_pattern(
- cur_entry.data.search_pattern.is_substitute_pattern);
- set_no_hlsearch(!cur_entry.data.search_pattern.highlighted);
- }
- // Do not free shada entry: its allocated memory was saved above.
- break;
- }
- case kSDItemSubString: {
- if (!force) {
- SubReplacementString sub;
- sub_get_replacement(&sub);
- if (sub.sub != NULL && sub.timestamp >= cur_entry.timestamp) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- }
- sub_set_replacement((SubReplacementString) {
- .sub = cur_entry.data.sub_string.sub,
- .timestamp = cur_entry.timestamp,
- .additional_elements = cur_entry.data.sub_string.additional_elements,
- });
- // Without using regtilde and without / &cpo flag previous substitute
- // string is close to useless: you can only use it with :& or :~ and
- // that’s all because s//~ is not available until the first call to
- // regtilde. Vim was not calling this for some reason.
- (void) regtilde(cur_entry.data.sub_string.sub, p_magic);
- // Do not free shada entry: its allocated memory was saved above.
- break;
+ .magic = cur_entry.data.search_pattern.magic,
+ .no_scs = !cur_entry.data.search_pattern.smartcase,
+ .off = {
+ .dir = cur_entry.data.search_pattern.search_backward ? '?' : '/',
+ .line = cur_entry.data.search_pattern.has_line_offset,
+ .end = cur_entry.data.search_pattern.place_cursor_at_end,
+ .off = cur_entry.data.search_pattern.offset,
+ },
+ .pat = (char_u *)cur_entry.data.search_pattern.pat,
+ .additional_data = cur_entry.data.search_pattern.additional_data,
+ .timestamp = cur_entry.timestamp,
+ });
+ if (cur_entry.data.search_pattern.is_last_used) {
+ set_last_used_pattern(cur_entry.data.search_pattern.is_substitute_pattern);
+ set_no_hlsearch(!cur_entry.data.search_pattern.highlighted);
}
- case kSDItemHistoryEntry: {
- if (cur_entry.data.history_item.histtype >= HIST_COUNT) {
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemSubString:
+ if (!force) {
+ SubReplacementString sub;
+ sub_get_replacement(&sub);
+ if (sub.sub != NULL && sub.timestamp >= cur_entry.timestamp) {
shada_free_shada_entry(&cur_entry);
break;
}
- hms_insert(hms + cur_entry.data.history_item.histtype, cur_entry, true,
- true);
- // Do not free shada entry: its allocated memory was saved above.
+ }
+ sub_set_replacement((SubReplacementString) {
+ .sub = cur_entry.data.sub_string.sub,
+ .timestamp = cur_entry.timestamp,
+ .additional_elements = cur_entry.data.sub_string.additional_elements,
+ });
+ // Without using regtilde and without / &cpo flag previous substitute
+ // string is close to useless: you can only use it with :& or :~ and
+ // that’s all because s//~ is not available until the first call to
+ // regtilde. Vim was not calling this for some reason.
+ (void)regtilde(cur_entry.data.sub_string.sub, p_magic);
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemHistoryEntry:
+ if (cur_entry.data.history_item.histtype >= HIST_COUNT) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ hms_insert(hms + cur_entry.data.history_item.histtype, cur_entry, true,
+ true);
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemRegister:
+ if (cur_entry.data.reg.type != kMTCharWise
+ && cur_entry.data.reg.type != kMTLineWise
+ && cur_entry.data.reg.type != kMTBlockWise) {
+ shada_free_shada_entry(&cur_entry);
break;
}
- case kSDItemRegister: {
- if (cur_entry.data.reg.type != kMTCharWise
- && cur_entry.data.reg.type != kMTLineWise
- && cur_entry.data.reg.type != kMTBlockWise) {
+ if (!force) {
+ const yankreg_T *const reg = op_reg_get(cur_entry.data.reg.name);
+ if (reg == NULL || reg->timestamp >= cur_entry.timestamp) {
shada_free_shada_entry(&cur_entry);
break;
}
- if (!force) {
- const yankreg_T *const reg = op_reg_get(cur_entry.data.reg.name);
- if (reg == NULL || reg->timestamp >= cur_entry.timestamp) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- }
- if (!op_reg_set(cur_entry.data.reg.name, (yankreg_T) {
- .y_array = (char_u **)cur_entry.data.reg.contents,
- .y_size = cur_entry.data.reg.contents_size,
- .y_type = cur_entry.data.reg.type,
- .y_width = (colnr_T) cur_entry.data.reg.width,
- .timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.reg.additional_data,
- }, cur_entry.data.reg.is_unnamed)) {
- shada_free_shada_entry(&cur_entry);
- }
- // Do not free shada entry: its allocated memory was saved above.
- break;
}
- case kSDItemVariable: {
- var_set_global(cur_entry.data.global_var.name,
- cur_entry.data.global_var.value);
- cur_entry.data.global_var.value.v_type = VAR_UNKNOWN;
+ if (!op_reg_set(cur_entry.data.reg.name, (yankreg_T) {
+ .y_array = (char_u **)cur_entry.data.reg.contents,
+ .y_size = cur_entry.data.reg.contents_size,
+ .y_type = cur_entry.data.reg.type,
+ .y_width = (colnr_T)cur_entry.data.reg.width,
+ .timestamp = cur_entry.timestamp,
+ .additional_data = cur_entry.data.reg.additional_data,
+ }, cur_entry.data.reg.is_unnamed)) {
shada_free_shada_entry(&cur_entry);
- break;
}
- case kSDItemJump:
- case kSDItemGlobalMark: {
- buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
- if (buf != NULL) {
- XFREE_CLEAR(cur_entry.data.filemark.fname);
- }
- xfmark_T fm = (xfmark_T) {
- .fname = (char_u *) (buf == NULL
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemVariable:
+ var_set_global(cur_entry.data.global_var.name,
+ cur_entry.data.global_var.value);
+ cur_entry.data.global_var.value.v_type = VAR_UNKNOWN;
+ shada_free_shada_entry(&cur_entry);
+ break;
+ case kSDItemJump:
+ case kSDItemGlobalMark: {
+ buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
+ if (buf != NULL) {
+ XFREE_CLEAR(cur_entry.data.filemark.fname);
+ }
+ xfmark_T fm = (xfmark_T) {
+ .fname = (char_u *)(buf == NULL
? cur_entry.data.filemark.fname
: NULL),
- .fmark = {
- .mark = cur_entry.data.filemark.mark,
- .fnum = (buf == NULL ? 0 : buf->b_fnum),
- .timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.filemark.additional_data,
- },
- };
- if (cur_entry.type == kSDItemGlobalMark) {
- if (!mark_set_global(cur_entry.data.filemark.name, fm, !force)) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- } else {
+ .fmark = {
+ .mark = cur_entry.data.filemark.mark,
+ .fnum = (buf == NULL ? 0 : buf->b_fnum),
+ .timestamp = cur_entry.timestamp,
+ .additional_data = cur_entry.data.filemark.additional_data,
+ },
+ };
+ if (cur_entry.type == kSDItemGlobalMark) {
+ if (!mark_set_global(cur_entry.data.filemark.name, fm, !force)) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ } else {
#define SDE_TO_XFMARK(entry) fm
#define ADJUST_IDX(i) \
- if (curwin->w_jumplistidx >= i \
- && curwin->w_jumplistidx + 1 <= curwin->w_jumplistlen) { \
- curwin->w_jumplistidx++; \
- }
+ if (curwin->w_jumplistidx >= i \
+ && curwin->w_jumplistidx + 1 <= curwin->w_jumplistlen) { \
+ curwin->w_jumplistidx++; \
+ }
#define DUMMY_AFTERFREE(entry)
- MERGE_JUMPS(curwin->w_jumplistlen, curwin->w_jumplist, xfmark_T,
- fmark.timestamp, fmark.mark, cur_entry,
- (buf == NULL
+ MERGE_JUMPS(curwin->w_jumplistlen, curwin->w_jumplist, xfmark_T,
+ fmark.timestamp, fmark.mark, cur_entry,
+ (buf == NULL
? (jl_entry.fname != NULL
&& STRCMP(fm.fname, jl_entry.fname) == 0)
: fm.fmark.fnum == jl_entry.fmark.fnum),
- free_xfmark, SDE_TO_XFMARK, ADJUST_IDX, DUMMY_AFTERFREE);
+ free_xfmark, SDE_TO_XFMARK, ADJUST_IDX, DUMMY_AFTERFREE);
#undef SDE_TO_XFMARK
#undef ADJUST_IDX
#undef DUMMY_AFTERFREE
- }
- // Do not free shada entry: its allocated memory was saved above.
- break;
}
- case kSDItemBufferList: {
- for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) {
- char *const sfname = path_try_shorten_fname(
- cur_entry.data.buffer_list.buffers[i].fname);
- buf_T *const buf = buflist_new(
- cur_entry.data.buffer_list.buffers[i].fname, sfname, 0,
- BLN_LISTED);
- if (buf != NULL) {
- RESET_FMARK(&buf->b_last_cursor,
- cur_entry.data.buffer_list.buffers[i].pos, 0);
- buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum,
- buf->b_last_cursor.mark.col, false);
- buf->additional_data =
- cur_entry.data.buffer_list.buffers[i].additional_data;
- cur_entry.data.buffer_list.buffers[i].additional_data = NULL;
- }
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ }
+ case kSDItemBufferList:
+ for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) {
+ char *const sfname = path_try_shorten_fname(cur_entry.data.buffer_list.buffers[i].fname);
+ buf_T *const buf = buflist_new(cur_entry.data.buffer_list.buffers[i].fname, sfname, 0,
+ BLN_LISTED);
+ if (buf != NULL) {
+ RESET_FMARK(&buf->b_last_cursor,
+ cur_entry.data.buffer_list.buffers[i].pos, 0);
+ buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum,
+ buf->b_last_cursor.mark.col, false);
+ buf->additional_data =
+ cur_entry.data.buffer_list.buffers[i].additional_data;
+ cur_entry.data.buffer_list.buffers[i].additional_data = NULL;
}
- shada_free_shada_entry(&cur_entry);
- break;
}
- case kSDItemChange:
- case kSDItemLocalMark: {
- if (get_old_files && !in_strset(&oldfiles_set,
- cur_entry.data.filemark.fname)) {
- char *fname = cur_entry.data.filemark.fname;
- if (want_marks) {
- // Do not bother with allocating memory for the string if already
- // allocated string from cur_entry can be used. It cannot be used if
- // want_marks is set because this way it may be used for a mark.
- fname = xstrdup(fname);
- }
- int kh_ret;
- (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
- tv_list_append_allocated_string(oldfiles_list, fname);
- if (!want_marks) {
- // Avoid free because this string was already used.
- cur_entry.data.filemark.fname = NULL;
- }
+ shada_free_shada_entry(&cur_entry);
+ break;
+ case kSDItemChange:
+ case kSDItemLocalMark: {
+ if (get_old_files && !in_strset(&oldfiles_set,
+ cur_entry.data.filemark.fname)) {
+ char *fname = cur_entry.data.filemark.fname;
+ if (want_marks) {
+ // Do not bother with allocating memory for the string if already
+ // allocated string from cur_entry can be used. It cannot be used if
+ // want_marks is set because this way it may be used for a mark.
+ fname = xstrdup(fname);
}
+ int kh_ret;
+ (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
+ tv_list_append_allocated_string(oldfiles_list, fname);
if (!want_marks) {
- shada_free_shada_entry(&cur_entry);
- break;
+ // Avoid free because this string was already used.
+ cur_entry.data.filemark.fname = NULL;
}
- buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
- if (buf == NULL) {
+ }
+ if (!want_marks) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
+ if (buf == NULL) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ const fmark_T fm = (fmark_T) {
+ .mark = cur_entry.data.filemark.mark,
+ .fnum = 0,
+ .timestamp = cur_entry.timestamp,
+ .additional_data = cur_entry.data.filemark.additional_data,
+ };
+ if (cur_entry.type == kSDItemLocalMark) {
+ if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) {
shada_free_shada_entry(&cur_entry);
break;
}
- const fmark_T fm = (fmark_T) {
- .mark = cur_entry.data.filemark.mark,
- .fnum = 0,
- .timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.filemark.additional_data,
- };
- if (cur_entry.type == kSDItemLocalMark) {
- if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- } else {
- int kh_ret;
- (void) kh_put(bufset, &cl_bufs, (uintptr_t) buf, &kh_ret);
+ } else {
+ int kh_ret;
+ (void)kh_put(bufset, &cl_bufs, (uintptr_t)buf, &kh_ret);
#define SDE_TO_FMARK(entry) fm
#define AFTERFREE(entry) (entry).data.filemark.fname = NULL
#define DUMMY_IDX_ADJ(i)
- MERGE_JUMPS(buf->b_changelistlen, buf->b_changelist, fmark_T,
- timestamp, mark, cur_entry, true,
- free_fmark, SDE_TO_FMARK, DUMMY_IDX_ADJ, AFTERFREE);
+ MERGE_JUMPS(buf->b_changelistlen, buf->b_changelist, fmark_T,
+ timestamp, mark, cur_entry, true,
+ free_fmark, SDE_TO_FMARK, DUMMY_IDX_ADJ, AFTERFREE);
#undef SDE_TO_FMARK
#undef AFTERFREE
#undef DUMMY_IDX_ADJ
- }
- // Do not free shada entry: except for fname, its allocated memory (i.e.
- // additional_data attribute contents if non-NULL) was saved above.
- xfree(cur_entry.data.filemark.fname);
- break;
}
+ // Do not free shada entry: except for fname, its allocated memory (i.e.
+ // additional_data attribute contents if non-NULL) was saved above.
+ xfree(cur_entry.data.filemark.fname);
+ break;
+ }
}
}
shada_read_main_cycle_end:
@@ -1490,7 +1457,7 @@ shada_read_main_cycle_end:
}
if (cl_bufs.n_occupied) {
FOR_ALL_TAB_WINDOWS(tp, wp) {
- (void) tp;
+ (void)tp;
if (in_bufset(&cl_bufs, wp->w_buffer)) {
wp->w_changelistidx = wp->w_buffer->b_changelistlen;
}
@@ -1499,7 +1466,7 @@ shada_read_main_cycle_end:
kh_dealloc(bufset, &cl_bufs);
const char *key;
kh_foreach_key(&fname_bufs, key, {
- xfree((void *) key);
+ xfree((void *)key);
})
kh_dealloc(fnamebufs, &fname_bufs);
kh_dealloc(strset, &oldfiles_set);
@@ -1544,33 +1511,33 @@ static char *shada_filename(const char *file)
// If shell is not performing them then they should be done in main.c
// where arguments are parsed, *not here*.
expand_env((char_u *)file, &(NameBuff[0]), MAXPATHL);
- file = (const char *) &(NameBuff[0]);
+ file = (const char *)&(NameBuff[0]);
}
}
return xstrdup(file);
}
#define PACK_STATIC_STR(s) \
- do { \
- msgpack_pack_str(spacker, sizeof(s) - 1); \
- msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \
- } while (0)
+ do { \
+ msgpack_pack_str(spacker, sizeof(s) - 1); \
+ msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \
+ } while (0)
#define PACK_STRING(s) \
- do { \
- const String s_ = (s); \
- msgpack_pack_str(spacker, s_.size); \
- if (s_.size) { \
- msgpack_pack_str_body(spacker, s_.data, s_.size); \
- } \
- } while (0)
+ do { \
+ const String s_ = (s); \
+ msgpack_pack_str(spacker, s_.size); \
+ if (s_.size) { \
+ msgpack_pack_str_body(spacker, s_.data, s_.size); \
+ } \
+ } while (0)
#define PACK_BIN(s) \
- do { \
- const String s_ = (s); \
- msgpack_pack_bin(spacker, s_.size); \
- if (s_.size > 0) { \
- msgpack_pack_bin_body(spacker, s_.data, s_.size); \
- } \
- } while (0)
+ do { \
+ const String s_ = (s); \
+ msgpack_pack_bin(spacker, s_.size); \
+ if (s_.size > 0) { \
+ msgpack_pack_bin_body(spacker, s_.data, s_.size); \
+ } \
+ } while (0)
/// Write single ShaDa entry
///
@@ -1580,8 +1547,7 @@ static char *shada_filename(const char *file)
/// restrictions.
///
/// @return kSDWriteSuccessfull, kSDWriteFailed or kSDWriteIgnError.
-static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
- ShadaEntry entry,
+static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntry entry,
const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL
{
@@ -1625,244 +1591,239 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
#define CHECK_DEFAULT(entry, attr) \
(sd_default_values[entry.type].data.attr == entry.data.attr)
#define ONE_IF_NOT_DEFAULT(entry, attr) \
- ((size_t) (!CHECK_DEFAULT(entry, attr)))
+ ((size_t)(!CHECK_DEFAULT(entry, attr)))
switch (entry.type) {
- case kSDItemMissing: {
- abort();
+ case kSDItemMissing:
+ abort();
+ case kSDItemUnknown:
+ if (spacker->callback(spacker->data, entry.data.unknown_item.contents,
+ (unsigned)entry.data.unknown_item.size) == -1) {
+ goto shada_pack_entry_error;
}
- case kSDItemUnknown: {
- if (spacker->callback(spacker->data, entry.data.unknown_item.contents,
- (unsigned) entry.data.unknown_item.size) == -1) {
- goto shada_pack_entry_error;
- }
- break;
+ break;
+ case kSDItemHistoryEntry: {
+ const bool is_hist_search =
+ entry.data.history_item.histtype == HIST_SEARCH;
+ const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)(
+ tv_list_len(entry.data.
+ history_item.
+ additional_elements));
+ msgpack_pack_array(spacker, arr_size);
+ msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
+ PACK_BIN(cstr_as_string(entry.data.history_item.string));
+ if (is_hist_search) {
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep);
}
- case kSDItemHistoryEntry: {
- const bool is_hist_search =
- entry.data.history_item.histtype == HIST_SEARCH;
- const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)(
- tv_list_len(entry.data.history_item.additional_elements));
- msgpack_pack_array(spacker, arr_size);
- msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
- PACK_BIN(cstr_as_string(entry.data.history_item.string));
- if (is_hist_search) {
- msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep);
- }
- DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
- "history entry item");
- break;
- }
- case kSDItemVariable: {
- if (entry.data.global_var.value.v_type == VAR_TYPE_BLOB) {
- // Strings and Blobs both pack as msgpack BINs; differentiate them by
- // storing an additional VAR_TYPE_BLOB element alongside Blobs
- list_T *const list = tv_list_alloc(1);
- tv_list_append_number(list, VAR_TYPE_BLOB);
- entry.data.global_var.additional_elements = list;
- }
- const size_t arr_size = 2 + (size_t)(
- tv_list_len(entry.data.global_var.additional_elements));
- msgpack_pack_array(spacker, arr_size);
- const String varname = cstr_as_string(entry.data.global_var.name);
- PACK_BIN(varname);
- char vardesc[256] = "variable g:";
- memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
- varname.size + 1);
- if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
- == FAIL) {
- ret = kSDWriteIgnError;
- EMSG2(_(WERR "Failed to write variable %s"),
- entry.data.global_var.name);
- goto shada_pack_entry_error;
- }
- DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
- "variable item");
- break;
+ DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
+ "history entry item");
+ break;
+ }
+ case kSDItemVariable: {
+ if (entry.data.global_var.value.v_type == VAR_TYPE_BLOB) {
+ // Strings and Blobs both pack as msgpack BINs; differentiate them by
+ // storing an additional VAR_TYPE_BLOB element alongside Blobs
+ list_T *const list = tv_list_alloc(1);
+ tv_list_append_number(list, VAR_TYPE_BLOB);
+ entry.data.global_var.additional_elements = list;
}
- case kSDItemSubString: {
- const size_t arr_size = 1 + (size_t)(
- tv_list_len(entry.data.sub_string.additional_elements));
- msgpack_pack_array(spacker, arr_size);
- PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
- DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
- "sub string item");
- break;
+ const size_t arr_size = 2 + (size_t)(
+ tv_list_len(entry.data.global_var.additional_elements));
+ msgpack_pack_array(spacker, arr_size);
+ const String varname = cstr_as_string(entry.data.global_var.name);
+ PACK_BIN(varname);
+ char vardesc[256] = "variable g:";
+ memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
+ varname.size + 1);
+ if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
+ == FAIL) {
+ ret = kSDWriteIgnError;
+ EMSG2(_(WERR "Failed to write variable %s"),
+ entry.data.global_var.name);
+ goto shada_pack_entry_error;
}
- case kSDItemSearchPattern: {
- const size_t map_size = (size_t) (
- 1 // Search pattern is always present
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_substitute_pattern)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward)
- // finally, additional data:
- + (size_t) (
- entry.data.search_pattern.additional_data
+ DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
+ "variable item");
+ break;
+ }
+ case kSDItemSubString: {
+ const size_t arr_size = 1 + (size_t)(
+ tv_list_len(entry.data.sub_string.additional_elements));
+ msgpack_pack_array(spacker, arr_size);
+ PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
+ DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
+ "sub string item");
+ break;
+ }
+ case kSDItemSearchPattern: {
+ const size_t map_size = (size_t)(
+ 1 // Search pattern is always present
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end)
+ + ONE_IF_NOT_DEFAULT(entry,
+ search_pattern.is_substitute_pattern)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward)
+ // finally, additional data:
+ + (size_t)(
+ entry.data.search_pattern.additional_data
? entry.data.search_pattern.additional_data->dv_hashtab.ht_used
: 0));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(SEARCH_KEY_PAT);
- PACK_BIN(cstr_as_string(entry.data.search_pattern.pat));
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(SEARCH_KEY_PAT);
+ PACK_BIN(cstr_as_string(entry.data.search_pattern.pat));
#define PACK_BOOL(entry, name, attr) \
- do { \
- if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \
- PACK_STATIC_STR(name); \
- if (sd_default_values[entry.type].data.search_pattern.attr) { \
- msgpack_pack_false(spacker); \
- } else { \
- msgpack_pack_true(spacker); \
- } \
- } \
- } while (0)
- PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic);
- PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used);
- PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase);
- PACK_BOOL(entry, SEARCH_KEY_HAS_LINE_OFFSET, has_line_offset);
- PACK_BOOL(entry, SEARCH_KEY_PLACE_CURSOR_AT_END, place_cursor_at_end);
- PACK_BOOL(entry, SEARCH_KEY_IS_SUBSTITUTE_PATTERN, is_substitute_pattern);
- PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted);
- PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward);
- if (!CHECK_DEFAULT(entry, search_pattern.offset)) {
- PACK_STATIC_STR(SEARCH_KEY_OFFSET);
- msgpack_pack_int64(spacker, entry.data.search_pattern.offset);
- }
-#undef PACK_BOOL
- DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
- "search pattern item");
- break;
+ do { \
+ if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \
+ PACK_STATIC_STR(name); \
+ if (sd_default_values[entry.type].data.search_pattern.attr) { \
+ msgpack_pack_false(spacker); \
+ } else { \
+ msgpack_pack_true(spacker); \
+ } \
+ } \
+ } while (0)
+ PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic);
+ PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used);
+ PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase);
+ PACK_BOOL(entry, SEARCH_KEY_HAS_LINE_OFFSET, has_line_offset);
+ PACK_BOOL(entry, SEARCH_KEY_PLACE_CURSOR_AT_END, place_cursor_at_end);
+ PACK_BOOL(entry, SEARCH_KEY_IS_SUBSTITUTE_PATTERN, is_substitute_pattern);
+ PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted);
+ PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward);
+ if (!CHECK_DEFAULT(entry, search_pattern.offset)) {
+ PACK_STATIC_STR(SEARCH_KEY_OFFSET);
+ msgpack_pack_int64(spacker, entry.data.search_pattern.offset);
}
- case kSDItemChange:
- case kSDItemGlobalMark:
- case kSDItemLocalMark:
- case kSDItemJump: {
- const size_t map_size = (size_t) (
- 1 // File name
- + ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum)
- + ONE_IF_NOT_DEFAULT(entry, filemark.mark.col)
- + ONE_IF_NOT_DEFAULT(entry, filemark.name)
- // Additional entries, if any:
- + (size_t) (
- entry.data.filemark.additional_data == NULL
+#undef PACK_BOOL
+ DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
+ "search pattern item");
+ break;
+ }
+ case kSDItemChange:
+ case kSDItemGlobalMark:
+ case kSDItemLocalMark:
+ case kSDItemJump: {
+ const size_t map_size = (size_t)(
+ 1 // File name
+ + ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum)
+ + ONE_IF_NOT_DEFAULT(entry, filemark.mark.col)
+ + ONE_IF_NOT_DEFAULT(entry, filemark.name)
+ // Additional entries, if any:
+ + (size_t)(
+ entry.data.filemark.additional_data == NULL
? 0
: entry.data.filemark.additional_data->dv_hashtab.ht_used));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(KEY_FILE);
- PACK_BIN(cstr_as_string(entry.data.filemark.fname));
- if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) {
- PACK_STATIC_STR(KEY_LNUM);
- msgpack_pack_long(spacker, entry.data.filemark.mark.lnum);
- }
- if (!CHECK_DEFAULT(entry, filemark.mark.col)) {
- PACK_STATIC_STR(KEY_COL);
- msgpack_pack_long(spacker, entry.data.filemark.mark.col);
- }
- assert(entry.type == kSDItemJump || entry.type == kSDItemChange
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(KEY_FILE);
+ PACK_BIN(cstr_as_string(entry.data.filemark.fname));
+ if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) {
+ PACK_STATIC_STR(KEY_LNUM);
+ msgpack_pack_long(spacker, entry.data.filemark.mark.lnum);
+ }
+ if (!CHECK_DEFAULT(entry, filemark.mark.col)) {
+ PACK_STATIC_STR(KEY_COL);
+ msgpack_pack_long(spacker, entry.data.filemark.mark.col);
+ }
+ assert(entry.type == kSDItemJump || entry.type == kSDItemChange
? CHECK_DEFAULT(entry, filemark.name)
: true);
- if (!CHECK_DEFAULT(entry, filemark.name)) {
- PACK_STATIC_STR(KEY_NAME_CHAR);
- msgpack_pack_uint8(spacker, (uint8_t) entry.data.filemark.name);
- }
- DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
- "mark (change, jump, global or local) item");
- break;
+ if (!CHECK_DEFAULT(entry, filemark.name)) {
+ PACK_STATIC_STR(KEY_NAME_CHAR);
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.filemark.name);
}
- case kSDItemRegister: {
- const size_t map_size = (size_t) (
- 2 // Register contents and name
- + ONE_IF_NOT_DEFAULT(entry, reg.type)
- + ONE_IF_NOT_DEFAULT(entry, reg.width)
- + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed)
- // Additional entries, if any:
- + (size_t) (entry.data.reg.additional_data == NULL
+ DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
+ "mark (change, jump, global or local) item");
+ break;
+ }
+ case kSDItemRegister: {
+ const size_t map_size = (size_t)(
+ 2 // Register contents and name
+ + ONE_IF_NOT_DEFAULT(entry, reg.type)
+ + ONE_IF_NOT_DEFAULT(entry, reg.width)
+ + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed)
+ // Additional entries, if any:
+ + (size_t)(entry.data.reg.additional_data == NULL
? 0
: entry.data.reg.additional_data->dv_hashtab.ht_used));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(REG_KEY_CONTENTS);
- msgpack_pack_array(spacker, entry.data.reg.contents_size);
- for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
- PACK_BIN(cstr_as_string(entry.data.reg.contents[i]));
- }
- PACK_STATIC_STR(KEY_NAME_CHAR);
- msgpack_pack_char(spacker, entry.data.reg.name);
- if (!CHECK_DEFAULT(entry, reg.type)) {
- PACK_STATIC_STR(REG_KEY_TYPE);
- msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type);
- }
- if (!CHECK_DEFAULT(entry, reg.width)) {
- PACK_STATIC_STR(REG_KEY_WIDTH);
- msgpack_pack_uint64(spacker, (uint64_t) entry.data.reg.width);
- }
- if (!CHECK_DEFAULT(entry, reg.is_unnamed)) {
- PACK_STATIC_STR(REG_KEY_UNNAMED);
- if (entry.data.reg.is_unnamed) {
- msgpack_pack_true(spacker);
- } else {
- msgpack_pack_false(spacker);
- }
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(REG_KEY_CONTENTS);
+ msgpack_pack_array(spacker, entry.data.reg.contents_size);
+ for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
+ PACK_BIN(cstr_as_string(entry.data.reg.contents[i]));
+ }
+ PACK_STATIC_STR(KEY_NAME_CHAR);
+ msgpack_pack_char(spacker, entry.data.reg.name);
+ if (!CHECK_DEFAULT(entry, reg.type)) {
+ PACK_STATIC_STR(REG_KEY_TYPE);
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type);
+ }
+ if (!CHECK_DEFAULT(entry, reg.width)) {
+ PACK_STATIC_STR(REG_KEY_WIDTH);
+ msgpack_pack_uint64(spacker, (uint64_t)entry.data.reg.width);
+ }
+ if (!CHECK_DEFAULT(entry, reg.is_unnamed)) {
+ PACK_STATIC_STR(REG_KEY_UNNAMED);
+ if (entry.data.reg.is_unnamed) {
+ msgpack_pack_true(spacker);
+ } else {
+ msgpack_pack_false(spacker);
}
- DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
- break;
}
- case kSDItemBufferList: {
- msgpack_pack_array(spacker, entry.data.buffer_list.size);
- for (size_t i = 0; i < entry.data.buffer_list.size; i++) {
- const size_t map_size = (size_t) (
- 1 // Buffer name
- + (size_t) (entry.data.buffer_list.buffers[i].pos.lnum
- != default_pos.lnum)
- + (size_t) (entry.data.buffer_list.buffers[i].pos.col
- != default_pos.col)
- // Additional entries, if any:
- + (size_t) (
- entry.data.buffer_list.buffers[i].additional_data == NULL
+ DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
+ break;
+ }
+ case kSDItemBufferList:
+ msgpack_pack_array(spacker, entry.data.buffer_list.size);
+ for (size_t i = 0; i < entry.data.buffer_list.size; i++) {
+ const size_t map_size = (size_t)(
+ 1 // Buffer name
+ + (size_t)(entry.data.buffer_list.buffers[i].pos.lnum
+ != default_pos.lnum)
+ + (size_t)(entry.data.buffer_list.buffers[i].pos.col
+ != default_pos.col)
+ // Additional entries, if any:
+ + (size_t)(
+ entry.data.buffer_list.buffers[i].additional_data
+ == NULL
? 0
: (entry.data.buffer_list.buffers[i].additional_data
->dv_hashtab.ht_used)));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(KEY_FILE);
- PACK_BIN(cstr_as_string(entry.data.buffer_list.buffers[i].fname));
- if (entry.data.buffer_list.buffers[i].pos.lnum != 1) {
- PACK_STATIC_STR(KEY_LNUM);
- msgpack_pack_uint64(
- spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.lnum);
- }
- if (entry.data.buffer_list.buffers[i].pos.col != 0) {
- PACK_STATIC_STR(KEY_COL);
- msgpack_pack_uint64(
- spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.col);
- }
- DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
- "buffer list subitem");
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(KEY_FILE);
+ PACK_BIN(cstr_as_string(entry.data.buffer_list.buffers[i].fname));
+ if (entry.data.buffer_list.buffers[i].pos.lnum != 1) {
+ PACK_STATIC_STR(KEY_LNUM);
+ msgpack_pack_uint64(spacker, (uint64_t)entry.data.buffer_list.buffers[i].pos.lnum);
}
- break;
+ if (entry.data.buffer_list.buffers[i].pos.col != 0) {
+ PACK_STATIC_STR(KEY_COL);
+ msgpack_pack_uint64(spacker, (uint64_t)entry.data.buffer_list.buffers[i].pos.col);
+ }
+ DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
+ "buffer list subitem");
}
- case kSDItemHeader: {
- msgpack_pack_map(spacker, entry.data.header.size);
- for (size_t i = 0; i < entry.data.header.size; i++) {
- PACK_STRING(entry.data.header.items[i].key);
- const Object obj = entry.data.header.items[i].value;
- switch (obj.type) {
- case kObjectTypeString: {
- PACK_BIN(obj.data.string);
- break;
- }
- case kObjectTypeInteger: {
- msgpack_pack_int64(spacker, (int64_t) obj.data.integer);
- break;
- }
- default: {
- abort();
- }
- }
+ break;
+ case kSDItemHeader:
+ msgpack_pack_map(spacker, entry.data.header.size);
+ for (size_t i = 0; i < entry.data.header.size; i++) {
+ PACK_STRING(entry.data.header.items[i].key);
+ const Object obj = entry.data.header.items[i].value;
+ switch (obj.type) {
+ case kObjectTypeString:
+ PACK_BIN(obj.data.string);
+ break;
+ case kObjectTypeInteger:
+ msgpack_pack_int64(spacker, (int64_t)obj.data.integer);
+ break;
+ default:
+ abort();
}
- break;
}
+ break;
}
#undef CHECK_DEFAULT
#undef ONE_IF_NOT_DEFAULT
@@ -1872,17 +1833,17 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
goto shada_pack_entry_error;
}
} else {
- if (msgpack_pack_uint64(packer, (uint64_t) entry.type) == -1) {
+ if (msgpack_pack_uint64(packer, (uint64_t)entry.type) == -1) {
goto shada_pack_entry_error;
}
}
- if (msgpack_pack_uint64(packer, (uint64_t) entry.timestamp) == -1) {
+ if (msgpack_pack_uint64(packer, (uint64_t)entry.timestamp) == -1) {
goto shada_pack_entry_error;
}
if (sbuf.size > 0) {
- if ((msgpack_pack_uint64(packer, (uint64_t) sbuf.size) == -1)
+ if ((msgpack_pack_uint64(packer, (uint64_t)sbuf.size) == -1)
|| (packer->callback(packer->data, sbuf.data,
- (unsigned) sbuf.size) == -1)) {
+ (unsigned)sbuf.size) == -1)) {
goto shada_pack_entry_error;
}
}
@@ -1905,9 +1866,9 @@ shada_pack_entry_error:
/// @param[in] entry Entry written.
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
/// restrictions.
-static inline ShaDaWriteResult shada_pack_pfreed_entry(
- msgpack_packer *const packer, PossiblyFreedShadaEntry entry,
- const size_t max_kbyte)
+static inline ShaDaWriteResult shada_pack_pfreed_entry(msgpack_packer *const packer,
+ PossiblyFreedShadaEntry entry,
+ const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
ShaDaWriteResult ret = kSDWriteSuccessfull;
@@ -1945,9 +1906,10 @@ static int compare_file_marks(const void *a, const void *b)
///
/// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or
/// kSDReadStatusSuccess.
-static inline ShaDaReadResult shada_parse_msgpack(
- ShaDaReadDef *const sd_reader, const size_t length,
- msgpack_unpacked *ret_unpacked, char **const ret_buf)
+static inline ShaDaReadResult shada_parse_msgpack(ShaDaReadDef *const sd_reader,
+ const size_t length,
+ msgpack_unpacked *ret_unpacked,
+ char **const ret_buf)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
const uintmax_t initial_fpos = sd_reader->fpos;
@@ -1964,47 +1926,42 @@ shada_parse_msgpack_read_next: {}
msgpack_unpacked unpacked;
msgpack_unpacked_init(&unpacked);
const msgpack_unpack_return result =
- msgpack_unpack_next(&unpacked, buf, length, &off);
+ msgpack_unpack_next(&unpacked, buf, length, &off);
ShaDaReadResult ret = kSDReadStatusSuccess;
switch (result) {
- case MSGPACK_UNPACK_SUCCESS: {
- if (off < length) {
- goto shada_parse_msgpack_extra_bytes;
- }
- break;
- }
- case MSGPACK_UNPACK_PARSE_ERROR: {
- emsgf(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
- "at position %" PRIu64),
- (uint64_t) initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
+ case MSGPACK_UNPACK_SUCCESS:
+ if (off < length) {
+ goto shada_parse_msgpack_extra_bytes;
}
- case MSGPACK_UNPACK_NOMEM_ERROR: {
- if (!did_try_to_free) {
- did_try_to_free = true;
- try_to_free_memory();
- goto shada_parse_msgpack_read_next;
- }
- EMSG(_(e_outofmem));
- ret = kSDReadStatusReadError;
- break;
- }
- case MSGPACK_UNPACK_CONTINUE: {
- emsgf(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
- "at position %" PRIu64),
- (uint64_t) initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
+ break;
+ case MSGPACK_UNPACK_PARSE_ERROR:
+ emsgf(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ ret = kSDReadStatusNotShaDa;
+ break;
+ case MSGPACK_UNPACK_NOMEM_ERROR:
+ if (!did_try_to_free) {
+ did_try_to_free = true;
+ try_to_free_memory();
+ goto shada_parse_msgpack_read_next;
}
- case MSGPACK_UNPACK_EXTRA_BYTES: {
+ EMSG(_(e_outofmem));
+ ret = kSDReadStatusReadError;
+ break;
+ case MSGPACK_UNPACK_CONTINUE:
+ emsgf(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ ret = kSDReadStatusNotShaDa;
+ break;
+ case MSGPACK_UNPACK_EXTRA_BYTES:
shada_parse_msgpack_extra_bytes:
- emsgf(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
- "at position %" PRIu64),
- (uint64_t) initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
- }
+ emsgf(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ ret = kSDReadStatusNotShaDa;
+ break;
}
if (ret_buf != NULL && ret == kSDReadStatusSuccess) {
if (ret_unpacked == NULL) {
@@ -2034,81 +1991,67 @@ static const char *shada_format_entry(const ShadaEntry entry)
vim_snprintf(S_LEN(ret), "%s", "[ ] ts=%" PRIu64 " ");
// ^ Space for `can_free_entry`
switch (entry.type) {
- case kSDItemMissing: {
- vim_snprintf_add(S_LEN(ret), "Missing");
- break;
- }
- case kSDItemHeader: {
- vim_snprintf_add(S_LEN(ret), "Header { TODO }");
- break;
- }
- case kSDItemBufferList: {
- vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
- break;
- }
- case kSDItemUnknown: {
- vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
- break;
- }
- case kSDItemSearchPattern: {
- vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
- break;
- }
- case kSDItemSubString: {
- vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
- break;
- }
- case kSDItemHistoryEntry: {
- vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
- break;
- }
- case kSDItemRegister: {
- vim_snprintf_add(S_LEN(ret), "Register { TODO }");
- break;
- }
- case kSDItemVariable: {
- vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
- break;
- }
+ case kSDItemMissing:
+ vim_snprintf_add(S_LEN(ret), "Missing");
+ break;
+ case kSDItemHeader:
+ vim_snprintf_add(S_LEN(ret), "Header { TODO }");
+ break;
+ case kSDItemBufferList:
+ vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
+ break;
+ case kSDItemUnknown:
+ vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
+ break;
+ case kSDItemSearchPattern:
+ vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
+ break;
+ case kSDItemSubString:
+ vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
+ break;
+ case kSDItemHistoryEntry:
+ vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
+ break;
+ case kSDItemRegister:
+ vim_snprintf_add(S_LEN(ret), "Register { TODO }");
+ break;
+ case kSDItemVariable:
+ vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
+ break;
#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
- do { \
- typval_T ad_tv = { \
- .v_type = VAR_DICT, \
- .vval.v_dict = entry.data.filemark.additional_data \
- }; \
- size_t ad_len; \
- char *const ad = encode_tv2string(&ad_tv, &ad_len); \
- vim_snprintf_add( \
- S_LEN(ret), \
- entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
- "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
- "ad={%p:[%zu]%.64s} }", \
- name_fmt_arg, \
- strlen(entry.data.filemark.fname), \
- entry.data.filemark.fname, \
- entry.data.filemark.mark.lnum, \
- entry.data.filemark.mark.col, \
- entry.data.filemark.mark.coladd, \
- (void *)entry.data.filemark.additional_data, \
- ad_len, \
- ad); \
- } while (0)
- case kSDItemGlobalMark: {
- FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
- break;
- }
- case kSDItemChange: {
- FORMAT_MARK_ENTRY("Change", "%s", "");
- break;
- }
- case kSDItemLocalMark: {
- FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
- break;
- }
- case kSDItemJump: {
- FORMAT_MARK_ENTRY("Jump", "%s", "");
- break;
- }
+ do { \
+ typval_T ad_tv = { \
+ .v_type = VAR_DICT, \
+ .vval.v_dict = entry.data.filemark.additional_data \
+ }; \
+ size_t ad_len; \
+ char *const ad = encode_tv2string(&ad_tv, &ad_len); \
+ vim_snprintf_add(S_LEN(ret), \
+ entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
+ "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
+ "ad={%p:[%zu]%.64s} }", \
+ name_fmt_arg, \
+ strlen(entry.data.filemark.fname), \
+ entry.data.filemark.fname, \
+ entry.data.filemark.mark.lnum, \
+ entry.data.filemark.mark.col, \
+ entry.data.filemark.mark.coladd, \
+ (void *)entry.data.filemark.additional_data, \
+ ad_len, \
+ ad); \
+ } while (0)
+ case kSDItemGlobalMark:
+ FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ case kSDItemChange:
+ FORMAT_MARK_ENTRY("Change", "%s", "");
+ break;
+ case kSDItemLocalMark:
+ FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ case kSDItemJump:
+ FORMAT_MARK_ENTRY("Jump", "%s", "");
+ break;
#undef FORMAT_MARK_ENTRY
}
return ret;
@@ -2119,8 +2062,7 @@ static const char *shada_format_entry(const ShadaEntry entry)
/// @param[in] entry ShaDa entry to format.
///
/// @return string representing ShaDa entry in a static buffer.
-static const char *shada_format_pfreed_entry(
- const PossiblyFreedShadaEntry pfs_entry)
+static const char *shada_format_pfreed_entry(const PossiblyFreedShadaEntry pfs_entry)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
{
char *ret = (char *)shada_format_entry(pfs_entry.data);
@@ -2136,10 +2078,11 @@ static const char *shada_format_pfreed_entry(
/// @param[in,out] ret_wms Location where results are saved.
/// @param[out] packer MessagePack packer for entries which are not
/// merged.
-static inline ShaDaWriteResult shada_read_when_writing(
- ShaDaReadDef *const sd_reader, const unsigned srni_flags,
- const size_t max_kbyte, WriteMergerState *const wms,
- msgpack_packer *const packer)
+static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_reader,
+ const unsigned srni_flags,
+ const size_t max_kbyte,
+ WriteMergerState *const wms,
+ msgpack_packer *const packer)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
ShaDaWriteResult ret = kSDWriteSuccessfull;
@@ -2149,217 +2092,202 @@ static inline ShaDaWriteResult shada_read_when_writing(
max_kbyte))
!= kSDReadStatusFinished) {
switch (srni_ret) {
- case kSDReadStatusSuccess: {
- break;
- }
- case kSDReadStatusFinished: {
- // Should be handled by the while condition.
- abort();
- }
- case kSDReadStatusNotShaDa: {
- ret = kSDWriteReadNotShada;
- FALLTHROUGH;
- }
- case kSDReadStatusReadError: {
- return ret;
- }
- case kSDReadStatusMalformed: {
- continue;
- }
+ case kSDReadStatusSuccess:
+ break;
+ case kSDReadStatusFinished:
+ // Should be handled by the while condition.
+ abort();
+ case kSDReadStatusNotShaDa:
+ ret = kSDWriteReadNotShada;
+ FALLTHROUGH;
+ case kSDReadStatusReadError:
+ return ret;
+ case kSDReadStatusMalformed:
+ continue;
}
#define COMPARE_WITH_ENTRY(wms_entry_, entry) \
- do { \
- PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
- if (wms_entry->data.type != kSDItemMissing) { \
- if (wms_entry->data.timestamp >= (entry).timestamp) { \
- shada_free_shada_entry(&(entry)); \
- break; \
- } \
- if (wms_entry->can_free_entry) { \
- shada_free_shada_entry(&wms_entry->data); \
- } \
+ do { \
+ PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
+ if (wms_entry->data.type != kSDItemMissing) { \
+ if (wms_entry->data.timestamp >= (entry).timestamp) { \
+ shada_free_shada_entry(&(entry)); \
+ break; \
+ } \
+ if (wms_entry->can_free_entry) { \
+ shada_free_shada_entry(&wms_entry->data); \
} \
- *wms_entry = pfs_entry; \
- } while (0)
+ } \
+ *wms_entry = pfs_entry; \
+ } while (0)
const PossiblyFreedShadaEntry pfs_entry = {
.can_free_entry = true,
.data = entry,
};
switch (entry.type) {
- case kSDItemMissing: {
+ case kSDItemMissing:
+ break;
+ case kSDItemHeader:
+ case kSDItemBufferList:
+ abort();
+ case kSDItemUnknown:
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
+ break;
+ case kSDItemSearchPattern:
+ COMPARE_WITH_ENTRY((entry.data.search_pattern.is_substitute_pattern
+ ? &wms->sub_search_pattern
+ : &wms->search_pattern), entry);
+ break;
+ case kSDItemSubString:
+ COMPARE_WITH_ENTRY(&wms->replacement, entry);
+ break;
+ case kSDItemHistoryEntry:
+ if (entry.data.history_item.histtype >= HIST_COUNT) {
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
break;
}
- case kSDItemHeader:
- case kSDItemBufferList: {
- abort();
+ if (wms->hms[entry.data.history_item.histtype].hmll.size != 0) {
+ hms_insert(&wms->hms[entry.data.history_item.histtype], entry, true,
+ true);
+ } else {
+ shada_free_shada_entry(&entry);
}
- case kSDItemUnknown: {
+ break;
+ case kSDItemRegister: {
+ const int idx = op_reg_index(entry.data.reg.name);
+ if (idx < 0) {
ret = shada_pack_entry(packer, entry, 0);
shada_free_shada_entry(&entry);
break;
}
- case kSDItemSearchPattern: {
- COMPARE_WITH_ENTRY((entry.data.search_pattern.is_substitute_pattern
- ? &wms->sub_search_pattern
- : &wms->search_pattern), entry);
- break;
- }
- case kSDItemSubString: {
- COMPARE_WITH_ENTRY(&wms->replacement, entry);
- break;
+ COMPARE_WITH_ENTRY(&wms->registers[idx], entry);
+ break;
+ }
+ case kSDItemVariable:
+ if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
+ ret = shada_pack_entry(packer, entry, 0);
}
- case kSDItemHistoryEntry: {
- if (entry.data.history_item.histtype >= HIST_COUNT) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
+ shada_free_shada_entry(&entry);
+ break;
+ case kSDItemGlobalMark:
+ if (ascii_isdigit(entry.data.filemark.name)) {
+ bool processed_mark = false;
+ // Completely ignore numbered mark names, make a list sorted by
+ // timestamp.
+ for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
+ ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
+ if (wms_entry.type != kSDItemGlobalMark) {
+ continue;
+ }
+ // Ignore duplicates.
+ if (wms_entry.timestamp == entry.timestamp
+ && (wms_entry.data.filemark.additional_data == NULL
+ && entry.data.filemark.additional_data == NULL)
+ && marks_equal(wms_entry.data.filemark.mark,
+ entry.data.filemark.mark)
+ && strcmp(wms_entry.data.filemark.fname,
+ entry.data.filemark.fname) == 0) {
+ shada_free_shada_entry(&entry);
+ processed_mark = true;
+ break;
+ }
+ if (wms_entry.timestamp >= entry.timestamp) {
+ processed_mark = true;
+ if (i < ARRAY_SIZE(wms->numbered_marks)) {
+ replace_numbered_mark(wms, i, pfs_entry);
+ } else {
+ shada_free_shada_entry(&entry);
+ }
+ break;
+ }
}
- if (wms->hms[entry.data.history_item.histtype].hmll.size != 0) {
- hms_insert(&wms->hms[entry.data.history_item.histtype], entry, true,
- true);
- } else {
- shada_free_shada_entry(&entry);
+ if (!processed_mark) {
+ replace_numbered_mark(wms, 0, pfs_entry);
}
- break;
- }
- case kSDItemRegister: {
- const int idx = op_reg_index(entry.data.reg.name);
+ } else {
+ const int idx = mark_global_index(entry.data.filemark.name);
if (idx < 0) {
ret = shada_pack_entry(packer, entry, 0);
shada_free_shada_entry(&entry);
break;
}
- COMPARE_WITH_ENTRY(&wms->registers[idx], entry);
- break;
+ COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
}
- case kSDItemVariable: {
- if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
- ret = shada_pack_entry(packer, entry, 0);
- }
+ break;
+ case kSDItemChange:
+ case kSDItemLocalMark: {
+ if (shada_removable(entry.data.filemark.fname)) {
shada_free_shada_entry(&entry);
break;
}
- case kSDItemGlobalMark: {
- if (ascii_isdigit(entry.data.filemark.name)) {
- bool processed_mark = false;
- // Completely ignore numbered mark names, make a list sorted by
- // timestamp.
- for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
- ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
- if (wms_entry.type != kSDItemGlobalMark) {
- continue;
- }
- // Ignore duplicates.
- if (wms_entry.timestamp == entry.timestamp
- && (wms_entry.data.filemark.additional_data == NULL
- && entry.data.filemark.additional_data == NULL)
- && marks_equal(wms_entry.data.filemark.mark,
- entry.data.filemark.mark)
- && strcmp(wms_entry.data.filemark.fname,
- entry.data.filemark.fname) == 0) {
+ const char *const fname = (const char *)entry.data.filemark.fname;
+ khiter_t k;
+ int kh_ret;
+ k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
+ FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
+ if (kh_ret > 0) {
+ memset(filemarks, 0, sizeof(*filemarks));
+ }
+ if (entry.timestamp > filemarks->greatest_timestamp) {
+ filemarks->greatest_timestamp = entry.timestamp;
+ }
+ if (entry.type == kSDItemLocalMark) {
+ const int idx = mark_local_index(entry.data.filemark.name);
+ if (idx < 0) {
+ filemarks->additional_marks = xrealloc(filemarks->additional_marks,
+ (++filemarks->additional_marks_size
+ * sizeof(filemarks->additional_marks[0])));
+ filemarks->additional_marks[filemarks->additional_marks_size - 1] =
+ entry;
+ } else {
+ PossiblyFreedShadaEntry *const wms_entry = &filemarks->marks[idx];
+ if (wms_entry->data.type != kSDItemMissing) {
+ if (wms_entry->data.timestamp >= entry.timestamp) {
shada_free_shada_entry(&entry);
- processed_mark = true;
break;
}
- if (wms_entry.timestamp >= entry.timestamp) {
- processed_mark = true;
- if (i < ARRAY_SIZE(wms->numbered_marks)) {
- replace_numbered_mark(wms, i, pfs_entry);
- } else {
- shada_free_shada_entry(&entry);
+ if (wms_entry->can_free_entry) {
+ if (kh_key(&wms->file_marks, k)
+ == wms_entry->data.data.filemark.fname) {
+ kh_key(&wms->file_marks, k) = entry.data.filemark.fname;
}
- break;
+ shada_free_shada_entry(&wms_entry->data);
}
}
- if (!processed_mark) {
- replace_numbered_mark(wms, 0, pfs_entry);
- }
- } else {
- const int idx = mark_global_index(entry.data.filemark.name);
- if (idx < 0) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
- }
- COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
- }
- break;
- }
- case kSDItemChange:
- case kSDItemLocalMark: {
- if (shada_removable(entry.data.filemark.fname)) {
- shada_free_shada_entry(&entry);
- break;
- }
- const char *const fname = (const char *) entry.data.filemark.fname;
- khiter_t k;
- int kh_ret;
- k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
- FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
- if (kh_ret > 0) {
- memset(filemarks, 0, sizeof(*filemarks));
+ *wms_entry = pfs_entry;
}
- if (entry.timestamp > filemarks->greatest_timestamp) {
- filemarks->greatest_timestamp = entry.timestamp;
- }
- if (entry.type == kSDItemLocalMark) {
- const int idx = mark_local_index(entry.data.filemark.name);
- if (idx < 0) {
- filemarks->additional_marks = xrealloc(
- filemarks->additional_marks,
- (++filemarks->additional_marks_size
- * sizeof(filemarks->additional_marks[0])));
- filemarks->additional_marks[filemarks->additional_marks_size - 1] =
- entry;
- } else {
- PossiblyFreedShadaEntry *const wms_entry = &filemarks->marks[idx];
- if (wms_entry->data.type != kSDItemMissing) {
- if (wms_entry->data.timestamp >= entry.timestamp) {
- shada_free_shada_entry(&entry);
- break;
- }
- if (wms_entry->can_free_entry) {
- if (kh_key(&wms->file_marks, k)
- == wms_entry->data.data.filemark.fname) {
- kh_key(&wms->file_marks, k) = entry.data.filemark.fname;
- }
- shada_free_shada_entry(&wms_entry->data);
- }
- }
- *wms_entry = pfs_entry;
- }
- } else {
+ } else {
#define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \
- do { \
- if (entry.can_free_entry) { \
- shada_free_shada_entry(&entry.data); \
- } \
- } while (0)
+ do { \
+ if (entry.can_free_entry) { \
+ shada_free_shada_entry(&entry.data); \
+ } \
+ } while (0)
#define SDE_TO_PFSDE(entry) \
- ((PossiblyFreedShadaEntry) { .can_free_entry = true, .data = entry })
+ ((PossiblyFreedShadaEntry) { .can_free_entry = true, .data = entry })
#define AFTERFREE_DUMMY(entry)
#define DUMMY_IDX_ADJ(i)
- MERGE_JUMPS(filemarks->changes_size, filemarks->changes,
- PossiblyFreedShadaEntry, data.timestamp,
- data.data.filemark.mark, entry, true,
- FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
- DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
- }
- break;
- }
- case kSDItemJump: {
- MERGE_JUMPS(wms->jumps_size, wms->jumps, PossiblyFreedShadaEntry,
- data.timestamp, data.data.filemark.mark, entry,
- strcmp(jl_entry.data.data.filemark.fname,
- entry.data.filemark.fname) == 0,
+ MERGE_JUMPS(filemarks->changes_size, filemarks->changes,
+ PossiblyFreedShadaEntry, data.timestamp,
+ data.data.filemark.mark, entry, true,
FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
+ }
+ break;
+ }
+ case kSDItemJump:
+ MERGE_JUMPS(wms->jumps_size, wms->jumps, PossiblyFreedShadaEntry,
+ data.timestamp, data.data.filemark.mark, entry,
+ strcmp(jl_entry.data.data.filemark.fname,
+ entry.data.filemark.fname) == 0,
+ FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
+ DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
#undef FREE_POSSIBLY_FREED_SHADA_ENTRY
#undef SDE_TO_PFSDE
#undef DUMMY_IDX_ADJ
#undef AFTERFREE_DUMMY
- break;
- }
+ break;
}
}
#undef COMPARE_WITH_ENTRY
@@ -2372,8 +2300,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
/// @param[in] removable_bufs Cache of buffers ignored due to their location.
///
/// @return true or false.
-static inline bool ignore_buf(const buf_T *const buf,
- khash_t(bufset) *const removable_bufs)
+static inline bool ignore_buf(const buf_T *const buf, khash_t(bufset) *const removable_bufs)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
@@ -2385,8 +2312,7 @@ static inline bool ignore_buf(const buf_T *const buf,
/// @param[in] removable_bufs Buffers which are ignored
///
/// @return ShadaEntry List of buffers to save, kSDItemBufferList entry.
-static inline ShadaEntry shada_get_buflist(
- khash_t(bufset) *const removable_bufs)
+static inline ShadaEntry shada_get_buflist(khash_t(bufset) *const removable_bufs)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
int max_bufs = get_shada_parameter('%');
@@ -2400,14 +2326,14 @@ static inline ShadaEntry shada_get_buflist(
ShadaEntry buflist_entry = (ShadaEntry) {
.type = kSDItemBufferList,
- .timestamp = os_time(),
- .data = {
- .buffer_list = {
- .size = buf_count,
- .buffers = xmalloc(buf_count
- * sizeof(*buflist_entry.data.buffer_list.buffers)),
- },
+ .timestamp = os_time(),
+ .data = {
+ .buffer_list = {
+ .size = buf_count,
+ .buffers = xmalloc(buf_count
+ * sizeof(*buflist_entry.data.buffer_list.buffers)),
},
+ },
};
size_t i = 0;
FOR_ALL_BUFFERS(buf) {
@@ -2419,8 +2345,8 @@ static inline ShadaEntry shada_get_buflist(
}
buflist_entry.data.buffer_list.buffers[i] = (struct buffer_list_buffer) {
.pos = buf->b_last_cursor.mark,
- .fname = (char *)buf->b_ffname,
- .additional_data = buf->additional_data,
+ .fname = (char *)buf->b_ffname,
+ .additional_data = buf->additional_data,
};
i++;
}
@@ -2442,8 +2368,7 @@ static inline ShadaEntry shada_get_buflist(
/// saved.
static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
const SearchPatternGetter get_pattern,
- const bool is_substitute_pattern,
- const bool search_last_used,
+ const bool is_substitute_pattern, const bool search_last_used,
const bool search_highlighted)
FUNC_ATTR_ALWAYS_INLINE
{
@@ -2464,7 +2389,7 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
? defaults.data.search_pattern.has_line_offset
: pat.off.line),
.place_cursor_at_end = (
- is_substitute_pattern
+ is_substitute_pattern
? defaults.data.search_pattern.place_cursor_at_end
: pat.off.end),
.offset = (is_substitute_pattern
@@ -2488,8 +2413,7 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
///
/// @param[in] wms The WriteMergerState used when writing.
/// @param[in] max_reg_lines The maximum number of register lines.
-static inline void shada_initialize_registers(WriteMergerState *const wms,
- int max_reg_lines)
+static inline void shada_initialize_registers(WriteMergerState *const wms, int max_reg_lines)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
const void *reg_iter = NULL;
@@ -2534,8 +2458,7 @@ static inline void shada_initialize_registers(WriteMergerState *const wms,
/// @param[out] wms Merger state to adjust.
/// @param[in] idx Index at which new mark should be placed.
/// @param[in] entry New mark.
-static inline void replace_numbered_mark(WriteMergerState *const wms,
- const size_t idx,
+static inline void replace_numbered_mark(WriteMergerState *const wms, const size_t idx,
const PossiblyFreedShadaEntry entry)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
@@ -2573,8 +2496,7 @@ static inline void find_removable_bufs(khash_t(bufset) *removable_bufs)
/// @param[in] sd_reader Structure containing file reader definition. If it is
/// not NULL then contents of this file will be merged
/// with current Neovim runtime.
-static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
- ShaDaReadDef *const sd_reader)
+static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ARG(1)
{
ShaDaWriteResult ret = kSDWriteSuccessfull;
@@ -2595,8 +2517,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
const bool dump_registers = (max_reg_lines != 0);
khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
- const size_t max_kbyte = (size_t) max_kbyte_i;
- const size_t num_marked_files = (size_t) get_shada_parameter('\'');
+ const size_t max_kbyte = (size_t)max_kbyte_i;
+ const size_t num_marked_files = (size_t)get_shada_parameter('\'');
const bool dump_global_marks = get_shada_parameter('f') != 0;
bool dump_history = false;
@@ -2609,20 +2531,21 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (num_saved > 0) {
dump_history = true;
dump_one_history[i] = true;
- hms_init(&wms->hms[i], i, (size_t) num_saved, sd_reader != NULL, false);
+ hms_init(&wms->hms[i], i, (size_t)num_saved, sd_reader != NULL, false);
} else {
dump_one_history[i] = false;
}
}
- const unsigned srni_flags = (unsigned) (
- kSDReadUndisableableData
- | kSDReadUnknown
- | (dump_history ? kSDReadHistory : 0)
- | (dump_registers ? kSDReadRegisters : 0)
- | (dump_global_vars ? kSDReadVariables : 0)
- | (dump_global_marks ? kSDReadGlobalMarks : 0)
- | (num_marked_files ? kSDReadLocalMarks | kSDReadChanges : 0));
+ const unsigned srni_flags = (unsigned)(
+ kSDReadUndisableableData
+ | kSDReadUnknown
+ | (dump_history ? kSDReadHistory : 0)
+ | (dump_registers ? kSDReadRegisters : 0)
+ | (dump_global_vars ? kSDReadVariables : 0)
+ | (dump_global_marks ? kSDReadGlobalMarks : 0)
+ | (num_marked_files ? kSDReadLocalMarks |
+ kSDReadChanges : 0));
msgpack_packer *const packer = msgpack_packer_new(sd_writer,
&msgpack_sd_writer_write);
@@ -2652,11 +2575,11 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
{ STATIC_CSTR_AS_STRING("version"),
STRING_OBJ(cstr_as_string(longVersion)) },
{ STATIC_CSTR_AS_STRING("max_kbyte"),
- INTEGER_OBJ((Integer) max_kbyte) },
+ INTEGER_OBJ((Integer)max_kbyte) },
{ STATIC_CSTR_AS_STRING("pid"),
- INTEGER_OBJ((Integer) os_get_pid()) },
+ INTEGER_OBJ((Integer)os_get_pid()) },
{ STATIC_CSTR_AS_STRING("encoding"),
- STRING_OBJ(cstr_as_string((char *) p_enc)) },
+ STRING_OBJ(cstr_as_string((char *)p_enc)) },
}),
}
}
@@ -2688,34 +2611,32 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
break;
}
switch (vartv.v_type) {
- case VAR_FUNC:
- case VAR_PARTIAL:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ tv_clear(&vartv);
+ continue;
+ case VAR_DICT: {
+ dict_T *di = vartv.vval.v_dict;
+ int copyID = get_copyID();
+ if (!set_ref_in_ht(&di->dv_hashtab, copyID, NULL)
+ && copyID == di->dv_copyID) {
tv_clear(&vartv);
continue;
- case VAR_DICT:
- {
- dict_T *di = vartv.vval.v_dict;
- int copyID = get_copyID();
- if (!set_ref_in_ht(&di->dv_hashtab, copyID, NULL)
- && copyID == di->dv_copyID) {
- tv_clear(&vartv);
- continue;
- }
- break;
- }
- case VAR_LIST:
- {
- list_T *l = vartv.vval.v_list;
- int copyID = get_copyID();
- if (!set_ref_in_list(l, copyID, NULL)
- && copyID == l->lv_copyID) {
- tv_clear(&vartv);
- continue;
- }
- break;
- }
- default:
- break;
+ }
+ break;
+ }
+ case VAR_LIST: {
+ list_T *l = vartv.vval.v_list;
+ int copyID = get_copyID();
+ if (!set_ref_in_list(l, copyID, NULL)
+ && copyID == l->lv_copyID) {
+ tv_clear(&vartv);
+ continue;
+ }
+ break;
+ }
+ default:
+ break;
}
typval_T tgttv;
tv_copy(&vartv, &tgttv);
@@ -2725,7 +2646,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.timestamp = cur_timestamp,
.data = {
.global_var = {
- .name = (char *) name,
+ .name = (char *)name,
.value = tgttv,
.additional_elements = NULL,
}
@@ -2740,7 +2661,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
tv_clear(&tgttv);
if (spe_ret == kSDWriteSuccessfull) {
int kh_ret;
- (void) kh_put(strset, &wms->dumped_variables, name, &kh_ret);
+ (void)kh_put(strset, &wms->dumped_variables, name, &kh_ret);
}
} while (var_iter != NULL);
}
@@ -2773,7 +2694,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.timestamp = sub.timestamp,
.data = {
.sub_string = {
- .sub = (char *) sub.sub,
+ .sub = (char *)sub.sub,
.additional_elements = sub.additional_elements,
}
}
@@ -2795,17 +2716,17 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
const char *fname;
if (fm.fmark.fnum == 0) {
assert(fm.fname != NULL);
- if (shada_removable((const char *) fm.fname)) {
+ if (shada_removable((const char *)fm.fname)) {
continue;
}
- fname = (const char *) fm.fname;
+ fname = (const char *)fm.fname;
} else {
const buf_T *const buf = buflist_findnr(fm.fmark.fnum);
if (buf == NULL || buf->b_ffname == NULL
|| in_bufset(&removable_bufs, buf)) {
continue;
}
- fname = (const char *) buf->b_ffname;
+ fname = (const char *)buf->b_ffname;
}
const PossiblyFreedShadaEntry pf_entry = {
.can_free_entry = false,
@@ -2842,7 +2763,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
continue;
}
const void *local_marks_iter = NULL;
- const char *const fname = (const char *) buf->b_ffname;
+ const char *const fname = (const char *)buf->b_ffname;
khiter_t k;
int kh_ret;
k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
@@ -2866,7 +2787,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.filemark = {
.mark = fm.mark,
.name = name,
- .fname = (char *) fname,
+ .fname = (char *)fname,
.additional_data = fm.additional_data,
}
}
@@ -2886,7 +2807,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.data = {
.filemark = {
.mark = fm.mark,
- .fname = (char *) fname,
+ .fname = (char *)fname,
.additional_data = fm.additional_data,
}
}
@@ -2896,13 +2817,13 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
filemarks->greatest_timestamp = fm.timestamp;
}
}
- filemarks->changes_size = (size_t) buf->b_changelistlen;
+ filemarks->changes_size = (size_t)buf->b_changelistlen;
}
}
if (sd_reader != NULL) {
- const ShaDaWriteResult srww_ret = shada_read_when_writing(
- sd_reader, srni_flags, max_kbyte, wms, packer);
+ const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms,
+ packer);
if (srww_ret != kSDWriteSuccessfull) {
ret = srww_ret;
}
@@ -2968,7 +2889,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
const size_t file_markss_size = kh_size(&wms->file_marks);
FileMarks **const all_file_markss =
- xmalloc(file_markss_size * sizeof(*all_file_markss));
+ xmalloc(file_markss_size * sizeof(*all_file_markss));
FileMarks **cur_file_marks = all_file_markss;
for (khint_t i = kh_begin(&wms->file_marks); i != kh_end(&wms->file_marks);
i++) {
@@ -2976,7 +2897,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
*cur_file_marks++ = &kh_val(&wms->file_marks, i);
}
}
- qsort((void *) all_file_markss, file_markss_size, sizeof(*all_file_markss),
+ qsort((void *)all_file_markss, file_markss_size, sizeof(*all_file_markss),
&compare_file_marks);
const size_t file_markss_to_dump = MIN(num_marked_files, file_markss_size);
for (size_t i = 0; i < file_markss_to_dump; i++) {
@@ -3007,11 +2928,10 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (dump_one_history[i]) {
hms_insert_whole_neovim_history(&wms->hms[i]);
HMS_ITER(&wms->hms[i], cur_entry, {
- if (shada_pack_pfreed_entry(
- packer, (PossiblyFreedShadaEntry) {
- .data = cur_entry->data,
- .can_free_entry = cur_entry->can_free_entry,
- }, max_kbyte) == kSDWriteFailed) {
+ if (shada_pack_pfreed_entry(packer, (PossiblyFreedShadaEntry) {
+ .data = cur_entry->data,
+ .can_free_entry = cur_entry->can_free_entry,
+ }, max_kbyte) == kSDWriteFailed) {
ret = kSDWriteFailed;
break;
}
@@ -3082,7 +3002,7 @@ int shada_write_file(const char *const file, bool nomerge)
}
// Save permissions from the original file, with modifications:
- int perm = (int) os_getperm(fname);
+ int perm = (int)os_getperm(fname);
perm = (perm >= 0) ? ((perm & 0777) | 0600) : 0600;
// ^3 ^1 ^2 ^2,3
// 1: Strip SUID bit if any.
@@ -3090,8 +3010,7 @@ int shada_write_file(const char *const file, bool nomerge)
// 3: If somebody happened to delete the file after it was opened for
// reading use u=rw permissions.
shada_write_file_open: {}
- sd_writer.cookie = file_open_new(
- &error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
+ sd_writer.cookie = file_open_new(&error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
if (sd_writer.cookie == NULL) {
if (error == UV_EEXIST || error == UV_ELOOP) {
// File already exists, try another name
@@ -3244,8 +3163,7 @@ int shada_read_marks(void)
/// @param[in] missing_ok If true, do not error out when file is missing.
///
/// @return OK in case of success, FAIL otherwise.
-int shada_read_everything(const char *const fname, const bool forceit,
- const bool missing_ok)
+int shada_read_everything(const char *const fname, const bool forceit, const bool missing_ok)
{
return shada_read_file(fname,
kShaDaWantInfo|kShaDaWantMarks|kShaDaGetOldfiles
@@ -3259,81 +3177,71 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
return;
}
switch (entry->type) {
- case kSDItemMissing: {
- break;
- }
- case kSDItemUnknown: {
- xfree(entry->data.unknown_item.contents);
- break;
- }
- case kSDItemHeader: {
- api_free_dictionary(entry->data.header);
- break;
- }
- case kSDItemChange:
- case kSDItemJump:
- case kSDItemGlobalMark:
- case kSDItemLocalMark: {
- tv_dict_unref(entry->data.filemark.additional_data);
- xfree(entry->data.filemark.fname);
- break;
+ case kSDItemMissing:
+ break;
+ case kSDItemUnknown:
+ xfree(entry->data.unknown_item.contents);
+ break;
+ case kSDItemHeader:
+ api_free_dictionary(entry->data.header);
+ break;
+ case kSDItemChange:
+ case kSDItemJump:
+ case kSDItemGlobalMark:
+ case kSDItemLocalMark:
+ tv_dict_unref(entry->data.filemark.additional_data);
+ xfree(entry->data.filemark.fname);
+ break;
+ case kSDItemSearchPattern:
+ tv_dict_unref(entry->data.search_pattern.additional_data);
+ xfree(entry->data.search_pattern.pat);
+ break;
+ case kSDItemRegister:
+ tv_dict_unref(entry->data.reg.additional_data);
+ for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
+ xfree(entry->data.reg.contents[i]);
}
- case kSDItemSearchPattern: {
- tv_dict_unref(entry->data.search_pattern.additional_data);
- xfree(entry->data.search_pattern.pat);
- break;
- }
- case kSDItemRegister: {
- tv_dict_unref(entry->data.reg.additional_data);
- for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
- xfree(entry->data.reg.contents[i]);
- }
- xfree(entry->data.reg.contents);
- break;
- }
- case kSDItemHistoryEntry: {
- tv_list_unref(entry->data.history_item.additional_elements);
- xfree(entry->data.history_item.string);
- break;
- }
- case kSDItemVariable: {
- tv_list_unref(entry->data.global_var.additional_elements);
- xfree(entry->data.global_var.name);
- tv_clear(&entry->data.global_var.value);
- break;
- }
- case kSDItemSubString: {
- tv_list_unref(entry->data.sub_string.additional_elements);
- xfree(entry->data.sub_string.sub);
- break;
- }
- case kSDItemBufferList: {
- for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
- xfree(entry->data.buffer_list.buffers[i].fname);
- tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
- }
- xfree(entry->data.buffer_list.buffers);
- break;
+ xfree(entry->data.reg.contents);
+ break;
+ case kSDItemHistoryEntry:
+ tv_list_unref(entry->data.history_item.additional_elements);
+ xfree(entry->data.history_item.string);
+ break;
+ case kSDItemVariable:
+ tv_list_unref(entry->data.global_var.additional_elements);
+ xfree(entry->data.global_var.name);
+ tv_clear(&entry->data.global_var.value);
+ break;
+ case kSDItemSubString:
+ tv_list_unref(entry->data.sub_string.additional_elements);
+ xfree(entry->data.sub_string.sub);
+ break;
+ case kSDItemBufferList:
+ for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
+ xfree(entry->data.buffer_list.buffers[i].fname);
+ tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
}
+ xfree(entry->data.buffer_list.buffers);
+ break;
}
}
#ifndef HAVE_BE64TOH
static inline uint64_t be64toh(uint64_t big_endian_64_bits)
{
-#ifdef ORDER_BIG_ENDIAN
+# ifdef ORDER_BIG_ENDIAN
return big_endian_64_bits;
-#else
+# else
// It may appear that when !defined(ORDER_BIG_ENDIAN) actual order is big
// endian. This variant is suboptimal, but it works regardless of actual
// order.
- uint8_t *buf = (uint8_t *) &big_endian_64_bits;
+ uint8_t *buf = (uint8_t *)&big_endian_64_bits;
uint64_t ret = 0;
for (size_t i = 8; i; i--) {
- ret |= ((uint64_t) buf[i - 1]) << ((8 - i) * 8);
+ ret |= ((uint64_t)buf[i - 1]) << ((8 - i) * 8);
}
return ret;
-#endif
+# endif
}
#endif
@@ -3346,8 +3254,7 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits)
/// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if
/// there were not enough bytes to read or kSDReadStatusReadError if
/// there was some error while reading.
-static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
- char *const buffer,
+static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
const size_t length)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -3385,8 +3292,7 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
/// @return kSDReadStatusSuccess if reading was successful,
/// kSDReadStatusNotShaDa if there were not enough bytes to read or
/// kSDReadStatusReadError if reading failed for whatever reason.
-static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
- const int first_char,
+static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const int first_char,
uint64_t *const result)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -3401,42 +3307,37 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
emsgf(_(RCERR "Error while reading ShaDa file: "
"expected positive integer at position %" PRIu64
", but got nothing"),
- (uint64_t) fpos);
+ (uint64_t)fpos);
return kSDReadStatusNotShaDa;
}
}
if (~first_char & 0x80) {
// Positive fixnum
- *result = (uint64_t) ((uint8_t) first_char);
+ *result = (uint64_t)((uint8_t)first_char);
} else {
size_t length = 0;
switch (first_char) {
- case 0xCC: { // uint8
- length = 1;
- break;
- }
- case 0xCD: { // uint16
- length = 2;
- break;
- }
- case 0xCE: { // uint32
- length = 4;
- break;
- }
- case 0xCF: { // uint64
- length = 8;
- break;
- }
- default: {
- emsgf(_(RCERR "Error while reading ShaDa file: "
- "expected positive integer at position %" PRIu64),
- (uint64_t) fpos);
- return kSDReadStatusNotShaDa;
- }
+ case 0xCC: // uint8
+ length = 1;
+ break;
+ case 0xCD: // uint16
+ length = 2;
+ break;
+ case 0xCE: // uint32
+ length = 4;
+ break;
+ case 0xCF: // uint64
+ length = 8;
+ break;
+ default:
+ emsgf(_(RCERR "Error while reading ShaDa file: "
+ "expected positive integer at position %" PRIu64),
+ (uint64_t)fpos);
+ return kSDReadStatusNotShaDa;
}
uint64_t buf = 0;
- char *buf_u8 = (char *) &buf;
+ char *buf_u8 = (char *)&buf;
ShaDaReadResult fl_ret;
if ((fl_ret = fread_len(sd_reader, &(buf_u8[sizeof(buf)-length]), length))
!= kSDReadStatusSuccess) {
@@ -3448,24 +3349,24 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
}
#define READERR(entry_name, error_desc) \
- RERR "Error while reading ShaDa file: " \
- entry_name " entry at position %" PRIu64 " " \
- error_desc
+ RERR "Error while reading ShaDa file: " \
+ entry_name " entry at position %" PRIu64 " " \
+ error_desc
#define CHECK_KEY(key, expected) ( \
- key.via.str.size == sizeof(expected) - 1 \
- && STRNCMP(key.via.str.ptr, expected, sizeof(expected) - 1) == 0)
+ key.via.str.size == sizeof(expected) - 1 \
+ && STRNCMP(key.via.str.ptr, expected, sizeof(expected) - 1) == 0)
#define CLEAR_GA_AND_ERROR_OUT(ga) \
- do { \
- ga_clear(&ga); \
- goto shada_read_next_item_error; \
- } while (0)
+ do { \
+ ga_clear(&ga); \
+ goto shada_read_next_item_error; \
+ } while (0)
#define ID(s) s
#define BINDUP(b) xmemdupz(b.ptr, b.size)
-#define TOINT(s) ((int) (s))
-#define TOLONG(s) ((long) (s))
-#define TOCHAR(s) ((char) (s))
-#define TOU8(s) ((uint8_t) (s))
-#define TOSIZE(s) ((size_t) (s))
+#define TOINT(s) ((int)(s))
+#define TOLONG(s) ((long)(s))
+#define TOCHAR(s) ((char)(s))
+#define TOU8(s) ((uint8_t)(s))
+#define TOSIZE(s) ((size_t)(s))
#define CHECKED_ENTRY(condition, error_desc, entry_name, obj, tgt, attr, \
proc) \
do { \
@@ -3486,18 +3387,16 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
}
#define CHECKED_KEY(un, entry_name, name, error_desc, tgt, condition, attr, \
proc) \
- else if (CHECK_KEY( /* NOLINT(readability/braces) */ \
- un.data.via.map.ptr[i].key, name)) { \
- CHECKED_ENTRY( \
- condition, "has " name " key value " error_desc, \
- entry_name, un.data.via.map.ptr[i].val, \
- tgt, attr, proc); \
+ else if (CHECK_KEY( /* NOLINT(readability/braces) */ \
+ un.data.via.map.ptr[i].key, name)) { \
+ CHECKED_ENTRY(condition, "has " name " key value " error_desc, \
+ entry_name, un.data.via.map.ptr[i].val, \
+ tgt, attr, proc); \
}
#define TYPED_KEY(un, entry_name, name, type_name, tgt, objtype, attr, proc) \
- CHECKED_KEY( \
- un, entry_name, name, "which is not " type_name, tgt, \
- un.data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \
- attr, proc)
+ CHECKED_KEY(un, entry_name, name, "which is not " type_name, tgt, \
+ un.data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \
+ attr, proc)
#define BOOLEAN_KEY(un, entry_name, name, tgt) \
TYPED_KEY(un, entry_name, name, "a boolean", tgt, BOOLEAN, boolean, ID)
#define STRING_KEY(un, entry_name, name, tgt) \
@@ -3506,19 +3405,18 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, \
BIN_CONVERTED)
#define INT_KEY(un, entry_name, name, tgt, proc) \
- CHECKED_KEY( \
- un, entry_name, name, "which is not an integer", tgt, \
- ((un.data.via.map.ptr[i].val.type \
- == MSGPACK_OBJECT_POSITIVE_INTEGER) \
- || (un.data.via.map.ptr[i].val.type \
- == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \
- i64, proc)
+ CHECKED_KEY(un, entry_name, name, "which is not an integer", tgt, \
+ ((un.data.via.map.ptr[i].val.type \
+ == MSGPACK_OBJECT_POSITIVE_INTEGER) \
+ || (un.data.via.map.ptr[i].val.type \
+ == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \
+ i64, proc)
#define INTEGER_KEY(un, entry_name, name, tgt) \
INT_KEY(un, entry_name, name, tgt, TOINT)
#define LONG_KEY(un, entry_name, name, tgt) \
INT_KEY(un, entry_name, name, tgt, TOLONG)
#define ADDITIONAL_KEY(un) \
- else { /* NOLINT(readability/braces) */ \
+ else { /* NOLINT(readability/braces) */ \
ga_grow(&ad_ga, 1); \
memcpy(((char *)ad_ga.ga_data) + ((size_t)ad_ga.ga_len \
* sizeof(*un.data.via.map.ptr)), \
@@ -3529,54 +3427,54 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
#define CONVERTED(str, len) (xmemdupz((str), (len)))
#define BIN_CONVERTED(b) CONVERTED(b.ptr, b.size)
#define SET_ADDITIONAL_DATA(tgt, name) \
- do { \
- if (ad_ga.ga_len) { \
- msgpack_object obj = { \
- .type = MSGPACK_OBJECT_MAP, \
- .via = { \
- .map = { \
- .size = (uint32_t) ad_ga.ga_len, \
- .ptr = ad_ga.ga_data, \
- } \
- } \
- }; \
- typval_T adtv; \
- if (msgpack_to_vim(obj, &adtv) == FAIL \
- || adtv.v_type != VAR_DICT) { \
- emsgf(_(READERR(name, \
- "cannot be converted to a VimL dictionary")), \
- initial_fpos); \
- ga_clear(&ad_ga); \
- tv_clear(&adtv); \
- goto shada_read_next_item_error; \
+ do { \
+ if (ad_ga.ga_len) { \
+ msgpack_object obj = { \
+ .type = MSGPACK_OBJECT_MAP, \
+ .via = { \
+ .map = { \
+ .size = (uint32_t)ad_ga.ga_len, \
+ .ptr = ad_ga.ga_data, \
} \
- tgt = adtv.vval.v_dict; \
} \
+ }; \
+ typval_T adtv; \
+ if (msgpack_to_vim(obj, &adtv) == FAIL \
+ || adtv.v_type != VAR_DICT) { \
+ emsgf(_(READERR(name, \
+ "cannot be converted to a VimL dictionary")), \
+ initial_fpos); \
ga_clear(&ad_ga); \
- } while (0)
+ tv_clear(&adtv); \
+ goto shada_read_next_item_error; \
+ } \
+ tgt = adtv.vval.v_dict; \
+ } \
+ ga_clear(&ad_ga); \
+ } while (0)
#define SET_ADDITIONAL_ELEMENTS(src, src_maxsize, tgt, name) \
- do { \
- if ((src).size > (size_t) (src_maxsize)) { \
- msgpack_object obj = { \
- .type = MSGPACK_OBJECT_ARRAY, \
- .via = { \
- .array = { \
- .size = ((src).size - (uint32_t) (src_maxsize)), \
- .ptr = (src).ptr + (src_maxsize), \
- } \
- } \
- }; \
- typval_T aetv; \
- if (msgpack_to_vim(obj, &aetv) == FAIL) { \
- emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
- initial_fpos); \
- tv_clear(&aetv); \
- goto shada_read_next_item_error; \
+ do { \
+ if ((src).size > (size_t)(src_maxsize)) { \
+ msgpack_object obj = { \
+ .type = MSGPACK_OBJECT_ARRAY, \
+ .via = { \
+ .array = { \
+ .size = ((src).size - (uint32_t)(src_maxsize)), \
+ .ptr = (src).ptr + (src_maxsize), \
} \
- assert(aetv.v_type == VAR_LIST); \
- (tgt) = aetv.vval.v_list; \
} \
- } while (0)
+ }; \
+ typval_T aetv; \
+ if (msgpack_to_vim(obj, &aetv) == FAIL) { \
+ emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
+ initial_fpos); \
+ tv_clear(&aetv); \
+ goto shada_read_next_item_error; \
+ } \
+ assert(aetv.v_type == VAR_LIST); \
+ (tgt) = aetv.vval.v_list; \
+ } \
+ } while (0)
/// Iterate over shada file contents
///
@@ -3588,10 +3486,8 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
/// greater then given.
///
/// @return Any value from ShaDaReadResult enum.
-static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader,
- ShadaEntry *const entry,
- const unsigned flags,
- const size_t max_kbyte)
+static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader, ShadaEntry *const entry,
+ const unsigned flags, const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
ShaDaReadResult ret = kSDReadStatusMalformed;
@@ -3607,11 +3503,11 @@ shada_read_next_item_start:
// First: manually unpack type, timestamp and length.
// This is needed to avoid both seeking and having to maintain a buffer.
- uint64_t type_u64 = (uint64_t) kSDItemMissing;
+ uint64_t type_u64 = (uint64_t)kSDItemMissing;
uint64_t timestamp_u64;
uint64_t length_u64;
- const uint64_t initial_fpos = (uint64_t) sd_reader->fpos;
+ const uint64_t initial_fpos = (uint64_t)sd_reader->fpos;
const int first_char = read_char(sd_reader);
if (first_char == EOF && sd_reader->eof) {
return kSDReadStatusFinished;
@@ -3654,7 +3550,7 @@ shada_read_next_item_start:
if ((type_u64 > SHADA_LAST_ENTRY
? !(flags & kSDReadUnknown)
- : !((unsigned) (1 << type_u64) & flags))
+ : !((unsigned)(1 << type_u64) & flags))
|| (max_kbyte && length > max_kbyte * 1024)) {
// First entry is unknown or equal to "\n" (10)? Most likely this means that
// current file is not a ShaDa file because first item should normally be
@@ -3682,16 +3578,16 @@ shada_read_next_item_start:
entry->data.unknown_item.size = length;
entry->data.unknown_item.type = type_u64;
if (initial_fpos == 0) {
- const ShaDaReadResult spm_ret = shada_parse_msgpack(
- sd_reader, length, NULL, &entry->data.unknown_item.contents);
+ const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length, NULL,
+ &entry->data.unknown_item.contents);
if (spm_ret != kSDReadStatusSuccess) {
entry->type = kSDItemMissing;
}
return spm_ret;
} else {
entry->data.unknown_item.contents = xmalloc(length);
- const ShaDaReadResult fl_ret = fread_len(
- sd_reader, entry->data.unknown_item.contents, length);
+ const ShaDaReadResult fl_ret =
+ fread_len(sd_reader, entry->data.unknown_item.contents, length);
if (fl_ret != kSDReadStatusSuccess) {
shada_free_shada_entry(entry);
entry->type = kSDItemMissing;
@@ -3711,373 +3607,367 @@ shada_read_next_item_start:
}
ret = kSDReadStatusMalformed;
entry->data = sd_default_values[type_u64].data;
- switch ((ShadaEntryType) type_u64) {
- case kSDItemHeader: {
- if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
- emsgf(_(READERR("header", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
- break;
+ switch ((ShadaEntryType)type_u64) {
+ case kSDItemHeader:
+ if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
+ emsgf(_(READERR("header", "is not a dictionary")), initial_fpos);
+ goto shada_read_next_item_error;
}
- case kSDItemSearchPattern: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(READERR("search pattern", "is not a dictionary")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "search pattern")
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC,
- entry->data.search_pattern.magic)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE,
- entry->data.search_pattern.smartcase)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET,
- entry->data.search_pattern.has_line_offset)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END,
- entry->data.search_pattern.place_cursor_at_end)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED,
- entry->data.search_pattern.is_last_used)
- BOOLEAN_KEY(unpacked, "search pattern",
- SEARCH_KEY_IS_SUBSTITUTE_PATTERN,
- entry->data.search_pattern.is_substitute_pattern)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED,
- entry->data.search_pattern.highlighted)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD,
- entry->data.search_pattern.search_backward)
- INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET,
- entry->data.search_pattern.offset)
- CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT,
- entry->data.search_pattern.pat)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.search_pattern.pat == NULL) {
- emsgf(_(READERR("search pattern", "has no pattern")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
- "search pattern");
- break;
+ break;
+ case kSDItemSearchPattern: {
+ if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(READERR("search pattern", "is not a dictionary")),
+ initial_fpos);
+ goto shada_read_next_item_error;
}
- case kSDItemChange:
- case kSDItemJump:
- case kSDItemGlobalMark:
- case kSDItemLocalMark: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(READERR("mark", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "mark")
- if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
- if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
- emsgf(_(READERR("mark", "has n key which is only valid for "
- "local and global mark entries")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- CHECKED_ENTRY(
- (unpacked.data.via.map.ptr[i].val.type
- == MSGPACK_OBJECT_POSITIVE_INTEGER),
- "has n key value which is not an unsigned integer",
- "mark", unpacked.data.via.map.ptr[i].val,
- entry->data.filemark.name, u64, TOCHAR);
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
+ for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
+ CHECK_KEY_IS_STR(unpacked, "search pattern")
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC,
+ entry->data.search_pattern.magic)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE,
+ entry->data.search_pattern.smartcase)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET,
+ entry->data.search_pattern.has_line_offset)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END,
+ entry->data.search_pattern.place_cursor_at_end)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED,
+ entry->data.search_pattern.is_last_used)
+ BOOLEAN_KEY(unpacked, "search pattern",
+ SEARCH_KEY_IS_SUBSTITUTE_PATTERN,
+ entry->data.search_pattern.is_substitute_pattern)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED,
+ entry->data.search_pattern.highlighted)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD,
+ entry->data.search_pattern.search_backward)
+ INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET,
+ entry->data.search_pattern.offset)
+ CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT,
+ entry->data.search_pattern.pat)
+ ADDITIONAL_KEY(unpacked)
+ }
+ if (entry->data.search_pattern.pat == NULL) {
+ emsgf(_(READERR("search pattern", "has no pattern")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
+ "search pattern");
+ break;
+ }
+ case kSDItemChange:
+ case kSDItemJump:
+ case kSDItemGlobalMark:
+ case kSDItemLocalMark: {
+ if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(READERR("mark", "is not a dictionary")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
+ for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
+ CHECK_KEY_IS_STR(unpacked, "mark")
+ if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
+ if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
+ emsgf(_(READERR("mark", "has n key which is only valid for "
+ "local and global mark entries")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
- LONG_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum)
- INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col)
- STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname)
- ADDITIONAL_KEY(unpacked)
+ CHECKED_ENTRY((unpacked.data.via.map.ptr[i].val.type
+ == MSGPACK_OBJECT_POSITIVE_INTEGER),
+ "has n key value which is not an unsigned integer",
+ "mark", unpacked.data.via.map.ptr[i].val,
+ entry->data.filemark.name, u64, TOCHAR);
}
- if (entry->data.filemark.fname == NULL) {
- emsgf(_(READERR("mark", "is missing file name")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.filemark.mark.lnum <= 0) {
- emsgf(_(READERR("mark", "has invalid line number")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.filemark.mark.col < 0) {
- emsgf(_(READERR("mark", "has invalid column number")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
- break;
+ LONG_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum)
+ INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col)
+ STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname)
+ ADDITIONAL_KEY(unpacked)
}
- case kSDItemRegister: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(READERR("register", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "register")
- if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
- REG_KEY_CONTENTS)) {
- if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("register",
- "has " REG_KEY_CONTENTS
- " key with non-array value")),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
- emsgf(_(READERR("register",
- "has " REG_KEY_CONTENTS " key with empty array")),
- initial_fpos);
+ if (entry->data.filemark.fname == NULL) {
+ emsgf(_(READERR("mark", "is missing file name")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (entry->data.filemark.mark.lnum <= 0) {
+ emsgf(_(READERR("mark", "has invalid line number")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (entry->data.filemark.mark.col < 0) {
+ emsgf(_(READERR("mark", "has invalid column number")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
+ break;
+ }
+ case kSDItemRegister: {
+ if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(READERR("register", "is not a dictionary")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
+ for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
+ CHECK_KEY_IS_STR(unpacked, "register")
+ if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
+ REG_KEY_CONTENTS)) {
+ if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("register",
+ "has " REG_KEY_CONTENTS
+ " key with non-array value")),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
+ emsgf(_(READERR("register",
+ "has " REG_KEY_CONTENTS " key with empty array")),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ const msgpack_object_array arr =
+ unpacked.data.via.map.ptr[i].val.via.array;
+ for (size_t j = 0; j < arr.size; j++) {
+ if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("register", "has " REG_KEY_CONTENTS " array "
+ "with non-binary value")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
- const msgpack_object_array arr =
- unpacked.data.via.map.ptr[i].val.via.array;
- for (size_t j = 0; j < arr.size; j++) {
- if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("register", "has " REG_KEY_CONTENTS " array "
- "with non-binary value")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- }
- entry->data.reg.contents_size = arr.size;
- entry->data.reg.contents = xmalloc(arr.size * sizeof(char *));
- for (size_t j = 0; j < arr.size; j++) {
- entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin);
- }
}
- BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED,
- entry->data.reg.is_unnamed)
- TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer",
- entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8)
- TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer",
- entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR)
- TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer",
- entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.reg.contents == NULL) {
- emsgf(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ entry->data.reg.contents_size = arr.size;
+ entry->data.reg.contents = xmalloc(arr.size * sizeof(char *));
+ for (size_t j = 0; j < arr.size; j++) {
+ entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin);
+ }
}
- SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register");
- break;
+ BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED,
+ entry->data.reg.is_unnamed)
+ TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer",
+ entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8)
+ TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer",
+ entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR)
+ TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer",
+ entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
+ ADDITIONAL_KEY(unpacked)
}
- case kSDItemHistoryEntry: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("history", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 2) {
- emsgf(_(READERR("history", "does not have enough elements")),
- initial_fpos);
+ if (entry->data.reg.contents == NULL) {
+ emsgf(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register");
+ break;
+ }
+ case kSDItemHistoryEntry: {
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("history", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size < 2) {
+ emsgf(_(READERR("history", "does not have enough elements")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[0].type
+ != MSGPACK_OBJECT_POSITIVE_INTEGER) {
+ emsgf(_(READERR("history", "has wrong history type type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[1].type
+ != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("history", "has wrong history string type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
+ unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
+ emsgf(_(READERR("history", "contains string with zero byte inside")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.history_item.histtype =
+ (uint8_t)unpacked.data.via.array.ptr[0].via.u64;
+ const bool is_hist_search =
+ entry->data.history_item.histtype == HIST_SEARCH;
+ if (is_hist_search) {
+ if (unpacked.data.via.array.size < 3) {
+ emsgf(_(READERR("search history",
+ "does not have separator character")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[0].type
+ if (unpacked.data.via.array.ptr[2].type
!= MSGPACK_OBJECT_POSITIVE_INTEGER) {
- emsgf(_(READERR("history", "has wrong history type type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[1].type
- != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("history", "has wrong history string type")),
- initial_fpos);
+ emsgf(_(READERR("search history",
+ "has wrong history separator type")), initial_fpos);
goto shada_read_next_item_error;
}
- if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
- unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
- emsgf(_(READERR("history", "contains string with zero byte inside")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.history_item.histtype =
- (uint8_t) unpacked.data.via.array.ptr[0].via.u64;
- const bool is_hist_search =
- entry->data.history_item.histtype == HIST_SEARCH;
- if (is_hist_search) {
- if (unpacked.data.via.array.size < 3) {
- emsgf(_(READERR("search history",
- "does not have separator character")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[2].type
- != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- emsgf(_(READERR("search history",
- "has wrong history separator type")), initial_fpos);
+ entry->data.history_item.sep =
+ (char)unpacked.data.via.array.ptr[2].via.u64;
+ }
+ size_t strsize;
+ strsize = (
+ unpacked.data.via.array.ptr[1].via.bin.size
+ + 1 // Zero byte
+ + 1); // Separator character
+ entry->data.history_item.string = xmalloc(strsize);
+ memcpy(entry->data.history_item.string,
+ unpacked.data.via.array.ptr[1].via.bin.ptr,
+ unpacked.data.via.array.ptr[1].via.bin.size);
+ entry->data.history_item.string[strsize - 2] = 0;
+ entry->data.history_item.string[strsize - 1] =
+ entry->data.history_item.sep;
+ SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search),
+ entry->data.history_item.additional_elements,
+ "history");
+ break;
+ }
+ case kSDItemVariable: {
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("variable", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size < 2) {
+ emsgf(_(READERR("variable", "does not have enough elements")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("variable", "has wrong variable name type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.global_var.name =
+ xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr,
+ unpacked.data.via.array.ptr[0].via.bin.size);
+ SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
+ entry->data.global_var.additional_elements,
+ "variable");
+ bool is_blob = false;
+ // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB
+ // element is stored with Blobs which can be used to differentiate them
+ if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_BIN) {
+ const listitem_T *type_item
+ = tv_list_first(entry->data.global_var.additional_elements);
+ if (type_item != NULL) {
+ const typval_T *type_tv = TV_LIST_ITEM_TV(type_item);
+ if (type_tv->v_type != VAR_NUMBER
+ || type_tv->vval.v_number != VAR_TYPE_BLOB) {
+ emsgf(_(READERR("variable", "has wrong variable type")),
+ initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.history_item.sep =
- (char) unpacked.data.via.array.ptr[2].via.u64;
+ is_blob = true;
}
- size_t strsize;
- strsize = (
- unpacked.data.via.array.ptr[1].via.bin.size
- + 1 // Zero byte
- + 1); // Separator character
- entry->data.history_item.string = xmalloc(strsize);
- memcpy(entry->data.history_item.string,
- unpacked.data.via.array.ptr[1].via.bin.ptr,
- unpacked.data.via.array.ptr[1].via.bin.size);
- entry->data.history_item.string[strsize - 2] = 0;
- entry->data.history_item.string[strsize - 1] =
- entry->data.history_item.sep;
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search),
- entry->data.history_item.additional_elements,
- "history");
- break;
}
- case kSDItemVariable: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("variable", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 2) {
- emsgf(_(READERR("variable", "does not have enough elements")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("variable", "has wrong variable name type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.global_var.name =
- xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr,
- unpacked.data.via.array.ptr[0].via.bin.size);
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
- entry->data.global_var.additional_elements,
- "variable");
- bool is_blob = false;
- // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB
- // element is stored with Blobs which can be used to differentiate them
- if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_BIN) {
- const listitem_T *type_item
- = tv_list_first(entry->data.global_var.additional_elements);
- if (type_item != NULL) {
- const typval_T *type_tv = TV_LIST_ITEM_TV(type_item);
- if (type_tv->v_type != VAR_NUMBER
- || type_tv->vval.v_number != VAR_TYPE_BLOB) {
- emsgf(_(READERR("variable", "has wrong variable type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- is_blob = true;
- }
- }
- if (is_blob) {
- const msgpack_object_bin *const bin
- = &unpacked.data.via.array.ptr[1].via.bin;
- blob_T *const blob = tv_blob_alloc();
- ga_concat_len(&blob->bv_ga, bin->ptr, (size_t)bin->size);
- tv_blob_set_ret(&entry->data.global_var.value, blob);
- } else if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
- &(entry->data.global_var.value)) == FAIL) {
- emsgf(_(READERR("variable", "has value that cannot "
- "be converted to the VimL value")), initial_fpos);
- goto shada_read_next_item_error;
- }
- break;
+ if (is_blob) {
+ const msgpack_object_bin *const bin
+ = &unpacked.data.via.array.ptr[1].via.bin;
+ blob_T *const blob = tv_blob_alloc();
+ ga_concat_len(&blob->bv_ga, bin->ptr, (size_t)bin->size);
+ tv_blob_set_ret(&entry->data.global_var.value, blob);
+ } else if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
+ &(entry->data.global_var.value)) == FAIL) {
+ emsgf(_(READERR("variable", "has value that cannot "
+ "be converted to the VimL value")), initial_fpos);
+ goto shada_read_next_item_error;
}
- case kSDItemSubString: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("sub string", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 1) {
- emsgf(_(READERR("sub string", "does not have enough elements")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("sub string", "has wrong sub string type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.sub_string.sub =
- BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin);
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1,
- entry->data.sub_string.additional_elements,
- "sub string");
+ break;
+ }
+ case kSDItemSubString:
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("sub string", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size < 1) {
+ emsgf(_(READERR("sub string", "does not have enough elements")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("sub string", "has wrong sub string type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.sub_string.sub =
+ BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin);
+ SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1,
+ entry->data.sub_string.additional_elements,
+ "sub string");
+ break;
+ case kSDItemBufferList:
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("buffer list", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size == 0) {
break;
}
- case kSDItemBufferList: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("buffer list", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size == 0) {
- break;
- }
- entry->data.buffer_list.buffers =
- xcalloc(unpacked.data.via.array.size,
- sizeof(*entry->data.buffer_list.buffers));
- for (size_t i = 0; i < unpacked.data.via.array.size; i++) {
- entry->data.buffer_list.size++;
- msgpack_unpacked unpacked_2 = (msgpack_unpacked) {
- .data = unpacked.data.via.array.ptr[i],
- };
+ entry->data.buffer_list.buffers =
+ xcalloc(unpacked.data.via.array.size,
+ sizeof(*entry->data.buffer_list.buffers));
+ for (size_t i = 0; i < unpacked.data.via.array.size; i++) {
+ entry->data.buffer_list.size++;
+ msgpack_unpacked unpacked_2 = (msgpack_unpacked) {
+ .data = unpacked.data.via.array.ptr[i],
+ };
+ {
+ if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry that is not a dictionary"),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.buffer_list.buffers[i].pos = default_pos;
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1);
{
- if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry that is not a dictionary"),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.buffer_list.buffers[i].pos = default_pos;
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1);
+ // XXX: Temporarily reassign `i` because the macros depend on it.
+ const size_t j = i;
{
- // XXX: Temporarily reassign `i` because the macros depend on it.
- const size_t j = i;
- {
- for (i = 0; i < unpacked_2.data.via.map.size; i++) { // -V535
- CHECK_KEY_IS_STR(unpacked_2, "buffer list entry")
- LONG_KEY(unpacked_2, "buffer list entry", KEY_LNUM,
- entry->data.buffer_list.buffers[j].pos.lnum)
- INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL,
- entry->data.buffer_list.buffers[j].pos.col)
- STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE,
- entry->data.buffer_list.buffers[j].fname)
- ADDITIONAL_KEY(unpacked_2)
- }
+ for (i = 0; i < unpacked_2.data.via.map.size; i++) { // -V535
+ CHECK_KEY_IS_STR(unpacked_2, "buffer list entry")
+ LONG_KEY(unpacked_2, "buffer list entry", KEY_LNUM,
+ entry->data.buffer_list.buffers[j].pos.lnum)
+ INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL,
+ entry->data.buffer_list.buffers[j].pos.col)
+ STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE,
+ entry->data.buffer_list.buffers[j].fname)
+ ADDITIONAL_KEY(unpacked_2)
}
- i = j; // XXX: Restore `i`.
}
- if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry with invalid line number"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.buffer_list.buffers[i].pos.col < 0) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry with invalid column number"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.buffer_list.buffers[i].fname == NULL) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry that does not have a file name"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(
- entry->data.buffer_list.buffers[i].additional_data,
- "buffer list entry");
+ i = j; // XXX: Restore `i`.
+ }
+ if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry with invalid line number"),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (entry->data.buffer_list.buffers[i].pos.col < 0) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry with invalid column number"),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
+ if (entry->data.buffer_list.buffers[i].fname == NULL) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry that does not have a file name"),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.buffer_list.buffers[i].additional_data,
+ "buffer list entry");
}
- break;
- }
- case kSDItemMissing:
- case kSDItemUnknown: {
- abort();
}
+ break;
+ case kSDItemMissing:
+ case kSDItemUnknown:
+ abort();
}
- entry->type = (ShadaEntryType) type_u64;
+ entry->type = (ShadaEntryType)type_u64;
ret = kSDReadStatusSuccess;
shada_read_next_item_end:
if (buf != NULL) {
@@ -4086,7 +3976,7 @@ shada_read_next_item_end:
}
return ret;
shada_read_next_item_error:
- entry->type = (ShadaEntryType) type_u64;
+ entry->type = (ShadaEntryType)type_u64;
shada_free_shada_entry(entry);
entry->type = kSDItemMissing;
goto shada_read_next_item_end;
@@ -4121,13 +4011,13 @@ shada_read_next_item_error:
static bool shada_removable(const char *name)
FUNC_ATTR_WARN_UNUSED_RESULT
{
- char *p;
+ char *p;
char part[MAXPATHL + 1];
bool retval = false;
char *new_name = home_replace_save(NULL, name);
- for (p = (char *) p_shada; *p; ) {
- (void) copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
+ for (p = (char *)p_shada; *p; ) {
+ (void)copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
if (part[0] == 'r') {
home_replace(NULL, part + 1, NameBuff, MAXPATHL, true);
size_t n = STRLEN(NameBuff);
@@ -4148,8 +4038,8 @@ static bool shada_removable(const char *name)
/// location.
///
/// @return number of jumplist entries
-static inline size_t shada_init_jumps(
- PossiblyFreedShadaEntry *jumps, khash_t(bufset) *const removable_bufs)
+static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps,
+ khash_t(bufset) *const removable_bufs)
{
if (!curwin->w_jumplistlen) {
return 0;
@@ -4176,9 +4066,9 @@ static inline size_t shada_init_jumps(
: fm.fmark.fnum != 0) {
continue;
}
- const char *const fname = (char *) (fm.fmark.fnum == 0
+ const char *const fname = (char *)(fm.fmark.fnum == 0
? (fm.fname == NULL ? NULL : fm.fname)
- : buf ? buf->b_ffname : NULL);
+ : buf ? buf->b_ffname : NULL);
if (fname == NULL) {
continue;
}
@@ -4191,7 +4081,7 @@ static inline size_t shada_init_jumps(
.filemark = {
.name = NUL,
.mark = fm.fmark.mark,
- .fname = (char *) fname,
+ .fname = (char *)fname,
.additional_data = fm.fmark.additional_data,
}
}
@@ -4272,9 +4162,8 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf)
do {
typval_T vartv;
const char *name = NULL;
- var_iter = var_shada_iter(
- var_iter, &name, &vartv,
- VAR_FLAVOUR_DEFAULT | VAR_FLAVOUR_SESSION | VAR_FLAVOUR_SHADA);
+ var_iter = var_shada_iter(var_iter, &name, &vartv,
+ VAR_FLAVOUR_DEFAULT | VAR_FLAVOUR_SESSION | VAR_FLAVOUR_SHADA);
if (name == NULL) {
break;
}
@@ -4304,8 +4193,7 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf)
/// Wrapper for reading from msgpack_sbuffer.
///
/// @return number of bytes read.
-static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest,
- const size_t size)
+static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
@@ -4327,8 +4215,7 @@ static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest,
///
/// @return FAIL in case of failure, OK in case of success. May set
/// sd_reader->eof.
-static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader,
- const size_t offset)
+static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
@@ -4346,8 +4233,7 @@ static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader,
///
/// @param[in] sbuf msgpack_sbuffer to read from.
/// @param[out] sd_reader Location where reader structure will be saved.
-static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf,
- ShaDaReadDef *sd_reader)
+static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, ShaDaReadDef *sd_reader)
FUNC_ATTR_NONNULL_ALL
{
*sd_reader = (ShaDaReadDef) {
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index c6f59b42b8..25427de6bf 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -6,33 +6,33 @@
//
-#include "nvim/vim.h"
-#include "nvim/sign.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
-#include "nvim/ex_docmd.h"
#include "nvim/edit.h"
+#include "nvim/ex_docmd.h"
#include "nvim/fold.h"
#include "nvim/move.h"
+#include "nvim/option.h"
#include "nvim/screen.h"
+#include "nvim/sign.h"
#include "nvim/syntax.h"
-#include "nvim/option.h"
+#include "nvim/vim.h"
/// Struct to hold the sign properties.
typedef struct sign sign_T;
struct sign
{
- sign_T *sn_next; // next sign in list
- int sn_typenr; // type number of sign
- char_u *sn_name; // name of sign
- char_u *sn_icon; // name of pixmap
- char_u *sn_text; // text used instead of pixmap
- int sn_line_hl; // highlight ID for line
- int sn_text_hl; // highlight ID for text
- int sn_num_hl; // highlight ID for line number
+ sign_T *sn_next; // next sign in list
+ int sn_typenr; // type number of sign
+ char_u *sn_name; // name of sign
+ char_u *sn_icon; // name of pixmap
+ char_u *sn_text; // text used instead of pixmap
+ int sn_line_hl; // highlight ID for line
+ int sn_text_hl; // highlight ID for text
+ int sn_num_hl; // highlight ID for line number
};
static sign_T *first_sign = NULL;
@@ -42,19 +42,19 @@ static void sign_list_defined(sign_T *sp);
static void sign_undefine(sign_T *sp, sign_T *sp_prev);
static char *cmds[] = {
- "define",
+ "define",
#define SIGNCMD_DEFINE 0
- "undefine",
+ "undefine",
#define SIGNCMD_UNDEFINE 1
- "list",
+ "list",
#define SIGNCMD_LIST 2
- "place",
+ "place",
#define SIGNCMD_PLACE 3
- "unplace",
+ "unplace",
#define SIGNCMD_UNPLACE 4
- "jump",
+ "jump",
#define SIGNCMD_JUMP 5
- NULL
+ NULL
#define SIGNCMD_LAST 6
};
@@ -65,17 +65,17 @@ static int next_sign_id = 1; // next sign id in the global group
/// Initialize data needed for managing signs
void init_signs(void)
{
- hash_init(&sg_table); // sign group hash table
+ hash_init(&sg_table); // sign group hash table
}
/// A new sign in group 'groupname' is added. If the group is not present,
/// create it. Otherwise reference the group.
///
-static signgroup_T * sign_group_ref(const char_u *groupname)
+static signgroup_T *sign_group_ref(const char_u *groupname)
{
- hash_T hash;
- hashitem_T *hi;
- signgroup_T *group;
+ hash_T hash;
+ hashitem_T *hi;
+ signgroup_T *group;
hash = hash_hash(groupname);
hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash);
@@ -100,7 +100,7 @@ static signgroup_T * sign_group_ref(const char_u *groupname)
/// removed, then remove the group.
static void sign_group_unref(char_u *groupname)
{
- hashitem_T *hi;
+ hashitem_T *hi;
signgroup_T *group;
hi = hash_find(&sg_table, groupname);
@@ -120,10 +120,10 @@ static void sign_group_unref(char_u *groupname)
/// or in a named group. If 'group' is '*', then the sign is part of the group.
bool sign_in_group(sign_entry_T *sign, const char_u *group)
{
- return ((group != NULL && STRCMP(group, "*") == 0)
- || (group == NULL && sign->se_group == NULL)
- || (group != NULL && sign->se_group != NULL
- && STRCMP(group, sign->se_group->sg_name) == 0));
+ return ((group != NULL && STRCMP(group, "*") == 0)
+ || (group == NULL && sign->se_group == NULL)
+ || (group != NULL && sign->se_group != NULL
+ && STRCMP(group, sign->se_group->sg_name) == 0));
}
/// Get the next free sign identifier in the specified group
@@ -166,17 +166,19 @@ int sign_group_get_next_signid(buf_T *buf, const char_u *groupname)
/// Insert a new sign into the signlist for buffer 'buf' between the 'prev' and
/// 'next' signs.
-static void insert_sign(
- buf_T *buf, // buffer to store sign in
- sign_entry_T *prev, // previous sign entry
- sign_entry_T *next, // next sign entry
- int id, // sign ID
- const char_u *group, // sign group; NULL for global group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr, // typenr of sign we are adding
- bool has_text_or_icon // sign has text or icon
-)
+///
+/// @param buf buffer to store sign in
+/// @param prev previous sign entry
+/// @param next next sign entry
+/// @param id sign ID
+/// @param group sign group; NULL for global group
+/// @param prio sign priority
+/// @param lnum line number which gets the mark
+/// @param typenr typenr of sign we are adding
+/// @param has_text_or_icon sign has text or icon
+static void insert_sign(buf_T *buf, sign_entry_T *prev, sign_entry_T *next, int id,
+ const char_u *group, int prio, linenr_T lnum, int typenr,
+ bool has_text_or_icon)
{
sign_entry_T *newsign = xmalloc(sizeof(sign_entry_T));
newsign->se_id = id;
@@ -212,18 +214,19 @@ static void insert_sign(
}
/// Insert a new sign sorted by line number and sign priority.
-static void insert_sign_by_lnum_prio(
- buf_T *buf, // buffer to store sign in
- sign_entry_T *prev, // previous sign entry
- int id, // sign ID
- const char_u *group, // sign group; NULL for global group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr, // typenr of sign we are adding
- bool has_text_or_icon // sign has text or icon
-)
+///
+/// @param buf buffer to store sign in
+/// @param prev previous sign entry
+/// @param id sign ID
+/// @param group sign group; NULL for global group
+/// @param prio sign priority
+/// @param lnum line number which gets the mark
+/// @param typenr typenr of sign we are adding
+/// @param has_text_or_icon sign has text or icon
+static void insert_sign_by_lnum_prio(buf_T *buf, sign_entry_T *prev, int id, const char_u *group,
+ int prio, linenr_T lnum, int typenr, bool has_text_or_icon)
{
- sign_entry_T *sign;
+ sign_entry_T *sign;
// keep signs sorted by lnum, priority and id: insert new sign at
// the proper position in the list for this lnum.
@@ -242,9 +245,9 @@ static void insert_sign_by_lnum_prio(
}
/// Get the name of a sign by its typenr.
-char_u * sign_typenr2name(int typenr)
+char_u *sign_typenr2name(int typenr)
{
- sign_T *sp;
+ sign_T *sp;
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (sp->sn_typenr == typenr) {
@@ -255,9 +258,9 @@ char_u * sign_typenr2name(int typenr)
}
/// Return information about a sign in a Dict
-dict_T * sign_get_info(sign_entry_T *sign)
+dict_T *sign_get_info(sign_entry_T *sign)
{
- dict_T *d = tv_dict_alloc();
+ dict_T *d = tv_dict_alloc();
tv_dict_add_nr(d, S_LEN("id"), sign->se_id);
tv_dict_add_str(d, S_LEN("group"), ((sign->se_group == NULL)
? (char *)""
@@ -345,15 +348,16 @@ static void sign_sort_by_prio_on_line(buf_T *buf, sign_entry_T *sign)
/// Add the sign into the signlist. Find the right spot to do it though.
-void buf_addsign(
- buf_T *buf, // buffer to store sign in
- int id, // sign ID
- const char_u *groupname, // sign group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr, // typenr of sign we are adding
- bool has_text_or_icon // sign has text or icon
-)
+///
+/// @param buf buffer to store sign in
+/// @param id sign ID
+/// @param groupname sign group
+/// @param prio sign priority
+/// @param lnum line number which gets the mark
+/// @param typenr typenr of sign we are adding
+/// @param has_text_or_icon sign has text or icon
+void buf_addsign(buf_T *buf, int id, const char_u *groupname, int prio, linenr_T lnum, int typenr,
+ bool has_text_or_icon)
{
sign_entry_T *sign; // a sign in the signlist
sign_entry_T *prev; // the previous sign
@@ -368,53 +372,51 @@ void buf_addsign(
sign_sort_by_prio_on_line(buf, sign);
return;
} else if (lnum < sign->se_lnum) {
- insert_sign_by_lnum_prio(
- buf,
- prev,
- id,
- groupname,
- prio,
- lnum,
- typenr,
- has_text_or_icon);
+ insert_sign_by_lnum_prio(buf,
+ prev,
+ id,
+ groupname,
+ prio,
+ lnum,
+ typenr,
+ has_text_or_icon);
return;
}
prev = sign;
}
- insert_sign_by_lnum_prio(
- buf,
- prev,
- id,
- groupname,
- prio,
- lnum,
- typenr,
- has_text_or_icon);
+ insert_sign_by_lnum_prio(buf,
+ prev,
+ id,
+ groupname,
+ prio,
+ lnum,
+ typenr,
+ has_text_or_icon);
}
-// For an existing, placed sign "markId" change the type to "typenr".
-// Returns the line number of the sign, or zero if the sign is not found.
-linenr_T buf_change_sign_type(
- buf_T *buf, // buffer to store sign in
- int markId, // sign ID
- const char_u *group, // sign group
- int typenr, // typenr of sign we are adding
- int prio // sign priority
-)
+/// For an existing, placed sign "markId" change the type to "typenr".
+/// Returns the line number of the sign, or zero if the sign is not found.
+///
+/// @param buf buffer to store sign in
+/// @param markId sign ID
+/// @param group sign group
+/// @param typenr typenr of sign we are adding
+/// @param prio sign priority
+linenr_T buf_change_sign_type(buf_T *buf, int markId, const char_u *group, int typenr, int prio)
{
- sign_entry_T *sign; // a sign in the signlist
+ sign_entry_T *sign; // a sign in the signlist
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_id == markId && sign_in_group(sign, group)) {
- sign->se_typenr = typenr;
- sign->se_priority = prio;
- sign_sort_by_prio_on_line(buf, sign);
- return sign->se_lnum;
- }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_id == markId && sign_in_group(sign, group)) {
+ sign->se_typenr = typenr;
+ sign->se_priority = prio;
+ sign_sort_by_prio_on_line(buf, sign);
+ return sign->se_lnum;
}
+ }
- return (linenr_T)0;
+ return (linenr_T)0;
}
/// Return the sign attrs which has the attribute specified by 'type'. Returns
@@ -426,44 +428,43 @@ linenr_T buf_change_sign_type(
/// @param max_signs the number of signs, with priority for the ones
/// with the highest Ids.
/// @return Attrs of the matching sign, or NULL
-sign_attrs_T * sign_get_attr(SignType type, sign_attrs_T sattrs[],
- int idx, int max_signs)
+sign_attrs_T *sign_get_attr(SignType type, sign_attrs_T sattrs[], int idx, int max_signs)
{
- sign_attrs_T *matches[SIGN_SHOW_MAX];
- int nr_matches = 0;
-
- for (int i = 0; i < SIGN_SHOW_MAX; i++) {
- if ( (type == SIGN_TEXT && sattrs[i].sat_text != NULL)
- || (type == SIGN_LINEHL && sattrs[i].sat_linehl != 0)
- || (type == SIGN_NUMHL && sattrs[i].sat_numhl != 0)) {
- matches[nr_matches] = &sattrs[i];
- nr_matches++;
- // attr list is sorted with most important (priority, id), thus we
- // may stop as soon as we have max_signs matches
- if (nr_matches >= max_signs) {
- break;
- }
- }
+ sign_attrs_T *matches[SIGN_SHOW_MAX];
+ int nr_matches = 0;
+
+ for (int i = 0; i < SIGN_SHOW_MAX; i++) {
+ if ( (type == SIGN_TEXT && sattrs[i].sat_text != NULL)
+ || (type == SIGN_LINEHL && sattrs[i].sat_linehl != 0)
+ || (type == SIGN_NUMHL && sattrs[i].sat_numhl != 0)) {
+ matches[nr_matches] = &sattrs[i];
+ nr_matches++;
+ // attr list is sorted with most important (priority, id), thus we
+ // may stop as soon as we have max_signs matches
+ if (nr_matches >= max_signs) {
+ break;
+ }
}
+ }
- if (nr_matches > idx) {
- return matches[nr_matches - idx - 1];
- }
+ if (nr_matches > idx) {
+ return matches[nr_matches - idx - 1];
+ }
- return NULL;
+ return NULL;
}
/// Lookup a sign by typenr. Returns NULL if sign is not found.
-static sign_T * find_sign_by_typenr(int typenr)
+static sign_T *find_sign_by_typenr(int typenr)
{
- sign_T *sp;
+ sign_T *sp;
- for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
- if (sp->sn_typenr == typenr) {
- return sp;
- }
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
+ if (sp->sn_typenr == typenr) {
+ return sp;
}
- return NULL;
+ }
+ return NULL;
}
/// Return the attributes of all the signs placed on line 'lnum' in buffer
@@ -474,44 +475,44 @@ static sign_T * find_sign_by_typenr(int typenr)
/// @return Number of signs of which attrs were found
int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
{
- sign_entry_T *sign;
- sign_T *sp;
+ sign_entry_T *sign;
+ sign_T *sp;
- int nr_matches = 0;
+ int nr_matches = 0;
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_lnum > lnum) {
- // Signs are sorted by line number in the buffer. No need to check
- // for signs after the specified line number 'lnum'.
- break;
- }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_lnum > lnum) {
+ // Signs are sorted by line number in the buffer. No need to check
+ // for signs after the specified line number 'lnum'.
+ break;
+ }
- if (sign->se_lnum == lnum) {
- sign_attrs_T sattr;
- memset(&sattr, 0, sizeof(sattr));
- sattr.sat_typenr = sign->se_typenr;
- sp = find_sign_by_typenr(sign->se_typenr);
- if (sp != NULL) {
- sattr.sat_text = sp->sn_text;
- if (sattr.sat_text != NULL && sp->sn_text_hl != 0) {
- sattr.sat_texthl = syn_id2attr(sp->sn_text_hl);
- }
- if (sp->sn_line_hl != 0) {
- sattr.sat_linehl = syn_id2attr(sp->sn_line_hl);
- }
- if (sp->sn_num_hl != 0) {
- sattr.sat_numhl = syn_id2attr(sp->sn_num_hl);
- }
- }
-
- sattrs[nr_matches] = sattr;
- nr_matches++;
- if (nr_matches == SIGN_SHOW_MAX) {
- break;
- }
+ if (sign->se_lnum == lnum) {
+ sign_attrs_T sattr;
+ memset(&sattr, 0, sizeof(sattr));
+ sattr.sat_typenr = sign->se_typenr;
+ sp = find_sign_by_typenr(sign->se_typenr);
+ if (sp != NULL) {
+ sattr.sat_text = sp->sn_text;
+ if (sattr.sat_text != NULL && sp->sn_text_hl != 0) {
+ sattr.sat_texthl = syn_id2attr(sp->sn_text_hl);
+ }
+ if (sp->sn_line_hl != 0) {
+ sattr.sat_linehl = syn_id2attr(sp->sn_line_hl);
+ }
+ if (sp->sn_num_hl != 0) {
+ sattr.sat_numhl = syn_id2attr(sp->sn_num_hl);
}
+ }
+
+ sattrs[nr_matches] = sattr;
+ nr_matches++;
+ if (nr_matches == SIGN_SHOW_MAX) {
+ break;
+ }
}
- return nr_matches;
+ }
+ return nr_matches;
}
/// Delete sign 'id' in group 'group' from buffer 'buf'.
@@ -520,14 +521,15 @@ int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
/// If 'group' is '*', then delete the sign in all the groups. If 'group' is
/// NULL, then delete the sign in the global group. Otherwise delete the sign in
/// the specified group.
-/// Returns the line number of the deleted sign. If multiple signs are deleted,
+///
+/// @param buf buffer sign is stored in
+/// @param atlnum sign at this line, 0 - at any line
+/// @param id sign id
+/// @param group sign group
+///
+/// @return the line number of the deleted sign. If multiple signs are deleted,
/// then returns the line number of the last sign deleted.
-linenr_T buf_delsign(
- buf_T *buf, // buffer sign is stored in
- linenr_T atlnum, // sign at this line, 0 - at any line
- int id, // sign id
- char_u *group // sign group
-)
+linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group)
{
sign_entry_T **lastp; // pointer to pointer to current sign
sign_entry_T *sign; // a sign in a b_signlist
@@ -580,30 +582,30 @@ linenr_T buf_delsign(
/// Find the line number of the sign with the requested id in group 'group'. If
/// the sign does not exist, return 0 as the line number. This will still let
/// the correct file get loaded.
-int buf_findsign(
- buf_T *buf, // buffer to store sign in
- int id, // sign ID
- char_u *group // sign group
-)
+///
+/// @param buf buffer to store sign in
+/// @param id sign ID
+/// @param group sign group
+int buf_findsign(buf_T *buf, int id, char_u *group)
{
- sign_entry_T *sign; // a sign in the signlist
+ sign_entry_T *sign; // a sign in the signlist
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_id == id && sign_in_group(sign, group)) {
- return (int)sign->se_lnum;
- }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_id == id && sign_in_group(sign, group)) {
+ return (int)sign->se_lnum;
}
+ }
- return 0;
+ return 0;
}
/// Return the sign at line 'lnum' in buffer 'buf'. Returns NULL if a sign is
/// not found at the line. If 'groupname' is NULL, searches in the global group.
-static sign_entry_T * buf_getsign_at_line(
- buf_T *buf, // buffer whose sign we are searching for
- linenr_T lnum, // line number of sign
- char_u *groupname // sign group name
-)
+///
+/// @param buf buffer whose sign we are searching for
+/// @param lnum line number of sign
+/// @param groupname sign group name
+static sign_entry_T *buf_getsign_at_line(buf_T *buf, linenr_T lnum, char_u *groupname)
{
sign_entry_T *sign; // a sign in the signlist
@@ -623,61 +625,61 @@ static sign_entry_T * buf_getsign_at_line(
}
/// Return the identifier of the sign at line number 'lnum' in buffer 'buf'.
-int buf_findsign_id(
- buf_T *buf, // buffer whose sign we are searching for
- linenr_T lnum, // line number of sign
- char_u *groupname // sign group name
-)
+///
+/// @param buf buffer whose sign we are searching for
+/// @param lnum line number of sign
+/// @param groupname sign group name
+int buf_findsign_id(buf_T *buf, linenr_T lnum, char_u *groupname)
{
- sign_entry_T *sign; // a sign in the signlist
+ sign_entry_T *sign; // a sign in the signlist
- sign = buf_getsign_at_line(buf, lnum, groupname);
- if (sign != NULL) {
- return sign->se_id;
- }
+ sign = buf_getsign_at_line(buf, lnum, groupname);
+ if (sign != NULL) {
+ return sign->se_id;
+ }
- return 0;
+ return 0;
}
/// Delete signs in buffer "buf".
void buf_delete_signs(buf_T *buf, char_u *group)
{
- sign_entry_T *sign;
- sign_entry_T **lastp; // pointer to pointer to current sign
- sign_entry_T *next;
+ sign_entry_T *sign;
+ sign_entry_T **lastp; // pointer to pointer to current sign
+ sign_entry_T *next;
- // When deleting the last sign need to redraw the windows to remove the
- // sign column. Not when curwin is NULL (this means we're exiting).
- if (buf->b_signlist != NULL && curwin != NULL) {
- changed_line_abv_curs();
- }
+ // When deleting the last sign need to redraw the windows to remove the
+ // sign column. Not when curwin is NULL (this means we're exiting).
+ if (buf->b_signlist != NULL && curwin != NULL) {
+ changed_line_abv_curs();
+ }
- lastp = &buf->b_signlist;
- for (sign = buf->b_signlist; sign != NULL; sign = next) {
- next = sign->se_next;
- if (sign_in_group(sign, group)) {
- *lastp = next;
- if (next != NULL) {
- next->se_prev = sign->se_prev;
- }
- if (sign->se_group != NULL) {
- sign_group_unref(sign->se_group->sg_name);
- }
- xfree(sign);
- } else {
- lastp = &sign->se_next;
+ lastp = &buf->b_signlist;
+ for (sign = buf->b_signlist; sign != NULL; sign = next) {
+ next = sign->se_next;
+ if (sign_in_group(sign, group)) {
+ *lastp = next;
+ if (next != NULL) {
+ next->se_prev = sign->se_prev;
+ }
+ if (sign->se_group != NULL) {
+ sign_group_unref(sign->se_group->sg_name);
}
+ xfree(sign);
+ } else {
+ lastp = &sign->se_next;
}
- buf->b_signcols_valid = false;
+ }
+ buf->b_signcols_valid = false;
}
/// List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
void sign_list_placed(buf_T *rbuf, char_u *sign_group)
{
buf_T *buf;
- sign_entry_T *sign;
- char lbuf[MSG_BUF_LEN];
- char group[MSG_BUF_LEN];
+ sign_entry_T *sign;
+ char lbuf[MSG_BUF_LEN];
+ char group[MSG_BUF_LEN];
MSG_PUTS_TITLE(_("\n--- Signs ---"));
msg_putchar('\n');
@@ -720,12 +722,7 @@ void sign_list_placed(buf_T *rbuf, char_u *sign_group)
}
/// Adjust a placed sign for inserted/deleted lines.
-void sign_mark_adjust(
- linenr_T line1,
- linenr_T line2,
- long amount,
- long amount_after
-)
+void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
{
sign_entry_T *sign; // a sign in a b_signlist
sign_entry_T *next; // the next sign in a b_signlist
@@ -769,26 +766,26 @@ void sign_mark_adjust(
/// Find index of a ":sign" subcmd from its name.
/// "*end_cmd" must be writable.
-static int sign_cmd_idx(
- char_u *begin_cmd, // begin of sign subcmd
- char_u *end_cmd // just after sign subcmd
-)
+///
+/// @param begin_cmd begin of sign subcmd
+/// @param end_cmd just after sign subcmd
+static int sign_cmd_idx(char_u *begin_cmd, char_u *end_cmd)
{
- int idx;
- char_u save = *end_cmd;
+ int idx;
+ char_u save = *end_cmd;
- *end_cmd = (char_u)NUL;
- for (idx = 0; ; idx++) {
- if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) {
- break;
- }
+ *end_cmd = (char_u)NUL;
+ for (idx = 0; ; idx++) {
+ if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) {
+ break;
}
- *end_cmd = save;
- return idx;
+ }
+ *end_cmd = save;
+ return idx;
}
/// Find a sign by name. Also returns pointer to the previous sign.
-static sign_T * sign_find(const char_u *name, sign_T **sp_prev)
+static sign_T *sign_find(const char_u *name, sign_T **sp_prev)
{
sign_T *sp;
@@ -808,10 +805,10 @@ static sign_T * sign_find(const char_u *name, sign_T **sp_prev)
}
/// Allocate a new sign
-static sign_T * alloc_new_sign(char_u *name)
+static sign_T *alloc_new_sign(char_u *name)
{
- sign_T *sp;
- sign_T *lp;
+ sign_T *sp;
+ sign_T *lp;
int start = next_sign_typenr;
// Allocate a new sign.
@@ -858,8 +855,8 @@ static void sign_define_init_icon(sign_T *sp, char_u *icon)
/// Initialize the text for a new sign
static int sign_define_init_text(sign_T *sp, char_u *text)
{
- char_u *s;
- char_u *endp;
+ char_u *s;
+ char_u *endp;
int cells;
size_t len;
@@ -904,17 +901,11 @@ static int sign_define_init_text(sign_T *sp, char_u *text)
}
/// Define a new sign or update an existing sign
-int sign_define_by_name(
- char_u *name,
- char_u *icon,
- char_u *linehl,
- char_u *text,
- char_u *texthl,
- char_u *numhl
-)
+int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl,
+ char_u *numhl)
{
- sign_T *sp_prev;
- sign_T *sp;
+ sign_T *sp_prev;
+ sign_T *sp;
sp = sign_find(name, &sp_prev);
if (sp == NULL) {
@@ -966,8 +957,8 @@ int sign_define_by_name(
/// Free the sign specified by 'name'.
int sign_undefine_by_name(const char_u *name)
{
- sign_T *sp_prev;
- sign_T *sp;
+ sign_T *sp_prev;
+ sign_T *sp;
sp = sign_find(name, &sp_prev);
if (sp == NULL) {
@@ -982,18 +973,18 @@ int sign_undefine_by_name(const char_u *name)
static void may_force_numberwidth_recompute(buf_T *buf, int unplace)
{
FOR_ALL_TAB_WINDOWS(tp, wp)
- if (wp->w_buffer == buf
- && (wp->w_p_nu || wp->w_p_rnu)
- && (unplace || wp->w_nrwidth_width < 2)
- && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
- wp->w_nrwidth_line_count = 0;
- }
+ if (wp->w_buffer == buf
+ && (wp->w_p_nu || wp->w_p_rnu)
+ && (unplace || wp->w_nrwidth_width < 2)
+ && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
+ wp->w_nrwidth_line_count = 0;
+ }
}
/// List the signs matching 'name'
static void sign_list_by_name(char_u *name)
{
- sign_T *sp;
+ sign_T *sp;
sp = sign_find(name, NULL);
if (sp != NULL) {
@@ -1005,14 +996,8 @@ static void sign_list_by_name(char_u *name)
/// Place a sign at the specified file location or update a sign.
-int sign_place(
- int *sign_id,
- const char_u *sign_group,
- const char_u *sign_name,
- buf_T *buf,
- linenr_T lnum,
- int prio
-)
+int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign_name, buf_T *buf,
+ linenr_T lnum, int prio)
{
sign_T *sp;
@@ -1038,14 +1023,13 @@ int sign_place(
// ":sign place {id} line={lnum} name={name} file={fname}":
// place a sign
bool has_text_or_icon = sp->sn_text != NULL || sp->sn_icon != NULL;
- buf_addsign(
- buf,
- *sign_id,
- sign_group,
- prio,
- lnum,
- sp->sn_typenr,
- has_text_or_icon);
+ buf_addsign(buf,
+ *sign_id,
+ sign_group,
+ prio,
+ lnum,
+ sp->sn_typenr,
+ has_text_or_icon);
} else {
// ":sign place {id} file={fname}": change sign type and/or priority
lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr, prio);
@@ -1075,7 +1059,7 @@ int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
redraw_buf_later(buf, NOT_VALID);
buf_delete_signs(buf, sign_group);
} else {
- linenr_T lnum;
+ linenr_T lnum;
// Delete only the specified signs
lnum = buf_delsign(buf, atlnum, sign_id, sign_group);
@@ -1098,7 +1082,7 @@ int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
/// Unplace the sign at the current cursor line.
static void sign_unplace_at_cursor(char_u *groupname)
{
- int id = -1;
+ int id = -1;
id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum, groupname);
if (id > 0) {
@@ -1144,13 +1128,13 @@ linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf)
/// ":sign define {name} ..." command
static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
{
- char_u *arg;
- char_u *p = cmdline;
- char_u *icon = NULL;
- char_u *text = NULL;
- char_u *linehl = NULL;
- char_u *texthl = NULL;
- char_u *numhl = NULL;
+ char_u *arg;
+ char_u *p = cmdline;
+ char_u *icon = NULL;
+ char_u *text = NULL;
+ char_u *linehl = NULL;
+ char_u *texthl = NULL;
+ char_u *numhl = NULL;
int failed = false;
// set values for a defined sign.
@@ -1194,14 +1178,8 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
}
/// ":sign place" command
-static void sign_place_cmd(
- buf_T *buf,
- linenr_T lnum,
- char_u *sign_name,
- int id,
- char_u *group,
- int prio
-)
+static void sign_place_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group,
+ int prio)
{
if (id <= 0) {
// List signs placed in a file/buffer
@@ -1233,62 +1211,56 @@ static void sign_place_cmd(
}
/// ":sign unplace" command
-static void sign_unplace_cmd(
- buf_T *buf,
- linenr_T lnum,
- char_u *sign_name,
- int id,
- char_u *group
-)
+static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group)
{
- if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0')) {
- EMSG(_(e_invarg));
- return;
- }
+ if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0')) {
+ EMSG(_(e_invarg));
+ return;
+ }
- if (id == -2) {
- if (buf != NULL) {
- // :sign unplace * file={fname}
- // :sign unplace * group={group} file={fname}
- // :sign unplace * group=* file={fname}
- // :sign unplace * buffer={nr}
- // :sign unplace * group={group} buffer={nr}
- // :sign unplace * group=* buffer={nr}
- sign_unplace(0, group, buf, 0);
- } else {
- // :sign unplace *
- // :sign unplace * group={group}
- // :sign unplace * group=*
- FOR_ALL_BUFFERS(cbuf) {
- if (cbuf->b_signlist != NULL) {
- buf_delete_signs(cbuf, group);
- }
+ if (id == -2) {
+ if (buf != NULL) {
+ // :sign unplace * file={fname}
+ // :sign unplace * group={group} file={fname}
+ // :sign unplace * group=* file={fname}
+ // :sign unplace * buffer={nr}
+ // :sign unplace * group={group} buffer={nr}
+ // :sign unplace * group=* buffer={nr}
+ sign_unplace(0, group, buf, 0);
+ } else {
+ // :sign unplace *
+ // :sign unplace * group={group}
+ // :sign unplace * group=*
+ FOR_ALL_BUFFERS(cbuf) {
+ if (cbuf->b_signlist != NULL) {
+ buf_delete_signs(cbuf, group);
}
}
+ }
+ } else {
+ if (buf != NULL) {
+ // :sign unplace {id} file={fname}
+ // :sign unplace {id} group={group} file={fname}
+ // :sign unplace {id} group=* file={fname}
+ // :sign unplace {id} buffer={nr}
+ // :sign unplace {id} group={group} buffer={nr}
+ // :sign unplace {id} group=* buffer={nr}
+ sign_unplace(id, group, buf, 0);
} else {
- if (buf != NULL) {
- // :sign unplace {id} file={fname}
- // :sign unplace {id} group={group} file={fname}
- // :sign unplace {id} group=* file={fname}
- // :sign unplace {id} buffer={nr}
- // :sign unplace {id} group={group} buffer={nr}
- // :sign unplace {id} group=* buffer={nr}
- sign_unplace(id, group, buf, 0);
+ if (id == -1) {
+ // :sign unplace group={group}
+ // :sign unplace group=*
+ sign_unplace_at_cursor(group);
} else {
- if (id == -1) {
- // :sign unplace group={group}
- // :sign unplace group=*
- sign_unplace_at_cursor(group);
- } else {
- // :sign unplace {id}
- // :sign unplace {id} group={group}
- // :sign unplace {id} group=*
- FOR_ALL_BUFFERS(cbuf) {
- sign_unplace(id, group, cbuf, 0);
- }
+ // :sign unplace {id}
+ // :sign unplace {id} group={group}
+ // :sign unplace {id} group=*
+ FOR_ALL_BUFFERS(cbuf) {
+ sign_unplace(id, group, cbuf, 0);
}
}
}
+ }
}
/// Jump to a placed sign commands:
@@ -1296,13 +1268,7 @@ static void sign_unplace_cmd(
/// :sign jump {id} buffer={nr}
/// :sign jump {id} group={group} file={fname}
/// :sign jump {id} group={group} buffer={nr}
-static void sign_jump_cmd(
- buf_T *buf,
- linenr_T lnum,
- char_u *sign_name,
- int id,
- char_u *group
-)
+static void sign_jump_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group)
{
if (sign_name == NULL && group == NULL && id == -1) {
EMSG(_(e_argreq));
@@ -1324,21 +1290,13 @@ static void sign_jump_cmd(
/// ":sign jump" commands.
/// The supported arguments are: line={lnum} name={name} group={group}
/// priority={prio} and file={fname} or buffer={nr}.
-static int parse_sign_cmd_args(
- int cmd,
- char_u *arg,
- char_u **sign_name,
- int *signid,
- char_u **group,
- int *prio,
- buf_T **buf,
- linenr_T *lnum
-)
+static int parse_sign_cmd_args(int cmd, char_u *arg, char_u **sign_name, int *signid,
+ char_u **group, int *prio, buf_T **buf, linenr_T *lnum)
{
- char_u *arg1;
- char_u *name;
- char_u *filename = NULL;
- int lnum_arg = false;
+ char_u *arg1;
+ char_u *name;
+ char_u *filename = NULL;
+ int lnum_arg = false;
// first arg could be placed sign id
arg1 = arg;
@@ -1448,7 +1406,7 @@ void ex_sign(exarg_T *eap)
} else if (*arg == NUL) {
EMSG(_("E156: Missing sign name"));
} else {
- char_u *name;
+ char_u *name;
// Isolate the sign name. If it's a number skip leading zeroes,
// so that "099" and "99" are the same sign. But keep "0".
@@ -1574,12 +1532,8 @@ list_T *get_buffer_signs(buf_T *buf)
}
/// Return information about all the signs placed in a buffer
-static void sign_get_placed_in_buf(
- buf_T *buf,
- linenr_T lnum,
- int sign_id,
- const char_u *sign_group,
- list_T *retlist)
+static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const char_u *sign_group,
+ list_T *retlist)
{
dict_T *d;
list_T *l;
@@ -1609,13 +1563,8 @@ static void sign_get_placed_in_buf(
/// Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the
/// sign placed at the line number. If 'lnum' is zero, return all the signs
/// placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers.
-void sign_get_placed(
- buf_T *buf,
- linenr_T lnum,
- int sign_id,
- const char_u *sign_group,
- list_T *retlist
-)
+void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, const char_u *sign_group,
+ list_T *retlist)
{
if (buf != NULL) {
sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist);
@@ -1697,13 +1646,13 @@ void free_signs(void)
static enum
{
- EXP_SUBCMD, // expand :sign sub-commands
- EXP_DEFINE, // expand :sign define {name} args
- EXP_PLACE, // expand :sign place {id} args
- EXP_LIST, // expand :sign place args
- EXP_UNPLACE, // expand :sign unplace"
- EXP_SIGN_NAMES, // expand with name of placed signs
- EXP_SIGN_GROUPS, // expand with name of placed sign groups
+ EXP_SUBCMD, // expand :sign sub-commands
+ EXP_DEFINE, // expand :sign define {name} args
+ EXP_PLACE, // expand :sign place {id} args
+ EXP_LIST, // expand :sign place args
+ EXP_UNPLACE, // expand :sign unplace"
+ EXP_SIGN_NAMES, // expand with name of placed signs
+ EXP_SIGN_GROUPS, // expand with name of placed sign groups
} expand_what;
// Return the n'th sign name (used for command line completion)
@@ -1740,45 +1689,45 @@ static char_u *get_nth_sign_group_name(int idx)
/// Function given to ExpandGeneric() to obtain the sign command
/// expansion.
-char_u * get_sign_name(expand_T *xp, int idx)
+char_u *get_sign_name(expand_T *xp, int idx)
{
switch (expand_what) {
- case EXP_SUBCMD:
- return (char_u *)cmds[idx];
- case EXP_DEFINE: {
- char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
- NULL };
- return (char_u *)define_arg[idx];
- }
- case EXP_PLACE: {
- char *place_arg[] = { "line=", "name=", "group=", "priority=", "file=",
- "buffer=", NULL };
- return (char_u *)place_arg[idx];
- }
- case EXP_LIST: {
- char *list_arg[] = { "group=", "file=", "buffer=", NULL };
- return (char_u *)list_arg[idx];
- }
- case EXP_UNPLACE: {
- char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
- return (char_u *)unplace_arg[idx];
- }
- case EXP_SIGN_NAMES:
- return get_nth_sign_name(idx);
- case EXP_SIGN_GROUPS:
- return get_nth_sign_group_name(idx);
- default:
- return NULL;
+ case EXP_SUBCMD:
+ return (char_u *)cmds[idx];
+ case EXP_DEFINE: {
+ char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
+ NULL };
+ return (char_u *)define_arg[idx];
+ }
+ case EXP_PLACE: {
+ char *place_arg[] = { "line=", "name=", "group=", "priority=", "file=",
+ "buffer=", NULL };
+ return (char_u *)place_arg[idx];
+ }
+ case EXP_LIST: {
+ char *list_arg[] = { "group=", "file=", "buffer=", NULL };
+ return (char_u *)list_arg[idx];
+ }
+ case EXP_UNPLACE: {
+ char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
+ return (char_u *)unplace_arg[idx];
+ }
+ case EXP_SIGN_NAMES:
+ return get_nth_sign_name(idx);
+ case EXP_SIGN_GROUPS:
+ return get_nth_sign_group_name(idx);
+ default:
+ return NULL;
}
}
/// Handle command line completion for :sign command.
void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
{
- char_u *end_subcmd;
- char_u *last;
- int cmd_idx;
- char_u *begin_subcmd_args;
+ char_u *end_subcmd;
+ char_u *last;
+ int cmd_idx;
+ char_u *begin_subcmd_args;
// Default: expand subcommands.
xp->xp_context = EXPAND_SIGN;
@@ -1822,70 +1771,70 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
// Expand last argument name (before equal sign).
xp->xp_pattern = last;
switch (cmd_idx) {
- case SIGNCMD_DEFINE:
- expand_what = EXP_DEFINE;
- break;
- case SIGNCMD_PLACE:
- // List placed signs
- if (ascii_isdigit(*begin_subcmd_args)) {
- // :sign place {id} {args}...
- expand_what = EXP_PLACE;
- } else {
- // :sign place {args}...
- expand_what = EXP_LIST;
- }
- break;
- case SIGNCMD_LIST:
- case SIGNCMD_UNDEFINE:
- // :sign list <CTRL-D>
- // :sign undefine <CTRL-D>
- expand_what = EXP_SIGN_NAMES;
- break;
- case SIGNCMD_JUMP:
- case SIGNCMD_UNPLACE:
- expand_what = EXP_UNPLACE;
- break;
- default:
- xp->xp_context = EXPAND_NOTHING;
+ case SIGNCMD_DEFINE:
+ expand_what = EXP_DEFINE;
+ break;
+ case SIGNCMD_PLACE:
+ // List placed signs
+ if (ascii_isdigit(*begin_subcmd_args)) {
+ // :sign place {id} {args}...
+ expand_what = EXP_PLACE;
+ } else {
+ // :sign place {args}...
+ expand_what = EXP_LIST;
+ }
+ break;
+ case SIGNCMD_LIST:
+ case SIGNCMD_UNDEFINE:
+ // :sign list <CTRL-D>
+ // :sign undefine <CTRL-D>
+ expand_what = EXP_SIGN_NAMES;
+ break;
+ case SIGNCMD_JUMP:
+ case SIGNCMD_UNPLACE:
+ expand_what = EXP_UNPLACE;
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
}
} else {
- // Expand last argument value (after equal sign).
+ // Expand last argument value (after equal sign).
xp->xp_pattern = p + 1;
switch (cmd_idx) {
- case SIGNCMD_DEFINE:
- if (STRNCMP(last, "texthl", 6) == 0
- || STRNCMP(last, "linehl", 6) == 0
- || STRNCMP(last, "numhl", 5) == 0) {
- xp->xp_context = EXPAND_HIGHLIGHT;
- } else if (STRNCMP(last, "icon", 4) == 0) {
- xp->xp_context = EXPAND_FILES;
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- break;
- case SIGNCMD_PLACE:
- if (STRNCMP(last, "name", 4) == 0) {
- expand_what = EXP_SIGN_NAMES;
- } else if (STRNCMP(last, "group", 5) == 0) {
- expand_what = EXP_SIGN_GROUPS;
- } else if (STRNCMP(last, "file", 4) == 0) {
- xp->xp_context = EXPAND_BUFFERS;
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- break;
- case SIGNCMD_UNPLACE:
- case SIGNCMD_JUMP:
- if (STRNCMP(last, "group", 5) == 0) {
- expand_what = EXP_SIGN_GROUPS;
- } else if (STRNCMP(last, "file", 4) == 0) {
- xp->xp_context = EXPAND_BUFFERS;
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- break;
- default:
+ case SIGNCMD_DEFINE:
+ if (STRNCMP(last, "texthl", 6) == 0
+ || STRNCMP(last, "linehl", 6) == 0
+ || STRNCMP(last, "numhl", 5) == 0) {
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ } else if (STRNCMP(last, "icon", 4) == 0) {
+ xp->xp_context = EXPAND_FILES;
+ } else {
xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ case SIGNCMD_PLACE:
+ if (STRNCMP(last, "name", 4) == 0) {
+ expand_what = EXP_SIGN_NAMES;
+ } else if (STRNCMP(last, "group", 5) == 0) {
+ expand_what = EXP_SIGN_GROUPS;
+ } else if (STRNCMP(last, "file", 4) == 0) {
+ xp->xp_context = EXPAND_BUFFERS;
+ } else {
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ case SIGNCMD_UNPLACE:
+ case SIGNCMD_JUMP:
+ if (STRNCMP(last, "group", 5) == 0) {
+ expand_what = EXP_SIGN_GROUPS;
+ } else if (STRNCMP(last, "file", 4) == 0) {
+ xp->xp_context = EXPAND_BUFFERS;
+ } else {
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
}
}
}
@@ -1914,11 +1863,11 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict)
goto cleanup;
}
if (dict != NULL) {
- icon = tv_dict_get_string(dict, "icon" , true);
+ icon = tv_dict_get_string(dict, "icon", true);
linehl = tv_dict_get_string(dict, "linehl", true);
- text = tv_dict_get_string(dict, "text" , true);
+ text = tv_dict_get_string(dict, "text", true);
texthl = tv_dict_get_string(dict, "texthl", true);
- numhl = tv_dict_get_string(dict, "numhl" , true);
+ numhl = tv_dict_get_string(dict, "numhl", true);
}
if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl,
@@ -1942,27 +1891,23 @@ cleanup:
/// values in 'retlist'.
void sign_define_multiple(list_T *l, list_T *retlist)
{
- int retval;
+ int retval;
- TV_LIST_ITER_CONST(l, li, {
- retval = -1;
- if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) {
- retval = sign_define_from_dict(NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
- } else {
- EMSG(_(e_dictreq));
- }
- tv_list_append_number(retlist, retval);
- });
+ TV_LIST_ITER_CONST(l, li, {
+ retval = -1;
+ if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) {
+ retval = sign_define_from_dict(NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
+ } else {
+ EMSG(_(e_dictreq));
+ }
+ tv_list_append_number(retlist, retval);
+ });
}
/// Place a new sign using the values specified in dict 'dict'. Returns the sign
/// identifier if successfully placed, otherwise returns 0.
-int sign_place_from_dict(
- typval_T *id_tv,
- typval_T *group_tv,
- typval_T *name_tv,
- typval_T *buf_tv,
- dict_T *dict)
+int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *name_tv, typval_T *buf_tv,
+ dict_T *dict)
{
int sign_id = 0;
char_u *group = NULL;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 610a359141..3e56ad561b 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -72,15 +72,14 @@
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <wctype.h>
-/* for offsetof() */
+// for offsetof()
#include <stddef.h>
#include "nvim/ascii.h"
-#include "nvim/spell.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
@@ -92,6 +91,7 @@
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/mark.h"
@@ -100,21 +100,21 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
+#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/undo.h"
#include "nvim/ui.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
+#include "nvim/undo.h"
// only used for su_badflags
#define WF_MIXCAP 0x20 // mix of upper and lower case: macaRONI
@@ -151,26 +151,26 @@ typedef struct suginfo_S {
int su_maxscore; // maximum score for adding to su_ga
int su_sfmaxscore; // idem, for when doing soundfold words
garray_T su_sga; // like su_ga, sound-folded scoring
- char_u *su_badptr; // start of bad word in line
+ char_u *su_badptr; // start of bad word in line
int su_badlen; // length of detected bad word in line
int su_badflags; // caps flags for bad word
char_u su_badword[MAXWLEN]; // bad word truncated at su_badlen
char_u su_fbadword[MAXWLEN]; // su_badword case-folded
char_u su_sal_badword[MAXWLEN]; // su_badword soundfolded
hashtab_T su_banned; // table with banned words
- slang_T *su_sallang; // default language for sound folding
+ slang_T *su_sallang; // default language for sound folding
} suginfo_T;
// One word suggestion. Used in "si_ga".
typedef struct {
- char_u *st_word; // suggested word, allocated string
+ char_u *st_word; // suggested word, allocated string
int st_wordlen; // STRLEN(st_word)
int st_orglen; // length of replaced text
int st_score; // lower is better
int st_altscore; // used when st_score compares equal
bool st_salscore; // st_score is for soundalike
bool st_had_bonus; // bonus already included in score
- slang_T *st_slang; // language used for sound folding
+ slang_T *st_slang; // language used for sound folding
} suggest_T;
#define SUG(ga, i) (((suggest_T *)(ga).ga_data)[i])
@@ -235,14 +235,14 @@ typedef struct {
// Structure to store info for word matching.
typedef struct matchinf_S {
- langp_T *mi_lp; // info for language and region
+ langp_T *mi_lp; // info for language and region
// pointers to original text to be checked
- char_u *mi_word; // start of word being checked
- char_u *mi_end; // end of matching word so far
- char_u *mi_fend; // next char to be added to mi_fword
- char_u *mi_cend; // char after what was used for
- // mi_capflags
+ char_u *mi_word; // start of word being checked
+ char_u *mi_end; // end of matching word so far
+ char_u *mi_fend; // next char to be added to mi_fword
+ char_u *mi_cend; // char after what was used for
+ // mi_capflags
// case-folded text
char_u mi_fword[MAXWLEN + 1]; // mi_word case-folded
@@ -265,11 +265,11 @@ typedef struct matchinf_S {
// others
int mi_result; // result so far: SP_BAD, SP_OK, etc.
int mi_capflags; // WF_ONECAP WF_ALLCAP WF_KEEPCAP
- win_T *mi_win; // buffer being checked
+ win_T *mi_win; // buffer being checked
// for NOBREAK
int mi_result2; // "mi_resul" without following word
- char_u *mi_end2; // "mi_end" without following word
+ char_u *mi_end2; // "mi_end" without following word
} matchinf_T;
// Structure used for the cookie argument of do_in_runtimepath().
@@ -334,26 +334,24 @@ char *e_format = N_("E759: Format error in spell file");
static char_u *repl_from = NULL;
static char_u *repl_to = NULL;
-// Main spell-checking function.
-// "ptr" points to a character that could be the start of a word.
-// "*attrp" is set to the highlight index for a badly spelled word. For a
-// non-word or when it's OK it remains unchanged.
-// This must only be called when 'spelllang' is not empty.
-//
-// "capcol" is used to check for a Capitalised word after the end of a
-// sentence. If it's zero then perform the check. Return the column where to
-// check next, or -1 when no sentence end was found. If it's NULL then don't
-// worry.
-//
-// Returns the length of the word in bytes, also when it's OK, so that the
-// caller can skip over the word.
-size_t spell_check(
- win_T *wp, // current window
- char_u *ptr,
- hlf_T *attrp,
- int *capcol, // column to check for Capital
- bool docount // count good words
-)
+/// Main spell-checking function.
+/// "ptr" points to a character that could be the start of a word.
+/// "*attrp" is set to the highlight index for a badly spelled word. For a
+/// non-word or when it's OK it remains unchanged.
+/// This must only be called when 'spelllang' is not empty.
+///
+/// "capcol" is used to check for a Capitalised word after the end of a
+/// sentence. If it's zero then perform the check. Return the column where to
+/// check next, or -1 when no sentence end was found. If it's NULL then don't
+/// worry.
+///
+/// @param wp current window
+/// @param capcol column to check for Capital
+/// @param docount count good words
+///
+/// @return the length of the word in bytes, also when it's OK, so that the
+/// caller can skip over the word.
+size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docount)
{
matchinf_T mi; // Most things are put in "mi" so that it can
// be passed to functions quickly.
@@ -383,7 +381,7 @@ size_t spell_check(
// julifeest".
if (*ptr >= '0' && *ptr <= '9') {
if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) {
- mi.mi_end = (char_u*) skipbin((char*) ptr + 2);
+ mi.mi_end = (char_u *)skipbin((char *)ptr + 2);
} else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
mi.mi_end = skiphex(ptr + 2);
} else {
@@ -486,7 +484,7 @@ size_t spell_check(
// Count the word in the first language where it's found to be OK.
if (count_word && mi.mi_result == SP_OK) {
count_common_word(mi.mi_lp->lp_slang, ptr,
- (int)(mi.mi_end - ptr), 1);
+ (int)(mi.mi_end - ptr), 1);
count_word = false;
}
}
@@ -499,8 +497,8 @@ size_t spell_check(
return nrlen;
}
} else if (!spell_iswordp_nmw(ptr, wp)) {
- // When we are at a non-word character there is no error, just
- // skip over the character (try looking for a word after it).
+ // When we are at a non-word character there is no error, just
+ // skip over the character (try looking for a word after it).
if (capcol != NULL && wp->w_s->b_cap_prog != NULL) {
regmatch_T regmatch;
@@ -521,7 +519,7 @@ size_t spell_check(
MB_PTR_ADV(mi.mi_end);
} else if (mi.mi_result == SP_BAD
&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
- char_u *p, *fp;
+ char_u *p, *fp;
int save_result = mi.mi_result;
// First language in 'spelllang' is NOBREAK. Find first position
@@ -576,10 +574,10 @@ static void find_word(matchinf_T *mip, int mode)
{
int wlen = 0;
int flen;
- char_u *ptr;
- slang_T *slang = mip->mi_lp->lp_slang;
- char_u *byts;
- idx_T *idxs;
+ char_u *ptr;
+ slang_T *slang = mip->mi_lp->lp_slang;
+ char_u *byts;
+ idx_T *idxs;
if (mode == FIND_KEEPWORD || mode == FIND_KEEPCOMPOUND) {
// Check for word with matching case in keep-case tree.
@@ -588,9 +586,10 @@ static void find_word(matchinf_T *mip, int mode)
byts = slang->sl_kbyts;
idxs = slang->sl_kidxs;
- if (mode == FIND_KEEPCOMPOUND)
+ if (mode == FIND_KEEPCOMPOUND) {
// Skip over the previously found word(s).
wlen += mip->mi_compoff;
+ }
} else {
// Check for case-folded in case-folded tree.
ptr = mip->mi_fword;
@@ -607,12 +606,11 @@ static void find_word(matchinf_T *mip, int mode)
wlen = mip->mi_compoff;
flen -= mip->mi_compoff;
}
-
}
- if (byts == NULL)
+ if (byts == NULL) {
return; // array is empty
-
+ }
idx_T arridx = 0;
int endlen[MAXWLEN]; // length at possible word endings
idx_T endidx[MAXWLEN]; // possible word endings
@@ -625,8 +623,9 @@ static void find_word(matchinf_T *mip, int mode)
// - we reach the end of the tree,
// - or we reach the end of the line.
for (;; ) {
- if (flen <= 0 && *mip->mi_fend != NUL)
+ if (flen <= 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
+ }
len = byts[arridx++];
@@ -648,35 +647,39 @@ static void find_word(matchinf_T *mip, int mode)
++arridx;
--len;
}
- if (len == 0)
+ if (len == 0) {
break; // no children, word must end here
+ }
}
// Stop looking at end of the line.
- if (ptr[wlen] == NUL)
+ if (ptr[wlen] == NUL) {
break;
+ }
// Perform a binary search in the list of accepted bytes.
c = ptr[wlen];
- if (c == TAB) // <Tab> is handled like <Space>
+ if (c == TAB) { // <Tab> is handled like <Space>
c = ' ';
+ }
idx_T lo = arridx;
idx_T hi = arridx + len - 1;
while (lo < hi) {
idx_T m = (lo + hi) / 2;
- if (byts[m] > c)
+ if (byts[m] > c) {
hi = m - 1;
- else if (byts[m] < c)
+ } else if (byts[m] < c) {
lo = m + 1;
- else {
+ } else {
lo = hi = m;
break;
}
}
// Stop if there is no matching byte.
- if (hi < lo || byts[lo] != c)
+ if (hi < lo || byts[lo] != c) {
break;
+ }
// Continue at the child (if there is one).
arridx = idxs[lo];
@@ -687,10 +690,12 @@ static void find_word(matchinf_T *mip, int mode)
// checked word.
if (c == ' ') {
for (;; ) {
- if (flen <= 0 && *mip->mi_fend != NUL)
+ if (flen <= 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
- if (ptr[wlen] != ' ' && ptr[wlen] != TAB)
+ }
+ if (ptr[wlen] != ' ' && ptr[wlen] != TAB) {
break;
+ }
++wlen;
--flen;
}
@@ -711,11 +716,13 @@ static void find_word(matchinf_T *mip, int mode)
continue; // not at first byte of character
}
if (spell_iswordp(ptr + wlen, mip->mi_win)) {
- if (slang->sl_compprog == NULL && !slang->sl_nobreak)
+ if (slang->sl_compprog == NULL && !slang->sl_nobreak) {
continue; // next char is a word character
+ }
word_ends = false;
- } else
+ } else {
word_ends = true;
+ }
// The prefix flag is before compound flags. Once a valid prefix flag
// has been found we try compound flags.
bool prefix_found = false;
@@ -754,23 +761,26 @@ static void find_word(matchinf_T *mip, int mode)
}
if (mip->mi_capflags == WF_KEEPCAP
- || !spell_valid_case(mip->mi_capflags, flags))
+ || !spell_valid_case(mip->mi_capflags, flags)) {
continue;
+ }
}
// When mode is FIND_PREFIX the word must support the prefix:
// check the prefix ID and the condition. Do that for the list at
// mip->mi_prefarridx that find_prefix() filled.
else if (mode == FIND_PREFIX && !prefix_found) {
c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
- flags,
- mip->mi_word + mip->mi_cprefixlen, slang,
- false);
- if (c == 0)
+ flags,
+ mip->mi_word + mip->mi_cprefixlen, slang,
+ false);
+ if (c == 0) {
continue;
+ }
// Use the WF_RARE flag for a rare prefix.
- if (c & WF_RAREPFX)
+ if (c & WF_RAREPFX) {
flags |= WF_RARE;
+ }
prefix_found = true;
}
@@ -790,8 +800,9 @@ static void find_word(matchinf_T *mip, int mode)
// that's too short... Myspell compatibility requires this
// anyway.
if (((unsigned)flags >> 24) == 0
- || wlen - mip->mi_compoff < slang->sl_compminlen)
+ || wlen - mip->mi_compoff < slang->sl_compminlen) {
continue;
+ }
// For multi-byte chars check character length against
// COMPOUNDMIN.
if (slang->sl_compminlen > 0
@@ -804,27 +815,32 @@ static void find_word(matchinf_T *mip, int mode)
// maximum for syllables is specified.
if (!word_ends && mip->mi_complen + mip->mi_compextra + 2
> slang->sl_compmax
- && slang->sl_compsylmax == MAXWLEN)
+ && slang->sl_compsylmax == MAXWLEN) {
continue;
+ }
// Don't allow compounding on a side where an affix was added,
// unless COMPOUNDPERMITFLAG was used.
- if (mip->mi_complen > 0 && (flags & WF_NOCOMPBEF))
+ if (mip->mi_complen > 0 && (flags & WF_NOCOMPBEF)) {
continue;
- if (!word_ends && (flags & WF_NOCOMPAFT))
+ }
+ if (!word_ends && (flags & WF_NOCOMPAFT)) {
continue;
+ }
// Quickly check if compounding is possible with this flag.
if (!byte_in_str(mip->mi_complen == 0
? slang->sl_compstartflags
: slang->sl_compallflags,
- ((unsigned)flags >> 24)))
+ ((unsigned)flags >> 24))) {
continue;
+ }
// If there is a match with a CHECKCOMPOUNDPATTERN rule
// discard the compound word.
- if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat))
+ if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat)) {
continue;
+ }
if (mode == FIND_COMPOUND) {
int capflags;
@@ -842,8 +858,9 @@ static void find_word(matchinf_T *mip, int mode)
}
capflags = captype(p, mip->mi_word + wlen);
if (capflags == WF_KEEPCAP || (capflags == WF_ALLCAP
- && (flags & WF_FIXCAP) != 0))
+ && (flags & WF_FIXCAP) != 0)) {
continue;
+ }
if (capflags != WF_ALLCAP) {
// When the character before the word is a word
@@ -876,23 +893,26 @@ static void find_word(matchinf_T *mip, int mode)
STRLCPY(fword, ptr, endlen[endidxcnt] + 1);
}
}
- if (!can_compound(slang, fword, mip->mi_compflags))
+ if (!can_compound(slang, fword, mip->mi_compflags)) {
continue;
+ }
} else if (slang->sl_comprules != NULL
- && !match_compoundrule(slang, mip->mi_compflags))
+ && !match_compoundrule(slang, mip->mi_compflags)) {
// The compound flags collected so far do not match any
// COMPOUNDRULE, discard the compounded word.
continue;
+ }
}
// Check NEEDCOMPOUND: can't use word without compounding.
- else if (flags & WF_NEEDCOMP)
+ else if (flags & WF_NEEDCOMP) {
continue;
+ }
int nobreak_result = SP_OK;
if (!word_ends) {
int save_result = mip->mi_result;
- char_u *save_end = mip->mi_end;
+ char_u *save_end = mip->mi_end;
langp_T *save_lp = mip->mi_lp;
// Check that a valid word follows. If there is one and we
@@ -900,8 +920,9 @@ static void find_word(matchinf_T *mip, int mode)
// always finished here. For NOBREAK we only check that a
// valid word follows.
// Recursive!
- if (slang->sl_nobreak)
+ if (slang->sl_nobreak) {
mip->mi_result = SP_BAD;
+ }
// Find following word in case-folded tree.
mip->mi_compoff = endlen[endidxcnt];
@@ -922,8 +943,9 @@ static void find_word(matchinf_T *mip, int mode)
c = mip->mi_compoff;
#endif
++mip->mi_complen;
- if (flags & WF_COMPROOT)
+ if (flags & WF_COMPROOT) {
++mip->mi_compextra;
+ }
// For NOBREAK we need to try all NOBREAK languages, at least
// to find the ".add" file(s).
@@ -931,8 +953,9 @@ static void find_word(matchinf_T *mip, int mode)
if (slang->sl_nobreak) {
mip->mi_lp = LANGP_ENTRY(mip->mi_win->w_s->b_langp, lpi);
if (mip->mi_lp->lp_slang->sl_fidxs == NULL
- || !mip->mi_lp->lp_slang->sl_nobreak)
+ || !mip->mi_lp->lp_slang->sl_nobreak) {
continue;
+ }
}
find_word(mip, FIND_COMPOUND);
@@ -956,12 +979,14 @@ static void find_word(matchinf_T *mip, int mode)
#endif
}
- if (!slang->sl_nobreak)
+ if (!slang->sl_nobreak) {
break;
+ }
}
--mip->mi_complen;
- if (flags & WF_COMPROOT)
+ if (flags & WF_COMPROOT) {
--mip->mi_compextra;
+ }
mip->mi_lp = save_lp;
if (slang->sl_nobreak) {
@@ -969,25 +994,28 @@ static void find_word(matchinf_T *mip, int mode)
mip->mi_result = save_result;
mip->mi_end = save_end;
} else {
- if (mip->mi_result == SP_OK)
+ if (mip->mi_result == SP_OK) {
break;
+ }
continue;
}
}
int res = SP_BAD;
- if (flags & WF_BANNED)
+ if (flags & WF_BANNED) {
res = SP_BANNED;
- else if (flags & WF_REGION) {
+ } else if (flags & WF_REGION) {
// Check region.
- if ((mip->mi_lp->lp_region & (flags >> 16)) != 0)
+ if ((mip->mi_lp->lp_region & (flags >> 16)) != 0) {
res = SP_OK;
- else
+ } else {
res = SP_LOCAL;
- } else if (flags & WF_RARE)
+ }
+ } else if (flags & WF_RARE) {
res = SP_RARE;
- else
+ } else {
res = SP_OK;
+ }
// Always use the longest match and the best result. For NOBREAK
// we separately keep the longest match without a following good
@@ -997,36 +1025,37 @@ static void find_word(matchinf_T *mip, int mode)
mip->mi_result2 = res;
mip->mi_end2 = mip->mi_word + wlen;
} else if (mip->mi_result2 == res
- && mip->mi_end2 < mip->mi_word + wlen)
+ && mip->mi_end2 < mip->mi_word + wlen) {
mip->mi_end2 = mip->mi_word + wlen;
+ }
} else if (mip->mi_result > res) {
mip->mi_result = res;
mip->mi_end = mip->mi_word + wlen;
- } else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen)
+ } else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen) {
mip->mi_end = mip->mi_word + wlen;
+ }
- if (mip->mi_result == SP_OK)
+ if (mip->mi_result == SP_OK) {
break;
+ }
}
- if (mip->mi_result == SP_OK)
+ if (mip->mi_result == SP_OK) {
break;
+ }
}
}
-// Returns true if there is a match between the word ptr[wlen] and
-// CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
-// word.
-// A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
-// end of ptr[wlen] and the second part matches after it.
-static bool
-match_checkcompoundpattern (
- char_u *ptr,
- int wlen,
- garray_T *gap // &sl_comppat
-)
+/// Returns true if there is a match between the word ptr[wlen] and
+/// CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
+/// word.
+/// A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
+/// end of ptr[wlen] and the second part matches after it.
+///
+/// @param gap &sl_comppat
+static bool match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap)
{
- char_u *p;
+ char_u *p;
int len;
for (int i = 0; i + 1 < gap->ga_len; i += 2) {
@@ -1036,8 +1065,9 @@ match_checkcompoundpattern (
// check if first part matches at end of previous word.
p = ((char_u **)gap->ga_data)[i];
len = (int)STRLEN(p);
- if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0)
+ if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0) {
return true;
+ }
}
}
return false;
@@ -1045,8 +1075,7 @@ match_checkcompoundpattern (
// Returns true if "flags" is a valid sequence of compound flags and "word"
// does not have too many syllables.
-static bool can_compound(slang_T *slang, const char_u *word,
- const char_u *flags)
+static bool can_compound(slang_T *slang, const char_u *word, const char_u *flags)
FUNC_ATTR_NONNULL_ALL
{
char_u uflags[MAXWLEN * 2] = { 0 };
@@ -1069,8 +1098,9 @@ static bool can_compound(slang_T *slang, const char_u *word,
// are too many syllables AND the number of compound words is above
// COMPOUNDWORDMAX then compounding is not allowed.
if (slang->sl_compsylmax < MAXWLEN
- && count_syllables(slang, word) > slang->sl_compsylmax)
+ && count_syllables(slang, word) > slang->sl_compsylmax) {
return (int)STRLEN(flags) < slang->sl_compmax;
+ }
return true;
}
@@ -1082,8 +1112,9 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, i
// If the flag doesn't appear in sl_compstartflags or sl_compallflags
// then it can't possibly compound.
if (!byte_in_str(sp->ts_complen == sp->ts_compsplit
- ? slang->sl_compstartflags : slang->sl_compallflags, flag))
+ ? slang->sl_compstartflags : slang->sl_compallflags, flag)) {
return false;
+ }
// If there are no wildcards, we can check if the flags collected so far
// possibly can form a match with COMPOUNDRULE patterns. This only
@@ -1105,7 +1136,7 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, i
// Caller must check that slang->sl_comprules is not NULL.
static bool match_compoundrule(slang_T *slang, char_u *compflags)
{
- char_u *p;
+ char_u *p;
int i;
int c;
@@ -1115,30 +1146,37 @@ static bool match_compoundrule(slang_T *slang, char_u *compflags)
// them against the current rule entry
for (i = 0;; ++i) {
c = compflags[i];
- if (c == NUL)
+ if (c == NUL) {
// found a rule that matches for the flags we have so far
return true;
- if (*p == '/' || *p == NUL)
+ }
+ if (*p == '/' || *p == NUL) {
break; // end of rule, it's too short
+ }
if (*p == '[') {
bool match = false;
// compare against all the flags in []
++p;
- while (*p != ']' && *p != NUL)
- if (*p++ == c)
+ while (*p != ']' && *p != NUL) {
+ if (*p++ == c) {
match = true;
- if (!match)
+ }
+ }
+ if (!match) {
break; // none matches
- } else if (*p != c)
+ }
+ } else if (*p != c) {
break; // flag of word doesn't match flag in pattern
+ }
++p;
}
// Skip to the next "/", where the next pattern starts.
p = vim_strchr(p, '/');
- if (p == NULL)
+ if (p == NULL) {
break;
+ }
}
// Checked all the rules and none of them match the flags, so there
@@ -1146,18 +1184,15 @@ static bool match_compoundrule(slang_T *slang, char_u *compflags)
return false;
}
-// Return non-zero if the prefix indicated by "arridx" matches with the prefix
-// ID in "flags" for the word "word".
-// The WF_RAREPFX flag is included in the return value for a rare prefix.
-static int
-valid_word_prefix (
- int totprefcnt, // nr of prefix IDs
- int arridx, // idx in sl_pidxs[]
- int flags,
- char_u *word,
- slang_T *slang,
- bool cond_req // only use prefixes with a condition
-)
+/// Return non-zero if the prefix indicated by "arridx" matches with the prefix
+/// ID in "flags" for the word "word".
+/// The WF_RAREPFX flag is included in the return value for a rare prefix.
+///
+/// @param totprefcnt nr of prefix IDs
+/// @param arridx idx in sl_pidxs[]
+/// @param cond_req only use prefixes with a condition
+static int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang,
+ bool cond_req)
{
int prefcnt;
int pidx;
@@ -1168,13 +1203,15 @@ valid_word_prefix (
pidx = slang->sl_pidxs[arridx + prefcnt];
// Check the prefix ID.
- if (prefid != (pidx & 0xff))
+ if (prefid != (pidx & 0xff)) {
continue;
+ }
// Check if the prefix doesn't combine and the word already has a
// suffix.
- if ((flags & WF_HAS_AFF) && (pidx & WF_PFX_NC))
+ if ((flags & WF_HAS_AFF) && (pidx & WF_PFX_NC)) {
continue;
+ }
// Check the condition, if there is one. The condition index is
// stored in the two bytes above the prefix ID byte.
@@ -1183,8 +1220,9 @@ valid_word_prefix (
if (!vim_regexec_prog(rp, false, word, 0)) {
continue;
}
- } else if (cond_req)
+ } else if (cond_req) {
continue;
+ }
// It's a match! Return the WF_ flags.
return pidx;
@@ -1206,16 +1244,16 @@ static void find_prefix(matchinf_T *mip, int mode)
int wlen = 0;
int flen;
int c;
- char_u *ptr;
+ char_u *ptr;
idx_T lo, hi, m;
- slang_T *slang = mip->mi_lp->lp_slang;
- char_u *byts;
- idx_T *idxs;
+ slang_T *slang = mip->mi_lp->lp_slang;
+ char_u *byts;
+ idx_T *idxs;
byts = slang->sl_pbyts;
- if (byts == NULL)
+ if (byts == NULL) {
return; // array is empty
-
+ }
// We use the case-folded word here, since prefixes are always
// case-folded.
ptr = mip->mi_fword;
@@ -1232,8 +1270,9 @@ static void find_prefix(matchinf_T *mip, int mode)
// - we reach the end of the tree,
// - or we reach the end of the line.
for (;; ) {
- if (flen == 0 && *mip->mi_fend != NUL)
+ if (flen == 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
+ }
len = byts[arridx++];
@@ -1254,9 +1293,10 @@ static void find_prefix(matchinf_T *mip, int mode)
// Find the word that comes after the prefix.
mip->mi_prefixlen = wlen;
- if (mode == FIND_COMPOUND)
+ if (mode == FIND_COMPOUND) {
// Skip over the previously found word(s).
mip->mi_prefixlen += mip->mi_compoff;
+ }
// Case-folded length may differ from original length.
mip->mi_cprefixlen = nofold_len(mip->mi_fword, mip->mi_prefixlen,
@@ -1264,13 +1304,15 @@ static void find_prefix(matchinf_T *mip, int mode)
find_word(mip, FIND_PREFIX);
- if (len == 0)
+ if (len == 0) {
break; // no children, word must end here
+ }
}
// Stop looking at end of the line.
- if (ptr[wlen] == NUL)
+ if (ptr[wlen] == NUL) {
break;
+ }
// Perform a binary search in the list of accepted bytes.
c = ptr[wlen];
@@ -1278,19 +1320,20 @@ static void find_prefix(matchinf_T *mip, int mode)
hi = arridx + len - 1;
while (lo < hi) {
m = (lo + hi) / 2;
- if (byts[m] > c)
+ if (byts[m] > c) {
hi = m - 1;
- else if (byts[m] < c)
+ } else if (byts[m] < c) {
lo = m + 1;
- else {
+ } else {
lo = hi = m;
break;
}
}
// Stop if there is no matching byte.
- if (hi < lo || byts[lo] != c)
+ if (hi < lo || byts[lo] != c) {
break;
+ }
// Continue at the child (if there is one).
arridx = idxs[lo];
@@ -1305,7 +1348,7 @@ static void find_prefix(matchinf_T *mip, int mode)
static int fold_more(matchinf_T *mip)
{
int flen;
- char_u *p;
+ char_u *p;
p = mip->mi_fend;
do {
@@ -1349,42 +1392,40 @@ static bool no_spell_checking(win_T *wp)
return false;
}
-// Moves to the next spell error.
-// "curline" is false for "[s", "]s", "[S" and "]S".
-// "curline" is true to find word under/after cursor in the same line.
-// For Insert mode completion "dir" is BACKWARD and "curline" is true: move
-// to after badly spelled word before the cursor.
-// Return 0 if not found, length of the badly spelled word otherwise.
-size_t
-spell_move_to (
- win_T *wp,
- int dir, // FORWARD or BACKWARD
- bool allwords, // true for "[s"/"]s", false for "[S"/"]S"
- bool curline,
- hlf_T *attrp // return: attributes of bad word or NULL
- // (only when "dir" is FORWARD)
-)
+/// Moves to the next spell error.
+/// "curline" is false for "[s", "]s", "[S" and "]S".
+/// "curline" is true to find word under/after cursor in the same line.
+/// For Insert mode completion "dir" is BACKWARD and "curline" is true: move
+/// to after badly spelled word before the cursor.
+///
+/// @param dir FORWARD or BACKWARD
+/// @param allwords true for "[s"/"]s", false for "[S"/"]S"
+/// @param attrp return: attributes of bad word or NULL (only when "dir" is FORWARD)
+///
+/// @return 0 if not found, length of the badly spelled word otherwise.
+size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *attrp)
{
linenr_T lnum;
pos_T found_pos;
size_t found_len = 0;
- char_u *line;
- char_u *p;
- char_u *endp;
+ char_u *line;
+ char_u *p;
+ char_u *endp;
hlf_T attr = HLF_COUNT;
size_t len;
int has_syntax = syntax_present(wp);
int col;
bool can_spell;
- char_u *buf = NULL;
+ char_u *buf = NULL;
size_t buflen = 0;
int skip = 0;
int capcol = -1;
bool found_one = false;
bool wrapped = false;
- if (no_spell_checking(wp))
+ if (no_spell_checking(wp)) {
return 0;
+ }
// Start looking for bad word at the start of the line, because we can't
// start halfway through a word, we don't know where it starts or ends.
@@ -1410,8 +1451,9 @@ spell_move_to (
assert(buf && buflen >= len + MAXWLEN + 2);
// In first line check first word for Capital.
- if (lnum == 1)
+ if (lnum == 1) {
capcol = 0;
+ }
// For checking first word with a capital skip white space.
if (capcol == 0) {
@@ -1431,10 +1473,11 @@ spell_move_to (
// Copy the line into "buf" and append the start of the next line if
// possible.
STRCPY(buf, line);
- if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ 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),
MAXWLEN);
+ }
p = buf + skip;
endp = buf + len;
while (p < endp) {
@@ -1443,8 +1486,9 @@ spell_move_to (
if (dir == BACKWARD
&& lnum == wp->w_cursor.lnum
&& !wrapped
- && (colnr_T)(p - buf) >= wp->w_cursor.col)
+ && (colnr_T)(p - buf) >= wp->w_cursor.col) {
break;
+ }
// start of word
attr = HLF_COUNT;
@@ -1464,11 +1508,13 @@ spell_move_to (
if (has_syntax) {
col = (int)(p - buf);
(void)syn_get_id(wp, lnum, (colnr_T)col,
- FALSE, &can_spell, FALSE);
- if (!can_spell)
+ FALSE, &can_spell, FALSE);
+ if (!can_spell) {
attr = HLF_COUNT;
- } else
+ }
+ } else {
can_spell = true;
+ }
if (can_spell) {
found_one = true;
@@ -1479,8 +1525,9 @@ spell_move_to (
// No need to search further.
wp->w_cursor = found_pos;
xfree(buf);
- if (attrp != NULL)
+ if (attrp != NULL) {
*attrp = attr;
+ }
return len;
} else if (curline) {
// Insert mode completion: put cursor after
@@ -1490,8 +1537,9 @@ spell_move_to (
}
found_len = len;
}
- } else
+ } else {
found_one = true;
+ }
}
}
@@ -1529,22 +1577,24 @@ spell_move_to (
// starting line again and accept the last match.
lnum = wp->w_buffer->b_ml.ml_line_count;
wrapped = true;
- if (!shortmess(SHM_SEARCH))
+ if (!shortmess(SHM_SEARCH)) {
give_warning((char_u *)_(top_bot_msg), true);
+ }
}
capcol = -1;
} else {
- if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ if (lnum < wp->w_buffer->b_ml.ml_line_count) {
++lnum;
- else if (!p_ws)
+ } else if (!p_ws) {
break; // at first line and 'nowrapscan'
- else {
+ } else {
// Wrap around to the start of the buffer. May search the
// starting line again and accept the first match.
lnum = 1;
wrapped = true;
- if (!shortmess(SHM_SEARCH))
+ if (!shortmess(SHM_SEARCH)) {
give_warning((char_u *)_(bot_top_msg), true);
+ }
}
// If we are back at the starting line and there is no match then
@@ -1555,17 +1605,19 @@ spell_move_to (
// Skip the characters at the start of the next line that were
// included in a match crossing line boundaries.
- if (attr == HLF_COUNT)
+ if (attr == HLF_COUNT) {
skip = (int)(p - endp);
- else
+ } else {
skip = 0;
+ }
// Capcol skips over the inserted space.
--capcol;
// But after empty line check first word in next line
- if (*skipwhite(line) == NUL)
+ if (*skipwhite(line) == NUL) {
capcol = 0;
+ }
}
line_breakcheck();
@@ -1581,12 +1633,13 @@ spell_move_to (
// to skip those bytes if the word was OK.
void spell_cat_line(char_u *buf, char_u *line, int maxlen)
{
- char_u *p;
+ char_u *p;
int n;
p = skipwhite(line);
- while (vim_strchr((char_u *)"*#/\"\t", *p) != NULL)
+ while (vim_strchr((char_u *)"*#/\"\t", *p) != NULL) {
p = skipwhite(p + 1);
+ }
if (*p != NUL) {
// Only worth concatenating if there is something else than spaces to
@@ -1630,8 +1683,9 @@ static void spell_load_lang(char_u *lang)
if (r == FAIL && *sl.sl_lang != NUL && round == 1
&& apply_autocmds(EVENT_SPELLFILEMISSING, lang,
- curbuf->b_fname, FALSE, curbuf))
+ curbuf->b_fname, FALSE, curbuf)) {
continue;
+ }
break;
}
break;
@@ -1647,9 +1701,8 @@ static void spell_load_lang(char_u *lang)
lang);
do_cmdline_cmd(autocmd_buf);
} else {
- smsg(
- _("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
- lang, spell_enc(), lang);
+ smsg(_("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
+ lang, spell_enc(), lang);
}
} else if (sl.sl_slang != NULL) {
// At least one file was loaded, now load ALL the additions.
@@ -1662,9 +1715,9 @@ static void spell_load_lang(char_u *lang)
// use "latin1" for "latin9". And limit to 60 characters (just in case).
char_u *spell_enc(void)
{
-
- if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0)
+ if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) {
return p_enc;
+ }
return (char_u *)"latin1";
}
@@ -1673,7 +1726,7 @@ char_u *spell_enc(void)
static void int_wordlist_spl(char_u *fname)
{
vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL,
- int_wordlist, spell_enc());
+ int_wordlist, spell_enc());
}
// Allocate a new slang_T for language "lang". "lang" can be NULL.
@@ -1683,8 +1736,9 @@ slang_T *slang_alloc(char_u *lang)
{
slang_T *lp = xcalloc(1, sizeof(slang_T));
- if (lang != NULL)
+ if (lang != NULL) {
lp->sl_name = vim_strsave(lang);
+ }
ga_init(&lp->sl_rep, sizeof(fromto_T), 10);
ga_init(&lp->sl_repsal, sizeof(fromto_T), 10);
lp->sl_compmax = MAXWLEN;
@@ -1722,7 +1776,7 @@ static void free_fromto(fromto_T *ftp) {
// Clear an slang_T so that the file can be reloaded.
void slang_clear(slang_T *lp)
{
- garray_T *gap;
+ garray_T *gap;
XFREE_CLEAR(lp->sl_fbyts);
XFREE_CLEAR(lp->sl_kbyts);
@@ -1792,17 +1846,18 @@ void slang_clear_sug(slang_T *lp)
// Invoked through do_in_runtimepath().
static void spell_load_cb(char_u *fname, void *cookie)
{
- spelload_T *slp = (spelload_T *)cookie;
- slang_T *slang;
+ spelload_T *slp = (spelload_T *)cookie;
+ slang_T *slang;
slang = spell_load_file(fname, slp->sl_lang, NULL, false);
if (slang != NULL) {
// When a previously loaded file has NOBREAK also use it for the
// ".add" files.
- if (slp->sl_nobreak && slang->sl_add)
+ if (slp->sl_nobreak && slang->sl_add) {
slang->sl_nobreak = true;
- else if (slang->sl_nobreak)
+ } else if (slang->sl_nobreak) {
slp->sl_nobreak = true;
+ }
slp->sl_slang = slang;
}
@@ -1818,10 +1873,10 @@ static void spell_load_cb(char_u *fname, void *cookie)
void count_common_word(slang_T *lp, char_u *word, int len, int count)
{
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
wordcount_T *wc;
char_u buf[MAXWLEN];
- char_u *p;
+ char_u *p;
if (len == -1) {
p = word;
@@ -1842,21 +1897,18 @@ void count_common_word(slang_T *lp, char_u *word, int len, int count)
hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
} else {
wc = HI2WC(hi);
- if ((wc->wc_count += count) < (unsigned)count) // check for overflow
+ if ((wc->wc_count += count) < (unsigned)count) { // check for overflow
wc->wc_count = MAXWORDCOUNT;
+ }
}
}
-// Adjust the score of common words.
-static int
-score_wordcount_adj (
- slang_T *slang,
- int score,
- char_u *word,
- bool split // word was split, less bonus
-)
+/// Adjust the score of common words.
+///
+/// @param split word was split, less bonus
+static int score_wordcount_adj(slang_T *slang, int score, char_u *word, bool split)
{
- hashitem_T *hi;
+ hashitem_T *hi;
wordcount_T *wc;
int bonus;
int newscore;
@@ -1864,18 +1916,21 @@ score_wordcount_adj (
hi = hash_find(&slang->sl_wordcount, word);
if (!HASHITEM_EMPTY(hi)) {
wc = HI2WC(hi);
- if (wc->wc_count < SCORE_THRES2)
+ if (wc->wc_count < SCORE_THRES2) {
bonus = SCORE_COMMON1;
- else if (wc->wc_count < SCORE_THRES3)
+ } else if (wc->wc_count < SCORE_THRES3) {
bonus = SCORE_COMMON2;
- else
+ } else {
bonus = SCORE_COMMON3;
- if (split)
+ }
+ if (split) {
newscore = score - bonus / 2;
- else
+ } else {
newscore = score - bonus;
- if (newscore < 0)
+ }
+ if (newscore < 0) {
return 0;
+ }
return newscore;
}
return score;
@@ -1885,11 +1940,13 @@ score_wordcount_adj (
// Like strchr() but independent of locale.
bool byte_in_str(char_u *str, int n)
{
- char_u *p;
+ char_u *p;
- for (p = str; *p != NUL; ++p)
- if (*p == n)
+ for (p = str; *p != NUL; ++p) {
+ if (*p == n) {
return true;
+ }
+ }
return false;
}
@@ -1897,24 +1954,27 @@ bool byte_in_str(char_u *str, int n)
// in "slang->sl_syl_items".
int init_syl_tab(slang_T *slang)
{
- char_u *p;
- char_u *s;
+ char_u *p;
+ char_u *s;
int l;
ga_init(&slang->sl_syl_items, sizeof(syl_item_T), 4);
p = vim_strchr(slang->sl_syllable, '/');
while (p != NULL) {
*p++ = NUL;
- if (*p == NUL) // trailing slash
+ if (*p == NUL) { // trailing slash
break;
+ }
s = p;
p = vim_strchr(p, '/');
- if (p == NULL)
+ if (p == NULL) {
l = (int)STRLEN(s);
- else
+ } else {
l = (int)(p - s);
- if (l >= SY_MAXLEN)
+ }
+ if (l >= SY_MAXLEN) {
return SP_FORMERROR;
+ }
syl_item_T *syl = GA_APPEND_VIA_PTR(syl_item_T, &slang->sl_syl_items);
STRLCPY(syl->sy_chars, s, l + 1);
@@ -1932,11 +1992,12 @@ static int count_syllables(slang_T *slang, const char_u *word)
int cnt = 0;
bool skip = false;
int len;
- syl_item_T *syl;
+ syl_item_T *syl;
int c;
- if (slang->sl_syllable == NULL)
+ if (slang->sl_syllable == NULL) {
return 0;
+ }
for (const char_u *p = word; *p != NUL; p += len) {
// When running into a space reset counter.
@@ -1951,8 +2012,9 @@ static int count_syllables(slang_T *slang, const char_u *word)
for (int i = 0; i < slang->sl_syl_items.ga_len; ++i) {
syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i;
if (syl->sy_len > len
- && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0)
+ && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0) {
len = syl->sy_len;
+ }
}
if (len != 0) { // found a match, count syllable
++cnt;
@@ -1961,9 +2023,9 @@ static int count_syllables(slang_T *slang, const char_u *word)
// No recognized syllable item, at least a syllable char then?
c = utf_ptr2char(p);
len = (*mb_ptr2len)(p);
- if (vim_strchr(slang->sl_syllable, c) == NULL)
+ if (vim_strchr(slang->sl_syllable, c) == NULL) {
skip = false; // No, search for next syllable
- else if (!skip) {
+ } else if (!skip) {
++cnt; // Yes, count it
skip = true; // don't count following syllable chars
}
@@ -1977,26 +2039,26 @@ static int count_syllables(slang_T *slang, const char_u *word)
char_u *did_set_spelllang(win_T *wp)
{
garray_T ga;
- char_u *splp;
- char_u *region;
+ char_u *splp;
+ char_u *region;
char_u region_cp[3];
bool filename;
int region_mask;
- slang_T *slang;
+ slang_T *slang;
int c;
char_u lang[MAXWLEN + 1];
char_u spf_name[MAXPATHL];
int len;
- char_u *p;
+ char_u *p;
int round;
- char_u *spf;
- char_u *use_region = NULL;
+ char_u *spf;
+ char_u *use_region = NULL;
bool dont_use_region = false;
bool nobreak = false;
- langp_T *lp, *lp2;
+ langp_T *lp, *lp2;
static bool recursive = false;
- char_u *ret_msg = NULL;
- char_u *spl_copy;
+ char_u *ret_msg = NULL;
+ char_u *spl_copy;
bufref_T bufref;
set_bufref(&bufref, wp->w_buffer);
@@ -2004,8 +2066,9 @@ char_u *did_set_spelllang(win_T *wp)
// We don't want to do this recursively. May happen when a language is
// not available and the SpellFileMissing autocommand opens a new buffer
// in which 'spell' is set.
- if (recursive)
+ if (recursive) {
return NULL;
+ }
recursive = true;
ga_init(&ga, sizeof(langp_T), 2);
@@ -2046,8 +2109,9 @@ char_u *did_set_spelllang(win_T *wp)
STRLCPY(region_cp, p + 1, 3);
memmove(p, p + 3, len - (p - lang) - 2);
region = region_cp;
- } else
+ } else {
dont_use_region = true;
+ }
// Check if we loaded this language before.
for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
@@ -2061,28 +2125,32 @@ char_u *did_set_spelllang(win_T *wp)
if (len > 3 && lang[len - 3] == '_') {
region = lang + len - 2;
lang[len - 3] = NUL;
- } else
+ } else {
dont_use_region = true;
+ }
// Check if we loaded this language before.
- for (slang = first_lang; slang != NULL; slang = slang->sl_next)
- if (STRICMP(lang, slang->sl_name) == 0)
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
+ if (STRICMP(lang, slang->sl_name) == 0) {
break;
+ }
+ }
}
if (region != NULL) {
// If the region differs from what was used before then don't
// use it for 'spellfile'.
- if (use_region != NULL && STRCMP(region, use_region) != 0)
+ if (use_region != NULL && STRCMP(region, use_region) != 0) {
dont_use_region = true;
+ }
use_region = region;
}
// If not found try loading the language now.
if (slang == NULL) {
- if (filename)
+ if (filename) {
(void)spell_load_file(lang, lang, NULL, false);
- else {
+ } else {
spell_load_lang(lang);
// SpellFileMissing autocommands may do anything, including
// destroying the buffer we are using...
@@ -2105,16 +2173,19 @@ char_u *did_set_spelllang(win_T *wp)
c = find_region(slang->sl_regions, region);
if (c == REGION_ALL) {
if (slang->sl_add) {
- if (*slang->sl_regions != NUL)
+ if (*slang->sl_regions != NUL) {
// This addition file is for other regions.
region_mask = 0;
- } else
+ }
+ } else {
// This is probably an error. Give a warning and
// accept the words anyway.
smsg(_("Warning: region %s not supported"),
region);
- } else
+ }
+ } else {
region_mask = 1 << c;
+ }
}
if (region_mask != 0) {
@@ -2123,8 +2194,9 @@ char_u *did_set_spelllang(win_T *wp)
p_->lp_region = region_mask;
use_midword(slang, wp);
- if (slang->sl_nobreak)
+ if (slang->sl_nobreak) {
nobreak = true;
+ }
}
}
}
@@ -2138,8 +2210,9 @@ char_u *did_set_spelllang(win_T *wp)
for (round = 0; round == 0 || *spf != NUL; ++round) {
if (round == 0) {
// Internal wordlist, if there is one.
- if (int_wordlist == NULL)
+ if (int_wordlist == NULL) {
continue;
+ }
int_wordlist_spl(spf_name);
} else {
// One entry in 'spellfile'.
@@ -2154,8 +2227,9 @@ char_u *did_set_spelllang(win_T *wp)
break;
}
}
- if (c < ga.ga_len)
+ if (c < ga.ga_len) {
continue;
+ }
}
// Check if it was loaded already.
@@ -2169,31 +2243,34 @@ char_u *did_set_spelllang(win_T *wp)
// Not loaded, try loading it now. The language name includes the
// region name, the region is ignored otherwise. for int_wordlist
// use an arbitrary name.
- if (round == 0)
+ if (round == 0) {
STRCPY(lang, "internal wordlist");
- else {
+ } else {
STRLCPY(lang, path_tail(spf_name), MAXWLEN + 1);
p = vim_strchr(lang, '.');
- if (p != NULL)
+ if (p != NULL) {
*p = NUL; // truncate at ".encoding.add"
+ }
}
slang = spell_load_file(spf_name, lang, NULL, true);
// If one of the languages has NOBREAK we assume the addition
// files also have this.
- if (slang != NULL && nobreak)
+ if (slang != NULL && nobreak) {
slang->sl_nobreak = true;
+ }
}
if (slang != NULL) {
region_mask = REGION_ALL;
if (use_region != NULL && !dont_use_region) {
// find region in sl_regions
c = find_region(slang->sl_regions, use_region);
- if (c != REGION_ALL)
+ if (c != REGION_ALL) {
region_mask = 1 << c;
- else if (*slang->sl_regions != NUL)
+ } else if (*slang->sl_regions != NUL) {
// This spell file is for other regions.
region_mask = 0;
+ }
}
if (region_mask != 0) {
@@ -2219,36 +2296,38 @@ char_u *did_set_spelllang(win_T *wp)
lp = LANGP_ENTRY(ga, i);
// sound folding
- if (!GA_EMPTY(&lp->lp_slang->sl_sal))
+ if (!GA_EMPTY(&lp->lp_slang->sl_sal)) {
// language does sound folding itself
lp->lp_sallang = lp->lp_slang;
- else
+ } else {
// find first similar language that does sound folding
for (int j = 0; j < ga.ga_len; ++j) {
lp2 = LANGP_ENTRY(ga, j);
if (!GA_EMPTY(&lp2->lp_slang->sl_sal)
&& STRNCMP(lp->lp_slang->sl_name,
- lp2->lp_slang->sl_name, 2) == 0) {
+ lp2->lp_slang->sl_name, 2) == 0) {
lp->lp_sallang = lp2->lp_slang;
break;
}
}
+ }
// REP items
- if (!GA_EMPTY(&lp->lp_slang->sl_rep))
+ if (!GA_EMPTY(&lp->lp_slang->sl_rep)) {
// language has REP items itself
lp->lp_replang = lp->lp_slang;
- else
+ } else {
// find first similar language that has REP items
for (int j = 0; j < ga.ga_len; ++j) {
lp2 = LANGP_ENTRY(ga, j);
if (!GA_EMPTY(&lp2->lp_slang->sl_rep)
&& STRNCMP(lp->lp_slang->sl_name,
- lp2->lp_slang->sl_name, 2) == 0) {
+ lp2->lp_slang->sl_name, 2) == 0) {
lp->lp_replang = lp2->lp_slang;
break;
}
}
+ }
}
theend:
@@ -2302,10 +2381,12 @@ static int find_region(char_u *rp, char_u *region)
int i;
for (i = 0;; i += 2) {
- if (rp[i] == NUL)
+ if (rp[i] == NUL) {
return REGION_ALL;
- if (rp[i] == region[0] && rp[i + 1] == region[1])
+ }
+ if (rp[i] == region[0] && rp[i + 1] == region[1]) {
break;
+ }
}
return i / 2;
}
@@ -2323,7 +2404,7 @@ static int find_region(char_u *rp, char_u *region)
int captype(char_u *word, char_u *end)
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *p;
+ char_u *p;
int firstcap;
bool allcap;
bool past_second = false; // past second word char
@@ -2356,10 +2437,12 @@ int captype(char_u *word, char_u *end)
}
}
- if (allcap)
+ if (allcap) {
return WF_ALLCAP;
- if (firstcap)
+ }
+ if (firstcap) {
return WF_ONECAP;
+ }
return 0;
}
@@ -2373,7 +2456,7 @@ static int badword_captype(char_u *word, char_u *end)
int c;
int l, u;
bool first;
- char_u *p;
+ char_u *p;
if (flags & WF_KEEPCAP) {
// Count the number of UPPER and lower case letters.
@@ -2383,23 +2466,27 @@ static int badword_captype(char_u *word, char_u *end)
c = PTR2CHAR(p);
if (SPELL_ISUPPER(c)) {
++u;
- if (p == word)
+ if (p == word) {
first = true;
- } else
+ }
+ } else {
++l;
+ }
}
// If there are more UPPER than lower case letters suggest an
// ALLCAP word. Otherwise, if the first letter is UPPER then
// suggest ONECAP. Exception: "ALl" most likely should be "All",
// require three upper case letters.
- if (u > l && u > 2)
+ if (u > l && u > 2) {
flags |= WF_ALLCAP;
- else if (first)
+ } else if (first) {
flags |= WF_ONECAP;
+ }
- if (u >= 2 && l >= 2) // maCARONI maCAroni
+ if (u >= 2 && l >= 2) { // maCARONI maCAroni
flags |= WF_MIXCAP;
+ }
}
return flags;
}
@@ -2407,7 +2494,7 @@ static int badword_captype(char_u *word, char_u *end)
// Delete the internal wordlist and its .spl file.
void spell_delete_wordlist(void)
{
- char_u fname[MAXPATHL] = {0};
+ char_u fname[MAXPATHL] = { 0 };
if (int_wordlist != NULL) {
os_remove((char *)int_wordlist);
@@ -2420,7 +2507,7 @@ void spell_delete_wordlist(void)
// Free all languages.
void spell_free_all(void)
{
- slang_T *slang;
+ slang_T *slang;
// Go through all buffers and handle 'spelllang'. <VN>
FOR_ALL_BUFFERS(buf) {
@@ -2475,10 +2562,10 @@ static int bytes2offset(char_u **pp)
c = *p++;
if ((c & 0x80) == 0x00) { // 1 byte
nr = c - 1;
- } else if ((c & 0xc0) == 0x80) { // 2 bytes
+ } else if ((c & 0xc0) == 0x80) { // 2 bytes
nr = (c & 0x3f) - 1;
nr = nr * 255 + (*p++ - 1);
- } else if ((c & 0xe0) == 0xc0) { // 3 bytes
+ } else if ((c & 0xe0) == 0xc0) { // 3 bytes
nr = (c & 0x1f) - 1;
nr = nr * 255 + (*p++ - 1);
nr = nr * 255 + (*p++ - 1);
@@ -2537,8 +2624,9 @@ void clear_spell_chartab(spelltab_T *sp)
// We include digits. A word shouldn't start with a digit, but handling
// that is done separately.
- for (i = '0'; i <= '9'; ++i)
+ for (i = '0'; i <= '9'; ++i) {
sp->st_isw[i] = true;
+ }
for (i = 'A'; i <= 'Z'; ++i) {
sp->st_isw[i] = true;
sp->st_isu[i] = true;
@@ -2627,9 +2715,10 @@ bool spell_iswordp_nmw(const char_u *p, win_T *wp)
static bool spell_mb_isword_class(int cl, const win_T *wp)
FUNC_ATTR_PURE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (wp->w_s->b_cjk)
+ if (wp->w_s->b_cjk) {
// East Asian characters are not considered word characters.
return cl == 2 || cl == 0x2800;
+ }
return cl >= 2 && cl != 0x2070 && cl != 0x2080 && cl != 3;
}
@@ -2641,11 +2730,12 @@ static bool spell_iswordp_w(const int *p, const win_T *wp)
const int *s;
if (*p < 256 ? wp->w_s->b_spell_ismw[*p]
- : (wp->w_s->b_spell_ismw_mb != NULL
- && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL))
+ : (wp->w_s->b_spell_ismw_mb != NULL
+ && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL)) {
s = p + 1;
- else
+ } else {
s = p;
+ }
if (*s > 255) {
return spell_mb_isword_class(utf_class(*s), wp);
@@ -2657,8 +2747,7 @@ static bool spell_iswordp_w(const int *p, const win_T *wp)
// Uses the character definitions from the .spl file.
// When using a multi-byte 'encoding' the length may change!
// Returns FAIL when something wrong.
-int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf,
- int buflen)
+int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int buflen)
FUNC_ATTR_NONNULL_ALL
{
if (len >= buflen) {
@@ -2708,8 +2797,8 @@ static int sps_limit = 9999; // max nr of suggestions given
// Sets "sps_flags" and "sps_limit".
int spell_check_sps(void)
{
- char_u *p;
- char_u *s;
+ char_u *p;
+ char_u *s;
char_u buf[MAXPATHL];
int f;
@@ -2742,12 +2831,14 @@ int spell_check_sps(void)
sps_limit = 9999;
return FAIL;
}
- if (f != 0)
+ if (f != 0) {
sps_flags = f;
+ }
}
- if (sps_flags == 0)
+ if (sps_flags == 0) {
sps_flags = SPS_BEST;
+ }
return OK;
}
@@ -2758,13 +2849,13 @@ int spell_check_sps(void)
// When "count" is non-zero use that suggestion.
void spell_suggest(int count)
{
- char_u *line;
+ char_u *line;
pos_T prev_cursor = curwin->w_cursor;
char_u wcopy[MAXWLEN + 2];
- char_u *p;
+ char_u *p;
int c;
suginfo_T sug;
- suggest_T *stp;
+ suggest_T *stp;
int mouse_used;
int need_cap;
int limit;
@@ -2833,36 +2924,39 @@ void spell_suggest(int count)
// Get the list of suggestions. Limit to 'lines' - 2 or the number in
// 'spellsuggest', whatever is smaller.
- if (sps_limit > (int)Rows - 2)
+ if (sps_limit > (int)Rows - 2) {
limit = (int)Rows - 2;
- else
+ } else {
limit = sps_limit;
+ }
spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit,
- true, need_cap, true);
+ true, need_cap, true);
- if (GA_EMPTY(&sug.su_ga))
+ if (GA_EMPTY(&sug.su_ga)) {
MSG(_("Sorry, no suggestions"));
- else if (count > 0) {
- if (count > sug.su_ga.ga_len)
+ } else if (count > 0) {
+ if (count > sug.su_ga.ga_len) {
smsg(_("Sorry, only %" PRId64 " suggestions"),
(int64_t)sug.su_ga.ga_len);
+ }
} else {
// When 'rightleft' is set the list is drawn right-left.
cmdmsg_rl = curwin->w_p_rl;
- if (cmdmsg_rl)
+ if (cmdmsg_rl) {
msg_col = Columns - 1;
+ }
// List the suggestions.
msg_start();
msg_row = Rows - 1; // for when 'cmdheight' > 1
lines_left = Rows; // avoid more prompt
vim_snprintf((char *)IObuff, IOSIZE, _("Change \"%.*s\" to:"),
- sug.su_badlen, sug.su_badptr);
+ sug.su_badlen, sug.su_badptr);
if (cmdmsg_rl && STRNCMP(IObuff, "Change", 6) == 0) {
// And now the rabbit from the high hat: Avoid showing the
// untranslated message rightleft.
vim_snprintf((char *)IObuff, IOSIZE, ":ot \"%.*s\" egnahC",
- sug.su_badlen, sug.su_badptr);
+ sug.su_badlen, sug.su_badptr);
}
msg_puts((const char *)IObuff);
msg_clr_eos();
@@ -2875,10 +2969,11 @@ void spell_suggest(int count)
// The suggested word may replace only part of the bad word, add
// the not replaced part.
STRLCPY(wcopy, stp->st_word, MAXWLEN + 1);
- if (sug.su_badlen > stp->st_orglen)
+ if (sug.su_badlen > stp->st_orglen) {
STRLCPY(wcopy + stp->st_wordlen,
- sug.su_badptr + stp->st_orglen,
- sug.su_badlen - stp->st_orglen + 1);
+ sug.su_badptr + stp->st_orglen,
+ sug.su_badlen - stp->st_orglen + 1);
+ }
vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1);
if (cmdmsg_rl) {
rl_mirror(IObuff);
@@ -2897,16 +2992,18 @@ void spell_suggest(int count)
if (p_verbose > 0) {
// Add the score.
- if (sps_flags & (SPS_DOUBLE | SPS_BEST))
+ if (sps_flags & (SPS_DOUBLE | SPS_BEST)) {
vim_snprintf((char *)IObuff, IOSIZE, " (%s%d - %d)",
- stp->st_salscore ? "s " : "",
- stp->st_score, stp->st_altscore);
- else
+ stp->st_salscore ? "s " : "",
+ stp->st_score, stp->st_altscore);
+ } else {
vim_snprintf((char *)IObuff, IOSIZE, " (%d)",
- stp->st_score);
- if (cmdmsg_rl)
+ stp->st_score);
+ }
+ if (cmdmsg_rl) {
// Mirror the numbers, but keep the leading space.
rl_mirror(IObuff + 1);
+ }
msg_advance(30);
msg_puts((const char *)IObuff);
}
@@ -2941,8 +3038,8 @@ void spell_suggest(int count)
// repl_to.
repl_from = vim_strnsave(sug.su_badptr, sug.su_badlen);
vim_snprintf((char *)IObuff, IOSIZE, "%s%.*s", stp->st_word,
- sug.su_badlen - stp->st_orglen,
- sug.su_badptr + stp->st_orglen);
+ sug.su_badlen - stp->st_orglen,
+ sug.su_badptr + stp->st_orglen);
repl_to = vim_strsave(IObuff);
} else {
// Replacing su_badlen or more, use the whole word.
@@ -2961,7 +3058,7 @@ void spell_suggest(int count)
ResetRedobuff();
AppendToRedobuff("ciw");
AppendToRedobuffLit(p + c,
- stp->st_wordlen + sug.su_badlen - stp->st_orglen);
+ stp->st_wordlen + sug.su_badlen - stp->st_orglen);
AppendCharToRedobuff(ESC);
// "p" may be freed here
@@ -2969,8 +3066,9 @@ void spell_suggest(int count)
curwin->w_cursor.col = c;
changed_bytes(curwin->w_cursor.lnum, c);
- } else
+ } else {
curwin->w_cursor = prev_cursor;
+ }
spell_find_cleanup(&sug);
xfree(line);
@@ -2982,27 +3080,28 @@ void spell_suggest(int count)
static bool check_need_cap(linenr_T lnum, colnr_T col)
{
bool need_cap = false;
- char_u *line;
- char_u *line_copy = NULL;
- char_u *p;
+ char_u *line;
+ char_u *line_copy = NULL;
+ char_u *p;
colnr_T endcol;
regmatch_T regmatch;
- if (curwin->w_s->b_cap_prog == NULL)
+ if (curwin->w_s->b_cap_prog == NULL) {
return false;
+ }
line = get_cursor_line_ptr();
endcol = 0;
if (getwhitecols(line) >= (int)col) {
// At start of line, check if previous line is empty or sentence
// ends there.
- if (lnum == 1)
+ if (lnum == 1) {
need_cap = true;
- else {
+ } else {
line = ml_get(lnum - 1);
- if (*skipwhite(line) == NUL)
+ if (*skipwhite(line) == NUL) {
need_cap = true;
- else {
+ } else {
// Append a space in place of the line break.
line_copy = concat_str(line, (char_u *)" ");
line = line_copy;
@@ -3042,10 +3141,10 @@ static bool check_need_cap(linenr_T lnum, colnr_T col)
void ex_spellrepall(exarg_T *eap)
{
pos_T pos = curwin->w_cursor;
- char_u *frompat;
+ char_u *frompat;
int addlen;
- char_u *line;
- char_u *p;
+ char_u *line;
+ char_u *p;
bool save_ws = p_ws;
linenr_T prev_lnum = 0;
@@ -3072,7 +3171,7 @@ void ex_spellrepall(exarg_T *eap)
// when changing "etc" to "etc.".
line = get_cursor_line_ptr();
if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col,
- repl_to, STRLEN(repl_to)) != 0) {
+ repl_to, STRLEN(repl_to)) != 0) {
p = xmalloc(STRLEN(line) + addlen + 1);
memmove(p, line, curwin->w_cursor.col);
STRCPY(p + curwin->w_cursor.col, repl_to);
@@ -3093,26 +3192,23 @@ void ex_spellrepall(exarg_T *eap)
curwin->w_cursor = pos;
xfree(frompat);
- if (sub_nsubs == 0)
+ if (sub_nsubs == 0) {
EMSG2(_("E753: Not found: %s"), repl_from);
- else
+ } else {
do_sub_msg(false);
+ }
}
-// Find spell suggestions for "word". Return them in the growarray "*gap" as
-// a list of allocated strings.
-void
-spell_suggest_list (
- garray_T *gap,
- char_u *word,
- int maxcount, // maximum nr of suggestions
- bool need_cap, // 'spellcapcheck' matched
- bool interactive
-)
+/// Find spell suggestions for "word". Return them in the growarray "*gap" as
+/// a list of allocated strings.
+///
+/// @param maxcount maximum nr of suggestions
+/// @param need_cap 'spellcapcheck' matched
+void spell_suggest_list(garray_T *gap, char_u *word, int maxcount, bool need_cap, bool interactive)
{
suginfo_T sug;
- suggest_T *stp;
- char_u *wcopy;
+ suggest_T *stp;
+ char_u *wcopy;
spell_find_suggest(word, 0, &sug, maxcount, false, need_cap, interactive);
@@ -3134,44 +3230,41 @@ spell_suggest_list (
spell_find_cleanup(&sug);
}
-// Find spell suggestions for the word at the start of "badptr".
-// Return the suggestions in "su->su_ga".
-// The maximum number of suggestions is "maxcount".
-// Note: does use info for the current window.
-// This is based on the mechanisms of Aspell, but completely reimplemented.
-static void
-spell_find_suggest (
- char_u *badptr,
- int badlen, // length of bad word or 0 if unknown
- suginfo_T *su,
- int maxcount,
- bool banbadword, // don't include badword in suggestions
- bool need_cap, // word should start with capital
- bool interactive
-)
+/// Find spell suggestions for the word at the start of "badptr".
+/// Return the suggestions in "su->su_ga".
+/// The maximum number of suggestions is "maxcount".
+/// Note: does use info for the current window.
+/// This is based on the mechanisms of Aspell, but completely reimplemented.
+///
+/// @param badlen length of bad word or 0 if unknown
+/// @param banbadword don't include badword in suggestions
+/// @param need_cap word should start with capital
+static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int maxcount,
+ bool banbadword, bool need_cap, bool interactive)
{
hlf_T attr = HLF_COUNT;
char_u buf[MAXPATHL];
- char_u *p;
+ char_u *p;
bool do_combine = false;
- char_u *sps_copy;
+ char_u *sps_copy;
static bool expr_busy = false;
int c;
- langp_T *lp;
+ langp_T *lp;
bool did_intern = false;
// Set the info in "*su".
memset(su, 0, sizeof(suginfo_T));
ga_init(&su->su_ga, (int)sizeof(suggest_T), 10);
ga_init(&su->su_sga, (int)sizeof(suggest_T), 10);
- if (*badptr == NUL)
+ if (*badptr == NUL) {
return;
+ }
hash_init(&su->su_banned);
su->su_badptr = badptr;
- if (badlen != 0)
+ if (badlen != 0) {
su->su_badlen = badlen;
- else {
+ } else {
size_t tmplen = spell_check(curwin, su->su_badptr, &attr, NULL, false);
assert(tmplen <= INT_MAX);
su->su_badlen = (int)tmplen;
@@ -3179,8 +3272,9 @@ spell_find_suggest (
su->su_maxcount = maxcount;
su->su_maxscore = SCORE_MAXINIT;
- if (su->su_badlen >= MAXWLEN)
+ if (su->su_badlen >= MAXWLEN) {
su->su_badlen = MAXWLEN - 1; // just in case
+ }
STRLCPY(su->su_badword, su->su_badptr, su->su_badlen + 1);
(void)spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword,
MAXWLEN);
@@ -3192,9 +3286,10 @@ spell_find_suggest (
// get caps flags for bad word
su->su_badflags = badword_captype(su->su_badptr,
- su->su_badptr + su->su_badlen);
- if (need_cap)
+ su->su_badptr + su->su_badlen);
+ if (need_cap) {
su->su_badflags |= WF_ONECAP;
+ }
// Find the default language for sound folding. We simply use the first
// one in 'spelllang' that supports sound folding. That's good for when
@@ -3210,9 +3305,10 @@ spell_find_suggest (
// Soundfold the bad word with the default sound folding, so that we don't
// have to do this many times.
- if (su->su_sallang != NULL)
+ if (su->su_sallang != NULL) {
spell_soundfold(su->su_sallang, su->su_fbadword, true,
- su->su_sal_badword);
+ su->su_sal_badword);
+ }
// If the word is not capitalised and spell_check() doesn't consider the
// word to be bad then it might need to be capitalised. Add a suggestion
@@ -3221,12 +3317,13 @@ spell_find_suggest (
if (!SPELL_ISUPPER(c) && attr == HLF_COUNT) {
make_case_word(su->su_badword, buf, WF_ONECAP);
add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE,
- 0, true, su->su_sallang, false);
+ 0, true, su->su_sallang, false);
}
// Ban the bad word itself. It may appear in another region.
- if (banbadword)
+ if (banbadword) {
add_banned(su, su->su_badword);
+ }
// Make a copy of 'spellsuggest', because the expression may change it.
sps_copy = vim_strsave(p_sps);
@@ -3258,10 +3355,11 @@ spell_find_suggest (
xfree(sps_copy);
- if (do_combine)
+ if (do_combine) {
// Combine the two list of suggestions. This must be done last,
// because sorting changes the order again.
score_combine(su);
+ }
}
// Find suggestions by evaluating expression "expr".
@@ -3297,9 +3395,9 @@ static void spell_suggest_expr(suginfo_T *su, char_u *expr)
// Find suggestions in file "fname". Used for "file:" in 'spellsuggest'.
static void spell_suggest_file(suginfo_T *su, char_u *fname)
{
- FILE *fd;
+ FILE *fd;
char_u line[MAXWLEN * 2];
- char_u *p;
+ char_u *p;
int len;
char_u cword[MAXWLEN];
@@ -3315,13 +3413,15 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname)
line_breakcheck();
p = vim_strchr(line, '/');
- if (p == NULL)
+ if (p == NULL) {
continue; // No Tab found, just skip the line.
+ }
*p++ = NUL;
if (STRICMP(su->su_badword, line) == 0) {
// Match! Isolate the good word, until CR or NL.
- for (len = 0; p[len] >= ' '; ++len)
+ for (len = 0; p[len] >= ' '; ++len) {
;
+ }
p[len] = NUL;
// If the suggestion doesn't have specific case duplicate the case
@@ -3332,7 +3432,7 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname)
}
add_suggestion(su, &su->su_ga, p, su->su_badlen,
- SCORE_FILE, 0, true, su->su_sallang, false);
+ SCORE_FILE, 0, true, su->su_sallang, false);
}
}
@@ -3360,15 +3460,17 @@ static void spell_suggest_intern(suginfo_T *su, bool interactive)
suggest_try_change(su);
// For the resulting top-scorers compute the sound-a-like score.
- if (sps_flags & SPS_DOUBLE)
+ if (sps_flags & SPS_DOUBLE) {
score_comp_sal(su);
+ }
// 3. Try finding sound-a-like words.
if ((sps_flags & SPS_FAST) == 0) {
- if (sps_flags & SPS_BEST)
+ if (sps_flags & SPS_BEST) {
// Adjust the word score for the suggestions found so far for how
// they sounds like.
rescore_suggestions(su);
+ }
// While going through the soundfold tree "su_maxscore" is the score
// for the soundfold word, limits the changes that are being tried,
@@ -3407,9 +3509,10 @@ static void spell_suggest_intern(suginfo_T *su, bool interactive)
}
if ((sps_flags & SPS_DOUBLE) == 0 && su->su_ga.ga_len != 0) {
- if (sps_flags & SPS_BEST)
+ if (sps_flags & SPS_BEST) {
// Adjust the word score for how it sounds like.
rescore_suggestions(su);
+ }
// Remove bogus suggestions, sort and truncate at "maxcount".
check_suggestions(su, &su->su_ga);
@@ -3420,7 +3523,7 @@ static void spell_suggest_intern(suginfo_T *su, bool interactive)
// Free the info put in "*su" by spell_find_suggest().
static void spell_find_cleanup(suginfo_T *su)
{
-# define FREE_SUG_WORD(sug) xfree(sug->st_word)
+#define FREE_SUG_WORD(sug) xfree(sug->st_word)
// Free the suggestions.
GA_DEEP_CLEAR(&su->su_ga, suggest_T, FREE_SUG_WORD);
GA_DEEP_CLEAR(&su->su_sga, suggest_T, FREE_SUG_WORD);
@@ -3459,11 +3562,13 @@ static void allcap_copy(char_u *word, char_u *wcopy)
if (c == 0xdf) {
c = 'S';
- if (d - wcopy >= MAXWLEN - 1)
+ if (d - wcopy >= MAXWLEN - 1) {
break;
+ }
*d++ = c;
- } else
+ } else {
c = SPELL_TOUPPER(c);
+ }
if (d - wcopy >= MAXWLEN - MB_MAXBYTES) {
break;
@@ -3476,7 +3581,7 @@ static void allcap_copy(char_u *word, char_u *wcopy)
// Try finding suggestions by recognizing specific situations.
static void suggest_try_special(suginfo_T *su)
{
- char_u *p;
+ char_u *p;
size_t len;
int c;
char_u word[MAXWLEN];
@@ -3496,7 +3601,7 @@ static void suggest_try_special(suginfo_T *su)
// Give a soundalike score of 0, compute the score as if deleting one
// character.
add_suggestion(su, &su->su_ga, word, su->su_badlen,
- RESCORE(SCORE_REP, 0), 0, true, su->su_sallang, false);
+ RESCORE(SCORE_REP, 0), 0, true, su->su_sallang, false);
}
}
@@ -3509,8 +3614,7 @@ proftime_T total;
proftime_T times[STATE_FINAL + 1];
long counts[STATE_FINAL + 1];
- static void
-prof_init(void)
+static void prof_init(void)
{
for (int i = 0; i <= STATE_FINAL; i++) {
profile_zero(&times[i]);
@@ -3521,8 +3625,7 @@ prof_init(void)
}
// call before changing state
- static void
-prof_store(state_T state)
+static void prof_store(state_T state)
{
profile_end(&current);
profile_add(&times[state], &current);
@@ -3531,8 +3634,7 @@ prof_store(state_T state)
}
# define PROF_STORE(state) prof_store(state);
- static void
-prof_report(char *name)
+static void prof_report(char *name)
{
FILE *fd = fopen("suggestprof", "a");
@@ -3554,8 +3656,8 @@ static void suggest_try_change(suginfo_T *su)
{
char_u fword[MAXWLEN]; // copy of the bad word, case-folded
int n;
- char_u *p;
- langp_T *lp;
+ char_u *p;
+ langp_T *lp;
// We make a copy of the case-folded bad word, so that we can modify it
// to find matches (esp. REP items). Append some more text, changing
@@ -3570,8 +3672,9 @@ static void suggest_try_change(suginfo_T *su)
// If reloading a spell file fails it's still in the list but
// everything has been cleared.
- if (lp->lp_slang->sl_fbyts == NULL)
+ if (lp->lp_slang->sl_fbyts == NULL) {
continue;
+ }
// Try it for this language. Will add possible suggestions.
//
@@ -3623,28 +3726,28 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
char_u tword[MAXWLEN]; // good word collected so far
trystate_T stack[MAXWLEN];
char_u preword[MAXWLEN * 3] = { 0 }; // word found with proper case;
- // concatenation of prefix compound
- // words and split word. NUL terminated
- // when going deeper but not when coming
- // back.
+ // concatenation of prefix compound
+ // words and split word. NUL terminated
+ // when going deeper but not when coming
+ // back.
char_u compflags[MAXWLEN]; // compound flags, one for each word
- trystate_T *sp;
+ trystate_T *sp;
int newscore;
int score;
- char_u *byts, *fbyts, *pbyts;
- idx_T *idxs, *fidxs, *pidxs;
+ char_u *byts, *fbyts, *pbyts;
+ idx_T *idxs, *fidxs, *pidxs;
int depth;
int c, c2, c3;
int n = 0;
int flags;
- garray_T *gap;
+ garray_T *gap;
idx_T arridx;
int len;
- char_u *p;
- fromto_T *ftp;
+ char_u *p;
+ fromto_T *ftp;
int fl = 0, tl;
int repextra = 0; // extra bytes in fword[] from REP item
- slang_T *slang = lp->lp_slang;
+ slang_T *slang = lp->lp_slang;
int fword_ends;
bool goodword_ends;
#ifdef DEBUG_TRIEWALK
@@ -3709,8 +3812,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_prefixdepth == PFD_PREFIXTREE) {
// Skip over the NUL bytes, we use them later.
- for (n = 0; n < len && byts[arridx + n] == 0; ++n)
+ for (n = 0; n < len && byts[arridx + n] == 0; ++n) {
;
+ }
sp->ts_curi += n;
// Always past NUL bytes now.
@@ -3727,7 +3831,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
flags = badword_captype(su->su_badptr, su->su_badptr + n);
su->su_badflags = badword_captype(su->su_badptr + n,
- su->su_badptr + su->su_badlen);
+ su->su_badptr + su->su_badlen);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "prefix");
#endif
@@ -3743,7 +3847,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// and make find_keepcap_word() works.
tword[sp->ts_twordlen] = NUL;
make_case_word(tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen, flags);
+ preword + sp->ts_prewordlen, flags);
sp->ts_prewordlen = (char_u)STRLEN(preword);
sp->ts_splitoff = sp->ts_twordlen;
}
@@ -3764,8 +3868,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
flags = (int)idxs[arridx];
// Skip words with the NOSUGGEST flag.
- if (flags & WF_NOSUGGEST)
+ if (flags & WF_NOSUGGEST) {
break;
+ }
fword_ends = (fword[sp->ts_fidx] == NUL
|| (soundfold
@@ -3782,17 +3887,20 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// none this must be the first try without a prefix.
n = stack[sp->ts_prefixdepth].ts_arridx;
len = pbyts[n++];
- for (c = 0; c < len && pbyts[n + c] == 0; ++c)
+ for (c = 0; c < len && pbyts[n + c] == 0; ++c) {
;
+ }
if (c > 0) {
c = valid_word_prefix(c, n, flags,
- tword + sp->ts_splitoff, slang, false);
- if (c == 0)
+ tword + sp->ts_splitoff, slang, false);
+ if (c == 0) {
break;
+ }
// Use the WF_RARE flag for a rare prefix.
- if (c & WF_RAREPFX)
+ if (c & WF_RAREPFX) {
flags |= WF_RARE;
+ }
// Tricky: when checking for both prefix and compounding
// we run into the prefix flag first.
@@ -3805,10 +3913,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Check NEEDCOMPOUND: can't use word without compounding. Do try
// appending another compound word below.
if (sp->ts_complen == sp->ts_compsplit && fword_ends
- && (flags & WF_NEEDCOMP))
+ && (flags & WF_NEEDCOMP)) {
goodword_ends = false;
- else
+ } else {
goodword_ends = true;
+ }
p = NULL;
compound_ok = true;
@@ -3821,18 +3930,19 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_fidx - sp->ts_splitfidx
== sp->ts_twordlen - sp->ts_splitoff
&& STRNCMP(fword + sp->ts_splitfidx,
- tword + sp->ts_splitoff,
- sp->ts_fidx - sp->ts_splitfidx) == 0) {
+ tword + sp->ts_splitoff,
+ sp->ts_fidx - sp->ts_splitfidx) == 0) {
preword[sp->ts_prewordlen] = NUL;
newscore = score_wordcount_adj(slang, sp->ts_score,
- preword + sp->ts_prewordlen,
- sp->ts_prewordlen > 0);
+ preword + sp->ts_prewordlen,
+ sp->ts_prewordlen > 0);
// Add the suggestion if the score isn't too bad.
- if (newscore <= su->su_maxscore)
+ if (newscore <= su->su_maxscore) {
add_suggestion(su, &su->su_ga, preword,
- sp->ts_splitfidx - repextra,
- newscore, 0, false,
- lp->lp_sallang, false);
+ sp->ts_splitfidx - repextra,
+ newscore, 0, false,
+ lp->lp_sallang, false);
+ }
break;
}
} else {
@@ -3856,23 +3966,26 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
compflags[sp->ts_complen] = ((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
STRLCPY(preword + sp->ts_prewordlen,
- tword + sp->ts_splitoff,
- sp->ts_twordlen - sp->ts_splitoff + 1);
+ tword + sp->ts_splitoff,
+ sp->ts_twordlen - sp->ts_splitoff + 1);
// Verify CHECKCOMPOUNDPATTERN rules.
if (match_checkcompoundpattern(preword, sp->ts_prewordlen,
- &slang->sl_comppat))
+ &slang->sl_comppat)) {
compound_ok = false;
+ }
if (compound_ok) {
p = preword;
- while (*skiptowhite(p) != NUL)
+ while (*skiptowhite(p) != NUL) {
p = skipwhite(skiptowhite(p));
+ }
if (fword_ends && !can_compound(slang, p,
- compflags + sp->ts_compsplit))
+ compflags + sp->ts_compsplit)) {
// Compound is not allowed. But it may still be
// possible if we add another (short) word.
compound_ok = false;
+ }
}
// Get pointer to last char of previous word.
@@ -3884,29 +3997,31 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Form the word with proper case in preword.
// If there is a word from a previous split, append.
// For the soundfold tree don't change the case, simply append.
- if (soundfold)
+ if (soundfold) {
STRCPY(preword + sp->ts_prewordlen, tword + sp->ts_splitoff);
- else if (flags & WF_KEEPCAP)
+ } else if (flags & WF_KEEPCAP) {
// Must find the word in the keep-case tree.
find_keepcap_word(slang, tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen);
- else {
+ preword + sp->ts_prewordlen);
+ } else {
// Include badflags: If the badword is onecap or allcap
// use that for the goodword too. But if the badword is
// allcap and it's only one char long use onecap.
c = su->su_badflags;
if ((c & WF_ALLCAP)
- && su->su_badlen == (*mb_ptr2len)(su->su_badptr)
- )
+ && su->su_badlen ==
+ (*mb_ptr2len)(su->su_badptr)) {
c = WF_ONECAP;
+ }
c |= flags;
// When appending a compound word after a word character don't
// use Onecap.
- if (p != NULL && spell_iswordp_nmw(p, curwin))
+ if (p != NULL && spell_iswordp_nmw(p, curwin)) {
c &= ~WF_ONECAP;
+ }
make_case_word(tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen, c);
+ preword + sp->ts_prewordlen, c);
}
if (!soundfold) {
@@ -3919,8 +4034,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if ((sp->ts_complen == sp->ts_compsplit
&& WAS_BANNED(su, preword + sp->ts_prewordlen))
|| WAS_BANNED(su, preword)) {
- if (slang->sl_compprog == NULL)
+ if (slang->sl_compprog == NULL) {
break;
+ }
// the word so far was banned but we may try compounding
goodword_ends = false;
}
@@ -3929,14 +4045,17 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
newscore = 0;
if (!soundfold) { // soundfold words don't have flags
if ((flags & WF_REGION)
- && (((unsigned)flags >> 16) & lp->lp_region) == 0)
+ && (((unsigned)flags >> 16) & lp->lp_region) == 0) {
newscore += SCORE_REGION;
- if (flags & WF_RARE)
+ }
+ if (flags & WF_RARE) {
newscore += SCORE_RARE;
+ }
if (!spell_valid_case(su->su_badflags,
- captype(preword + sp->ts_prewordlen, NULL)))
+ captype(preword + sp->ts_prewordlen, NULL))) {
newscore += SCORE_ICASE;
+ }
}
// TODO: how about splitting in the soundfold tree?
@@ -3951,15 +4070,16 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// print the stack of changes that brought us here
smsg("------ %s -------", fword);
- for (j = 0; j < depth; ++j)
+ for (j = 0; j < depth; ++j) {
smsg("%s", changename[j]);
+ }
}
#endif
if (soundfold) {
// For soundfolded words we need to find the original
// words, the edit distance and then add them.
add_sound_suggest(su, preword, sp->ts_score, lp);
- } else if (sp->ts_fidx > 0) {
+ } else if (sp->ts_fidx > 0) {
// Give a penalty when changing non-word char to word
// char, e.g., "thes," -> "these".
p = fword + sp->ts_fidx;
@@ -3974,15 +4094,15 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Give a bonus to words seen before.
score = score_wordcount_adj(slang,
- sp->ts_score + newscore,
- preword + sp->ts_prewordlen,
- sp->ts_prewordlen > 0);
+ sp->ts_score + newscore,
+ preword + sp->ts_prewordlen,
+ sp->ts_prewordlen > 0);
// Add the suggestion if the score isn't too bad.
if (score <= su->su_maxscore) {
add_suggestion(su, &su->su_ga, preword,
- sp->ts_fidx - repextra,
- score, 0, false, lp->lp_sallang, false);
+ sp->ts_fidx - repextra,
+ score, 0, false, lp->lp_sallang, false);
if (su->su_badflags & WF_MIXCAP) {
// We really don't know if the word should be
@@ -3990,13 +4110,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
c = captype(preword, NULL);
if (c == 0 || c == WF_ALLCAP) {
make_case_word(tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen,
- c == 0 ? WF_ALLCAP : 0);
+ preword + sp->ts_prewordlen,
+ c == 0 ? WF_ALLCAP : 0);
add_suggestion(su, &su->su_ga, preword,
- sp->ts_fidx - repextra,
- score + SCORE_ICASE, 0, false,
- lp->lp_sallang, false);
+ sp->ts_fidx - repextra,
+ score + SCORE_ICASE, 0, false,
+ lp->lp_sallang, false);
}
}
}
@@ -4006,8 +4126,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Try word split and/or compounding.
if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
// Don't split in the middle of a character
- && (sp->ts_tcharlen == 0)
- ) {
+ && (sp->ts_tcharlen == 0)) {
bool try_compound;
int try_split;
@@ -4045,7 +4164,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
|| sp->ts_complen + 1 - sp->ts_compsplit
< slang->sl_compmax)
&& (can_be_compound(sp, slang,
- compflags, ((unsigned)flags >> 24)))) {
+ compflags, ((unsigned)flags >> 24)))) {
try_compound = true;
compflags[sp->ts_complen] = ((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
@@ -4076,35 +4195,40 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// is only one word it must not have the NEEDCOMPOUND
// flag.
if (sp->ts_complen == sp->ts_compsplit
- && (flags & WF_NEEDCOMP))
+ && (flags & WF_NEEDCOMP)) {
break;
+ }
p = preword;
- while (*skiptowhite(p) != NUL)
+ while (*skiptowhite(p) != NUL) {
p = skipwhite(skiptowhite(p));
+ }
if (sp->ts_complen > sp->ts_compsplit
&& !can_compound(slang, p,
- compflags + sp->ts_compsplit))
+ compflags + sp->ts_compsplit)) {
break;
+ }
- if (slang->sl_nosplitsugs)
+ if (slang->sl_nosplitsugs) {
newscore += SCORE_SPLIT_NO;
- else
+ } else {
newscore += SCORE_SPLIT;
+ }
// Give a bonus to words seen before.
newscore = score_wordcount_adj(slang, newscore,
- preword + sp->ts_prewordlen, true);
+ preword + sp->ts_prewordlen, true);
}
if (TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
- if (!try_compound && !fword_ends)
+ if (!try_compound && !fword_ends) {
sprintf(changename[depth], "%.*s-%s: split",
- sp->ts_twordlen, tword, fword + sp->ts_fidx);
- else
+ sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ } else {
sprintf(changename[depth], "%.*s-%s: compound",
- sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ }
#endif
// Save things to be restored at STATE_SPLITUNDO.
sp->ts_save_badflags = su->su_badflags;
@@ -4115,8 +4239,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp = &stack[depth];
// Append a space to preword when splitting.
- if (!try_compound && !fword_ends)
+ if (!try_compound && !fword_ends) {
STRCAT(preword, " ");
+ }
sp->ts_prewordlen = (char_u)STRLEN(preword);
sp->ts_splitoff = sp->ts_twordlen;
sp->ts_splitfidx = sp->ts_fidx;
@@ -4127,8 +4252,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// character when the word ends. But only when the
// good word can end.
if (((!try_compound && !spell_iswordp_nmw(fword
- + sp->ts_fidx,
- curwin))
+ + sp->ts_fidx,
+ curwin))
|| fword_ends)
&& fword[sp->ts_fidx] != NUL
&& goodword_ends) {
@@ -4138,28 +4263,30 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (fword_ends) {
// Copy the skipped character to preword.
memmove(preword + sp->ts_prewordlen,
- fword + sp->ts_fidx, l);
+ fword + sp->ts_fidx, l);
sp->ts_prewordlen += l;
preword[sp->ts_prewordlen] = NUL;
- } else
+ } else {
sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
+ }
sp->ts_fidx += l;
}
// When compounding include compound flag in
// compflags[] (already set above). When splitting we
// may start compounding over again.
- if (try_compound)
+ if (try_compound) {
++sp->ts_complen;
- else
+ } else {
sp->ts_compsplit = sp->ts_complen;
+ }
sp->ts_prefixdepth = PFD_NOPREFIX;
// set su->su_badflags to the caps type at this
// position
n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
su->su_badflags = badword_captype(su->su_badptr + n,
- su->su_badptr + su->su_badlen);
+ su->su_badptr + su->su_badlen);
// Restart at top of the tree.
sp->ts_arridx = 0;
@@ -4194,8 +4321,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Past the NUL bytes in the node.
su->su_badflags = sp->ts_save_badflags;
if (fword[sp->ts_fidx] == NUL
- && sp->ts_tcharlen == 0
- ) {
+ && sp->ts_tcharlen == 0) {
// The badword ends, can't use STATE_PLAIN.
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_DEL;
@@ -4228,11 +4354,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// just deleted this byte, accepting it is always cheaper than
// delete + substitute.
if (c == fword[sp->ts_fidx]
- || (sp->ts_tcharlen > 0 && sp->ts_isdiff != DIFF_NONE)
- )
+ || (sp->ts_tcharlen > 0 &&
+ sp->ts_isdiff != DIFF_NONE)) {
newscore = 0;
- else
+ } else {
newscore = SCORE_SUBST;
+ }
if ((newscore == 0
|| (sp->ts_fidx >= sp->ts_fidxtry
&& ((sp->ts_flags & TSF_DIDDEL) == 0
@@ -4240,14 +4367,15 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
&& TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
- if (newscore > 0)
+ if (newscore > 0) {
sprintf(changename[depth], "%.*s-%s: subst %c to %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- fword[sp->ts_fidx], c);
- else
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx], c);
+ } else {
sprintf(changename[depth], "%.*s-%s: accept %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- fword[sp->ts_fidx]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx]);
+ }
#endif
++depth;
sp = &stack[depth];
@@ -4289,12 +4417,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
+ sp->ts_fcharstart))) {
sp->ts_score -= SCORE_SUBST - SCORE_SUBCOMP;
} else if (
- !soundfold
- && slang->sl_has_map
- && similar_chars(
- slang,
- utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen),
- utf_ptr2char(fword + sp->ts_fcharstart))) {
+ !soundfold
+ && slang->sl_has_map
+ && similar_chars(slang,
+ utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen),
+ utf_ptr2char(fword + sp->ts_fcharstart))) {
// For a similar character adjust score from
// SCORE_SUBST to SCORE_SIMILAR.
sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR;
@@ -4339,19 +4466,20 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_INS_PREP;
sp->ts_curi = 1;
- if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*')
+ if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*') {
// Deleting a vowel at the start of a word counts less, see
// soundalike_score().
newscore = 2 * SCORE_DEL / 3;
- else
+ } else {
newscore = SCORE_DEL;
+ }
if (fword[sp->ts_fidx] != NUL
&& TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: delete %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- fword[sp->ts_fidx]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx]);
#endif
++depth;
@@ -4421,19 +4549,20 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// accepting that byte is always better.
n += sp->ts_curi++;
c = byts[n];
- if (soundfold && sp->ts_twordlen == 0 && c == '*')
+ if (soundfold && sp->ts_twordlen == 0 && c == '*') {
// Inserting a vowel at the start of a word counts less,
// see soundalike_score().
newscore = 2 * SCORE_INS / 3;
- else
+ } else {
newscore = SCORE_INS;
+ }
if (c != fword[sp->ts_fidx]
&& TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: insert %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- c);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c);
#endif
++depth;
sp = &stack[depth];
@@ -4454,8 +4583,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// soundfold words (illogical but does give a better
// score).
if (sp->ts_twordlen >= 2
- && tword[sp->ts_twordlen - 2] == c)
+ && tword[sp->ts_twordlen - 2] == c) {
sp->ts_score -= SCORE_INS - SCORE_INSDUP;
+ }
}
}
break;
@@ -4566,8 +4696,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
go_deeper(stack, depth, SCORE_SWAP3);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: swap3 %c and %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- c, c3);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c, c3);
#endif
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNSWAP3;
@@ -4611,8 +4741,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
#ifdef DEBUG_TRIEWALK
p = fword + sp->ts_fidx;
sprintf(changename[depth], "%.*s-%s: rotate left %c%c%c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- p[0], p[1], p[2]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ p[0], p[1], p[2]);
#endif
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNROT3L;
@@ -4648,8 +4778,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
#ifdef DEBUG_TRIEWALK
p = fword + sp->ts_fidx;
sprintf(changename[depth], "%.*s-%s: rotate right %c%c%c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- p[0], p[1], p[2]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ p[0], p[1], p[2]);
#endif
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNROT3R;
@@ -4696,10 +4826,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Use the first byte to quickly find the first entry that may
// match. If the index is -1 there is none.
- if (soundfold)
+ if (soundfold) {
sp->ts_curi = slang->sl_repsal_first[fword[sp->ts_fidx]];
- else
+ } else {
sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]];
+ }
if (sp->ts_curi < 0) {
PROF_STORE(sp->ts_state)
@@ -4717,10 +4848,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// valid.
p = fword + sp->ts_fidx;
- if (soundfold)
+ if (soundfold) {
gap = &slang->sl_repsal;
- else
+ } else {
gap = &lp->lp_replang->sl_rep;
+ }
while (sp->ts_curi < gap->ga_len) {
ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
if (*ftp->ft_from != *p) {
@@ -4733,8 +4865,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
go_deeper(stack, depth, SCORE_REP);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: replace %s with %s",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- ftp->ft_from, ftp->ft_to);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ ftp->ft_from, ftp->ft_to);
#endif
// Need to undo this afterwards.
PROF_STORE(sp->ts_state)
@@ -4755,19 +4887,21 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
}
}
- if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP)
+ if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP) {
// No (more) matches.
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
+ }
break;
case STATE_REP_UNDO:
// Undo a REP replacement and continue with the next one.
- if (soundfold)
+ if (soundfold) {
gap = &slang->sl_repsal;
- else
+ } else {
gap = &lp->lp_replang->sl_rep;
+ }
ftp = (fromto_T *)gap->ga_data + sp->ts_curi - 1;
fl = (int)STRLEN(ftp->ft_from);
tl = (int)STRLEN(ftp->ft_to);
@@ -4815,7 +4949,7 @@ static void go_deeper(trystate_T *stack, int depth, int score_add)
// fword[flen] and return the byte length of that many chars in "word".
static int nofold_len(char_u *fword, int flen, char_u *word)
{
- char_u *p;
+ char_u *p;
int i = 0;
for (p = fword; p < fword + flen; MB_PTR_ADV(p)) {
@@ -4849,9 +4983,9 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
int len;
int c;
idx_T lo, hi, m;
- char_u *p;
- char_u *byts = slang->sl_kbyts; // array with bytes of the words
- idx_T *idxs = slang->sl_kidxs; // array with indexes
+ char_u *p;
+ char_u *byts = slang->sl_kbyts; // array with bytes of the words
+ idx_T *idxs = slang->sl_kidxs; // array with indexes
if (byts == NULL) {
// array is empty: "cannot happen"
@@ -4882,7 +5016,7 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
// kword is getting too long, continue one level up
--depth;
- } else if (++round[depth] > 2) {
+ } else if (++round[depth] > 2) {
// tried both fold-case and upper-case character, continue one
// level up
--depth;
@@ -4907,19 +5041,20 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
hi = tryidx + len - 1;
while (lo < hi) {
m = (lo + hi) / 2;
- if (byts[m] > c)
+ if (byts[m] > c) {
hi = m - 1;
- else if (byts[m] < c)
+ } else if (byts[m] < c) {
lo = m + 1;
- else {
+ } else {
lo = hi = m;
break;
}
}
// Stop if there is no matching byte.
- if (hi < lo || byts[lo] != c)
+ if (hi < lo || byts[lo] != c) {
break;
+ }
// Continue at the child (if there is one).
tryidx = idxs[lo];
@@ -4930,11 +5065,11 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
// level deeper.
if (round[depth] == 1) {
STRNCPY(kword + kwordlen[depth], fword + fwordidx[depth],
- flen);
+ flen);
kwordlen[depth + 1] = kwordlen[depth] + flen;
} else {
STRNCPY(kword + kwordlen[depth], uword + uwordidx[depth],
- ulen);
+ ulen);
kwordlen[depth + 1] = kwordlen[depth] + ulen;
}
fwordidx[depth + 1] = fwordidx[depth] + flen;
@@ -4955,11 +5090,11 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
// su->su_sga.
static void score_comp_sal(suginfo_T *su)
{
- langp_T *lp;
+ langp_T *lp;
char_u badsound[MAXWLEN];
int i;
- suggest_T *stp;
- suggest_T *sstp;
+ suggest_T *stp;
+ suggest_T *sstp;
int score;
ga_grow(&su->su_sga, su->su_ga.ga_len);
@@ -4998,13 +5133,13 @@ static void score_comp_sal(suginfo_T *su)
static void score_combine(suginfo_T *su)
{
garray_T ga;
- garray_T *gap;
- langp_T *lp;
- suggest_T *stp;
- char_u *p;
+ garray_T *gap;
+ langp_T *lp;
+ suggest_T *stp;
+ char_u *p;
char_u badsound[MAXWLEN];
int round;
- slang_T *slang = NULL;
+ slang_T *slang = NULL;
// Add the alternate score to su_ga.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
@@ -5017,11 +5152,12 @@ static void score_combine(suginfo_T *su)
for (int i = 0; i < su->su_ga.ga_len; ++i) {
stp = &SUG(su->su_ga, i);
stp->st_altscore = stp_sal_score(stp, su, slang, badsound);
- if (stp->st_altscore == SCORE_MAXMAX)
+ if (stp->st_altscore == SCORE_MAXMAX) {
stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4;
- else
+ } else {
stp->st_score = (stp->st_score * 3
+ stp->st_altscore) / 4;
+ }
stp->st_salscore = false;
}
break;
@@ -5030,7 +5166,7 @@ static void score_combine(suginfo_T *su)
if (slang == NULL) { // Using "double" without sound folding.
(void)cleanup_suggestions(&su->su_ga, su->su_maxscore,
- su->su_maxcount);
+ su->su_maxcount);
return;
}
@@ -5038,11 +5174,12 @@ static void score_combine(suginfo_T *su)
for (int i = 0; i < su->su_sga.ga_len; ++i) {
stp = &SUG(su->su_sga, i);
stp->st_altscore = spell_edit_score(slang,
- su->su_badword, stp->st_word);
- if (stp->st_score == SCORE_MAXMAX)
+ su->su_badword, stp->st_word);
+ if (stp->st_score == SCORE_MAXMAX) {
stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8;
- else
+ } else {
stp->st_score = (stp->st_score * 7 + stp->st_altscore) / 8;
+ }
stp->st_salscore = true;
}
@@ -5066,13 +5203,16 @@ static void score_combine(suginfo_T *su)
// Don't add a word if it's already there.
p = SUG(*gap, i).st_word;
int j;
- for (j = 0; j < ga.ga_len; ++j)
- if (STRCMP(stp[j].st_word, p) == 0)
+ for (j = 0; j < ga.ga_len; ++j) {
+ if (STRCMP(stp[j].st_word, p) == 0) {
break;
- if (j == ga.ga_len)
+ }
+ }
+ if (j == ga.ga_len) {
stp[ga.ga_len++] = SUG(*gap, i);
- else
+ } else {
xfree(p);
+ }
}
}
}
@@ -5091,19 +5231,15 @@ static void score_combine(suginfo_T *su)
su->su_ga = ga;
}
-// For the goodword in "stp" compute the soundalike score compared to the
-// badword.
-static int
-stp_sal_score (
- suggest_T *stp,
- suginfo_T *su,
- slang_T *slang,
- char_u *badsound // sound-folded badword
-)
+/// For the goodword in "stp" compute the soundalike score compared to the
+/// badword.
+///
+/// @param badsound sound-folded badword
+static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *badsound)
{
- char_u *p;
- char_u *pbad;
- char_u *pgood;
+ char_u *p;
+ char_u *pbad;
+ char_u *pgood;
char_u badsound2[MAXWLEN];
char_u fword[MAXWLEN];
char_u goodsound[MAXWLEN];
@@ -5111,9 +5247,9 @@ stp_sal_score (
int lendiff;
lendiff = su->su_badlen - stp->st_orglen;
- if (lendiff >= 0)
+ if (lendiff >= 0) {
pbad = badsound;
- else {
+ } else {
// soundfold the bad word with more characters following
(void)spell_casefold(curwin, su->su_badptr, stp->st_orglen, fword, MAXWLEN);
@@ -5122,9 +5258,11 @@ stp_sal_score (
// removing the space. Don't do it when the good word also contains a
// space.
if (ascii_iswhite(su->su_badptr[su->su_badlen])
- && *skiptowhite(stp->st_word) == NUL)
- for (p = fword; *(p = skiptowhite(p)) != NUL; )
+ && *skiptowhite(stp->st_word) == NUL) {
+ for (p = fword; *(p = skiptowhite(p)) != NUL; ) {
STRMOVE(p, p + 1);
+ }
+ }
spell_soundfold(slang, fword, true, badsound2);
pbad = badsound2;
@@ -5135,10 +5273,11 @@ stp_sal_score (
// what replaces the bad word.
STRCPY(goodword, stp->st_word);
STRLCPY(goodword + stp->st_wordlen,
- su->su_badptr + su->su_badlen - lendiff, lendiff + 1);
+ su->su_badptr + su->su_badlen - lendiff, lendiff + 1);
pgood = goodword;
- } else
+ } else {
pgood = stp->st_word;
+ }
// Sound-fold the word and compute the score for the difference.
spell_soundfold(slang, pgood, false, goodsound);
@@ -5153,17 +5292,18 @@ static sftword_T dumsft;
// Prepare for calling suggest_try_soundalike().
static void suggest_try_soundalike_prep(void)
{
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
// Do this for all languages that support sound folding and for which a
// .sug file has been loaded.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
slang = lp->lp_slang;
- if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL)
+ if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL) {
// prepare the hashtable used by add_sound_suggest()
hash_init(&slang->sl_sounddone);
+ }
}
}
@@ -5172,8 +5312,8 @@ static void suggest_try_soundalike_prep(void)
static void suggest_try_soundalike(suginfo_T *su)
{
char_u salword[MAXWLEN];
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
// Do this for all languages that support sound folding and for which a
// .sug file has been loaded.
@@ -5201,10 +5341,10 @@ static void suggest_try_soundalike(suginfo_T *su)
// Finish up after calling suggest_try_soundalike().
static void suggest_try_soundalike_finish(void)
{
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
int todo;
- hashitem_T *hi;
+ hashitem_T *hi;
// Do this for all languages that support sound folding and for which a
// .sug file has been loaded.
@@ -5214,11 +5354,12 @@ static void suggest_try_soundalike_finish(void)
if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL) {
// Free the info about handled words.
todo = (int)slang->sl_sounddone.ht_used;
- for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi)
+ for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
xfree(HI2SFT(hi));
--todo;
}
+ }
// Clear the hashtable, it may also be used by another region.
hash_clear(&slang->sl_sounddone);
@@ -5227,32 +5368,28 @@ static void suggest_try_soundalike_finish(void)
}
}
-// A match with a soundfolded word is found. Add the good word(s) that
-// produce this soundfolded word.
-static void
-add_sound_suggest (
- suginfo_T *su,
- char_u *goodword,
- int score, // soundfold score
- langp_T *lp
-)
+/// A match with a soundfolded word is found. Add the good word(s) that
+/// produce this soundfolded word.
+///
+/// @param score soundfold score
+static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_T *lp)
{
- slang_T *slang = lp->lp_slang; // language for sound folding
+ slang_T *slang = lp->lp_slang; // language for sound folding
int sfwordnr;
- char_u *nrline;
+ char_u *nrline;
int orgnr;
char_u theword[MAXWLEN];
int i;
int wlen;
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
int n;
int wordcount;
int wc;
int goodscore;
hash_T hash;
- hashitem_T *hi;
- sftword_T *sft;
+ hashitem_T *hi;
+ sftword_T *sft;
int bc, gc;
int limit;
@@ -5271,8 +5408,9 @@ add_sound_suggest (
hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash);
} else {
sft = HI2SFT(hi);
- if (score >= sft->sft_score)
+ if (score >= sft->sft_score) {
return;
+ }
sft->sft_score = score;
}
@@ -5299,25 +5437,28 @@ add_sound_suggest (
wordcount = 0;
for (wlen = 0; wlen < MAXWLEN - 3; ++wlen) {
i = 1;
- if (wordcount == orgnr && byts[n + 1] == NUL)
+ if (wordcount == orgnr && byts[n + 1] == NUL) {
break; // found end of word
-
- if (byts[n + 1] == NUL)
+ }
+ if (byts[n + 1] == NUL) {
++wordcount;
+ }
// skip over the NUL bytes
- for (; byts[n + i] == NUL; ++i)
+ for (; byts[n + i] == NUL; ++i) {
if (i > byts[n]) { // safety check
STRCPY(theword + wlen, "BAD");
wlen += 3;
goto badword;
}
+ }
// One of the siblings must have the word.
for (; i < byts[n]; ++i) {
wc = idxs[idxs[n + i]]; // nr of words under this byte
- if (wordcount + wc > orgnr)
+ if (wordcount + wc > orgnr) {
break;
+ }
wordcount += wc;
}
@@ -5330,12 +5471,13 @@ badword:
// Go over the possible flags and regions.
for (; i <= byts[n] && byts[n + i] == NUL; ++i) {
char_u cword[MAXWLEN];
- char_u *p;
+ char_u *p;
int flags = (int)idxs[n + i];
// Skip words with the NOSUGGEST flag
- if (flags & WF_NOSUGGEST)
+ if (flags & WF_NOSUGGEST) {
continue;
+ }
if (flags & WF_KEEPCAP) {
// Must find the word in the keep-case tree.
@@ -5347,23 +5489,26 @@ badword:
// Need to fix case according to "flags".
make_case_word(theword, cword, flags);
p = cword;
- } else
+ } else {
p = theword;
+ }
}
// Add the suggestion.
if (sps_flags & SPS_DOUBLE) {
// Add the suggestion if the score isn't too bad.
- if (score <= su->su_maxscore)
+ if (score <= su->su_maxscore) {
add_suggestion(su, &su->su_sga, p, su->su_badlen,
- score, 0, false, slang, false);
+ score, 0, false, slang, false);
+ }
} else {
// Add a penalty for words in another region.
if ((flags & WF_REGION)
- && (((unsigned)flags >> 16) & lp->lp_region) == 0)
+ && (((unsigned)flags >> 16) & lp->lp_region) == 0) {
goodscore = SCORE_REGION;
- else
+ } else {
goodscore = 0;
+ }
// Add a small penalty for changing the first letter from
// lower to upper case. Helps for "tath" -> "Kath", which is
@@ -5373,8 +5518,9 @@ badword:
if (SPELL_ISUPPER(gc)) {
bc = PTR2CHAR(su->su_badword);
if (!SPELL_ISUPPER(bc)
- && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc))
+ && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc)) {
goodscore += SCORE_ICASE / 2;
+ }
}
// Compute the score for the good word. This only does letter
@@ -5385,11 +5531,12 @@ badword:
// If the limit is very high then the iterative method is
// inefficient, using an array is quicker.
limit = MAXSCORE(su->su_sfmaxscore - goodscore, score);
- if (limit > SCORE_LIMITMAX)
+ if (limit > SCORE_LIMITMAX) {
goodscore += spell_edit_score(slang, su->su_badword, p);
- else
+ } else {
goodscore += spell_edit_score_limit(slang, su->su_badword,
- p, limit);
+ p, limit);
+ }
// When going over the limit don't bother to do the rest.
if (goodscore < SCORE_MAXMAX) {
@@ -5398,9 +5545,10 @@ badword:
// Add the suggestion if the score isn't too bad.
goodscore = RESCORE(goodscore, score);
- if (goodscore <= su->su_sfmaxscore)
+ if (goodscore <= su->su_sfmaxscore) {
add_suggestion(su, &su->su_ga, p, su->su_badlen,
- goodscore, score, true, slang, true);
+ goodscore, score, true, slang, true);
+ }
}
}
}
@@ -5414,9 +5562,9 @@ static int soundfold_find(slang_T *slang, char_u *word)
int len;
int wlen = 0;
int c;
- char_u *ptr = word;
- char_u *byts;
- idx_T *idxs;
+ char_u *ptr = word;
+ char_u *byts;
+ idx_T *idxs;
int wordnr = 0;
byts = slang->sl_sbyts;
@@ -5430,35 +5578,41 @@ static int soundfold_find(slang_T *slang, char_u *word)
// If the word ends we found the word. If not skip the NUL bytes.
c = ptr[wlen];
if (byts[arridx] == NUL) {
- if (c == NUL)
+ if (c == NUL) {
break;
+ }
// Skip over the zeros, there can be several.
while (len > 0 && byts[arridx] == NUL) {
++arridx;
--len;
}
- if (len == 0)
+ if (len == 0) {
return -1; // no children, word should have ended here
+ }
++wordnr;
}
// If the word ends we didn't find it.
- if (c == NUL)
+ if (c == NUL) {
return -1;
+ }
// Perform a binary search in the list of accepted bytes.
- if (c == TAB) // <Tab> is handled like <Space>
+ if (c == TAB) { // <Tab> is handled like <Space>
c = ' ';
+ }
while (byts[arridx] < c) {
// The word count is in the first idxs[] entry of the child.
wordnr += idxs[idxs[arridx]];
++arridx;
- if (--len == 0) // end of the bytes, didn't find it
+ if (--len == 0) { // end of the bytes, didn't find it
return -1;
+ }
}
- if (byts[arridx] != c) // didn't find the byte
+ if (byts[arridx] != c) { // didn't find the byte
return -1;
+ }
// Continue at the child (if there is one).
arridx = idxs[arridx];
@@ -5466,9 +5620,11 @@ static int soundfold_find(slang_T *slang, char_u *word)
// One space in the good word may stand for several spaces in the
// checked word.
- if (c == ' ')
- while (ptr[wlen] == ' ' || ptr[wlen] == TAB)
+ if (c == ' ') {
+ while (ptr[wlen] == ' ' || ptr[wlen] == TAB) {
++wlen;
+ }
+ }
}
return wordnr;
@@ -5477,15 +5633,16 @@ static int soundfold_find(slang_T *slang, char_u *word)
// Copy "fword" to "cword", fixing case according to "flags".
static void make_case_word(char_u *fword, char_u *cword, int flags)
{
- if (flags & WF_ALLCAP)
+ if (flags & WF_ALLCAP) {
// Make it all upper-case
allcap_copy(fword, cword);
- else if (flags & WF_ONECAP)
+ } else if (flags & WF_ONECAP) {
// Make the first letter upper-case
onecap_copy(fword, cword, true);
- else
+ } else {
// Use goodword as-is.
STRCPY(cword, fword);
+ }
}
// Returns true if "c1" and "c2" are similar characters according to the MAP
@@ -5494,7 +5651,7 @@ static bool similar_chars(slang_T *slang, int c1, int c2)
{
int m1, m2;
char_u buf[MB_MAXBYTES + 1];
- hashitem_T *hi;
+ hashitem_T *hi;
if (c1 >= 256) {
buf[utf_char2bytes(c1, buf)] = 0;
@@ -5526,25 +5683,20 @@ static bool similar_chars(slang_T *slang, int c1, int c2)
return m1 == m2;
}
-// Adds a suggestion to the list of suggestions.
-// For a suggestion that is already in the list the lowest score is remembered.
-static void
-add_suggestion (
- suginfo_T *su,
- garray_T *gap, // either su_ga or su_sga
- const char_u *goodword,
- int badlenarg, // len of bad word replaced with "goodword"
- int score,
- int altscore,
- bool had_bonus, // value for st_had_bonus
- slang_T *slang, // language for sound folding
- bool maxsf // su_maxscore applies to soundfold score,
- // su_sfmaxscore to the total score.
-)
+/// Adds a suggestion to the list of suggestions.
+/// For a suggestion that is already in the list the lowest score is remembered.
+///
+/// @param gap either su_ga or su_sga
+/// @param badlenarg len of bad word replaced with "goodword"
+/// @param had_bonus value for st_had_bonus
+/// @param slang language for sound folding
+/// @param maxsf su_maxscore applies to soundfold score, su_sfmaxscore to the total score.
+static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword, int badlenarg,
+ int score, int altscore, bool had_bonus, slang_T *slang, bool maxsf)
{
int goodlen; // len of goodword changed
int badlen; // len of bad word changed
- suggest_T *stp;
+ suggest_T *stp;
suggest_T new_sug;
// Minimize "badlen" for consistency. Avoids that changing "the the" to
@@ -5554,8 +5706,9 @@ add_suggestion (
for (;; ) {
goodlen = (int)(pgood - goodword);
badlen = (int)(pbad - su->su_badptr);
- if (goodlen <= 0 || badlen <= 0)
+ if (goodlen <= 0 || badlen <= 0) {
break;
+ }
MB_PTR_BACK(goodword, pgood);
MB_PTR_BACK(su->su_badptr, pbad);
if (utf_ptr2char(pgood) != utf_ptr2char(pbad)) {
@@ -5563,10 +5716,11 @@ add_suggestion (
}
}
- if (badlen == 0 && goodlen == 0)
+ if (badlen == 0 && goodlen == 0) {
// goodword doesn't change anything; may happen for "the the" changing
// the first "the" to itself.
return;
+ }
int i;
if (GA_EMPTY(gap)) {
@@ -5581,8 +5735,9 @@ add_suggestion (
&& stp->st_orglen == badlen
&& STRNCMP(stp->st_word, goodword, goodlen) == 0) {
// Found it. Remember the word with the lowest score.
- if (stp->st_slang == NULL)
+ if (stp->st_slang == NULL) {
stp->st_slang = slang;
+ }
new_sug.st_score = score;
new_sug.st_altscore = altscore;
@@ -5595,9 +5750,9 @@ add_suggestion (
// suggest_try_change() doesn't compute the soundalike
// word to keep it fast, while some special methods set
// the soundalike score to zero.
- if (had_bonus)
+ if (had_bonus) {
rescore_one(su, stp);
- else {
+ } else {
new_sug.st_word = stp->st_word;
new_sug.st_wordlen = stp->st_wordlen;
new_sug.st_slang = stp->st_slang;
@@ -5630,25 +5785,24 @@ add_suggestion (
// If we have too many suggestions now, sort the list and keep
// the best suggestions.
if (gap->ga_len > SUG_MAX_COUNT(su)) {
- if (maxsf)
+ if (maxsf) {
su->su_sfmaxscore = cleanup_suggestions(gap,
- su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
- else
+ su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
+ } else {
su->su_maxscore = cleanup_suggestions(gap,
- su->su_maxscore, SUG_CLEAN_COUNT(su));
+ su->su_maxscore, SUG_CLEAN_COUNT(su));
+ }
}
}
}
-// Suggestions may in fact be flagged as errors. Esp. for banned words and
-// for split words, such as "the the". Remove these from the list here.
-static void
-check_suggestions (
- suginfo_T *su,
- garray_T *gap // either su_ga or su_sga
-)
+/// Suggestions may in fact be flagged as errors. Esp. for banned words and
+/// for split words, such as "the the". Remove these from the list here.
+///
+/// @param gap either su_ga or su_sga
+static void check_suggestions(suginfo_T *su, garray_T *gap)
{
- suggest_T *stp;
+ suggest_T *stp;
char_u longword[MAXWLEN + 1];
int len;
hlf_T attr;
@@ -5662,16 +5816,17 @@ check_suggestions (
STRLCPY(longword, stp[i].st_word, MAXWLEN + 1);
len = stp[i].st_wordlen;
STRLCPY(longword + len, su->su_badptr + stp[i].st_orglen,
- MAXWLEN - len + 1);
+ MAXWLEN - len + 1);
attr = HLF_COUNT;
(void)spell_check(curwin, longword, &attr, NULL, false);
if (attr != HLF_COUNT) {
// Remove this entry.
xfree(stp[i].st_word);
--gap->ga_len;
- if (i < gap->ga_len)
+ if (i < gap->ga_len) {
memmove(stp + i, stp + i + 1,
- sizeof(suggest_T) * (gap->ga_len - i));
+ sizeof(suggest_T) * (gap->ga_len - i));
+ }
}
}
}
@@ -5680,9 +5835,9 @@ check_suggestions (
// Add a word to be banned.
static void add_banned(suginfo_T *su, char_u *word)
{
- char_u *s;
+ char_u *s;
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
hash = hash_hash(word);
const size_t word_len = STRLEN(word);
@@ -5707,23 +5862,24 @@ static void rescore_suggestions(suginfo_T *su)
// Recompute the score for one suggestion if sound-folding is possible.
static void rescore_one(suginfo_T *su, suggest_T *stp)
{
- slang_T *slang = stp->st_slang;
+ slang_T *slang = stp->st_slang;
char_u sal_badword[MAXWLEN];
- char_u *p;
+ char_u *p;
// Only rescore suggestions that have no sal score yet and do have a
// language.
if (slang != NULL && !GA_EMPTY(&slang->sl_sal) && !stp->st_had_bonus) {
- if (slang == su->su_sallang)
+ if (slang == su->su_sallang) {
p = su->su_sal_badword;
- else {
+ } else {
spell_soundfold(slang, su->su_fbadword, true, sal_badword);
p = sal_badword;
}
stp->st_altscore = stp_sal_score(stp, su, slang, p);
- if (stp->st_altscore == SCORE_MAXMAX)
+ if (stp->st_altscore == SCORE_MAXMAX) {
stp->st_altscore = SCORE_BIG;
+ }
stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
stp->st_had_bonus = true;
}
@@ -5734,28 +5890,27 @@ static void rescore_one(suginfo_T *su, suggest_T *stp)
// First on "st_score", then "st_altscore" then alphabetically.
static int sug_compare(const void *s1, const void *s2)
{
- suggest_T *p1 = (suggest_T *)s1;
- suggest_T *p2 = (suggest_T *)s2;
+ suggest_T *p1 = (suggest_T *)s1;
+ suggest_T *p2 = (suggest_T *)s2;
int n = p1->st_score - p2->st_score;
if (n == 0) {
n = p1->st_altscore - p2->st_altscore;
- if (n == 0)
+ if (n == 0) {
n = STRICMP(p1->st_word, p2->st_word);
+ }
}
return n;
}
-// Cleanup the suggestions:
-// - Sort on score.
-// - Remove words that won't be displayed.
-// Returns the maximum score in the list or "maxscore" unmodified.
-static int
-cleanup_suggestions (
- garray_T *gap,
- int maxscore,
- int keep // nr of suggestions to keep
-)
+/// Cleanup the suggestions:
+/// - Sort on score.
+/// - Remove words that won't be displayed.
+///
+/// @param keep nr of suggestions to keep
+///
+/// @return the maximum score in the list or "maxscore" unmodified.
+static int cleanup_suggestions(garray_T *gap, int maxscore, int keep)
FUNC_ATTR_NONNULL_ALL
{
if (gap->ga_len > 0) {
@@ -5823,12 +5978,12 @@ char *eval_soundfold(const char *const word)
void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res)
{
char_u fword[MAXWLEN];
- char_u *word;
+ char_u *word;
- if (slang->sl_sofo)
+ if (slang->sl_sofo) {
// SOFOFROM and SOFOTO used
spell_soundfold_sofo(slang, inword, res);
- else {
+ } else {
// SAL items used. Requires the word to be case-folded.
if (folded) {
word = inword;
@@ -5892,12 +6047,12 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
// Multi-byte version of spell_soundfold().
static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
{
- salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
+ salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
int word[MAXWLEN] = { 0 };
int wres[MAXWLEN] = { 0 };
int l;
- int *ws;
- int *pf;
+ int *ws;
+ int *pf;
int i, j, z;
int reslen;
int n, k = 0;
@@ -5954,27 +6109,34 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
&& ws[0] != NUL; ++n) {
// Quickly skip entries that don't match the word. Most
// entries are less then three chars, optimize for that.
- if (c != ws[0])
+ if (c != ws[0]) {
continue;
+ }
k = smp[n].sm_leadlen;
if (k > 1) {
- if (word[i + 1] != ws[1])
+ if (word[i + 1] != ws[1]) {
continue;
+ }
if (k > 2) {
- for (j = 2; j < k; ++j)
- if (word[i + j] != ws[j])
+ for (j = 2; j < k; ++j) {
+ if (word[i + j] != ws[j]) {
break;
- if (j < k)
+ }
+ }
+ if (j < k) {
continue;
+ }
}
}
if ((pf = smp[n].sm_oneof_w) != NULL) {
// Check for match with one of the chars in "sm_oneof".
- while (*pf != NUL && *pf != word[i + k])
+ while (*pf != NUL && *pf != word[i + k]) {
++pf;
- if (*pf == NUL)
+ }
+ if (*pf == NUL) {
continue;
+ }
++k;
}
char_u *s = smp[n].sm_rules;
@@ -5986,15 +6148,17 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
k--;
s++;
}
- if (*s == '<')
+ if (*s == '<') {
s++;
+ }
if (ascii_isdigit(*s)) {
// determine priority
pri = *s - '0';
s++;
}
- if (*s == '^' && *(s + 1) == '^')
+ if (*s == '^' && *(s + 1) == '^') {
s++;
+ }
if (*s == NUL
|| (*s == '^'
@@ -6017,19 +6181,24 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
for (; ((ws = smp[n0].sm_lead_w)[0] & 0xff)
== (c0 & 0xff); ++n0) {
// Quickly skip entries that don't match the word.
- if (c0 != ws[0])
+ if (c0 != ws[0]) {
continue;
+ }
k0 = smp[n0].sm_leadlen;
if (k0 > 1) {
- if (word[i + k] != ws[1])
+ if (word[i + k] != ws[1]) {
continue;
+ }
if (k0 > 2) {
pf = word + i + k + 1;
- for (j = 2; j < k0; ++j)
- if (*pf++ != ws[j])
+ for (j = 2; j < k0; ++j) {
+ if (*pf++ != ws[j]) {
break;
- if (j < k0)
+ }
+ }
+ if (j < k0) {
continue;
+ }
}
}
k0 += k - 1;
@@ -6037,10 +6206,12 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
if ((pf = smp[n0].sm_oneof_w) != NULL) {
// Check for match with one of the chars in
// "sm_oneof".
- while (*pf != NUL && *pf != word[i + k0])
+ while (*pf != NUL && *pf != word[i + k0]) {
++pf;
- if (*pf == NUL)
+ }
+ if (*pf == NUL) {
continue;
+ }
++k0;
}
@@ -6051,8 +6222,9 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// "if (k0 == k)"
s++;
}
- if (*s == '<')
+ if (*s == '<') {
s++;
+ }
if (ascii_isdigit(*s)) {
p0 = *s - '0';
s++;
@@ -6062,22 +6234,25 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// *s == '^' cuts
|| (*s == '$'
&& !spell_iswordp_w(word + i + k0,
- curwin))) {
- if (k0 == k)
+ curwin))) {
+ if (k0 == k) {
// this is just a piece of the string
continue;
+ }
- if (p0 < pri)
+ if (p0 < pri) {
// priority too low
continue;
+ }
// rule fits; stop search
break;
}
}
if (p0 >= pri && (smp[n0].sm_lead_w[0] & 0xff)
- == (c0 & 0xff))
+ == (c0 & 0xff)) {
continue;
+ }
}
// replace string
@@ -6088,20 +6263,23 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// rule with '<' is used
if (reslen > 0 && ws != NULL && *ws != NUL
&& (wres[reslen - 1] == c
- || wres[reslen - 1] == *ws))
+ || wres[reslen - 1] == *ws)) {
reslen--;
+ }
z0 = 1;
z = 1;
k0 = 0;
- if (ws != NULL)
+ if (ws != NULL) {
while (*ws != NUL && word[i + k0] != NUL) {
word[i + k0] = *ws;
k0++;
ws++;
}
- if (k > k0)
+ }
+ if (k > k0) {
memmove(word + i + k0, word + i + k,
- sizeof(int) * (wordlen - (i + k) + 1));
+ sizeof(int) * (wordlen - (i + k) + 1));
+ }
// new "actual letter"
c = word[i];
@@ -6109,23 +6287,27 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// no '<' rule used
i += k - 1;
z = 0;
- if (ws != NULL)
+ if (ws != NULL) {
while (*ws != NUL && ws[1] != NUL
&& reslen < MAXWLEN) {
- if (reslen == 0 || wres[reslen - 1] != *ws)
+ if (reslen == 0 || wres[reslen - 1] != *ws) {
wres[reslen++] = *ws;
+ }
ws++;
}
+ }
// new "actual letter"
- if (ws == NULL)
+ if (ws == NULL) {
c = NUL;
- else
+ } else {
c = *ws;
+ }
if (strstr((char *)s, "^^") != NULL) {
- if (c != NUL)
+ if (c != NUL) {
wres[reslen++] = c;
+ }
memmove(word, word + i + 1,
- sizeof(int) * (wordlen - (i + 1) + 1));
+ sizeof(int) * (wordlen - (i + 1) + 1));
i = 0;
z0 = 1;
}
@@ -6133,7 +6315,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
break;
}
}
- } else if (ascii_iswhite(c)) {
+ } else if (ascii_iswhite(c)) {
c = ' ';
k = 1;
}
@@ -6141,9 +6323,10 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
if (z0 == 0) {
if (k && !p0 && reslen < MAXWLEN && c != NUL
&& (!slang->sl_collapse || reslen == 0
- || wres[reslen - 1] != c))
+ || wres[reslen - 1] != c)) {
// condense only double letters
wres[reslen++] = c;
+ }
i++;
z = 0;
@@ -6162,35 +6345,36 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
res[l] = NUL;
}
-// Compute a score for two sound-a-like words.
-// This permits up to two inserts/deletes/swaps/etc. to keep things fast.
-// Instead of a generic loop we write out the code. That keeps it fast by
-// avoiding checks that will not be possible.
-static int
-soundalike_score (
- char_u *goodstart, // sound-folded good word
- char_u *badstart // sound-folded bad word
-)
+/// Compute a score for two sound-a-like words.
+/// This permits up to two inserts/deletes/swaps/etc. to keep things fast.
+/// Instead of a generic loop we write out the code. That keeps it fast by
+/// avoiding checks that will not be possible.
+///
+/// @param goodstart sound-folded good word
+/// @param badstart sound-folded bad word
+static int soundalike_score(char_u *goodstart, char_u *badstart)
{
- char_u *goodsound = goodstart;
- char_u *badsound = badstart;
+ char_u *goodsound = goodstart;
+ char_u *badsound = badstart;
int goodlen;
int badlen;
int n;
- char_u *pl, *ps;
- char_u *pl2, *ps2;
+ char_u *pl, *ps;
+ char_u *pl2, *ps2;
int score = 0;
// Adding/inserting "*" at the start (word starts with vowel) shouldn't be
// counted so much, vowels in the middle of the word aren't counted at all.
if ((*badsound == '*' || *goodsound == '*') && *badsound != *goodsound) {
if ((badsound[0] == NUL && goodsound[1] == NUL)
- || (goodsound[0] == NUL && badsound[1] == NUL))
+ || (goodsound[0] == NUL && badsound[1] == NUL)) {
// changing word with vowel to word without a sound
return SCORE_DEL;
- if (badsound[0] == NUL || goodsound[0] == NUL)
+ }
+ if (badsound[0] == NUL || goodsound[0] == NUL) {
// more than two changes
return SCORE_MAXMAX;
+ }
if (badsound[1] == goodsound[1]
|| (badsound[1] != NUL
@@ -6199,10 +6383,11 @@ soundalike_score (
// handle like a substitute
} else {
score = 2 * SCORE_DEL / 3;
- if (*badsound == '*')
+ if (*badsound == '*') {
++badsound;
- else
+ } else {
++goodsound;
+ }
}
}
@@ -6212,8 +6397,9 @@ soundalike_score (
// Return quickly if the lengths are too different to be fixed by two
// changes.
n = goodlen - badlen;
- if (n < -2 || n > 2)
+ if (n < -2 || n > 2) {
return SCORE_MAXMAX;
+ }
if (n > 0) {
pl = goodsound; // goodsound is longest
@@ -6239,8 +6425,9 @@ soundalike_score (
++ps;
}
// strings must be equal after second delete
- if (STRCMP(pl + 1, ps) == 0)
+ if (STRCMP(pl + 1, ps) == 0) {
return score + SCORE_DEL * 2;
+ }
// Failed to compare.
break;
@@ -6253,20 +6440,23 @@ soundalike_score (
pl2 = pl + 1;
ps2 = ps;
while (*pl2 == *ps2) {
- if (*pl2 == NUL) // reached the end
+ if (*pl2 == NUL) { // reached the end
return score + SCORE_DEL;
+ }
++pl2;
++ps2;
}
// 2: delete then swap, then rest must be equal
if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
- && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ && STRCMP(pl2 + 2, ps2 + 2) == 0) {
return score + SCORE_DEL + SCORE_SWAP;
+ }
// 3: delete then substitute, then the rest must be equal
- if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0) {
return score + SCORE_DEL + SCORE_SUBST;
+ }
// 4: first swap then delete
if (pl[0] == ps[1] && pl[1] == ps[0]) {
@@ -6277,8 +6467,9 @@ soundalike_score (
++ps2;
}
// delete a char and then strings must be equal
- if (STRCMP(pl2 + 1, ps2) == 0)
+ if (STRCMP(pl2 + 1, ps2) == 0) {
return score + SCORE_SWAP + SCORE_DEL;
+ }
}
// 5: first substitute then delete
@@ -6289,8 +6480,9 @@ soundalike_score (
++ps2;
}
// delete a char and then strings must be equal
- if (STRCMP(pl2 + 1, ps2) == 0)
+ if (STRCMP(pl2 + 1, ps2) == 0) {
return score + SCORE_SUBST + SCORE_DEL;
+ }
// Failed to compare.
break;
@@ -6299,47 +6491,54 @@ soundalike_score (
// Lengths are equal, thus changes must result in same length: An
// insert is only possible in combination with a delete.
// 1: check if for identical strings
- if (*pl == NUL)
+ if (*pl == NUL) {
return score;
+ }
// 2: swap
if (pl[0] == ps[1] && pl[1] == ps[0]) {
pl2 = pl + 2; // swap, skip two chars
ps2 = ps + 2;
while (*pl2 == *ps2) {
- if (*pl2 == NUL) // reached the end
+ if (*pl2 == NUL) { // reached the end
return score + SCORE_SWAP;
+ }
++pl2;
++ps2;
}
// 3: swap and swap again
if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
- && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ && STRCMP(pl2 + 2, ps2 + 2) == 0) {
return score + SCORE_SWAP + SCORE_SWAP;
+ }
// 4: swap and substitute
- if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0) {
return score + SCORE_SWAP + SCORE_SUBST;
+ }
}
// 5: substitute
pl2 = pl + 1;
ps2 = ps + 1;
while (*pl2 == *ps2) {
- if (*pl2 == NUL) // reached the end
+ if (*pl2 == NUL) { // reached the end
return score + SCORE_SUBST;
+ }
++pl2;
++ps2;
}
// 6: substitute and swap
if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
- && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ && STRCMP(pl2 + 2, ps2 + 2) == 0) {
return score + SCORE_SUBST + SCORE_SWAP;
+ }
// 7: substitute and substitute
- if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0) {
return score + SCORE_SUBST + SCORE_SUBST;
+ }
// 8: insert then delete
pl2 = pl;
@@ -6348,8 +6547,9 @@ soundalike_score (
++pl2;
++ps2;
}
- if (STRCMP(pl2 + 1, ps2) == 0)
+ if (STRCMP(pl2 + 1, ps2) == 0) {
return score + SCORE_INS + SCORE_DEL;
+ }
// 9: delete then insert
pl2 = pl + 1;
@@ -6358,8 +6558,9 @@ soundalike_score (
++pl2;
++ps2;
}
- if (STRCMP(pl2, ps2 + 1) == 0)
+ if (STRCMP(pl2, ps2 + 1) == 0) {
return score + SCORE_INS + SCORE_DEL;
+ }
// Failed to compare.
break;
@@ -6408,8 +6609,9 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
cnt = xmalloc(sizeof(int) * (badlen + 1) * (goodlen + 1));
CNT(0, 0) = 0;
- for (j = 1; j <= goodlen; ++j)
+ for (j = 1; j <= goodlen; ++j) {
CNT(0, j) = CNT(0, j - 1) + SCORE_INS;
+ }
for (i = 1; i <= badlen; ++i) {
CNT(i, 0) = CNT(i - 1, 0) + SCORE_DEL;
@@ -6420,16 +6622,17 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
CNT(i, j) = CNT(i - 1, j - 1);
} else {
// Use a better score when there is only a case difference.
- if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc)) {
CNT(i, j) = SCORE_ICASE + CNT(i - 1, j - 1);
- else {
+ } else {
// For a similar character use SCORE_SIMILAR.
if (slang != NULL
&& slang->sl_has_map
- && similar_chars(slang, gc, bc))
+ && similar_chars(slang, gc, bc)) {
CNT(i, j) = SCORE_SIMILAR + CNT(i - 1, j - 1);
- else
+ } else {
CNT(i, j) = SCORE_SUBST + CNT(i - 1, j - 1);
+ }
}
if (i > 1 && j > 1) {
@@ -6437,16 +6640,19 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
pgc = wgoodword[j - 2];
if (bc == pgc && pbc == gc) {
t = SCORE_SWAP + CNT(i - 2, j - 2);
- if (t < CNT(i, j))
+ if (t < CNT(i, j)) {
CNT(i, j) = t;
+ }
}
}
t = SCORE_DEL + CNT(i - 1, j);
- if (t < CNT(i, j))
+ if (t < CNT(i, j)) {
CNT(i, j) = t;
+ }
t = SCORE_INS + CNT(i, j - 1);
- if (t < CNT(i, j))
+ if (t < CNT(i, j)) {
CNT(i, j) = t;
+ }
}
}
}
@@ -6515,11 +6721,13 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
bc = wbadword[bi];
gc = wgoodword[gi];
- if (bc != gc) // stop at a char that's different
+ if (bc != gc) { // stop at a char that's different
break;
+ }
if (bc == NUL) { // both words end
- if (score < minscore)
+ if (score < minscore) {
minscore = score;
+ }
goto pop; // do next alternative
}
++bi;
@@ -6528,14 +6736,16 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
if (gc == NUL) { // goodword ends, delete badword chars
do {
- if ((score += SCORE_DEL) >= minscore)
+ if ((score += SCORE_DEL) >= minscore) {
goto pop; // do next alternative
+ }
} while (wbadword[++bi] != NUL);
minscore = score;
- } else if (bc == NUL) { // badword ends, insert badword chars
+ } else if (bc == NUL) { // badword ends, insert badword chars
do {
- if ((score += SCORE_INS) >= minscore)
+ if ((score += SCORE_INS) >= minscore) {
goto pop; // do next alternative
+ }
} while (wgoodword[++gi] != NUL);
minscore = score;
} else { // both words continue
@@ -6586,16 +6796,17 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
// Substitute one character for another which is the same
// thing as deleting a character from both goodword and badword.
// Use a better score when there is only a case difference.
- if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc)) {
score += SCORE_ICASE;
- else {
+ } else {
// For a similar character use SCORE_SIMILAR.
if (slang != NULL
&& slang->sl_has_map
- && similar_chars(slang, gc, bc))
+ && similar_chars(slang, gc, bc)) {
score += SCORE_SIMILAR;
- else
+ } else {
score += SCORE_SUBST;
+ }
}
if (score < minscore) {
@@ -6607,8 +6818,9 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
}
pop:
// Get here to try the next alternative, pop it from the stack.
- if (stackidx == 0) // stack is empty, finished
+ if (stackidx == 0) { // stack is empty, finished
break;
+ }
// pop an item from the stack
--stackidx;
@@ -6620,8 +6832,9 @@ pop:
// When the score goes over "limit" it may actually be much higher.
// Return a very large number to avoid going below the limit when giving a
// bonus.
- if (minscore > limit)
+ if (minscore > limit) {
return SCORE_MAXMAX;
+ }
return minscore;
}
@@ -6656,7 +6869,7 @@ void ex_spellinfo(exarg_T *eap)
// ":spelldump"
void ex_spelldump(exarg_T *eap)
{
- char_u *spl;
+ char_u *spl;
long dummy;
if (no_spell_checking(curwin)) {
@@ -6685,50 +6898,49 @@ void ex_spelldump(exarg_T *eap)
redraw_later(curwin, NOT_VALID);
}
-// Go through all possible words and:
-// 1. When "pat" is NULL: dump a list of all words in the current buffer.
-// "ic" and "dir" are not used.
-// 2. When "pat" is not NULL: add matching words to insert mode completion.
-void
-spell_dump_compl (
- char_u *pat, // leading part of the word
- int ic, // ignore case
- Direction *dir, // direction for adding matches
- int dumpflags_arg // DUMPFLAG_*
-)
+/// Go through all possible words and:
+/// 1. When "pat" is NULL: dump a list of all words in the current buffer.
+/// "ic" and "dir" are not used.
+/// 2. When "pat" is not NULL: add matching words to insert mode completion.
+///
+/// @param pat leading part of the word
+/// @param ic ignore case
+/// @param dir direction for adding matches
+/// @param dumpflags_arg DUMPFLAG_*
+void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg)
{
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
char_u word[MAXWLEN];
int c;
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
linenr_T lnum = 0;
int round;
int depth;
int n;
int flags;
- char_u *region_names = NULL; // region names being used
+ char_u *region_names = NULL; // region names being used
bool do_region = true; // dump region names and numbers
- char_u *p;
+ char_u *p;
int dumpflags = dumpflags_arg;
int patlen;
// When ignoring case or when the pattern starts with capital pass this on
// to dump_word().
if (pat != NULL) {
- if (ic)
+ if (ic) {
dumpflags |= DUMPFLAG_ICASE;
- else {
+ } else {
n = captype(pat, NULL);
- if (n == WF_ONECAP)
+ if (n == WF_ONECAP) {
dumpflags |= DUMPFLAG_ONECAP;
- else if (n == WF_ALLCAP
- && (int)STRLEN(pat) > mb_ptr2len(pat)
- )
+ } else if (n == WF_ALLCAP
+ && (int)STRLEN(pat) > mb_ptr2len(pat)) {
dumpflags |= DUMPFLAG_ALLCAP;
+ }
}
}
@@ -6738,9 +6950,9 @@ spell_dump_compl (
lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
p = lp->lp_slang->sl_regions;
if (p[0] != 0) {
- if (region_names == NULL) // first language with regions
+ if (region_names == NULL) { // first language with regions
region_names = p;
- else if (STRCMP(region_names, p) != 0) {
+ } else if (STRCMP(region_names, p) != 0) {
do_region = false; // region names are different
break;
}
@@ -6752,15 +6964,17 @@ spell_dump_compl (
vim_snprintf((char *)IObuff, IOSIZE, "/regions=%s", region_names);
ml_append(lnum++, IObuff, (colnr_T)0, false);
}
- } else
+ } else {
do_region = false;
+ }
// Loop over all files loaded for the entries in 'spelllang'.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
slang = lp->lp_slang;
- if (slang->sl_fbyts == NULL) // reloading failed
+ if (slang->sl_fbyts == NULL) { // reloading failed
continue;
+ }
if (pat == NULL) {
vim_snprintf((char *)IObuff, IOSIZE, "# file: %s", slang->sl_fname);
@@ -6769,10 +6983,11 @@ spell_dump_compl (
// When matching with a pattern and there are no prefixes only use
// parts of the tree that match "pat".
- if (pat != NULL && slang->sl_pbyts == NULL)
+ if (pat != NULL && slang->sl_pbyts == NULL) {
patlen = (int)STRLEN(pat);
- else
+ } else {
patlen = -1;
+ }
// round 1: case-folded tree
// round 2: keep-case tree
@@ -6786,9 +7001,9 @@ spell_dump_compl (
byts = slang->sl_kbyts;
idxs = slang->sl_kidxs;
}
- if (byts == NULL)
+ if (byts == NULL) {
continue; // array is empty
-
+ }
depth = 0;
arridx[0] = 0;
curi[0] = 1;
@@ -6817,23 +7032,26 @@ spell_dump_compl (
|| (((unsigned)flags >> 16)
& lp->lp_region) != 0)) {
word[depth] = NUL;
- if (!do_region)
+ if (!do_region) {
flags &= ~WF_REGION;
+ }
// Dump the basic word if there is no prefix or
// when it's the first one.
c = (unsigned)flags >> 24;
if (c == 0 || curi[depth] == 2) {
dump_word(slang, word, pat, dir,
- dumpflags, flags, lnum);
- if (pat == NULL)
+ dumpflags, flags, lnum);
+ if (pat == NULL) {
++lnum;
+ }
}
// Apply the prefix, if there is one.
- if (c != 0)
+ if (c != 0) {
lnum = dump_prefixes(slang, word, pat, dir,
- dumpflags, flags, lnum);
+ dumpflags, flags, lnum);
+ }
}
} else {
// Normal char, go one level deeper.
@@ -6849,8 +7067,9 @@ spell_dump_compl (
// ignore case...
assert(depth >= 0);
if (depth <= patlen
- && mb_strnicmp(word, pat, (size_t)depth) != 0)
+ && mb_strnicmp(word, pat, (size_t)depth) != 0) {
--depth;
+ }
}
}
}
@@ -6860,22 +7079,23 @@ spell_dump_compl (
// Dumps one word: apply case modifications and append a line to the buffer.
// When "lnum" is zero add insert mode completion.
-static void dump_word(slang_T *slang, char_u *word, char_u *pat,
- Direction *dir, int dumpflags, int wordflags,
- linenr_T lnum)
+static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, int dumpflags,
+ int wordflags, linenr_T lnum)
{
bool keepcap = false;
- char_u *p;
- char_u *tw;
+ char_u *p;
+ char_u *tw;
char_u cword[MAXWLEN];
char_u badword[MAXWLEN + 10];
int i;
int flags = wordflags;
- if (dumpflags & DUMPFLAG_ONECAP)
+ if (dumpflags & DUMPFLAG_ONECAP) {
flags |= WF_ONECAP;
- if (dumpflags & DUMPFLAG_ALLCAP)
+ }
+ if (dumpflags & DUMPFLAG_ALLCAP) {
flags |= WF_ALLCAP;
+ }
if ((dumpflags & DUMPFLAG_KEEPCASE) == 0 && (flags & WF_CAPMASK) != 0) {
// Need to fix case according to "flags".
@@ -6885,8 +7105,9 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat,
p = word;
if ((dumpflags & DUMPFLAG_KEEPCASE)
&& ((captype(word, NULL) & WF_KEEPCAP) == 0
- || (flags & WF_FIXCAP) != 0))
+ || (flags & WF_FIXCAP) != 0)) {
keepcap = true;
+ }
}
tw = p;
@@ -6917,13 +7138,13 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat,
}
if (dumpflags & DUMPFLAG_COUNT) {
- hashitem_T *hi;
+ hashitem_T *hi;
// Include the word count for ":spelldump!".
hi = hash_find(&slang->sl_wordcount, tw);
if (!HASHITEM_EMPTY(hi)) {
vim_snprintf((char *)IObuff, IOSIZE, "%s\t%d",
- tw, HI2WC(hi)->wc_count);
+ tw, HI2WC(hi)->wc_count);
p = IObuff;
}
}
@@ -6939,20 +7160,16 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat,
}
}
-// For ":spelldump": Find matching prefixes for "word". Prepend each to
-// "word" and append a line to the buffer.
-// When "lnum" is zero add insert mode completion.
-// Return the updated line number.
-static linenr_T
-dump_prefixes (
- slang_T *slang,
- char_u *word, // case-folded word
- char_u *pat,
- Direction *dir,
- int dumpflags,
- int flags, // flags with prefix ID
- linenr_T startlnum
-)
+/// For ":spelldump": Find matching prefixes for "word". Prepend each to
+/// "word" and append a line to the buffer.
+/// When "lnum" is zero add insert mode completion.
+///
+/// @param word case-folded word
+/// @param flags flags with prefix ID
+///
+/// @return the updated line number.
+static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Direction *dir,
+ int dumpflags, int flags, linenr_T startlnum)
{
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
@@ -6960,8 +7177,8 @@ dump_prefixes (
char_u word_up[MAXWLEN];
bool has_word_up = false;
int c;
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
linenr_T lnum = startlnum;
int depth;
int n;
@@ -6998,19 +7215,22 @@ dump_prefixes (
c = byts[n];
if (c == 0) {
// End of prefix, find out how many IDs there are.
- for (i = 1; i < len; ++i)
- if (byts[n + i] != 0)
+ for (i = 1; i < len; ++i) {
+ if (byts[n + i] != 0) {
break;
+ }
+ }
curi[depth] += i - 1;
c = valid_word_prefix(i, n, flags, word, slang, false);
if (c != 0) {
STRLCPY(prefix + depth, word, MAXWLEN - depth);
dump_word(slang, prefix, pat, dir, dumpflags,
- (c & WF_RAREPFX) ? (flags | WF_RARE)
- : flags, lnum);
- if (lnum != 0)
+ (c & WF_RAREPFX) ? (flags | WF_RARE)
+ : flags, lnum);
+ if (lnum != 0) {
++lnum;
+ }
}
// Check for prefix that matches the word when the
@@ -7018,14 +7238,15 @@ dump_prefixes (
// a condition.
if (has_word_up) {
c = valid_word_prefix(i, n, flags, word_up, slang,
- true);
+ true);
if (c != 0) {
STRLCPY(prefix + depth, word_up, MAXWLEN - depth);
dump_word(slang, prefix, pat, dir, dumpflags,
- (c & WF_RAREPFX) ? (flags | WF_RARE)
- : flags, lnum);
- if (lnum != 0)
+ (c & WF_RAREPFX) ? (flags | WF_RARE)
+ : flags, lnum);
+ if (lnum != 0) {
++lnum;
+ }
}
}
} else {
@@ -7045,7 +7266,7 @@ dump_prefixes (
// Uses the spell-checking word characters.
char_u *spell_to_word_end(char_u *start, win_T *win)
{
- char_u *p = start;
+ char_u *p = start;
while (*p != NUL && spell_iswordp(p, win)) {
MB_PTR_ADV(p);
@@ -7060,8 +7281,8 @@ char_u *spell_to_word_end(char_u *start, win_T *win)
// Returns the column number of the word.
int spell_word_start(int startcol)
{
- char_u *line;
- char_u *p;
+ char_u *line;
+ char_u *p;
int col = 0;
if (no_spell_checking(curwin)) {
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 843ecec1b1..772275df84 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -226,19 +226,17 @@
// stored as an offset to the previous number in as
// few bytes as possible, see offset2bytes())
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
#include <wctype.h>
-#include "nvim/vim.h"
-#include "nvim/spell_defs.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/ex_cmds2.h"
#include "nvim/fileio.h"
-#include "nvim/memory.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/os.h"
@@ -246,9 +244,11 @@
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/spell.h"
+#include "nvim/spell_defs.h"
#include "nvim/spellfile.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#ifndef UNIX // it's in os/unix_defs.h for Unix
# include <time.h> // for time_t
@@ -310,7 +310,7 @@ static char *msg_compressing = N_("Compressing word tree...");
// and .dic file.
// Main structure to store the contents of a ".aff" file.
typedef struct afffile_S {
- char_u *af_enc; // "SET", normalized, alloc'ed string or NULL
+ char_u *af_enc; // "SET", normalized, alloc'ed string or NULL
int af_flagtype; // AFT_CHAR, AFT_LONG, AFT_NUM or AFT_CAPLONG
unsigned af_rare; // RARE ID for rare word
unsigned af_keepcase; // KEEPCASE ID for keep-case word
@@ -338,17 +338,17 @@ typedef struct afffile_S {
typedef struct affentry_S affentry_T;
// Affix entry from ".aff" file. Used for prefixes and suffixes.
struct affentry_S {
- affentry_T *ae_next; // next affix with same name/number
- char_u *ae_chop; // text to chop off basic word (can be NULL)
- char_u *ae_add; // text to add to basic word (can be NULL)
- char_u *ae_flags; // flags on the affix (can be NULL)
- char_u *ae_cond; // condition (NULL for ".")
- regprog_T *ae_prog; // regexp program for ae_cond or NULL
+ affentry_T *ae_next; // next affix with same name/number
+ char_u *ae_chop; // text to chop off basic word (can be NULL)
+ char_u *ae_add; // text to add to basic word (can be NULL)
+ char_u *ae_flags; // flags on the affix (can be NULL)
+ char_u *ae_cond; // condition (NULL for ".")
+ regprog_T *ae_prog; // regexp program for ae_cond or NULL
char ae_compforbid; // COMPOUNDFORBIDFLAG found
char ae_comppermit; // COMPOUNDPERMITFLAG found
};
-# define AH_KEY_LEN 17 // 2 x 8 bytes + NUL
+#define AH_KEY_LEN 17 // 2 x 8 bytes + NUL
// Affix header from ".aff" file. Used for af_pref and af_suff.
typedef struct affheader_S {
@@ -357,7 +357,7 @@ typedef struct affheader_S {
int ah_newID; // prefix ID after renumbering; 0 if not used
int ah_combine; // suffix may combine with prefix
int ah_follows; // another affix block should be following
- affentry_T *ah_first; // first affix entry
+ affentry_T *ah_first; // first affix entry
} affheader_T;
#define HI2AH(hi) ((affheader_T *)(hi)->hi_key)
@@ -381,7 +381,7 @@ typedef struct compitem_S {
typedef struct sblock_S sblock_T;
struct sblock_S {
int sb_used; // nr of bytes already in use
- sblock_T *sb_next; // next block in list
+ sblock_T *sb_next; // next block in list
char_u sb_data[1]; // data, actually longer
};
@@ -397,9 +397,9 @@ struct wordnode_S {
wordnode_T *next; // next node with same hash key
wordnode_T *wnode; // parent node that will write this node
} wn_u2;
- wordnode_T *wn_child; // child (next byte in word)
- wordnode_T *wn_sibling; // next sibling (alternate byte in word,
- // always sorted)
+ wordnode_T *wn_child; // child (next byte in word)
+ wordnode_T *wn_sibling; // next sibling (alternate byte in word,
+ // always sorted)
int wn_refs; // Nr. of references to this node. Only
// relevant for first node in a list of
// siblings, in following siblings it is
@@ -425,29 +425,29 @@ struct wordnode_S {
// Info used while reading the spell files.
typedef struct spellinfo_S {
- wordnode_T *si_foldroot; // tree with case-folded words
+ wordnode_T *si_foldroot; // tree with case-folded words
long si_foldwcount; // nr of words in si_foldroot
- wordnode_T *si_keeproot; // tree with keep-case words
+ wordnode_T *si_keeproot; // tree with keep-case words
long si_keepwcount; // nr of words in si_keeproot
- wordnode_T *si_prefroot; // tree with postponed prefixes
+ wordnode_T *si_prefroot; // tree with postponed prefixes
long si_sugtree; // creating the soundfolding trie
- sblock_T *si_blocks; // memory blocks used
+ sblock_T *si_blocks; // memory blocks used
long si_blocks_cnt; // memory blocks allocated
int si_did_emsg; // TRUE when ran out of memory
long si_compress_cnt; // words to add before lowering
// compression limit
- wordnode_T *si_first_free; // List of nodes that have been freed during
- // compression, linked by "wn_child" field.
+ wordnode_T *si_first_free; // List of nodes that have been freed during
+ // compression, linked by "wn_child" field.
long si_free_count; // number of nodes in si_first_free
#ifdef SPELL_PRINTTREE
int si_wordnode_nr; // sequence nr for nodes
#endif
- buf_T *si_spellbuf; // buffer used to store soundfold word table
+ buf_T *si_spellbuf; // buffer used to store soundfold word table
int si_ascii; // handling only ASCII words
int si_add; // addition file
@@ -457,18 +457,18 @@ typedef struct spellinfo_S {
int si_memtot; // runtime memory used
int si_verbose; // verbose messages
int si_msg_count; // number of words added since last message
- char_u *si_info; // info text chars or NULL
+ char_u *si_info; // info text chars or NULL
int si_region_count; // number of regions supported (1 when there
// are no regions)
char_u si_region_name[MAXREGIONS * 2 + 1];
- // region names; used only if
- // si_region_count > 1)
+ // region names; used only if
+ // si_region_count > 1)
garray_T si_rep; // list of fromto_T entries from REP lines
garray_T si_repsal; // list of fromto_T entries from REPSAL lines
garray_T si_sal; // list of fromto_T entries from SAL lines
- char_u *si_sofofr; // SOFOFROM text
- char_u *si_sofoto; // SOFOTO text
+ char_u *si_sofofr; // SOFOFROM text
+ char_u *si_sofoto; // SOFOTO text
int si_nosugfile; // NOSUGFILE item found
int si_nosplitsugs; // NOSPLITSUGS item found
int si_nocompoundsugs; // NOCOMPOUNDSUGS item found
@@ -478,16 +478,16 @@ typedef struct spellinfo_S {
time_t si_sugtime; // timestamp for .sug file
int si_rem_accents; // soundsalike: remove accents
garray_T si_map; // MAP info concatenated
- char_u *si_midword; // MIDWORD chars or NULL
+ char_u *si_midword; // MIDWORD chars or NULL
int si_compmax; // max nr of words for compounding
int si_compminlen; // minimal length for compounding
int si_compsylmax; // max nr of syllables for compounding
int si_compoptions; // COMP_ flags
garray_T si_comppat; // CHECKCOMPOUNDPATTERN items, each stored as
// a string
- char_u *si_compflags; // flags used for compounding
+ char_u *si_compflags; // flags used for compounding
char_u si_nobreak; // NOBREAK
- char_u *si_syllable; // syllable string
+ char_u *si_syllable; // syllable string
garray_T si_prefcond; // table with conditions for postponed
// prefixes, each stored as a string
int si_newprefID; // current value for ah_newID
@@ -508,16 +508,16 @@ typedef struct spellinfo_S {
/// @return Allows to proceed if everything is OK, returns SP_TRUNCERROR if
/// there are not enough bytes, returns SP_OTHERERROR if reading failed.
#define SPELL_READ_BYTES(buf, n, fd, exit_code) \
- do { \
- const size_t n__SPRB = (n); \
- FILE *const fd__SPRB = (fd); \
- char *const buf__SPRB = (buf); \
- const size_t read_bytes__SPRB = fread(buf__SPRB, 1, n__SPRB, fd__SPRB); \
- if (read_bytes__SPRB != n__SPRB) { \
- exit_code; \
- return feof(fd__SPRB) ? SP_TRUNCERROR : SP_OTHERERROR; \
- } \
- } while (0)
+ do { \
+ const size_t n__SPRB = (n); \
+ FILE *const fd__SPRB = (fd); \
+ char *const buf__SPRB = (buf); \
+ const size_t read_bytes__SPRB = fread(buf__SPRB, 1, n__SPRB, fd__SPRB); \
+ if (read_bytes__SPRB != n__SPRB) { \
+ exit_code; \
+ return feof(fd__SPRB) ? SP_TRUNCERROR : SP_OTHERERROR; \
+ } \
+ } while (0)
/// Like #SPELL_READ_BYTES, but also error out if NUL byte was read
///
@@ -525,16 +525,16 @@ typedef struct spellinfo_S {
/// there are not enough bytes, returns SP_OTHERERROR if reading failed,
/// returns SP_FORMERROR if read out a NUL byte.
#define SPELL_READ_NONNUL_BYTES(buf, n, fd, exit_code) \
- do { \
- const size_t n__SPRNB = (n); \
- FILE *const fd__SPRNB = (fd); \
- char *const buf__SPRNB = (buf); \
- SPELL_READ_BYTES(buf__SPRNB, n__SPRNB, fd__SPRNB, exit_code); \
- if (memchr(buf__SPRNB, NUL, (size_t)n__SPRNB)) { \
- exit_code; \
- return SP_FORMERROR; \
- } \
- } while (0)
+ do { \
+ const size_t n__SPRNB = (n); \
+ FILE *const fd__SPRNB = (fd); \
+ char *const buf__SPRNB = (buf); \
+ SPELL_READ_BYTES(buf__SPRNB, n__SPRNB, fd__SPRNB, exit_code); \
+ if (memchr(buf__SPRNB, NUL, (size_t)n__SPRNB)) { \
+ exit_code; \
+ return SP_FORMERROR; \
+ } \
+ } while (0)
/// Check that spell file starts with a magic string
///
@@ -556,40 +556,36 @@ static inline int spell_check_magic_string(FILE *const fd)
return 0;
}
-// Load one spell file and store the info into a slang_T.
-//
-// This is invoked in three ways:
-// - From spell_load_cb() to load a spell file for the first time. "lang" is
-// the language name, "old_lp" is NULL. Will allocate an slang_T.
-// - To reload a spell file that was changed. "lang" is NULL and "old_lp"
-// points to the existing slang_T.
-// - Just after writing a .spl file; it's read back to produce the .sug file.
-// "old_lp" is NULL and "lang" is NULL. Will allocate an slang_T.
-//
-// Returns the slang_T the spell file was loaded into. NULL for error.
-slang_T *
-spell_load_file (
- char_u *fname,
- char_u *lang,
- slang_T *old_lp,
- bool silent // no error if file doesn't exist
-)
+/// Load one spell file and store the info into a slang_T.
+///
+/// This is invoked in three ways:
+/// - From spell_load_cb() to load a spell file for the first time. "lang" is
+/// the language name, "old_lp" is NULL. Will allocate an slang_T.
+/// - To reload a spell file that was changed. "lang" is NULL and "old_lp"
+/// points to the existing slang_T.
+/// - Just after writing a .spl file; it's read back to produce the .sug file.
+/// "old_lp" is NULL and "lang" is NULL. Will allocate an slang_T.
+///
+/// @param silent no error if file doesn't exist
+///
+/// @return the slang_T the spell file was loaded into. NULL for error.
+slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool silent)
{
- FILE *fd;
- char_u *p;
+ FILE *fd;
+ char_u *p;
int n;
int len;
- char_u *save_sourcing_name = sourcing_name;
+ char_u *save_sourcing_name = sourcing_name;
linenr_T save_sourcing_lnum = sourcing_lnum;
- slang_T *lp = NULL;
+ slang_T *lp = NULL;
int c = 0;
int res;
fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
- if (!silent)
+ if (!silent) {
EMSG2(_(e_notopen), fname);
- else if (p_verbose > 2) {
+ } else if (p_verbose > 2) {
verbose_enter();
smsg((char *)e_notopen, fname);
verbose_leave();
@@ -610,8 +606,9 @@ spell_load_file (
// Check for .add.spl.
lp->sl_add = strstr((char *)path_tail(fname), SPL_FNAME_ADD) != NULL;
- } else
+ } else {
lp = old_lp;
+ }
// Set sourcing_name, so that error messages mention the file name.
sourcing_name = fname;
@@ -620,19 +617,16 @@ spell_load_file (
// <HEADER>: <fileID>
const int scms_ret = spell_check_magic_string(fd);
switch (scms_ret) {
- case SP_FORMERROR:
- case SP_TRUNCERROR: {
- emsgf("%s", _("E757: This does not look like a spell file"));
- goto endFAIL;
- }
- case SP_OTHERERROR: {
- emsgf(_("E5042: Failed to read spell file %s: %s"),
- fname, strerror(ferror(fd)));
- goto endFAIL;
- }
- case 0: {
- break;
- }
+ case SP_FORMERROR:
+ case SP_TRUNCERROR:
+ emsgf("%s", _("E757: This does not look like a spell file"));
+ goto endFAIL;
+ case SP_OTHERERROR:
+ emsgf(_("E5042: Failed to read spell file %s: %s"),
+ fname, strerror(ferror(fd)));
+ goto endFAIL;
+ case 0:
+ break;
}
c = getc(fd); // <versionnr>
if (c < VIMSPELLVERSION) {
@@ -648,19 +642,22 @@ spell_load_file (
// <section>: <sectionID> <sectionflags> <sectionlen> (section contents)
for (;; ) {
n = getc(fd); // <sectionID> or <sectionend>
- if (n == SN_END)
+ if (n == SN_END) {
break;
+ }
c = getc(fd); // <sectionflags>
len = get4c(fd); // <sectionlen>
- if (len < 0)
+ if (len < 0) {
goto truncerr;
+ }
res = 0;
switch (n) {
case SN_INFO:
lp->sl_info = READ_STRING(fd, len); // <infotext>
- if (lp->sl_info == NULL)
+ if (lp->sl_info == NULL) {
goto endFAIL;
+ }
break;
case SN_REGION:
@@ -673,8 +670,9 @@ spell_load_file (
case SN_MIDWORD:
lp->sl_midword = READ_STRING(fd, len); // <midword>
- if (lp->sl_midword == NULL)
+ if (lp->sl_midword == NULL) {
goto endFAIL;
+ }
break;
case SN_PREFCOND:
@@ -699,8 +697,9 @@ spell_load_file (
case SN_MAP:
p = READ_STRING(fd, len); // <mapstr>
- if (p == NULL)
+ if (p == NULL) {
goto endFAIL;
+ }
set_map_str(lp, p);
xfree(p);
break;
@@ -731,10 +730,12 @@ spell_load_file (
case SN_SYLLABLE:
lp->sl_syllable = READ_STRING(fd, len); // <syllable>
- if (lp->sl_syllable == NULL)
+ if (lp->sl_syllable == NULL) {
goto endFAIL;
- if (init_syl_tab(lp) == FAIL)
+ }
+ if (init_syl_tab(lp) == FAIL) {
goto endFAIL;
+ }
break;
default:
@@ -744,9 +745,11 @@ spell_load_file (
EMSG(_("E770: Unsupported section in spell file"));
goto endFAIL;
}
- while (--len >= 0)
- if (getc(fd) < 0)
+ while (--len >= 0) {
+ if (getc(fd) < 0) {
goto truncerr;
+ }
+ }
break;
}
someerror:
@@ -759,8 +762,9 @@ truncerr:
EMSG(_(e_spell_trunc));
goto endFAIL;
}
- if (res == SP_OTHERERROR)
+ if (res == SP_OTHERERROR) {
goto endFAIL;
+ }
}
// <LWORDTREE>
@@ -792,16 +796,19 @@ truncerr:
goto endOK;
endFAIL:
- if (lang != NULL)
+ if (lang != NULL) {
// truncating the name signals the error to spell_load_lang()
*lang = NUL;
- if (lp != NULL && old_lp == NULL)
+ }
+ if (lp != NULL && old_lp == NULL) {
slang_free(lp);
+ }
lp = NULL;
endOK:
- if (fd != NULL)
+ if (fd != NULL) {
fclose(fd);
+ }
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
@@ -827,8 +834,9 @@ static void tree_count_words(char_u *byts, idx_T *idxs)
if (curi[depth] > byts[arridx[depth]]) {
// Done all bytes at this node, go up one level.
idxs[arridx[depth]] = wordcount[depth];
- if (depth > 0)
+ if (depth > 0) {
wordcount[depth - 1] += wordcount[depth];
+ }
--depth;
fast_breakcheck();
@@ -862,10 +870,10 @@ static void tree_count_words(char_u *byts, idx_T *idxs)
// Load the .sug files for languages that have one and weren't loaded yet.
void suggest_load_files(void)
{
- langp_T *lp;
- slang_T *slang;
- char_u *dotp;
- FILE *fd;
+ langp_T *lp;
+ slang_T *slang;
+ char_u *dotp;
+ FILE *fd;
char_u buf[MAXWLEN];
int i;
time_t timestamp;
@@ -895,21 +903,22 @@ void suggest_load_files(void)
}
// <SUGHEADER>: <fileID> <versionnr> <timestamp>
- for (i = 0; i < VIMSUGMAGICL; ++i)
+ for (i = 0; i < VIMSUGMAGICL; ++i) {
buf[i] = getc(fd); // <fileID>
+ }
if (STRNCMP(buf, VIMSUGMAGIC, VIMSUGMAGICL) != 0) {
EMSG2(_("E778: This does not look like a .sug file: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
}
c = getc(fd); // <versionnr>
if (c < VIMSUGVERSION) {
EMSG2(_("E779: Old .sug file, needs to be updated: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
- } else if (c > VIMSUGVERSION) {
+ } else if (c > VIMSUGVERSION) {
EMSG2(_("E780: .sug file is for newer version of Vim: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
}
@@ -918,7 +927,7 @@ void suggest_load_files(void)
timestamp = get8ctime(fd); // <timestamp>
if (timestamp != slang->sl_sugtime) {
EMSG2(_("E781: .sug file doesn't match .spl file: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
}
@@ -928,7 +937,7 @@ void suggest_load_files(void)
false, 0) != 0) {
someerror:
EMSG2(_("E782: error while reading .sug file: %s"),
- slang->sl_fname);
+ slang->sl_fname);
slang_clear_sug(slang);
goto nextone;
}
@@ -942,8 +951,9 @@ someerror:
// <sugwcount>
wcount = get4c(fd);
- if (wcount < 0)
+ if (wcount < 0) {
goto someerror;
+ }
// Read all the wordnr lists into the buffer, one NUL terminated
// list per line.
@@ -956,8 +966,9 @@ someerror:
goto someerror;
}
GA_APPEND(char_u, &ga, c);
- if (c == NUL)
+ if (c == NUL) {
break;
+ }
}
if (ml_append_buf(slang->sl_sugbuf, (linenr_T)wordnr,
ga.ga_data, ga.ga_len, true) == FAIL) {
@@ -972,8 +983,9 @@ someerror:
tree_count_words(slang->sl_sbyts, slang->sl_sidxs);
nextone:
- if (fd != NULL)
+ if (fd != NULL) {
fclose(fd);
+ }
STRCPY(dotp, ".spl");
}
}
@@ -988,7 +1000,7 @@ nextone:
static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
{
int cnt = 0;
- char_u *str;
+ char_u *str;
// read the length bytes, MSB first
for (int i = 0; i < cnt_bytes; i++) {
@@ -1001,12 +1013,13 @@ static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
cnt = (cnt << 8) + (unsigned)c;
}
*cntp = cnt;
- if (cnt == 0)
+ if (cnt == 0) {
return NULL; // nothing to read, return NULL
-
+ }
str = READ_STRING(fd, cnt);
- if (str == NULL)
+ if (str == NULL) {
*cntp = SP_OTHERERROR;
+ }
return str;
}
@@ -1027,14 +1040,15 @@ static int read_region_section(FILE *fd, slang_T *lp, int len)
// Return SP_*ERROR flags.
static int read_charflags_section(FILE *fd)
{
- char_u *flags;
- char_u *fol;
+ char_u *flags;
+ char_u *fol;
int flagslen, follen;
// <charflagslen> <charflags>
flags = read_cnt_string(fd, 1, &flagslen);
- if (flagslen < 0)
+ if (flagslen < 0) {
return flagslen;
+ }
// <folcharslen> <folchars>
fol = read_cnt_string(fd, 2, &follen);
@@ -1044,15 +1058,17 @@ static int read_charflags_section(FILE *fd)
}
// Set the word-char flags and fill SPELL_ISUPPER() table.
- if (flags != NULL && fol != NULL)
+ if (flags != NULL && fol != NULL) {
set_spell_charflags(flags, flagslen, fol);
+ }
xfree(flags);
xfree(fol);
// When <charflagslen> is zero then <fcharlen> must also be zero.
- if ((flags == NULL) != (fol == NULL))
+ if ((flags == NULL) != (fol == NULL)) {
return SP_FORMERROR;
+ }
return 0;
}
@@ -1094,11 +1110,12 @@ static int read_prefcond_section(FILE *fd, slang_T *lp)
static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
{
int cnt;
- fromto_T *ftp;
+ fromto_T *ftp;
cnt = get2c(fd); // <repcount>
- if (cnt < 0)
+ if (cnt < 0) {
return SP_TRUNCERROR;
+ }
ga_grow(gap, cnt);
@@ -1107,15 +1124,18 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
int c;
ftp = &((fromto_T *)gap->ga_data)[gap->ga_len];
ftp->ft_from = read_cnt_string(fd, 1, &c);
- if (c < 0)
+ if (c < 0) {
return c;
- if (c == 0)
+ }
+ if (c == 0) {
return SP_FORMERROR;
+ }
ftp->ft_to = read_cnt_string(fd, 1, &c);
if (c <= 0) {
xfree(ftp->ft_from);
- if (c < 0)
+ if (c < 0) {
return c;
+ }
return SP_FORMERROR;
}
}
@@ -1126,8 +1146,9 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
}
for (int i = 0; i < gap->ga_len; ++i) {
ftp = &((fromto_T *)gap->ga_data)[i];
- if (first[*ftp->ft_from] == -1)
+ if (first[*ftp->ft_from] == -1) {
first[*ftp->ft_from] = i;
+ }
}
return 0;
}
@@ -1137,10 +1158,10 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
static int read_sal_section(FILE *fd, slang_T *slang)
{
int cnt;
- garray_T *gap;
- salitem_T *smp;
+ garray_T *gap;
+ salitem_T *smp;
int ccnt;
- char_u *p;
+ char_u *p;
slang->sl_sofo = false;
@@ -1156,8 +1177,9 @@ static int read_sal_section(FILE *fd, slang_T *slang)
}
cnt = get2c(fd); // <salcount>
- if (cnt < 0)
+ if (cnt < 0) {
return SP_TRUNCERROR;
+ }
gap = &slang->sl_sal;
ga_init(gap, sizeof(salitem_T), 10);
@@ -1169,8 +1191,9 @@ static int read_sal_section(FILE *fd, slang_T *slang)
smp = &((salitem_T *)gap->ga_data)[gap->ga_len];
ccnt = getc(fd); // <salfromlen>
- if (ccnt < 0)
+ if (ccnt < 0) {
return SP_TRUNCERROR;
+ }
p = xmalloc(ccnt + 2);
smp->sm_lead = p;
@@ -1178,8 +1201,9 @@ static int read_sal_section(FILE *fd, slang_T *slang)
int i = 0;
for (; i < ccnt; ++i) {
c = getc(fd); // <salfrom>
- if (vim_strchr((char_u *)"0123456789(-<^$", c) != NULL)
+ if (vim_strchr((char_u *)"0123456789(-<^$", c) != NULL) {
break;
+ }
*p++ = c;
}
smp->sm_leadlen = (int)(p - smp->sm_lead);
@@ -1190,15 +1214,18 @@ static int read_sal_section(FILE *fd, slang_T *slang)
smp->sm_oneof = p;
for (++i; i < ccnt; ++i) {
c = getc(fd); // <salfrom>
- if (c == ')')
+ if (c == ')') {
break;
+ }
*p++ = c;
}
*p++ = NUL;
- if (++i < ccnt)
+ if (++i < ccnt) {
c = getc(fd);
- } else
+ }
+ } else {
smp->sm_oneof = NULL;
+ }
// Any following chars go in sm_rules.
smp->sm_rules = p;
@@ -1209,7 +1236,8 @@ static int read_sal_section(FILE *fd, slang_T *slang)
i++;
if (i < ccnt) {
SPELL_READ_NONNUL_BYTES( // <salfrom>
- (char *)p, (size_t)(ccnt - i), fd, xfree(smp->sm_lead));
+ (char *)p, (size_t)(ccnt - i), fd,
+ xfree(smp->sm_lead));
p += (ccnt - i);
}
*p++ = NUL;
@@ -1272,13 +1300,16 @@ static int read_words_section(FILE *fd, slang_T *lp, int len)
// Read one word at a time.
for (i = 0;; ++i) {
c = getc(fd);
- if (c == EOF)
+ if (c == EOF) {
return SP_TRUNCERROR;
+ }
word[i] = c;
- if (word[i] == NUL)
+ if (word[i] == NUL) {
break;
- if (i == MAXWLEN - 1)
+ }
+ if (i == MAXWLEN - 1) {
return SP_FORMERROR;
+ }
}
// Init the count to 10.
@@ -1293,15 +1324,16 @@ static int read_words_section(FILE *fd, slang_T *lp, int len)
static int read_sofo_section(FILE *fd, slang_T *slang)
{
int cnt;
- char_u *from, *to;
+ char_u *from, *to;
int res;
slang->sl_sofo = true;
// <sofofromlen> <sofofrom>
from = read_cnt_string(fd, 2, &cnt);
- if (cnt < 0)
+ if (cnt < 0) {
return cnt;
+ }
// <sofotolen> <sofoto>
to = read_cnt_string(fd, 2, &cnt);
@@ -1311,12 +1343,13 @@ static int read_sofo_section(FILE *fd, slang_T *slang)
}
// Store the info in slang->sl_sal and/or slang->sl_sal_first.
- if (from != NULL && to != NULL)
+ if (from != NULL && to != NULL) {
res = set_sofo(slang, from, to);
- else if (from != NULL || to != NULL)
+ } else if (from != NULL || to != NULL) {
res = SP_FORMERROR; // only one of two strings is an error
- else
+ } else {
res = 0;
+ }
xfree(from);
xfree(to);
@@ -1331,39 +1364,42 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
int todo = len;
int c;
int atstart;
- char_u *pat;
- char_u *pp;
- char_u *cp;
- char_u *ap;
- char_u *crp;
+ char_u *pat;
+ char_u *pp;
+ char_u *cp;
+ char_u *ap;
+ char_u *crp;
int cnt;
- garray_T *gap;
+ garray_T *gap;
- if (todo < 2)
+ if (todo < 2) {
return SP_FORMERROR; // need at least two bytes
-
+ }
--todo;
c = getc(fd); // <compmax>
- if (c < 2)
+ if (c < 2) {
c = MAXWLEN;
+ }
slang->sl_compmax = c;
--todo;
c = getc(fd); // <compminlen>
- if (c < 1)
+ if (c < 1) {
c = 0;
+ }
slang->sl_compminlen = c;
--todo;
c = getc(fd); // <compsylmax>
- if (c < 1)
+ if (c < 1) {
c = MAXWLEN;
+ }
slang->sl_compsylmax = c;
c = getc(fd); // <compoptions>
- if (c != 0)
+ if (c != 0) {
ungetc(c, fd); // be backwards compatible with Vim 7.0b
- else {
+ } else {
--todo;
c = getc(fd); // only use the lower byte for now
--todo;
@@ -1381,13 +1417,15 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
((char_u **)(gap->ga_data))[gap->ga_len++] =
read_cnt_string(fd, 1, &cnt);
// <comppatlen> <comppattext>
- if (cnt < 0)
+ if (cnt < 0) {
return cnt;
+ }
todo -= cnt + 1;
}
}
- if (todo < 0)
+ if (todo < 0) {
return SP_FORMERROR;
+ }
// Turn the COMPOUNDRULE items into a regexp pattern:
// "a[bc]/a*b+" -> "^\(a[bc]\|a*b\+\)$".
@@ -1436,17 +1474,18 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
if (atstart != 0) {
// At start of item: copy flags to "sl_compstartflags". For a
// [abc] item set "atstart" to 2 and copy up to the ']'.
- if (c == '[')
+ if (c == '[') {
atstart = 2;
- else if (c == ']')
+ } else if (c == ']') {
atstart = 0;
- else {
+ } else {
if (!byte_in_str(slang->sl_compstartflags, c)) {
*cp++ = c;
*cp = NUL;
}
- if (atstart == 1)
+ if (atstart == 1) {
atstart = 0;
+ }
}
}
@@ -1455,8 +1494,9 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
if (c == '?' || c == '+' || c == '*') {
XFREE_CLEAR(slang->sl_comprules);
crp = NULL;
- } else
+ } else {
*crp++ = c;
+ }
}
if (c == '/') { // slash separates two items
@@ -1476,13 +1516,15 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
*pp++ = '$';
*pp = NUL;
- if (crp != NULL)
+ if (crp != NULL) {
*crp = NUL;
+ }
slang->sl_compprog = vim_regcomp(pat, RE_MAGIC + RE_STRING + RE_STRICT);
xfree(pat);
- if (slang->sl_compprog == NULL)
+ if (slang->sl_compprog == NULL) {
return SP_FORMERROR;
+ }
return 0;
}
@@ -1491,8 +1533,8 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
// Returns SP_*ERROR flags when there is something wrong.
static int set_sofo(slang_T *lp, char_u *from, char_u *to)
{
- char_u *s;
- char_u *p;
+ char_u *s;
+ char_u *p;
// Use "sl_sal" as an array with 256 pointers to a list of wide
// characters. The index is the low byte of the character.
@@ -1554,10 +1596,10 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// Fill the first-index table for "lp".
static void set_sal_first(slang_T *lp)
{
- salfirst_T *sfirst;
- salitem_T *smp;
+ salfirst_T *sfirst;
+ salitem_T *smp;
int c;
- garray_T *gap = &lp->sl_sal;
+ garray_T *gap = &lp->sl_sal;
sfirst = lp->sl_sal_first;
for (int i = 0; i < 256; ++i) {
@@ -1613,24 +1655,21 @@ static int *mb_str2wide(char_u *s)
return res;
}
-// Reads a tree from the .spl or .sug file.
-// Allocates the memory and stores pointers in "bytsp" and "idxsp".
-// This is skipped when the tree has zero length.
-// Returns zero when OK, SP_ value for an error.
-static int
-spell_read_tree (
- FILE *fd,
- char_u **bytsp,
- long *bytsp_len,
- idx_T **idxsp,
- bool prefixtree, // true for the prefix tree
- int prefixcnt // when "prefixtree" is true: prefix count
-)
+/// Reads a tree from the .spl or .sug file.
+/// Allocates the memory and stores pointers in "bytsp" and "idxsp".
+/// This is skipped when the tree has zero length.
+///
+/// @param prefixtree true for the prefix tree
+/// @param prefixcnt when "prefixtree" is true: prefix count
+///
+/// @return zero when OK, SP_ value for an error.
+static int spell_read_tree(FILE *fd, char_u **bytsp, long *bytsp_len, idx_T **idxsp,
+ bool prefixtree, int prefixcnt)
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
int idx;
- char_u *bp;
- idx_T *ip;
+ char_u *bp;
+ idx_T *ip;
// The tree size was computed when writing the file, so that we can
// allocate it as one long block. <nodecount>
@@ -1656,30 +1695,28 @@ spell_read_tree (
// Recursively read the tree and store it in the array.
idx = read_tree_node(fd, bp, ip, len, 0, prefixtree, prefixcnt);
- if (idx < 0)
+ if (idx < 0) {
return idx;
+ }
}
return 0;
}
-// Read one row of siblings from the spell file and store it in the byte array
-// "byts" and index array "idxs". Recursively read the children.
-//
-// NOTE: The code here must match put_node()!
-//
-// Returns the index (>= 0) following the siblings.
-// Returns SP_TRUNCERROR if the file is shorter than expected.
-// Returns SP_FORMERROR if there is a format error.
-static idx_T
-read_tree_node (
- FILE *fd,
- char_u *byts,
- idx_T *idxs,
- int maxidx, // size of arrays
- idx_T startidx, // current index in "byts" and "idxs"
- bool prefixtree, // true for reading PREFIXTREE
- int maxprefcondnr // maximum for <prefcondnr>
-)
+/// Read one row of siblings from the spell file and store it in the byte array
+/// "byts" and index array "idxs". Recursively read the children.
+///
+/// NOTE: The code here must match put_node()!
+///
+/// Returns the index (>= 0) following the siblings.
+/// Returns SP_TRUNCERROR if the file is shorter than expected.
+/// Returns SP_FORMERROR if there is a format error.
+///
+/// @param maxidx size of arrays
+/// @param startidx current index in "byts" and "idxs"
+/// @param prefixtree true for reading PREFIXTREE
+/// @param maxprefcondnr maximum for <prefcondnr>
+static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx_T startidx,
+ bool prefixtree, int maxprefcondnr)
{
int len;
int i;
@@ -1690,18 +1727,21 @@ read_tree_node (
#define SHARED_MASK 0x8000000
len = getc(fd); // <siblingcount>
- if (len <= 0)
+ if (len <= 0) {
return SP_TRUNCERROR;
+ }
- if (startidx + len >= maxidx)
+ if (startidx + len >= maxidx) {
return SP_FORMERROR;
+ }
byts[idx++] = len;
// Read the byte values, flag/region bytes and shared indexes.
for (i = 1; i <= len; ++i) {
c = getc(fd); // <byte>
- if (c < 0)
+ if (c < 0) {
return SP_TRUNCERROR;
+ }
if (c <= BY_SPECIAL) {
if (c == BY_NOFLAGS && !prefixtree) {
// No flags, all regions.
@@ -1712,16 +1752,18 @@ read_tree_node (
// condition nr. In idxs[] store the prefix ID in the low
// byte, the condition index shifted up 8 bits, the flags
// shifted up 24 bits.
- if (c == BY_FLAGS)
+ if (c == BY_FLAGS) {
c = getc(fd) << 24; // <pflags>
- else
+ } else {
c = 0;
+ }
c |= getc(fd); // <affixID>
n = get2c(fd); // <prefcondnr>
- if (n >= maxprefcondnr)
+ if (n >= maxprefcondnr) {
return SP_FORMERROR;
+ }
c |= (n << 8);
} else { // c must be BY_FLAGS or BY_FLAGS2
// Read flags and optional region and prefix ID. In
@@ -1729,21 +1771,25 @@ read_tree_node (
// that and prefix ID above the region.
c2 = c;
c = getc(fd); // <flags>
- if (c2 == BY_FLAGS2)
+ if (c2 == BY_FLAGS2) {
c = (getc(fd) << 8) + c; // <flags2>
- if (c & WF_REGION)
+ }
+ if (c & WF_REGION) {
c = (getc(fd) << 16) + c; // <region>
- if (c & WF_AFX)
+ }
+ if (c & WF_AFX) {
c = (getc(fd) << 24) + c; // <affixID>
+ }
}
idxs[idx] = c;
c = 0;
- } else { // c == BY_INDEX
+ } else { // c == BY_INDEX
// <nodeidx>
n = get3c(fd);
- if (n < 0 || n >= maxidx)
+ if (n < 0 || n >= maxidx) {
return SP_FORMERROR;
+ }
idxs[idx] = n + SHARED_MASK;
c = getc(fd); // <xbyte>
}
@@ -1754,38 +1800,39 @@ read_tree_node (
// Recursively read the children for non-shared siblings.
// Skip the end-of-word ones (zero byte value) and the shared ones (and
// remove SHARED_MASK)
- for (i = 1; i <= len; ++i)
+ for (i = 1; i <= len; ++i) {
if (byts[startidx + i] != 0) {
- if (idxs[startidx + i] & SHARED_MASK)
+ if (idxs[startidx + i] & SHARED_MASK) {
idxs[startidx + i] &= ~SHARED_MASK;
- else {
+ } else {
idxs[startidx + i] = idx;
idx = read_tree_node(fd, byts, idxs, maxidx, idx,
- prefixtree, maxprefcondnr);
- if (idx < 0)
+ prefixtree, maxprefcondnr);
+ if (idx < 0) {
break;
+ }
}
}
+ }
return idx;
}
-// Reload the spell file "fname" if it's loaded.
-static void
-spell_reload_one (
- char_u *fname,
- bool added_word // invoked through "zg"
-)
+/// Reload the spell file "fname" if it's loaded.
+///
+/// @param added_word invoked through "zg"
+static void spell_reload_one(char_u *fname, bool added_word)
{
- slang_T *slang;
+ slang_T *slang;
bool didit = false;
for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
if (path_full_compare(fname, slang->sl_fname, false, true) == kEqualFiles) {
slang_clear(slang);
- if (spell_load_file(fname, NULL, slang, false) == NULL)
+ if (spell_load_file(fname, NULL, slang, false) == NULL) {
// reloading failed, clear the language
slang_clear(slang);
+ }
redraw_all_later(SOME_VALID);
didit = true;
}
@@ -1793,8 +1840,9 @@ spell_reload_one (
// When "zg" was used and the file wasn't loaded yet, should redo
// 'spelllang' to load it now.
- if (added_word && !didit)
+ if (added_word && !didit) {
did_set_spelllang(curwin);
+ }
}
// Functions for ":mkspell".
@@ -1820,13 +1868,14 @@ static long compress_added = 500000; // word count
// Sets "sps_flags".
int spell_check_msm(void)
{
- char_u *p = p_msm;
+ char_u *p = p_msm;
long start = 0;
long incr = 0;
long added = 0;
- if (!ascii_isdigit(*p))
+ if (!ascii_isdigit(*p)) {
return FAIL;
+ }
// block count = (value * 1024) / SBLOCKSIZE (but avoid overflow)
start = (getdigits_long(&p, true, 0) * 10) / (SBLOCKSIZE / 102);
if (*p != ',') {
@@ -1864,11 +1913,12 @@ int spell_check_msm(void)
// readable format, so that we can see what happens when adding a word and/or
// compressing the tree.
// Based on code from Olaf Seibert.
-#define PRINTLINESIZE 1000
-#define PRINTWIDTH 6
+# define PRINTLINESIZE 1000
+# define PRINTWIDTH 6
-#define PRINTSOME(l, depth, fmt, a1, a2) vim_snprintf(l + depth * PRINTWIDTH, \
- PRINTLINESIZE - PRINTWIDTH * depth, fmt, a1, a2)
+# define PRINTSOME(l, depth, fmt, a1, a2) vim_snprintf(l + depth * PRINTWIDTH, \
+ PRINTLINESIZE - PRINTWIDTH * depth, fmt, a1, \
+ a2)
static char line1[PRINTLINESIZE];
static char line2[PRINTLINESIZE];
@@ -1876,7 +1926,7 @@ static char line3[PRINTLINESIZE];
static void spell_clear_flags(wordnode_T *node)
{
- wordnode_T *np;
+ wordnode_T *np;
for (np = node; np != NULL; np = np->wn_sibling) {
np->wn_u1.index = FALSE;
@@ -1898,20 +1948,23 @@ static void spell_print_node(wordnode_T *node, int depth)
node->wn_u1.index = TRUE;
if (node->wn_byte != NUL) {
- if (node->wn_child != NULL)
+ if (node->wn_child != NULL) {
PRINTSOME(line1, depth, " %c -> ", node->wn_byte, 0);
- else
+ } else {
// Cannot happen?
PRINTSOME(line1, depth, " %c ???", node->wn_byte, 0);
- } else
+ }
+ } else {
PRINTSOME(line1, depth, " $ ", 0, 0);
+ }
PRINTSOME(line2, depth, "%d/%d ", node->wn_nr, node->wn_refs);
- if (node->wn_sibling != NULL)
+ if (node->wn_sibling != NULL) {
PRINTSOME(line3, depth, " | ", 0, 0);
- else
+ } else {
PRINTSOME(line3, depth, " ", 0, 0);
+ }
if (node->wn_byte == NUL) {
msg((char_u *)line1);
@@ -1920,8 +1973,9 @@ static void spell_print_node(wordnode_T *node, int depth)
}
// do the children
- if (node->wn_byte != NUL && node->wn_child != NULL)
+ if (node->wn_byte != NUL && node->wn_child != NULL) {
spell_print_node(node->wn_child, depth + 1);
+ }
// do the siblings
if (node->wn_sibling != NULL) {
@@ -1951,39 +2005,39 @@ static void spell_print_tree(wordnode_T *root)
// Returns an afffile_T, NULL for complete failure.
static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
{
- FILE *fd;
+ FILE *fd;
char_u rline[MAXLINELEN];
- char_u *line;
- char_u *pc = NULL;
+ char_u *line;
+ char_u *pc = NULL;
#define MAXITEMCNT 30
- char_u *(items[MAXITEMCNT]);
+ char_u *(items[MAXITEMCNT]);
int itemcnt;
- char_u *p;
+ char_u *p;
int lnum = 0;
affheader_T *cur_aff = NULL;
bool did_postpone_prefix = false;
int aff_todo = 0;
- hashtab_T *tp;
- char_u *low = NULL;
- char_u *fol = NULL;
- char_u *upp = NULL;
+ hashtab_T *tp;
+ char_u *low = NULL;
+ char_u *fol = NULL;
+ char_u *upp = NULL;
int do_rep;
int do_repsal;
int do_sal;
int do_mapline;
bool found_map = false;
- hashitem_T *hi;
+ hashitem_T *hi;
int l;
int compminlen = 0; // COMPOUNDMIN value
int compsylmax = 0; // COMPOUNDSYLMAX value
int compoptions = 0; // COMP_ flags
int compmax = 0; // COMPOUNDWORDMAX value
- char_u *compflags = NULL; // COMPOUNDFLAG and COMPOUNDRULE
- // concatenated
- char_u *midword = NULL; // MIDWORD value
- char_u *syllable = NULL; // SYLLABLE value
- char_u *sofofrom = NULL; // SOFOFROM value
- char_u *sofoto = NULL; // SOFOTO value
+ char_u *compflags = NULL; // COMPOUNDFLAG and COMPOUNDRULE
+ // concatenated
+ char_u *midword = NULL; // MIDWORD value
+ char_u *syllable = NULL; // SYLLABLE value
+ char_u *sofofrom = NULL; // SOFOFROM value
+ char_u *sofoto = NULL; // SOFOTO value
// Open the file.
fd = os_fopen((char *)fname, "r");
@@ -2019,8 +2073,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
++lnum;
// Skip comment lines.
- if (*rline == '#')
+ if (*rline == '#') {
continue;
+ }
// Convert from "SET" to 'encoding' when needed.
xfree(pc);
@@ -2041,22 +2096,29 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// item.
itemcnt = 0;
for (p = line;; ) {
- while (*p != NUL && *p <= ' ') // skip white space and CR/NL
+ while (*p != NUL && *p <= ' ') { // skip white space and CR/NL
++p;
- if (*p == NUL)
+ }
+ if (*p == NUL) {
break;
- if (itemcnt == MAXITEMCNT) // too many items
+ }
+ if (itemcnt == MAXITEMCNT) { // too many items
break;
+ }
items[itemcnt++] = p;
// A few items have arbitrary text argument, don't split them.
- if (itemcnt == 2 && spell_info_item(items[0]))
- while (*p >= ' ' || *p == TAB) // skip until CR/NL
+ if (itemcnt == 2 && spell_info_item(items[0])) {
+ while (*p >= ' ' || *p == TAB) { // skip until CR/NL
++p;
- else
- while (*p > ' ') // skip until white space or CR/NL
+ }
+ } else {
+ while (*p > ' ') { // skip until white space or CR/NL
++p;
- if (*p == NUL)
+ }
+ }
+ if (*p == NUL) {
break;
+ }
*p++ = NUL;
}
@@ -2067,21 +2129,23 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
aff->af_enc = enc_canonize(items[1]);
if (!spin->si_ascii
&& convert_setup(&spin->si_conv, aff->af_enc,
- p_enc) == FAIL)
+ p_enc) == FAIL) {
smsg(_("Conversion in %s not supported: from %s to %s"),
fname, aff->af_enc, p_enc);
+ }
spin->si_conv.vc_fail = true;
} else if (is_aff_rule(items, itemcnt, "FLAG", 2)
&& aff->af_flagtype == AFT_CHAR) {
- if (STRCMP(items[1], "long") == 0)
+ if (STRCMP(items[1], "long") == 0) {
aff->af_flagtype = AFT_LONG;
- else if (STRCMP(items[1], "num") == 0)
+ } else if (STRCMP(items[1], "num") == 0) {
aff->af_flagtype = AFT_NUM;
- else if (STRCMP(items[1], "caplong") == 0)
+ } else if (STRCMP(items[1], "caplong") == 0) {
aff->af_flagtype = AFT_CAPLONG;
- else
+ } else {
smsg(_("Invalid value for FLAG in %s line %d: %s"),
fname, lnum, items[1]);
+ }
if (aff->af_rare != 0
|| aff->af_keepcase != 0
|| aff->af_bad != 0
@@ -2092,10 +2156,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
|| aff->af_nosuggest != 0
|| compflags != NULL
|| aff->af_suff.ht_used > 0
- || aff->af_pref.ht_used > 0)
+ || aff->af_pref.ht_used > 0) {
smsg(_("FLAG after using flags in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (spell_info_item(items[0]) && itemcnt > 1) {
+ }
+ } else if (spell_info_item(items[0]) && itemcnt > 1) {
p = getroom(spin,
(spin->si_info == NULL ? 0 : STRLEN(spin->si_info))
+ STRLEN(items[0])
@@ -2111,7 +2176,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "MIDWORD", 2)
&& midword == NULL) {
midword = getroom_save(spin, items[1]);
- } else if (is_aff_rule(items, itemcnt, "TRY", 2)) {
+ } else if (is_aff_rule(items, itemcnt, "TRY", 2)) {
// ignored, we look in the tree for what chars may appear
}
// TODO: remove "RAR" later
@@ -2119,54 +2184,56 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
|| is_aff_rule(items, itemcnt, "RARE", 2))
&& aff->af_rare == 0) {
aff->af_rare = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
}
// TODO: remove "KEP" later
else if ((is_aff_rule(items, itemcnt, "KEP", 2)
|| is_aff_rule(items, itemcnt, "KEEPCASE", 2))
&& aff->af_keepcase == 0) {
aff->af_keepcase = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if ((is_aff_rule(items, itemcnt, "BAD", 2)
|| is_aff_rule(items, itemcnt, "FORBIDDENWORD", 2))
&& aff->af_bad == 0) {
aff->af_bad = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "NEEDAFFIX", 2)
&& aff->af_needaffix == 0) {
aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "CIRCUMFIX", 2)
&& aff->af_circumfix == 0) {
aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "NOSUGGEST", 2)
&& aff->af_nosuggest == 0) {
aff->af_nosuggest = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if ((is_aff_rule(items, itemcnt, "NEEDCOMPOUND", 2)
|| is_aff_rule(items, itemcnt, "ONLYINCOMPOUND", 2))
&& aff->af_needcomp == 0) {
aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "COMPOUNDROOT", 2)
&& aff->af_comproot == 0) {
aff->af_comproot = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "COMPOUNDFORBIDFLAG", 2)
&& aff->af_compforbid == 0) {
aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
- if (aff->af_pref.ht_used > 0)
+ fname, lnum);
+ if (aff->af_pref.ht_used > 0) {
smsg(_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"),
fname, lnum);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDPERMITFLAG", 2)
&& aff->af_comppermit == 0) {
aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
- if (aff->af_pref.ht_used > 0)
+ fname, lnum);
+ if (aff->af_pref.ht_used > 0) {
smsg(_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"),
fname, lnum);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDFLAG", 2)
&& compflags == NULL) {
// Turn flag "c" into COMPOUNDRULE compatible string "c+",
@@ -2175,20 +2242,22 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
STRCPY(p, items[1]);
STRCAT(p, "+");
compflags = p;
- } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) {
+ } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) {
// We don't use the count, but do check that it's a number and
// not COMPOUNDRULE mistyped.
- if (atoi((char *)items[1]) == 0)
+ if (atoi((char *)items[1]) == 0) {
smsg(_("Wrong COMPOUNDRULES value in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULE", 2)) {
+ }
+ } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULE", 2)) {
// Don't use the first rule if it is a number.
if (compflags != NULL || *skipdigits(items[1]) != NUL) {
// Concatenate this string to previously defined ones,
// using a slash to separate them.
l = (int)STRLEN(items[1]) + 1;
- if (compflags != NULL)
+ if (compflags != NULL) {
l += (int)STRLEN(compflags) + 1;
+ }
p = getroom(spin, l, false);
if (compflags != NULL) {
STRCPY(p, compflags);
@@ -2200,43 +2269,49 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2)
&& compmax == 0) {
compmax = atoi((char *)items[1]);
- if (compmax == 0)
+ if (compmax == 0) {
smsg(_("Wrong COMPOUNDWORDMAX value in %s line %d: %s"),
fname, lnum, items[1]);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDMIN", 2)
&& compminlen == 0) {
compminlen = atoi((char *)items[1]);
- if (compminlen == 0)
+ if (compminlen == 0) {
smsg(_("Wrong COMPOUNDMIN value in %s line %d: %s"),
fname, lnum, items[1]);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDSYLMAX", 2)
&& compsylmax == 0) {
compsylmax = atoi((char *)items[1]);
- if (compsylmax == 0)
+ if (compsylmax == 0) {
smsg(_("Wrong COMPOUNDSYLMAX value in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDDUP", 1)) {
+ }
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDDUP", 1)) {
compoptions |= COMP_CHECKDUP;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDREP", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDREP", 1)) {
compoptions |= COMP_CHECKREP;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDCASE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDCASE", 1)) {
compoptions |= COMP_CHECKCASE;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDTRIPLE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDTRIPLE", 1)) {
compoptions |= COMP_CHECKTRIPLE;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 2)) {
- if (atoi((char *)items[1]) == 0)
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 2)) {
+ if (atoi((char *)items[1]) == 0) {
smsg(_("Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 3)) {
- garray_T *gap = &spin->si_comppat;
+ }
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 3)) {
+ garray_T *gap = &spin->si_comppat;
int i;
// Only add the couple if it isn't already there.
- for (i = 0; i < gap->ga_len - 1; i += 2)
+ for (i = 0; i < gap->ga_len - 1; i += 2) {
if (STRCMP(((char_u **)(gap->ga_data))[i], items[1]) == 0
&& STRCMP(((char_u **)(gap->ga_data))[i + 1],
- items[2]) == 0)
+ items[2]) == 0) {
break;
+ }
+ }
if (i >= gap->ga_len) {
ga_grow(gap, 2);
((char_u **)(gap->ga_data))[gap->ga_len++]
@@ -2247,15 +2322,15 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "SYLLABLE", 2)
&& syllable == NULL) {
syllable = getroom_save(spin, items[1]);
- } else if (is_aff_rule(items, itemcnt, "NOBREAK", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "NOBREAK", 1)) {
spin->si_nobreak = true;
- } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) {
spin->si_nosplitsugs = true;
} else if (is_aff_rule(items, itemcnt, "NOCOMPOUNDSUGS", 1)) {
spin->si_nocompoundsugs = true;
- } else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1)) {
spin->si_nosugfile = true;
- } else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1)) {
aff->af_pfxpostpone = true;
} else if (is_aff_rule(items, itemcnt, "IGNOREEXTRA", 1)) {
aff->af_ignoreextra = true;
@@ -2266,10 +2341,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
int lasti = 4;
char_u key[AH_KEY_LEN];
- if (*items[0] == 'P')
+ if (*items[0] == 'P') {
tp = &aff->af_pref;
- else
+ } else {
tp = &aff->af_suff;
+ }
// Myspell allows the same affix name to be used multiple
// times. The affix files that do this have an undocumented
@@ -2279,12 +2355,14 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
hi = hash_find(tp, key);
if (!HASHITEM_EMPTY(hi)) {
cur_aff = HI2AH(hi);
- if (cur_aff->ah_combine != (*items[2] == 'Y'))
+ if (cur_aff->ah_combine != (*items[2] == 'Y')) {
smsg(_("Different combining flag in continued affix block in %s line %d: %s"),
fname, lnum, items[1]);
- if (!cur_aff->ah_follows)
+ }
+ if (!cur_aff->ah_follows) {
smsg(_("Duplicate affix in %s line %d: %s"),
fname, lnum, items[1]);
+ }
} else {
// New affix letter.
cur_aff = getroom(spin, sizeof(*cur_aff), true);
@@ -2317,20 +2395,23 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (itemcnt > lasti && STRCMP(items[lasti], "S") == 0) {
++lasti;
cur_aff->ah_follows = true;
- } else
+ } else {
cur_aff->ah_follows = false;
+ }
// Myspell allows extra text after the item, but that might
// mean mistakes go unnoticed. Require a comment-starter,
// unless IGNOREEXTRA is used. Hunspell uses a "-" item.
if (itemcnt > lasti
&& !aff->af_ignoreextra
- && *items[lasti] != '#')
+ && *items[lasti] != '#') {
smsg(_(e_afftrailing), fname, lnum, items[lasti]);
+ }
- if (STRCMP(items[2], "Y") != 0 && STRCMP(items[2], "N") != 0)
+ if (STRCMP(items[2], "Y") != 0 && STRCMP(items[2], "N") != 0) {
smsg(_("Expected Y or N in %s line %d: %s"),
- fname, lnum, items[2]);
+ fname, lnum, items[2]);
+ }
if (*items[0] == 'P' && aff->af_pfxpostpone) {
if (cur_aff->ah_newID == 0) {
@@ -2343,9 +2424,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// postponed. We know that only after handling all
// the items.
did_postpone_prefix = false;
- } else
+ } else {
// Did use the ID in a previous block.
did_postpone_prefix = true;
+ }
}
aff_todo = atoi((char *)items[3]);
@@ -2354,7 +2436,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
&& aff_todo > 0
&& STRCMP(cur_aff->ah_key, items[1]) == 0
&& itemcnt >= 5) {
- affentry_T *aff_entry;
+ affentry_T *aff_entry;
bool upper = false;
int lasti = 5;
@@ -2363,15 +2445,17 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// Hunspell uses a "-" item.
if (itemcnt > lasti && *items[lasti] != '#'
&& (STRCMP(items[lasti], "-") != 0
- || itemcnt != lasti + 1))
+ || itemcnt != lasti + 1)) {
smsg(_(e_afftrailing), fname, lnum, items[lasti]);
+ }
// New item for an affix letter.
aff_todo--;
aff_entry = getroom(spin, sizeof(*aff_entry), true);
- if (STRCMP(items[2], "0") != 0)
+ if (STRCMP(items[2], "0") != 0) {
aff_entry->ae_chop = getroom_save(spin, items[2]);
+ }
if (STRCMP(items[3], "0") != 0) {
aff_entry->ae_add = getroom_save(spin, items[3]);
@@ -2394,15 +2478,17 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
char_u buf[MAXLINELEN];
aff_entry->ae_cond = getroom_save(spin, items[4]);
- if (*items[0] == 'P')
+ if (*items[0] == 'P') {
sprintf((char *)buf, "^%s", items[4]);
- else
+ } else {
sprintf((char *)buf, "%s$", items[4]);
+ }
aff_entry->ae_prog = vim_regcomp(buf,
- RE_MAGIC + RE_STRING + RE_STRICT);
- if (aff_entry->ae_prog == NULL)
+ RE_MAGIC + RE_STRING + RE_STRICT);
+ if (aff_entry->ae_prog == NULL) {
smsg(_("Broken condition in %s line %d: %s"),
fname, lnum, items[4]);
+ }
}
// For postponed prefixes we need an entry in si_prefcond
@@ -2418,9 +2504,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// be empty or start with the same letter.
if (aff_entry->ae_chop != NULL
&& aff_entry->ae_add != NULL
- && aff_entry->ae_chop[(*mb_ptr2len)(
- aff_entry->ae_chop)] == NUL
- ) {
+ && aff_entry->ae_chop[(*mb_ptr2len)(aff_entry->ae_chop)] ==
+ NUL) {
int c, c_up;
c = PTR2CHAR(aff_entry->ae_chop);
@@ -2445,10 +2530,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
aff_entry->ae_cond = getroom_save(spin, buf);
if (aff_entry->ae_cond != NULL) {
sprintf((char *)buf, "^%s",
- aff_entry->ae_cond);
+ aff_entry->ae_cond);
vim_regfree(aff_entry->ae_prog);
- aff_entry->ae_prog = vim_regcomp(
- buf, RE_MAGIC + RE_STRING);
+ aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING);
}
}
}
@@ -2457,43 +2541,49 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (aff_entry->ae_chop == NULL) {
int idx;
- char_u **pp;
+ char_u **pp;
int n;
// Find a previously used condition.
for (idx = spin->si_prefcond.ga_len - 1; idx >= 0;
--idx) {
p = ((char_u **)spin->si_prefcond.ga_data)[idx];
- if (str_equal(p, aff_entry->ae_cond))
+ if (str_equal(p, aff_entry->ae_cond)) {
break;
+ }
}
if (idx < 0) {
// Not found, add a new condition.
idx = spin->si_prefcond.ga_len;
pp = GA_APPEND_VIA_PTR(char_u *, &spin->si_prefcond);
*pp = (aff_entry->ae_cond == NULL) ?
- NULL : getroom_save(spin, aff_entry->ae_cond);
+ NULL : getroom_save(spin, aff_entry->ae_cond);
}
// Add the prefix to the prefix tree.
- if (aff_entry->ae_add == NULL)
+ if (aff_entry->ae_add == NULL) {
p = (char_u *)"";
- else
+ } else {
p = aff_entry->ae_add;
+ }
// PFX_FLAGS is a negative number, so that
// tree_add_word() knows this is the prefix tree.
n = PFX_FLAGS;
- if (!cur_aff->ah_combine)
+ if (!cur_aff->ah_combine) {
n |= WFP_NC;
- if (upper)
+ }
+ if (upper) {
n |= WFP_UP;
- if (aff_entry->ae_comppermit)
+ }
+ if (aff_entry->ae_comppermit) {
n |= WFP_COMPPERMIT;
- if (aff_entry->ae_compforbid)
+ }
+ if (aff_entry->ae_compforbid) {
n |= WFP_COMPFORBID;
+ }
tree_add_word(spin, p, spin->si_prefroot, n,
- idx, cur_aff->ah_newID);
+ idx, cur_aff->ah_newID);
did_postpone_prefix = true;
}
@@ -2504,26 +2594,28 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
}
}
}
- } else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL) {
+ } else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL) {
fol = vim_strsave(items[1]);
- } else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL) {
+ } else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL) {
low = vim_strsave(items[1]);
- } else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL) {
+ } else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL) {
upp = vim_strsave(items[1]);
} else if (is_aff_rule(items, itemcnt, "REP", 2)
|| is_aff_rule(items, itemcnt, "REPSAL", 2)) {
/* Ignore REP/REPSAL count */;
- if (!isdigit(*items[1]))
+ if (!isdigit(*items[1])) {
smsg(_("Expected REP(SAL) count in %s line %d"),
fname, lnum);
+ }
} else if ((STRCMP(items[0], "REP") == 0
|| STRCMP(items[0], "REPSAL") == 0)
&& itemcnt >= 3) {
// REP/REPSAL item
// Myspell ignores extra arguments, we require it starts with
// # to detect mistakes.
- if (itemcnt > 3 && items[3][0] != '#')
+ if (itemcnt > 3 && items[3][0] != '#') {
smsg(_(e_afftrailing), fname, lnum, items[3]);
+ }
if (items[0][3] == 'S' ? do_repsal : do_rep) {
// Replace underscore with space (can't include a space
// directly).
@@ -2541,15 +2633,16 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
? &spin->si_repsal
: &spin->si_rep, items[1], items[2]);
}
- } else if (is_aff_rule(items, itemcnt, "MAP", 2)) {
+ } else if (is_aff_rule(items, itemcnt, "MAP", 2)) {
// MAP item or count
if (!found_map) {
// First line contains the count.
found_map = true;
- if (!isdigit(*items[1]))
+ if (!isdigit(*items[1])) {
smsg(_("Expected MAP count in %s line %d"),
fname, lnum);
- } else if (do_mapline) {
+ }
+ } else if (do_mapline) {
int c;
// Check that every character appears only once.
@@ -2575,17 +2668,18 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (do_sal) {
// SAL item (sounds-a-like)
// Either one of the known keys or a from-to pair.
- if (STRCMP(items[1], "followup") == 0)
+ if (STRCMP(items[1], "followup") == 0) {
spin->si_followup = sal_to_bool(items[2]);
- else if (STRCMP(items[1], "collapse_result") == 0)
+ } else if (STRCMP(items[1], "collapse_result") == 0) {
spin->si_collapse = sal_to_bool(items[2]);
- else if (STRCMP(items[1], "remove_accents") == 0)
+ } else if (STRCMP(items[1], "remove_accents") == 0) {
spin->si_rem_accents = sal_to_bool(items[2]);
- else
+ } else {
// when "to" is "_" it means empty
add_fromto(spin, &spin->si_sal, items[1],
- STRCMP(items[2], "_") == 0 ? (char_u *)""
- : items[2]);
+ STRCMP(items[2], "_") == 0 ? (char_u *)""
+ : items[2]);
+ }
}
} else if (is_aff_rule(items, itemcnt, "SOFOFROM", 2)
&& sofofrom == NULL) {
@@ -2593,19 +2687,20 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "SOFOTO", 2)
&& sofoto == NULL) {
sofoto = getroom_save(spin, items[1]);
- } else if (STRCMP(items[0], "COMMON") == 0) {
+ } else if (STRCMP(items[0], "COMMON") == 0) {
int i;
for (i = 1; i < itemcnt; ++i) {
if (HASHITEM_EMPTY(hash_find(&spin->si_commonwords,
- items[i]))) {
+ items[i]))) {
p = vim_strsave(items[i]);
hash_add(&spin->si_commonwords, p);
}
}
- } else
+ } else {
smsg(_("Unrecognized or duplicate item in %s line %d: %s"),
fname, lnum, items[0]);
+ }
}
}
@@ -2646,17 +2741,19 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
spin->si_compoptions |= compoptions;
}
- if (compflags != NULL)
+ if (compflags != NULL) {
process_compflags(spin, aff, compflags);
+ }
// Check that we didn't use too many renumbered flags.
if (spin->si_newcompID < spin->si_newprefID) {
- if (spin->si_newcompID == 127 || spin->si_newcompID == 255)
+ if (spin->si_newcompID == 127 || spin->si_newcompID == 255) {
MSG(_("Too many postponed prefixes"));
- else if (spin->si_newprefID == 0 || spin->si_newprefID == 127)
+ } else if (spin->si_newprefID == 0 || spin->si_newprefID == 127) {
MSG(_("Too many compound flags"));
- else
+ } else {
MSG(_("Too many postponed prefixes and/or compound flags"));
+ }
}
if (syllable != NULL) {
@@ -2665,12 +2762,12 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
}
if (sofofrom != NULL || sofoto != NULL) {
- if (sofofrom == NULL || sofoto == NULL)
+ if (sofofrom == NULL || sofoto == NULL) {
smsg(_("Missing SOFO%s line in %s"),
sofofrom == NULL ? "FROM" : "TO", fname);
- else if (!GA_EMPTY(&spin->si_sal))
+ } else if (!GA_EMPTY(&spin->si_sal)) {
smsg(_("Both SAL and SOFO lines in %s"), fname);
- else {
+ } else {
aff_check_string(spin->si_sofofr, sofofrom, "SOFOFROM");
aff_check_string(spin->si_sofoto, sofoto, "SOFOTO");
spin->si_sofofr = sofofrom;
@@ -2701,8 +2798,8 @@ static bool is_aff_rule(char_u **items, int itemcnt, char *rulename, int mincoun
// ae_flags to ae_comppermit and ae_compforbid.
static void aff_process_flags(afffile_T *affile, affentry_T *entry)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
unsigned flag;
if (entry->ae_flags != NULL
@@ -2713,16 +2810,19 @@ static void aff_process_flags(afffile_T *affile, affentry_T *entry)
if (flag == affile->af_comppermit || flag == affile->af_compforbid) {
STRMOVE(prevp, p);
p = prevp;
- if (flag == affile->af_comppermit)
+ if (flag == affile->af_comppermit) {
entry->ae_comppermit = true;
- else
+ } else {
entry->ae_compforbid = true;
+ }
}
- if (affile->af_flagtype == AFT_NUM && *p == ',')
+ if (affile->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
- if (*entry->ae_flags == NUL)
+ if (*entry->ae_flags == NUL) {
entry->ae_flags = NULL; // nothing left
+ }
}
}
@@ -2742,16 +2842,17 @@ static bool spell_info_item(char_u *s)
static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum)
{
unsigned res;
- char_u *p = item;
+ char_u *p = item;
res = get_affitem(flagtype, &p);
if (res == 0) {
- if (flagtype == AFT_NUM)
+ if (flagtype == AFT_NUM) {
smsg(_("Flag is not a number in %s line %d: %s"),
fname, lnum, item);
- else
+ } else {
smsg(_("Illegal flag in %s line %d: %s"),
fname, lnum, item);
+ }
}
if (*p != NUL) {
smsg(_(e_affname), fname, lnum, item);
@@ -2781,8 +2882,9 @@ static unsigned get_affitem(int flagtype, char_u **pp)
res = mb_ptr2char_adv((const char_u **)pp);
if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG
&& res >= 'A' && res <= 'Z')) {
- if (**pp == NUL)
+ if (**pp == NUL) {
return 0;
+ }
res = mb_ptr2char_adv((const char_u **)pp) + (res << 16);
}
}
@@ -2795,22 +2897,23 @@ static unsigned get_affitem(int flagtype, char_u **pp)
// they fit in one byte.
static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compflags)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
unsigned flag;
- compitem_T *ci;
+ compitem_T *ci;
int id;
int len;
- char_u *tp;
+ char_u *tp;
char_u key[AH_KEY_LEN];
- hashitem_T *hi;
+ hashitem_T *hi;
// Make room for the old and the new compflags, concatenated with a / in
// between. Processing it makes it shorter, but we don't know by how
// much, thus allocate the maximum.
len = (int)STRLEN(compflags) + 1;
- if (spin->si_compflags != NULL)
+ if (spin->si_compflags != NULL) {
len += (int)STRLEN(spin->si_compflags) + 1;
+ }
p = getroom(spin, len, false);
if (spin->si_compflags != NULL) {
STRCPY(p, spin->si_compflags);
@@ -2820,10 +2923,10 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
tp = p + STRLEN(p);
for (p = compflags; *p != NUL; ) {
- if (vim_strchr((char_u *)"/?*+[]", *p) != NULL)
+ if (vim_strchr((char_u *)"/?*+[]", *p) != NULL) {
// Copy non-flag characters directly.
*tp++ = *p++;
- else {
+ } else {
// First get the flag number, also checks validity.
prevp = p;
flag = get_affitem(aff->af_flagtype, &p);
@@ -2849,8 +2952,9 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
}
*tp++ = id;
}
- if (aff->af_flagtype == AFT_NUM && *p == ',')
+ if (aff->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
}
@@ -2872,7 +2976,7 @@ static void check_renumber(spellinfo_T *spin)
// Returns true if flag "flag" appears in affix list "afflist".
static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
{
- char_u *p;
+ char_u *p;
unsigned n;
switch (flagtype) {
@@ -2916,25 +3020,28 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
// Give a warning when "spinval" and "affval" numbers are set and not the same.
static void aff_check_number(int spinval, int affval, char *name)
{
- if (spinval != 0 && spinval != affval)
+ if (spinval != 0 && spinval != affval) {
smsg(_("%s value differs from what is used in another .aff file"),
name);
+ }
}
// Give a warning when "spinval" and "affval" strings are set and not the same.
static void aff_check_string(char_u *spinval, char_u *affval, char *name)
{
- if (spinval != NULL && STRCMP(spinval, affval) != 0)
+ if (spinval != NULL && STRCMP(spinval, affval) != 0) {
smsg(_("%s value differs from what is used in another .aff file"),
name);
+ }
}
// Returns true if strings "s1" and "s2" are equal. Also consider both being
// NULL as equal.
static bool str_equal(char_u *s1, char_u *s2)
{
- if (s1 == NULL || s2 == NULL)
+ if (s1 == NULL || s2 == NULL) {
return s1 == s2;
+ }
return STRCMP(s1, s2) == 0;
}
@@ -2960,11 +3067,11 @@ static bool sal_to_bool(char_u *s)
// Free the structure filled by spell_read_aff().
static void spell_free_aff(afffile_T *aff)
{
- hashtab_T *ht;
- hashitem_T *hi;
+ hashtab_T *ht;
+ hashitem_T *hi;
int todo;
affheader_T *ah;
- affentry_T *ae;
+ affentry_T *ae;
xfree(aff->af_enc);
@@ -2975,12 +3082,14 @@ static void spell_free_aff(afffile_T *aff)
if (!HASHITEM_EMPTY(hi)) {
--todo;
ah = HI2AH(hi);
- for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next)
+ for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next) {
vim_regfree(ae->ae_prog);
+ }
}
}
- if (ht == &aff->af_suff)
+ if (ht == &aff->af_suff) {
break;
+ }
}
hash_clear(&aff->af_pref);
@@ -2994,18 +3103,18 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
{
hashtab_T ht;
char_u line[MAXLINELEN];
- char_u *p;
- char_u *afflist;
+ char_u *p;
+ char_u *afflist;
char_u store_afflist[MAXWLEN];
int pfxlen;
bool need_affix;
- char_u *dw;
- char_u *pc;
- char_u *w;
+ char_u *dw;
+ char_u *pc;
+ char_u *w;
int l;
hash_T hash;
- hashitem_T *hi;
- FILE *fd;
+ hashitem_T *hi;
+ FILE *fd;
int lnum = 1;
int non_ascii = 0;
int retval = OK;
@@ -3042,16 +3151,18 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
while (!vim_fgets(line, MAXLINELEN, fd) && !got_int) {
line_breakcheck();
++lnum;
- if (line[0] == '#' || line[0] == '/')
+ if (line[0] == '#' || line[0] == '/') {
continue; // comment line
-
+ }
// Remove CR, LF and white space from the end. White space halfway through
// the word is kept to allow multi-word terms like "et al.".
l = (int)STRLEN(line);
- while (l > 0 && line[l - 1] <= ' ')
+ while (l > 0 && line[l - 1] <= ' ') {
--l;
- if (l == 0)
+ }
+ if (l == 0) {
continue; // empty line
+ }
line[l] = NUL;
// Convert from "SET" to 'encoding' when needed.
@@ -3117,15 +3228,17 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
hash = hash_hash(dw);
hi = hash_lookup(&ht, (const char *)dw, STRLEN(dw), hash);
if (!HASHITEM_EMPTY(hi)) {
- if (p_verbose > 0)
+ if (p_verbose > 0) {
smsg(_("Duplicate word in %s line %d: %s"),
fname, lnum, dw);
- else if (duplicate == 0)
+ } else if (duplicate == 0) {
smsg(_("First duplicate word in %s line %d: %s"),
fname, lnum, dw);
+ }
++duplicate;
- } else
+ } else {
hash_add_item(&ht, hi, dw, hash);
+ }
flags = 0;
store_afflist[0] = NUL;
@@ -3135,48 +3248,57 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
// Extract flags from the affix list.
flags |= get_affix_flags(affile, afflist);
- if (affile->af_needaffix != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_needaffix))
+ if (affile->af_needaffix != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_needaffix)) {
need_affix = true;
+ }
- if (affile->af_pfxpostpone)
+ if (affile->af_pfxpostpone) {
// Need to store the list of prefix IDs with the word.
pfxlen = get_pfxlist(affile, afflist, store_afflist);
+ }
- if (spin->si_compflags != NULL)
+ if (spin->si_compflags != NULL) {
// Need to store the list of compound flags with the word.
// Concatenate them to the list of prefix IDs.
get_compflags(affile, afflist, store_afflist + pfxlen);
+ }
}
// Add the word to the word tree(s).
if (store_word(spin, dw, flags, spin->si_region,
- store_afflist, need_affix) == FAIL)
+ store_afflist, need_affix) == FAIL) {
retval = FAIL;
+ }
if (afflist != NULL) {
// Find all matching suffixes and add the resulting words.
// Additionally do matching prefixes that combine.
if (store_aff_word(spin, dw, afflist, affile,
- &affile->af_suff, &affile->af_pref,
- CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL)
+ &affile->af_suff, &affile->af_pref,
+ CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL) {
retval = FAIL;
+ }
// Find all matching prefixes and add the resulting words.
if (store_aff_word(spin, dw, afflist, affile,
- &affile->af_pref, NULL,
- CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL)
+ &affile->af_pref, NULL,
+ CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL) {
retval = FAIL;
+ }
}
xfree(pc);
}
- if (duplicate > 0)
+ if (duplicate > 0) {
smsg(_("%d duplicate word(s) in %s"), duplicate, fname);
- if (spin->si_ascii && non_ascii > 0)
+ }
+ if (spin->si_ascii && non_ascii > 0) {
smsg(_("Ignored %d word(s) with non-ASCII characters in %s"),
non_ascii, fname);
+ }
hash_clear(&ht);
fclose(fd);
@@ -3189,24 +3311,34 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist)
{
int flags = 0;
- if (affile->af_keepcase != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_keepcase))
+ if (affile->af_keepcase != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_keepcase)) {
flags |= WF_KEEPCAP | WF_FIXCAP;
- if (affile->af_rare != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_rare))
+ }
+ if (affile->af_rare != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist, affile->af_rare)) {
flags |= WF_RARE;
- if (affile->af_bad != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_bad))
+ }
+ if (affile->af_bad != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist, affile->af_bad)) {
flags |= WF_BANNED;
- if (affile->af_needcomp != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_needcomp))
+ }
+ if (affile->af_needcomp != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_needcomp)) {
flags |= WF_NEEDCOMP;
- if (affile->af_comproot != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_comproot))
+ }
+ if (affile->af_comproot != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_comproot)) {
flags |= WF_COMPROOT;
- if (affile->af_nosuggest != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_nosuggest))
+ }
+ if (affile->af_nosuggest != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_nosuggest)) {
flags |= WF_NOSUGGEST;
+ }
return flags;
}
@@ -3216,12 +3348,12 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist)
// and return the number of affixes.
static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
int cnt = 0;
int id;
char_u key[AH_KEY_LEN];
- hashitem_T *hi;
+ hashitem_T *hi;
for (p = afflist; *p != NUL; ) {
prevp = p;
@@ -3232,12 +3364,14 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist
hi = hash_find(&affile->af_pref, key);
if (!HASHITEM_EMPTY(hi)) {
id = HI2AH(hi)->ah_newID;
- if (id != 0)
+ if (id != 0) {
store_afflist[cnt++] = id;
+ }
}
}
- if (affile->af_flagtype == AFT_NUM && *p == ',')
+ if (affile->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
store_afflist[cnt] = NUL;
@@ -3249,11 +3383,11 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist
// Puts the flags in "store_afflist[]".
static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_afflist)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
int cnt = 0;
char_u key[AH_KEY_LEN];
- hashitem_T *hi;
+ hashitem_T *hi;
for (p = afflist; *p != NUL; ) {
prevp = p;
@@ -3261,48 +3395,47 @@ static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_affl
// A flag is a compound flag if it appears in "af_comp".
STRLCPY(key, prevp, p - prevp + 1);
hi = hash_find(&affile->af_comp, key);
- if (!HASHITEM_EMPTY(hi))
+ if (!HASHITEM_EMPTY(hi)) {
store_afflist[cnt++] = HI2CI(hi)->ci_newID;
+ }
}
- if (affile->af_flagtype == AFT_NUM && *p == ',')
+ if (affile->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
store_afflist[cnt] = NUL;
}
-// Apply affixes to a word and store the resulting words.
-// "ht" is the hashtable with affentry_T that need to be applied, either
-// prefixes or suffixes.
-// "xht", when not NULL, is the prefix hashtable, to be used additionally on
-// the resulting words for combining affixes.
-//
-// Returns FAIL when out of memory.
-static int
-store_aff_word (
- spellinfo_T *spin, // spell info
- char_u *word, // basic word start
- char_u *afflist, // list of names of supported affixes
- afffile_T *affile,
- hashtab_T *ht,
- hashtab_T *xht,
- int condit, // CONDIT_SUF et al.
- int flags, // flags for the word
- char_u *pfxlist, // list of prefix IDs
- int pfxlen // nr of flags in "pfxlist" for prefixes, rest
- // is compound flags
-)
+/// Apply affixes to a word and store the resulting words.
+/// "ht" is the hashtable with affentry_T that need to be applied, either
+/// prefixes or suffixes.
+/// "xht", when not NULL, is the prefix hashtable, to be used additionally on
+/// the resulting words for combining affixes.
+///
+/// @param spin spell info
+/// @param word basic word start
+/// @param afflist list of names of supported affixes
+/// @param condit CONDIT_SUF et al.
+/// @param flags flags for the word
+/// @param pfxlist list of prefix IDs
+/// @param pfxlen nr of flags in "pfxlist" for prefixes, rest is compound flags
+///
+/// @return FAIL when out of memory.
+static int store_aff_word(spellinfo_T *spin, char_u *word, char_u *afflist, afffile_T *affile,
+ hashtab_T *ht, hashtab_T *xht, int condit, int flags, char_u *pfxlist,
+ int pfxlen)
{
int todo;
- hashitem_T *hi;
+ hashitem_T *hi;
affheader_T *ah;
- affentry_T *ae;
+ affentry_T *ae;
char_u newword[MAXWLEN];
int retval = OK;
int i, j;
- char_u *p;
+ char_u *p;
int use_flags;
- char_u *use_pfxlist;
+ char_u *use_pfxlist;
int use_pfxlen;
bool need_affix;
char_u store_afflist[MAXWLEN];
@@ -3320,7 +3453,7 @@ store_aff_word (
// supports this affix.
if (((condit & CONDIT_COMB) == 0 || ah->ah_combine)
&& flag_in_afflist(affile->af_flagtype, afflist,
- ah->ah_flag)) {
+ ah->ah_flag)) {
// Loop over all affix entries with this name.
for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next) {
// Check the condition. It's not logical to match case
@@ -3344,7 +3477,7 @@ store_aff_word (
== ((condit & CONDIT_AFF) == 0
|| ae->ae_flags == NULL
|| !flag_in_afflist(affile->af_flagtype,
- ae->ae_flags, affile->af_circumfix)))) {
+ ae->ae_flags, affile->af_circumfix)))) {
// Match. Remove the chop and add the affix.
if (xht == NULL) {
// prefix: chop/add at the start of the word
@@ -3374,8 +3507,9 @@ store_aff_word (
}
*p = NUL;
}
- if (ae->ae_add != NULL)
+ if (ae->ae_add != NULL) {
STRCAT(newword, ae->ae_add);
+ }
}
use_flags = flags;
@@ -3387,57 +3521,64 @@ store_aff_word (
// Extract flags from the affix list.
use_flags |= get_affix_flags(affile, ae->ae_flags);
- if (affile->af_needaffix != 0 && flag_in_afflist(
- affile->af_flagtype, ae->ae_flags,
- affile->af_needaffix))
+ if (affile->af_needaffix != 0 && flag_in_afflist(affile->af_flagtype, ae->ae_flags,
+ affile->af_needaffix)) {
need_affix = true;
+ }
// When there is a CIRCUMFIX flag the other affix
// must also have it and we don't add the word
// with one affix.
- if (affile->af_circumfix != 0 && flag_in_afflist(
- affile->af_flagtype, ae->ae_flags,
- affile->af_circumfix)) {
+ if (affile->af_circumfix != 0 && flag_in_afflist(affile->af_flagtype, ae->ae_flags,
+ affile->af_circumfix)) {
use_condit |= CONDIT_CFIX;
- if ((condit & CONDIT_CFIX) == 0)
+ if ((condit & CONDIT_CFIX) == 0) {
need_affix = true;
+ }
}
if (affile->af_pfxpostpone
|| spin->si_compflags != NULL) {
- if (affile->af_pfxpostpone)
+ if (affile->af_pfxpostpone) {
// Get prefix IDS from the affix list.
use_pfxlen = get_pfxlist(affile,
- ae->ae_flags, store_afflist);
- else
+ ae->ae_flags, store_afflist);
+ } else {
use_pfxlen = 0;
+ }
use_pfxlist = store_afflist;
// Combine the prefix IDs. Avoid adding the
// same ID twice.
for (i = 0; i < pfxlen; ++i) {
- for (j = 0; j < use_pfxlen; ++j)
- if (pfxlist[i] == use_pfxlist[j])
+ for (j = 0; j < use_pfxlen; ++j) {
+ if (pfxlist[i] == use_pfxlist[j]) {
break;
- if (j == use_pfxlen)
+ }
+ }
+ if (j == use_pfxlen) {
use_pfxlist[use_pfxlen++] = pfxlist[i];
+ }
}
- if (spin->si_compflags != NULL)
+ if (spin->si_compflags != NULL) {
// Get compound IDS from the affix list.
get_compflags(affile, ae->ae_flags,
- use_pfxlist + use_pfxlen);
- else
+ use_pfxlist + use_pfxlen);
+ } else {
use_pfxlist[use_pfxlen] = NUL;
+ }
// Combine the list of compound flags.
// Concatenate them to the prefix IDs list.
// Avoid adding the same ID twice.
for (i = pfxlen; pfxlist[i] != NUL; ++i) {
for (j = use_pfxlen;
- use_pfxlist[j] != NUL; ++j)
- if (pfxlist[i] == use_pfxlist[j])
+ use_pfxlist[j] != NUL; ++j) {
+ if (pfxlist[i] == use_pfxlist[j]) {
break;
+ }
+ }
if (use_pfxlist[j] == NUL) {
use_pfxlist[j++] = pfxlist[i];
use_pfxlist[j] = NUL;
@@ -3462,52 +3603,58 @@ store_aff_word (
// ... don't use a prefix list if combining
// affixes is not allowed. But do use the
// compound flags after them.
- if (!ah->ah_combine && use_pfxlist != NULL)
+ if (!ah->ah_combine && use_pfxlist != NULL) {
use_pfxlist += use_pfxlen;
+ }
}
// When compounding is supported and there is no
// "COMPOUNDPERMITFLAG" then forbid compounding on the
// side where the affix is applied.
if (spin->si_compflags != NULL && !ae->ae_comppermit) {
- if (xht != NULL)
+ if (xht != NULL) {
use_flags |= WF_NOCOMPAFT;
- else
+ } else {
use_flags |= WF_NOCOMPBEF;
+ }
}
// Store the modified word.
if (store_word(spin, newword, use_flags,
- spin->si_region, use_pfxlist,
- need_affix) == FAIL)
+ spin->si_region, use_pfxlist,
+ need_affix) == FAIL) {
retval = FAIL;
+ }
// When added a prefix or a first suffix and the affix
// has flags may add a(nother) suffix. RECURSIVE!
- if ((condit & CONDIT_SUF) && ae->ae_flags != NULL)
+ if ((condit & CONDIT_SUF) && ae->ae_flags != NULL) {
if (store_aff_word(spin, newword, ae->ae_flags,
- affile, &affile->af_suff, xht,
- use_condit & (xht == NULL
+ affile, &affile->af_suff, xht,
+ use_condit & (xht == NULL
? ~0 : ~CONDIT_SUF),
- use_flags, use_pfxlist, pfxlen) == FAIL)
+ use_flags, use_pfxlist, pfxlen) == FAIL) {
retval = FAIL;
+ }
+ }
// When added a suffix and combining is allowed also
// try adding a prefix additionally. Both for the
// word flags and for the affix flags. RECURSIVE!
if (xht != NULL && ah->ah_combine) {
if (store_aff_word(spin, newword,
- afflist, affile,
- xht, NULL, use_condit,
- use_flags, use_pfxlist,
- pfxlen) == FAIL
+ afflist, affile,
+ xht, NULL, use_condit,
+ use_flags, use_pfxlist,
+ pfxlen) == FAIL
|| (ae->ae_flags != NULL
&& store_aff_word(spin, newword,
- ae->ae_flags, affile,
- xht, NULL, use_condit,
- use_flags, use_pfxlist,
- pfxlen) == FAIL))
+ ae->ae_flags, affile,
+ xht, NULL, use_condit,
+ use_flags, use_pfxlist,
+ pfxlen) == FAIL)) {
retval = FAIL;
+ }
}
}
}
@@ -3521,12 +3668,12 @@ store_aff_word (
// Read a file with a list of words.
static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
{
- FILE *fd;
+ FILE *fd;
long lnum = 0;
char_u rline[MAXLINELEN];
- char_u *line;
- char_u *pc = NULL;
- char_u *p;
+ char_u *line;
+ char_u *pc = NULL;
+ char_u *p;
int l;
int retval = OK;
bool did_word = false;
@@ -3550,15 +3697,18 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
++lnum;
// Skip comment lines.
- if (*rline == '#')
+ if (*rline == '#') {
continue;
+ }
// Remove CR, LF and white space from the end.
l = (int)STRLEN(rline);
- while (l > 0 && rline[l - 1] <= ' ')
+ while (l > 0 && rline[l - 1] <= ' ') {
--l;
- if (l == 0)
+ }
+ if (l == 0) {
continue; // empty or blank line
+ }
rline[l] = NUL;
// Convert from "/encoding={encoding}" to 'encoding' when needed.
@@ -3586,16 +3736,17 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
smsg(_("/encoding= line after word ignored in %s line %ld: %s"),
fname, lnum, line - 1);
} else {
- char_u *enc;
+ char_u *enc;
// Setup for conversion to 'encoding'.
line += 9;
enc = enc_canonize(line);
if (!spin->si_ascii
&& convert_setup(&spin->si_conv, enc,
- p_enc) == FAIL)
+ p_enc) == FAIL) {
smsg(_("Conversion in %s not supported: from %s to %s"),
fname, line, p_enc);
+ }
xfree(enc);
spin->si_conv.vc_fail = true;
}
@@ -3635,15 +3786,16 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
if (p != NULL) {
*p++ = NUL;
while (*p != NUL) {
- if (*p == '=') // keep-case word
+ if (*p == '=') { // keep-case word
flags |= WF_KEEPCAP | WF_FIXCAP;
- else if (*p == '!') // Bad, bad, wicked word.
+ } else if (*p == '!') { // Bad, bad, wicked word.
flags |= WF_BANNED;
- else if (*p == '?') // Rare word.
+ } else if (*p == '?') { // Rare word.
flags |= WF_RARE;
- else if (ascii_isdigit(*p)) { // region number(s)
- if ((flags & WF_REGION) == 0) // first one
+ } else if (ascii_isdigit(*p)) { // region number(s)
+ if ((flags & WF_REGION) == 0) { // first one
regionmask = 0;
+ }
flags |= WF_REGION;
l = *p - '0';
@@ -3681,7 +3833,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
if (spin->si_ascii && non_ascii > 0) {
vim_snprintf((char *)IObuff, IOSIZE,
- _("Ignored %d words with non-ASCII characters"), non_ascii);
+ _("Ignored %d words with non-ASCII characters"), non_ascii);
spell_message(spin, IObuff);
}
@@ -3699,16 +3851,17 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
static void *getroom(spellinfo_T *spin, size_t len, bool align)
FUNC_ATTR_NONNULL_RET
{
- char_u *p;
- sblock_T *bl = spin->si_blocks;
+ char_u *p;
+ sblock_T *bl = spin->si_blocks;
assert(len <= SBLOCKSIZE);
-
- if (align && bl != NULL)
+
+ if (align && bl != NULL) {
// Round size up for alignment. On some systems structures need to be
// aligned to the size of a pointer (e.g., SPARC).
bl->sb_used = (bl->sb_used + sizeof(char *) - 1)
& ~(sizeof(char *) - 1);
+ }
if (bl == NULL || bl->sb_used + len > SBLOCKSIZE) {
// Allocate a block of memory. It is not freed until much later.
@@ -3737,7 +3890,7 @@ static char_u *getroom_save(spellinfo_T *spin, char_u *s)
// Free the list of allocated sblock_T.
static void free_blocks(sblock_T *bl)
{
- sblock_T *next;
+ sblock_T *next;
while (bl != NULL) {
next = bl->sb_next;
@@ -3754,22 +3907,20 @@ static wordnode_T *wordtree_alloc(spellinfo_T *spin)
return (wordnode_T *)getroom(spin, sizeof(wordnode_T), true);
}
-// Store a word in the tree(s).
-// Always store it in the case-folded tree. For a keep-case word this is
-// useful when the word can also be used with all caps (no WF_FIXCAP flag) and
-// used to find suggestions.
-// For a keep-case word also store it in the keep-case tree.
-// When "pfxlist" is not NULL store the word for each postponed prefix ID and
-// compound flag.
-static int
-store_word (
- spellinfo_T *spin,
- char_u *word,
- int flags, // extra flags, WF_BANNED
- int region, // supported region(s)
- const char_u *pfxlist, // list of prefix IDs or NULL
- bool need_affix // only store word with affix ID
-)
+/// Store a word in the tree(s).
+/// Always store it in the case-folded tree. For a keep-case word this is
+/// useful when the word can also be used with all caps (no WF_FIXCAP flag) and
+/// used to find suggestions.
+/// For a keep-case word also store it in the keep-case tree.
+/// When "pfxlist" is not NULL store the word for each postponed prefix ID and
+/// compound flag.
+///
+/// @param flags extra flags, wf_banned
+/// @param region supported region(s)
+/// @param pfxlist list of prefix ids or null
+/// @param need_affix only store word with affix id
+static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, const char_u *pfxlist,
+ bool need_affix)
{
int len = (int)STRLEN(word);
int ct = captype(word, word + len);
@@ -3807,12 +3958,13 @@ store_word (
// When "flags" < 0 we are adding to the prefix tree where "flags" is used for
// "rare" and "region" is the condition nr.
// Returns FAIL when out of memory.
-static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int flags, int region, int affixID)
+static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int flags, int region,
+ int affixID)
{
- wordnode_T *node = root;
- wordnode_T *np;
- wordnode_T *copyp, **copyprev;
- wordnode_T **prev = NULL;
+ wordnode_T *node = root;
+ wordnode_T *np;
+ wordnode_T *copyp, **copyprev;
+ wordnode_T **prev = NULL;
int i;
// Add each byte of the word to the tree, including the NUL at the end.
@@ -3826,11 +3978,13 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
for (copyp = node; copyp != NULL; copyp = copyp->wn_sibling) {
// Allocate a new node and copy the info.
np = get_wordnode(spin);
- if (np == NULL)
+ if (np == NULL) {
return FAIL;
+ }
np->wn_child = copyp->wn_child;
- if (np->wn_child != NULL)
+ if (np->wn_child != NULL) {
++np->wn_child->wn_refs; // child gets extra ref
+ }
np->wn_byte = copyp->wn_byte;
if (np->wn_byte == NUL) {
np->wn_flags = copyp->wn_flags;
@@ -3840,13 +3994,15 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
// Link the new node in the list, there will be one ref.
np->wn_refs = 1;
- if (copyprev != NULL)
+ if (copyprev != NULL) {
*copyprev = np;
+ }
copyprev = &np->wn_sibling;
// Let "node" point to the head of the copied list.
- if (copyp == node)
+ if (copyp == node) {
node = np;
+ }
}
}
@@ -3877,22 +4033,24 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
|| node->wn_affixID != affixID))) {
// Allocate a new node.
np = get_wordnode(spin);
- if (np == NULL)
+ if (np == NULL) {
return FAIL;
+ }
np->wn_byte = word[i];
// If "node" is NULL this is a new child or the end of the sibling
// list: ref count is one. Otherwise use ref count of sibling and
// make ref count of sibling one (matters when inserting in front
// of the list of siblings).
- if (node == NULL)
+ if (node == NULL) {
np->wn_refs = 1;
- else {
+ } else {
np->wn_refs = node->wn_refs;
node->wn_refs = 1;
}
- if (prev != NULL)
+ if (prev != NULL) {
*prev = np;
+ }
np->wn_sibling = node;
node = np;
}
@@ -3934,7 +4092,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
#ifndef SPELL_COMPRESS_ALLWAYS
if (spin->si_compress_cnt == 1 // NOLINT(readability/braces)
? spin->si_free_count < MAXWLEN
- : spin->si_blocks_cnt >= compress_start)
+ : spin->si_blocks_cnt >= compress_start)
#endif
{
// Decrement the block counter. The effect is that we compress again
@@ -3973,17 +4131,18 @@ static wordnode_T *get_wordnode(spellinfo_T *spin)
{
wordnode_T *n;
- if (spin->si_first_free == NULL)
+ if (spin->si_first_free == NULL) {
n = (wordnode_T *)getroom(spin, sizeof(wordnode_T), true);
- else {
+ } else {
n = spin->si_first_free;
spin->si_first_free = n->wn_child;
memset(n, 0, sizeof(wordnode_T));
--spin->si_free_count;
}
#ifdef SPELL_PRINTTREE
- if (n != NULL)
+ if (n != NULL) {
n->wn_nr = ++spin->si_wordnode_nr;
+ }
#endif
return n;
}
@@ -3995,13 +4154,14 @@ static wordnode_T *get_wordnode(spellinfo_T *spin)
static int deref_wordnode(spellinfo_T *spin, wordnode_T *node)
FUNC_ATTR_NONNULL_ALL
{
- wordnode_T *np;
+ wordnode_T *np;
int cnt = 0;
if (--node->wn_refs == 0) {
for (np = node; np != NULL; np = np->wn_sibling) {
- if (np->wn_child != NULL)
+ if (np->wn_child != NULL) {
cnt += deref_wordnode(spin, np->wn_child);
+ }
free_wordnode(spin, np);
++cnt;
}
@@ -4021,8 +4181,7 @@ static void free_wordnode(spellinfo_T *spin, wordnode_T *n)
}
// Compress a tree: find tails that are identical and can be shared.
-static void wordtree_compress(spellinfo_T *spin, wordnode_T *root,
- const char *name)
+static void wordtree_compress(spellinfo_T *spin, wordnode_T *root, const char *name)
FUNC_ATTR_NONNULL_ALL
{
hashtab_T ht;
@@ -4039,12 +4198,13 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root,
if (spin->si_verbose || p_verbose > 2)
#endif
{
- if (tot > 1000000)
+ if (tot > 1000000) {
perc = (tot - n) / (tot / 100);
- else if (tot == 0)
+ } else if (tot == 0) {
perc = 0;
- else
+ } else {
perc = (tot - n) * 100 / tot;
+ }
vim_snprintf((char *)IObuff, IOSIZE,
_("Compressed %s of %ld nodes; %ld (%ld%%) remaining"),
name, tot, tot - n, perc);
@@ -4057,22 +4217,18 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root,
}
}
-// Compress a node, its siblings and its children, depth first.
-// Returns the number of compressed nodes.
-static long node_compress(
- spellinfo_T *spin,
- wordnode_T *node,
- hashtab_T *ht,
- long *tot // total count of nodes before compressing,
- // incremented while going through the tree
-)
+/// Compress a node, its siblings and its children, depth first.
+/// Returns the number of compressed nodes.
+///
+/// @param tot total count of nodes before compressing, incremented while going through the tree
+static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, long *tot)
FUNC_ATTR_NONNULL_ALL
{
- wordnode_T *np;
- wordnode_T *tp;
- wordnode_T *child;
+ wordnode_T *np;
+ wordnode_T *tp;
+ wordnode_T *child;
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
long len = 0;
unsigned nr, n;
long compressed = 0;
@@ -4095,7 +4251,7 @@ static long node_compress(
// There are children we encountered before with a hash value
// identical to the current child. Now check if there is one
// that is really identical.
- for (tp = HI2WN(hi); tp != NULL; tp = tp->wn_u2.next)
+ for (tp = HI2WN(hi); tp != NULL; tp = tp->wn_u2.next) {
if (node_equal(child, tp)) {
// Found one! Now use that child in place of the
// current one. This means the current child and all
@@ -4105,6 +4261,7 @@ static long node_compress(
np->wn_child = tp;
break;
}
+ }
if (tp == NULL) {
// No other child with this hash value equals the child of
// the node, add it to the linked list after the first
@@ -4113,10 +4270,11 @@ static long node_compress(
child->wn_u2.next = tp->wn_u2.next;
tp->wn_u2.next = child;
}
- } else
+ } else {
// No other child has this hash value, add it to the
// hashtable.
hash_add_item(ht, hi, child->wn_u1.hashkey, hash);
+ }
}
}
*tot += len + 1; // add one for the node that stores the length
@@ -4127,12 +4285,13 @@ static long node_compress(
node->wn_u1.hashkey[0] = len;
nr = 0;
for (np = node; np != NULL; np = np->wn_sibling) {
- if (np->wn_byte == NUL)
+ if (np->wn_byte == NUL) {
// end node: use wn_flags, wn_region and wn_affixID
n = np->wn_flags + (np->wn_region << 8) + (np->wn_affixID << 16);
- else
+ } else {
// byte node: use the byte value and the child pointer
n = (unsigned)(np->wn_byte + ((uintptr_t)np->wn_child << 8));
+ }
nr = nr * 101 + n;
}
@@ -4156,18 +4315,20 @@ static long node_compress(
// Returns true when two nodes have identical siblings and children.
static bool node_equal(wordnode_T *n1, wordnode_T *n2)
{
- wordnode_T *p1;
- wordnode_T *p2;
+ wordnode_T *p1;
+ wordnode_T *p2;
for (p1 = n1, p2 = n2; p1 != NULL && p2 != NULL;
- p1 = p1->wn_sibling, p2 = p2->wn_sibling)
+ p1 = p1->wn_sibling, p2 = p2->wn_sibling) {
if (p1->wn_byte != p2->wn_byte
|| (p1->wn_byte == NUL
? (p1->wn_flags != p2->wn_flags
|| p1->wn_region != p2->wn_region
|| p1->wn_affixID != p2->wn_affixID)
- : (p1->wn_child != p2->wn_child)))
+ : (p1->wn_child != p2->wn_child))) {
break;
+ }
+ }
return p1 == NULL && p2 == NULL;
}
@@ -4176,8 +4337,8 @@ static bool node_equal(wordnode_T *n1, wordnode_T *n2)
// Function given to qsort() to sort the REP items on "from" string.
static int rep_compare(const void *s1, const void *s2)
{
- fromto_T *p1 = (fromto_T *)s1;
- fromto_T *p2 = (fromto_T *)s2;
+ fromto_T *p1 = (fromto_T *)s1;
+ fromto_T *p2 = (fromto_T *)s2;
return STRCMP(p1->ft_from, p2->ft_from);
}
@@ -4198,9 +4359,10 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
// <HEADER>: <fileID> <versionnr>
// <fileID>
size_t fwv = fwrite(VIMSPELLMAGIC, VIMSPELLMAGICL, 1, fd);
- if (fwv != (size_t)1)
+ if (fwv != (size_t)1) {
// Catch first write error, don't try writing more.
goto theend;
+ }
putc(VIMSPELLVERSION, fd); // <versionnr>
@@ -4225,8 +4387,9 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
fwv &= fwrite(spin->si_region_name, l, 1, fd);
// <regionname> ...
regionmask = (1 << spin->si_region_count) - 1;
- } else
+ } else {
regionmask = 0;
+ }
// SN_CHARFLAGS: <charflagslen> <charflags> <folcharslen> <folchars>
//
@@ -4254,10 +4417,12 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
fputc(128, fd); // <charflagslen>
for (size_t i = 128; i < 256; ++i) {
flags = 0;
- if (spelltab.st_isw[i])
+ if (spelltab.st_isw[i]) {
flags |= CF_WORD;
- if (spelltab.st_isu[i])
+ }
+ if (spelltab.st_isu[i]) {
flags |= CF_UPPER;
+ }
fputc(flags, fd); // <charflags>
}
@@ -4296,24 +4461,28 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
// round 3: SN_REPSAL section
for (unsigned int round = 1; round <= 3; ++round) {
garray_T *gap;
- if (round == 1)
+ if (round == 1) {
gap = &spin->si_rep;
- else if (round == 2) {
+ } else if (round == 2) {
// Don't write SN_SAL when using a SN_SOFO section
- if (spin->si_sofofr != NULL && spin->si_sofoto != NULL)
+ if (spin->si_sofofr != NULL && spin->si_sofoto != NULL) {
continue;
+ }
gap = &spin->si_sal;
- } else
+ } else {
gap = &spin->si_repsal;
+ }
// Don't write the section if there are no items.
- if (GA_EMPTY(gap))
+ if (GA_EMPTY(gap)) {
continue;
+ }
// Sort the REP/REPSAL items.
- if (round != 2)
+ if (round != 2) {
qsort(gap->ga_data, (size_t)gap->ga_len,
- sizeof(fromto_T), rep_compare);
+ sizeof(fromto_T), rep_compare);
+ }
int sect_id = round == 1 ? SN_REP : (round == 2 ? SN_SAL : SN_REPSAL);
putc(sect_id, fd); // <sectionID>
@@ -4329,18 +4498,22 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
l += 1 + STRLEN(ftp->ft_from); // count <*fromlen> and <*from>
l += 1 + STRLEN(ftp->ft_to); // count <*tolen> and <*to>
}
- if (round == 2)
+ if (round == 2) {
++l; // count <salflags>
+ }
put_bytes(fd, l, 4); // <sectionlen>
if (round == 2) {
int i = 0;
- if (spin->si_followup)
+ if (spin->si_followup) {
i |= SAL_F0LLOWUP;
- if (spin->si_collapse)
+ }
+ if (spin->si_collapse) {
i |= SAL_COLLAPSE;
- if (spin->si_rem_accents)
+ }
+ if (spin->si_rem_accents) {
i |= SAL_REM_ACCENTS;
+ }
putc(i, fd); // <salflags>
}
@@ -4354,11 +4527,11 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
l = STRLEN(p);
assert(l < INT_MAX);
putc((int)l, fd);
- if (l > 0)
+ if (l > 0) {
fwv &= fwrite(p, l, 1, fd);
+ }
}
}
-
}
// SN_SOFO: <sofofromlen> <sofofrom> <sofotolen> <sofoto>
@@ -4389,19 +4562,22 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
for (unsigned int round = 1; round <= 2; ++round) {
size_t todo;
size_t len = 0;
- hashitem_T *hi;
+ hashitem_T *hi;
todo = spin->si_commonwords.ht_used;
- for (hi = spin->si_commonwords.ht_array; todo > 0; ++hi)
+ for (hi = spin->si_commonwords.ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
size_t l = STRLEN(hi->hi_key) + 1;
len += l;
- if (round == 2) // <word>
+ if (round == 2) { // <word>
fwv &= fwrite(hi->hi_key, l, 1, fd);
+ }
--todo;
}
- if (round == 1)
+ }
+ if (round == 1) {
put_bytes(fd, len, 4); // <sectionlen>
+ }
}
}
@@ -4509,12 +4685,13 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
spin->si_memtot = 0;
for (unsigned int round = 1; round <= 3; ++round) {
wordnode_T *tree;
- if (round == 1)
+ if (round == 1) {
tree = spin->si_foldroot->wn_sibling;
- else if (round == 2)
+ } else if (round == 2) {
tree = spin->si_keeproot->wn_sibling;
- else
+ } else {
tree = spin->si_prefroot->wn_sibling;
+ }
// Clear the index and wnode fields in the tree.
clear_node(tree);
@@ -4534,16 +4711,20 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
}
// Write another byte to check for errors (file system full).
- if (putc(0, fd) == EOF)
+ if (putc(0, fd) == EOF) {
retval = FAIL;
+ }
theend:
- if (fclose(fd) == EOF)
+ if (fclose(fd) == EOF) {
retval = FAIL;
+ }
- if (fwv != (size_t)1)
+ if (fwv != (size_t)1) {
retval = FAIL;
- if (retval == FAIL)
+ }
+ if (retval == FAIL) {
EMSG(_(e_write));
+ }
return retval;
}
@@ -4553,54 +4734,54 @@ theend:
// space.
static void clear_node(wordnode_T *node)
{
- wordnode_T *np;
+ wordnode_T *np;
- if (node != NULL)
+ if (node != NULL) {
for (np = node; np != NULL; np = np->wn_sibling) {
np->wn_u1.index = 0;
np->wn_u2.wnode = NULL;
- if (np->wn_byte != NUL)
+ if (np->wn_byte != NUL) {
clear_node(np->wn_child);
+ }
}
+ }
}
-// Dump a word tree at node "node".
-//
-// This first writes the list of possible bytes (siblings). Then for each
-// byte recursively write the children.
-//
-// NOTE: The code here must match the code in read_tree_node(), since
-// assumptions are made about the indexes (so that we don't have to write them
-// in the file).
-//
-// Returns the number of nodes used.
-static int
-put_node (
- FILE *fd, // NULL when only counting
- wordnode_T *node,
- int idx,
- int regionmask,
- bool prefixtree // true for PREFIXTREE
-)
+/// Dump a word tree at node "node".
+///
+/// This first writes the list of possible bytes (siblings). Then for each
+/// byte recursively write the children.
+///
+/// NOTE: The code here must match the code in read_tree_node(), since
+/// assumptions are made about the indexes (so that we don't have to write them
+/// in the file).
+///
+/// @param fd NULL when only counting
+/// @param prefixtree true for PREFIXTREE
+///
+/// @return the number of nodes used.
+static int put_node(FILE *fd, wordnode_T *node, int idx, int regionmask, bool prefixtree)
{
// If "node" is zero the tree is empty.
- if (node == NULL)
+ if (node == NULL) {
return 0;
+ }
// Store the index where this node is written.
node->wn_u1.index = idx;
// Count the number of siblings.
int siblingcount = 0;
- for (wordnode_T *np = node; np != NULL; np = np->wn_sibling)
+ for (wordnode_T *np = node; np != NULL; np = np->wn_sibling) {
++siblingcount;
+ }
// Write the sibling count.
- if (fd != NULL)
+ if (fd != NULL) {
putc(siblingcount, fd); // <siblingcount>
-
+ }
// Write each sibling byte and optionally extra info.
for (wordnode_T *np = node; np != NULL; np = np->wn_sibling) {
if (np->wn_byte == 0) {
@@ -4611,9 +4792,9 @@ put_node (
// associated condition nr (stored in wn_region). The
// byte value is misused to store the "rare" and "not
// combining" flags
- if (np->wn_flags == (uint16_t)PFX_FLAGS)
+ if (np->wn_flags == (uint16_t)PFX_FLAGS) {
putc(BY_NOFLAGS, fd); // <byte>
- else {
+ } else {
putc(BY_FLAGS, fd); // <byte>
putc(np->wn_flags, fd); // <pflags>
}
@@ -4622,10 +4803,12 @@ put_node (
} else {
// For word trees we write the flag/region items.
int flags = np->wn_flags;
- if (regionmask != 0 && np->wn_region != regionmask)
+ if (regionmask != 0 && np->wn_region != regionmask) {
flags |= WF_REGION;
- if (np->wn_affixID != 0)
+ }
+ if (np->wn_affixID != 0) {
flags |= WF_AFX;
+ }
if (flags == 0) {
// word without flags or region
putc(BY_NOFLAGS, fd); // <byte>
@@ -4638,10 +4821,12 @@ put_node (
putc(BY_FLAGS, fd); // <byte>
putc(flags, fd); // <flags>
}
- if (flags & WF_REGION)
+ if (flags & WF_REGION) {
putc(np->wn_region, fd); // <region>
- if (flags & WF_AFX)
+ }
+ if (flags & WF_AFX) {
putc(np->wn_affixID, fd); // <affixID>
+ }
}
}
}
@@ -4653,15 +4838,17 @@ put_node (
putc(BY_INDEX, fd); // <byte>
put_bytes(fd, (uintmax_t)np->wn_child->wn_u1.index, 3); // <nodeidx>
}
- } else if (np->wn_child->wn_u2.wnode == NULL)
+ } else if (np->wn_child->wn_u2.wnode == NULL) {
// We will write the child below and give it an index.
np->wn_child->wn_u2.wnode = node;
+ }
- if (fd != NULL)
+ if (fd != NULL) {
if (putc(np->wn_byte, fd) == EOF) { // <byte> or <xbyte>
EMSG(_(e_write));
return 0;
}
+ }
}
}
@@ -4670,10 +4857,12 @@ put_node (
int newindex = idx + siblingcount + 1;
// Recursively dump the children of each sibling.
- for (wordnode_T *np = node; np != NULL; np = np->wn_sibling)
- if (np->wn_byte != 0 && np->wn_child->wn_u2.wnode == node)
+ for (wordnode_T *np = node; np != NULL; np = np->wn_sibling) {
+ if (np->wn_byte != 0 && np->wn_child->wn_u2.wnode == node) {
newindex = put_node(fd, np->wn_child, newindex, regionmask,
- prefixtree);
+ prefixtree);
+ }
+ }
return newindex;
}
@@ -4684,8 +4873,8 @@ put_node (
void ex_mkspell(exarg_T *eap)
{
int fcount;
- char_u **fnames;
- char_u *arg = eap->arg;
+ char_u **fnames;
+ char_u *arg = eap->arg;
bool ascii = false;
if (STRNCMP(arg, "-ascii", 6) == 0) {
@@ -4705,9 +4894,9 @@ void ex_mkspell(exarg_T *eap)
// Writes the file with the name "wfname", with ".spl" changed to ".sug".
static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
{
- char_u *fname = NULL;
+ char_u *fname = NULL;
int len;
- slang_T *slang;
+ slang_T *slang;
bool free_slang = false;
// Read back the .spl file that was written. This fills the required
@@ -4724,8 +4913,9 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
if (slang == NULL) {
spell_message(spin, (char_u *)_("Reading back spell file..."));
slang = spell_load_file(wfname, NULL, NULL, false);
- if (slang == NULL)
+ if (slang == NULL) {
return;
+ }
free_slang = true;
}
@@ -4740,15 +4930,17 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
// Go through the trie of good words, soundfold each word and add it to
// the soundfold trie.
spell_message(spin, (char_u *)_("Performing soundfolding..."));
- if (sug_filltree(spin, slang) == FAIL)
+ if (sug_filltree(spin, slang) == FAIL) {
goto theend;
+ }
// Create the table which links each soundfold word with a list of the
// good words it may come from. Creates buffer "spin->si_spellbuf".
// This also removes the wordnr from the NUL byte entries to make
// compression possible.
- if (sug_maketable(spin) == FAIL)
+ if (sug_maketable(spin) == FAIL) {
goto theend;
+ }
smsg(_("Number of words after soundfolding: %" PRId64),
(int64_t)spin->si_spellbuf->b_ml.ml_line_count);
@@ -4768,8 +4960,9 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
theend:
xfree(fname);
- if (free_slang)
+ if (free_slang) {
slang_free(slang);
+ }
free_blocks(spin->si_blocks);
close_spellbuf(spin->si_spellbuf);
}
@@ -4777,8 +4970,8 @@ theend:
// Build the soundfold trie for language "slang".
static int sug_filltree(spellinfo_T *spin, slang_T *slang)
{
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
int depth;
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
@@ -4809,13 +5002,13 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
if (curi[depth] > byts[arridx[depth]]) {
// Done all bytes at this node, go up one level.
idxs[arridx[depth]] = wordcount[depth];
- if (depth > 0)
+ if (depth > 0) {
wordcount[depth - 1] += wordcount[depth];
+ }
--depth;
line_breakcheck();
} else {
-
// Do one more byte at this node.
n = arridx[depth] + curi[depth];
++curi[depth];
@@ -4829,9 +5022,10 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
// We use the "flags" field for the MSB of the wordnr,
// "region" for the LSB of the wordnr.
if (tree_add_word(spin, tsalword, spin->si_foldroot,
- words_done >> 16, words_done & 0xffff,
- 0) == FAIL)
+ words_done >> 16, words_done & 0xffff,
+ 0) == FAIL) {
return FAIL;
+ }
++words_done;
++wordcount[depth];
@@ -4880,25 +5074,22 @@ static int sug_maketable(spellinfo_T *spin)
ga_init(&ga, 1, 100);
// recursively go through the tree
- if (sug_filltable(spin, spin->si_foldroot->wn_sibling, 0, &ga) == -1)
+ if (sug_filltable(spin, spin->si_foldroot->wn_sibling, 0, &ga) == -1) {
res = FAIL;
+ }
ga_clear(&ga);
return res;
}
-// Fill the table for one node and its children.
-// Returns the wordnr at the start of the node.
-// Returns -1 when out of memory.
-static int
-sug_filltable (
- spellinfo_T *spin,
- wordnode_T *node,
- int startwordnr,
- garray_T *gap // place to store line of numbers
-)
+/// Fill the table for one node and its children.
+/// Returns the wordnr at the start of the node.
+/// Returns -1 when out of memory.
+///
+/// @param gap place to store line of numbers
+static int sug_filltable(spellinfo_T *spin, wordnode_T *node, int startwordnr, garray_T *gap)
{
- wordnode_T *p, *np;
+ wordnode_T *p, *np;
int wordnr = startwordnr;
int nr;
int prev_nr;
@@ -4918,7 +5109,7 @@ sug_filltable (
nr -= prev_nr;
prev_nr += nr;
gap->ga_len += offset2bytes(nr,
- (char_u *)gap->ga_data + gap->ga_len);
+ (char_u *)gap->ga_data + gap->ga_len);
}
// add the NUL byte
@@ -4932,8 +5123,9 @@ sug_filltable (
// Remove extra NUL entries, we no longer need them. We don't
// bother freeing the nodes, the won't be reused anyway.
- while (p->wn_sibling != NULL && p->wn_sibling->wn_byte == NUL)
+ while (p->wn_sibling != NULL && p->wn_sibling->wn_byte == NUL) {
p->wn_sibling = p->wn_sibling->wn_sibling;
+ }
// Clear the flags on the remaining NUL node, so that compression
// works a lot better.
@@ -4941,8 +5133,9 @@ sug_filltable (
p->wn_region = 0;
} else {
wordnr = sug_filltable(spin, p->wn_child, wordnr, gap);
- if (wordnr == -1)
+ if (wordnr == -1) {
return -1;
+ }
}
}
return wordnr;
@@ -5002,7 +5195,7 @@ static void sug_write(spellinfo_T *spin, char_u *fname)
spell_message(spin, IObuff);
// <SUGHEADER>: <fileID> <versionnr> <timestamp>
- if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) { // <fileID>
+ if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) { // <fileID>
EMSG(_(e_write));
goto theend;
}
@@ -5049,11 +5242,12 @@ static void sug_write(spellinfo_T *spin, char_u *fname)
}
// Write another byte to check for errors.
- if (putc(0, fd) == EOF)
+ if (putc(0, fd) == EOF) {
EMSG(_(e_write));
+ }
vim_snprintf((char *)IObuff, IOSIZE,
- _("Estimated runtime memory use: %d bytes"), spin->si_memtot);
+ _("Estimated runtime memory use: %d bytes"), spin->si_memtot);
spell_message(spin, IObuff);
theend:
@@ -5062,23 +5256,20 @@ theend:
}
-// Create a Vim spell file from one or more word lists.
-// "fnames[0]" is the output file name.
-// "fnames[fcount - 1]" is the last input file name.
-// Exception: when "fnames[0]" ends in ".add" it's used as the input file name
-// and ".spl" is appended to make the output file name.
-static void
-mkspell (
- int fcount,
- char_u **fnames,
- bool ascii, // -ascii argument given
- bool over_write, // overwrite existing output file
- bool added_word // invoked through "zg"
-)
+/// Create a Vim spell file from one or more word lists.
+/// "fnames[0]" is the output file name.
+/// "fnames[fcount - 1]" is the last input file name.
+/// Exception: when "fnames[0]" ends in ".add" it's used as the input file name
+/// and ".spl" is appended to make the output file name.
+///
+/// @param ascii -ascii argument given
+/// @param over_write overwrite existing output file
+/// @param added_word invoked through "zg"
+static void mkspell(int fcount, char_u **fnames, bool ascii, bool over_write, bool added_word)
{
- char_u *fname = NULL;
- char_u *wfname;
- char_u **innames;
+ char_u *fname = NULL;
+ char_u *wfname;
+ char_u **innames;
int incount;
afffile_T *(afile[MAXREGIONS]);
int i;
@@ -5114,26 +5305,29 @@ mkspell (
// "path/en.latin1.add.spl".
incount = 1;
vim_snprintf((char *)wfname, MAXPATHL, "%s.spl", fnames[0]);
- } else if (fcount == 1) {
+ } else if (fcount == 1) {
// For ":mkspell path/vim" output file is "path/vim.latin1.spl".
incount = 1;
vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL,
- fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
- } else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0) {
+ fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ } else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0) {
// Name ends in ".spl", use as the file name.
STRLCPY(wfname, fnames[0], MAXPATHL);
- } else
+ } else {
// Name should be language, make the file name from it.
vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL,
- fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ }
// Check for .ascii.spl.
- if (strstr((char *)path_tail(wfname), SPL_FNAME_ASCII) != NULL)
+ if (strstr((char *)path_tail(wfname), SPL_FNAME_ASCII) != NULL) {
spin.si_ascii = true;
+ }
// Check for .add.spl.
- if (strstr((char *)path_tail(wfname), SPL_FNAME_ADD) != NULL)
+ if (strstr((char *)path_tail(wfname), SPL_FNAME_ADD) != NULL) {
spin.si_add = true;
+ }
}
if (incount <= 0) {
@@ -5184,8 +5378,9 @@ mkspell (
// one in the .spl file if the .aff file doesn't define one. That's
// better than guessing the contents, the table will match a
// previously loaded spell file.
- if (!spin.si_add)
+ if (!spin.si_add) {
spin.si_clear_chartab = true;
+ }
// Read all the .aff and .dic files.
// Text is converted to 'encoding'.
@@ -5199,28 +5394,31 @@ mkspell (
// Read the .aff file. Will init "spin->si_conv" based on the
// "SET" line.
afile[i] = spell_read_aff(&spin, fname);
- if (afile[i] == NULL)
+ if (afile[i] == NULL) {
error = true;
- else {
+ } else {
// Read the .dic file and store the words in the trees.
vim_snprintf((char *)fname, MAXPATHL, "%s.dic",
- innames[i]);
- if (spell_read_dic(&spin, fname, afile[i]) == FAIL)
+ innames[i]);
+ if (spell_read_dic(&spin, fname, afile[i]) == FAIL) {
error = true;
+ }
}
} else {
// No .aff file, try reading the file as a word list. Store
// the words in the trees.
- if (spell_read_wordfile(&spin, innames[i]) == FAIL)
+ if (spell_read_wordfile(&spin, innames[i]) == FAIL) {
error = true;
+ }
}
// Free any conversion stuff.
convert_setup(&spin.si_conv, NULL, NULL);
}
- if (spin.si_compflags != NULL && spin.si_nobreak)
+ if (spin.si_compflags != NULL && spin.si_nobreak) {
MSG(_("Warning: both compounding and NOBREAK specified"));
+ }
if (!error && !got_int) {
// Combine tails in the tree.
@@ -5240,12 +5438,13 @@ mkspell (
spell_message(&spin, (char_u *)_("Done!"));
vim_snprintf((char *)IObuff, IOSIZE,
- _("Estimated runtime memory use: %d bytes"), spin.si_memtot);
+ _("Estimated runtime memory use: %d bytes"), spin.si_memtot);
spell_message(&spin, IObuff);
// If the file is loaded need to reload it.
- if (!error)
+ if (!error) {
spell_reload_one(wfname, added_word);
+ }
}
// Free the allocated memory.
@@ -5258,18 +5457,20 @@ mkspell (
hash_clear_all(&spin.si_commonwords, 0);
// Free the .aff file structures.
- for (i = 0; i < incount; ++i)
- if (afile[i] != NULL)
+ for (i = 0; i < incount; ++i) {
+ if (afile[i] != NULL) {
spell_free_aff(afile[i]);
+ }
+ }
// Free all the bits and pieces at once.
free_blocks(spin.si_blocks);
// If there is soundfolding info and no NOSUGFILE item create the
// .sug file with the soundfolded word trie.
- if (spin.si_sugtime != 0 && !error && !got_int)
+ if (spin.si_sugtime != 0 && !error && !got_int) {
spell_make_sugfile(&spin, wfname);
-
+ }
}
theend:
@@ -5283,12 +5484,14 @@ static void spell_message(const spellinfo_T *spin, char_u *str)
FUNC_ATTR_NONNULL_ALL
{
if (spin->si_verbose || p_verbose > 2) {
- if (!spin->si_verbose)
+ if (!spin->si_verbose) {
verbose_enter();
+ }
MSG(str);
ui_flush();
- if (!spin->si_verbose)
+ if (!spin->si_verbose) {
verbose_leave();
+ }
}
}
@@ -5305,32 +5508,29 @@ void ex_spell(exarg_T *eap)
eap->cmdidx == CMD_spellundo);
}
-// Add "word[len]" to 'spellfile' as a good or bad word.
-void
-spell_add_word (
- char_u *word,
- int len,
- SpellAddType what, // SPELL_ADD_ values
- int idx, // "zG" and "zW": zero, otherwise index in
- // 'spellfile'
- bool undo // true for "zug", "zuG", "zuw" and "zuW"
-)
+/// Add "word[len]" to 'spellfile' as a good or bad word.
+///
+/// @param what SPELL_ADD_ values
+/// @param idx "zG" and "zW": zero, otherwise index in 'spellfile'
+/// @param bool // true for "zug", "zuG", "zuw" and "zuW"
+void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo)
{
- FILE *fd = NULL;
- buf_T *buf = NULL;
+ FILE *fd = NULL;
+ buf_T *buf = NULL;
bool new_spf = false;
- char_u *fname;
- char_u *fnamebuf = NULL;
+ char_u *fname;
+ char_u *fnamebuf = NULL;
char_u line[MAXWLEN * 2];
long fpos, fpos_next = 0;
int i;
- char_u *spf;
+ char_u *spf;
if (idx == 0) { // use internal wordlist
if (int_wordlist == NULL) {
int_wordlist = vim_tempname();
- if (int_wordlist == NULL)
+ if (int_wordlist == NULL) {
return;
+ }
}
fname = int_wordlist;
} else {
@@ -5348,8 +5548,9 @@ spell_add_word (
for (spf = curwin->w_s->b_p_spf, i = 1; *spf != NUL; ++i) {
copy_option_part(&spf, fnamebuf, MAXPATHL, ",");
- if (i == idx)
+ if (i == idx) {
break;
+ }
if (*spf == NUL) {
EMSGN(_("E765: 'spellfile' does not have %" PRId64 " entries"), idx);
xfree(fnamebuf);
@@ -5359,8 +5560,9 @@ spell_add_word (
// Check that the user isn't editing the .add file somewhere.
buf = buflist_findname_exp(fnamebuf);
- if (buf != NULL && buf->b_ml.ml_mfp == NULL)
+ if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
buf = NULL;
+ }
if (buf != NULL && bufIsChanged(buf)) {
EMSG(_(e_bufloaded));
xfree(fnamebuf);
@@ -5402,8 +5604,9 @@ spell_add_word (
}
}
}
- if (fd != NULL)
+ if (fd != NULL) {
fclose(fd);
+ }
}
}
@@ -5450,8 +5653,9 @@ spell_add_word (
mkspell(1, &fname, false, true, true);
// If the .add file is edited somewhere, reload it.
- if (buf != NULL)
+ if (buf != NULL) {
buf_reload(buf, buf->b_orig_mode);
+ }
redraw_all_later(SOME_VALID);
}
@@ -5461,13 +5665,13 @@ spell_add_word (
// Initialize 'spellfile' for the current buffer.
static void init_spellfile(void)
{
- char_u *buf;
+ char_u *buf;
int l;
- char_u *fname;
- char_u *rtp;
- char_u *lend;
+ char_u *fname;
+ char_u *rtp;
+ char_u *lend;
bool aspath = false;
- char_u *lstart = curbuf->b_s.b_p_spl;
+ char_u *lstart = curbuf->b_s.b_p_spl;
if (*curwin->w_s->b_p_spl != NUL && !GA_EMPTY(&curwin->w_s->b_langp)) {
buf = xmalloc(MAXPATHL);
@@ -5475,31 +5679,33 @@ static void init_spellfile(void)
// Find the end of the language name. Exclude the region. If there
// is a path separator remember the start of the tail.
for (lend = curwin->w_s->b_p_spl; *lend != NUL
- && vim_strchr((char_u *)",._", *lend) == NULL; ++lend)
+ && vim_strchr((char_u *)",._", *lend) == NULL; ++lend) {
if (vim_ispathsep(*lend)) {
aspath = true;
lstart = lend + 1;
}
+ }
// Loop over all entries in 'runtimepath'. Use the first one where we
// are allowed to write.
rtp = p_rtp;
while (*rtp != NUL) {
- if (aspath)
+ if (aspath) {
// Use directory of an entry with path, e.g., for
// "/dir/lg.utf-8.spl" use "/dir".
STRLCPY(buf, curbuf->b_s.b_p_spl,
- lstart - curbuf->b_s.b_p_spl);
- else
+ lstart - curbuf->b_s.b_p_spl);
+ } else {
// Copy the path from 'runtimepath' to buf[].
copy_option_part(&rtp, buf, MAXPATHL, ",");
+ }
if (os_file_is_writable((char *)buf) == 2) {
// Use the first language name from 'spelllang' and the
// encoding used in the first loaded .spl file.
- if (aspath)
+ if (aspath) {
STRLCPY(buf, curbuf->b_s.b_p_spl,
- lend - curbuf->b_s.b_p_spl + 1);
- else {
+ lend - curbuf->b_s.b_p_spl + 1);
+ } else {
// Create the "spell" directory if it doesn't exist yet.
l = (int)STRLEN(buf);
vim_snprintf((char *)buf + l, MAXPATHL - l, "/spell");
@@ -5509,7 +5715,7 @@ static void init_spellfile(void)
l = (int)STRLEN(buf);
vim_snprintf((char *)buf + l, MAXPATHL - l,
- "/%.*s", (int)(lend - lstart), lstart);
+ "/%.*s", (int)(lend - lstart), lstart);
}
l = (int)STRLEN(buf);
fname = LANGP_ENTRY(curwin->w_s->b_langp, 0)
@@ -5529,19 +5735,16 @@ static void init_spellfile(void)
}
}
-// Set the spell character tables from strings in the .spl file.
-static void
-set_spell_charflags (
- char_u *flags,
- int cnt, // length of "flags"
- char_u *fol
-)
+/// Set the spell character tables from strings in the .spl file.
+///
+/// @param cnt length of "flags"
+static void set_spell_charflags(char_u *flags, int cnt, char_u *fol)
{
// We build the new tables here first, so that we can compare with the
// previous one.
spelltab_T new_st;
int i;
- char_u *p = fol;
+ char_u *p = fol;
int c;
clear_spell_chartab(&new_st);
@@ -5555,8 +5758,9 @@ set_spell_charflags (
if (*p != NUL) {
c = mb_ptr2char_adv((const char_u **)&p);
new_st.st_fold[i + 128] = c;
- if (i + 128 != c && new_st.st_isu[i + 128] && c < 256)
+ if (i + 128 != c && new_st.st_isu[i + 128] && c < 256) {
new_st.st_upper[c] = i + 128;
+ }
}
}
@@ -5593,9 +5797,9 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
{
assert(gap->ga_len >= 0);
- if (fd != NULL)
+ if (fd != NULL) {
put_bytes(fd, (uintmax_t)gap->ga_len, 2); // <prefcondcnt>
-
+ }
size_t totlen = 2 + (size_t)gap->ga_len; // <prefcondcnt> and <condlen> bytes
size_t x = 1; // collect return value of fwrite()
for (int i = 0; i < gap->ga_len; ++i) {
@@ -5609,8 +5813,9 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
x &= fwrite(p, len, 1, fd);
}
totlen += len;
- } else if (fd != NULL)
+ } else if (fd != NULL) {
fputc(0, fd);
+ }
}
assert(totlen <= INT_MAX);
@@ -5620,7 +5825,7 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
// Use map string "map" for languages "lp".
static void set_map_str(slang_T *lp, char_u *map)
{
- char_u *p;
+ char_u *p;
int headc = 0;
int c;
int i;
@@ -5632,8 +5837,9 @@ static void set_map_str(slang_T *lp, char_u *map)
lp->sl_has_map = true;
// Init the array and hash tables empty.
- for (i = 0; i < 256; ++i)
+ for (i = 0; i < 256; ++i) {
lp->sl_map_array[i] = 0;
+ }
hash_init(&lp->sl_map_hash);
// The similar characters are stored separated with slashes:
@@ -5654,9 +5860,9 @@ static void set_map_str(slang_T *lp, char_u *map)
if (c >= 256) {
int cl = mb_char2len(c);
int headcl = mb_char2len(headc);
- char_u *b;
+ char_u *b;
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
b = xmalloc(cl + headcl + 2);
utf_char2bytes(c, b);
@@ -5673,8 +5879,9 @@ static void set_map_str(slang_T *lp, char_u *map)
EMSG(_("E783: duplicate char in MAP entry"));
xfree(b);
}
- } else
+ } else {
lp->sl_map_array[c] = headc;
+ }
}
}
}
diff --git a/src/nvim/state.c b/src/nvim/state.c
index 02d63d8ab1..04271d750c 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -3,19 +3,18 @@
#include <assert.h>
-#include "nvim/lib/kvec.h"
-
#include "nvim/ascii.h"
+#include "nvim/edit.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/getchar.h"
+#include "nvim/lib/kvec.h"
#include "nvim/log.h"
-#include "nvim/state.h"
-#include "nvim/vim.h"
#include "nvim/main.h"
-#include "nvim/getchar.h"
#include "nvim/option_defs.h"
-#include "nvim/ui.h"
#include "nvim/os/input.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/edit.h"
+#include "nvim/state.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "state.c.generated.h"
@@ -162,6 +161,11 @@ char *get_mode(void)
if (State & VREPLACE_FLAG) {
buf[0] = 'R';
buf[1] = 'v';
+ if (ins_compl_active()) {
+ buf[2] = 'c';
+ } else if (ctrl_x_mode_not_defined_yet()) {
+ buf[2] = 'x';
+ }
} else {
if (State & REPLACE_FLAG) {
buf[0] = 'R';
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 79a3db4843..11c1aa1760 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -1,28 +1,26 @@
// 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 <inttypes.h>
+#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include "nvim/assert.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/strings.h"
-#include "nvim/file_search.h"
+#include "nvim/assert.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/encode.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
-#include "nvim/func_attr.h"
#include "nvim/fold.h"
#include "nvim/func_attr.h"
#include "nvim/getchar.h"
@@ -35,8 +33,10 @@
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
-#include "nvim/option.h"
#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/os/shell.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
@@ -44,12 +44,11 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
+#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
-#include "nvim/eval/encode.h"
/// Copy "string" into newly allocated memory.
char_u *vim_strsave(const char_u *string)
@@ -84,8 +83,7 @@ char_u *vim_strsave_escaped(const char_u *string, const char_u *esc_chars)
* characters where rem_backslash() would remove the backslash.
* Escape the characters with "cc".
*/
-char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars,
- char_u cc, bool bsl)
+char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, char_u cc, bool bsl)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
/*
@@ -100,9 +98,10 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars,
p += l - 1;
continue;
}
- if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
- ++length; /* count a backslash */
- ++length; /* count an ordinary char */
+ if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) {
+ ++length; // count a backslash
+ }
+ ++length; // count an ordinary char
}
char_u *escaped_string = xmalloc(length);
@@ -112,11 +111,12 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars,
if (l > 1) {
memcpy(p2, p, l);
p2 += l;
- p += l - 1; /* skip multibyte char */
+ p += l - 1; // skip multibyte char
continue;
}
- if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
+ if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) {
*p2++ = cc;
+ }
*p2++ = *p;
}
*p2 = NUL;
@@ -182,12 +182,11 @@ char *vim_strnsave_unquoted(const char *const string, const size_t length)
* When "do_newline" is false do not escape newline unless it is csh shell.
* Returns the result in allocated memory.
*/
-char_u *vim_strsave_shellescape(const char_u *string,
- bool do_special, bool do_newline)
+char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_newline)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- char_u *d;
- char_u *escaped_string;
+ char_u *d;
+ char_u *escaped_string;
size_t l;
int csh_like;
bool fish_like;
@@ -202,7 +201,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
// itself must be escaped to get a literal '\'.
fish_like = fish_like_shell();
- /* First count the number of extra bytes required. */
+ // First count the number of extra bytes required.
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) {
#ifdef WIN32
@@ -217,12 +216,13 @@ char_u *vim_strsave_shellescape(const char_u *string,
}
if ((*p == '\n' && (csh_like || do_newline))
|| (*p == '!' && (csh_like || do_special))) {
- ++length; /* insert backslash */
- if (csh_like && do_special)
- ++length; /* insert backslash */
+ ++length; // insert backslash
+ if (csh_like && do_special) {
+ ++length; // insert backslash
+ }
}
if (do_special && find_cmdline_var(p, &l) >= 0) {
- ++length; /* insert backslash */
+ ++length; // insert backslash
p += l - 1;
}
if (*p == '\\' && fish_like) {
@@ -230,7 +230,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
}
}
- /* Allocate memory for the result and fill it. */
+ // Allocate memory for the result and fill it.
escaped_string = xmalloc(length);
d = escaped_string;
@@ -264,15 +264,17 @@ char_u *vim_strsave_shellescape(const char_u *string,
if ((*p == '\n' && (csh_like || do_newline))
|| (*p == '!' && (csh_like || do_special))) {
*d++ = '\\';
- if (csh_like && do_special)
+ if (csh_like && do_special) {
*d++ = '\\';
+ }
*d++ = *p++;
continue;
}
if (do_special && find_cmdline_var(p, &l) >= 0) {
- *d++ = '\\'; /* insert backslash */
- while (--l != SIZE_MAX) /* copy the var */
+ *d++ = '\\'; // insert backslash
+ while (--l != SIZE_MAX) { // copy the var
*d++ = *p++;
+ }
continue;
}
if (*p == '\\' && fish_like) {
@@ -285,11 +287,11 @@ char_u *vim_strsave_shellescape(const char_u *string,
}
// add terminating quote and finish with a NUL
-# ifdef WIN32
+#ifdef WIN32
if (!p_ssl) {
*d++ = '"';
} else
-# endif
+#endif
*d++ = '\'';
*d = NUL;
@@ -384,11 +386,12 @@ char *strcase_save(const char *const orig, bool upper)
void del_trailing_spaces(char_u *ptr)
FUNC_ATTR_NONNULL_ALL
{
- char_u *q;
+ char_u *q;
q = ptr + STRLEN(ptr);
- while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V)
+ while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V) {
*q = NUL;
+ }
}
#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP))
@@ -404,14 +407,16 @@ int vim_stricmp(const char *s1, const char *s2)
for (;; ) {
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
- if (i != 0)
- return i; /* this character different */
- if (*s1 == NUL)
- break; /* strings match until NUL */
+ if (i != 0) {
+ return i; // this character different
+ }
+ if (*s1 == NUL) {
+ break; // strings match until NUL
+ }
++s1;
++s2;
}
- return 0; /* strings match */
+ return 0; // strings match
}
#endif
@@ -428,15 +433,17 @@ int vim_strnicmp(const char *s1, const char *s2, size_t len)
while (len > 0) {
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
- if (i != 0)
- return i; /* this character different */
- if (*s1 == NUL)
- break; /* strings match until NUL */
+ if (i != 0) {
+ return i; // this character different
+ }
+ if (*s1 == NUL) {
+ break; // strings match until NUL
+ }
++s1;
++s2;
--len;
}
- return 0; /* strings match */
+ return 0; // strings match
}
#endif
@@ -490,10 +497,13 @@ bool has_non_ascii(const char_u *s)
{
const char_u *p;
- if (s != NULL)
- for (p = s; *p != NUL; ++p)
- if (*p >= 128)
+ if (s != NULL) {
+ for (p = s; *p != NUL; ++p) {
+ if (*p >= 128) {
return true;
+ }
+ }
+ }
return false;
}
@@ -504,7 +514,7 @@ bool has_non_ascii_len(const char *const s, const size_t len)
{
if (s != NULL) {
for (size_t i = 0; i < len; i++) {
- if ((uint8_t) s[i] >= 128) {
+ if ((uint8_t)s[i] >= 128) {
return true;
}
}
@@ -527,7 +537,7 @@ char_u *concat_str(const char_u *restrict str1, const char_u *restrict str2)
static const char *const e_printf =
- N_("E766: Insufficient arguments for printf()");
+ N_("E766: Insufficient arguments for printf()");
/// Get number argument from idxp entry in tvs
///
@@ -606,15 +616,14 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
#define OFF(attr) offsetof(union typval_vval_union, attr)
- STATIC_ASSERT(
- OFF(v_string) == OFF(v_list)
- && OFF(v_string) == OFF(v_dict)
- && OFF(v_string) == OFF(v_partial)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
- "Strings, dictionaries, lists and partials are expected to be pointers, "
- "so that all three of them can be accessed via v_string");
+ STATIC_ASSERT(OFF(v_string) == OFF(v_list)
+ && OFF(v_string) == OFF(v_dict)
+ && OFF(v_string) == OFF(v_partial)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
+ "Strings, dictionaries, lists and partials are expected to be pointers, "
+ "so that all three of them can be accessed via v_string");
#undef OFF
const int idx = *idxp - 1;
if (tvs[idx].v_type == VAR_UNKNOWN) {
@@ -735,8 +744,8 @@ int vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
// Return the representation of infinity for printf() function:
// "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
-static const char *infinity_str(bool positive, char fmt_spec,
- int force_sign, int space_for_positive)
+static const char *infinity_str(bool positive, char fmt_spec, int force_sign,
+ int space_for_positive)
{
static const char *table[] = {
"-inf", "inf", "+inf", " inf",
@@ -765,8 +774,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap)
///
/// @return Number of bytes excluding NUL byte that would be written to the
/// string if str_m was greater or equal to the return value.
-int vim_vsnprintf_typval(
- char *str, size_t str_m, const char *fmt, va_list ap, typval_T *const tvs)
+int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, typval_T *const tvs)
{
size_t str_l = 0;
bool str_avail = str_l < str_m;
@@ -800,7 +808,7 @@ int vim_vsnprintf_typval(
char length_modifier = '\0';
// temporary buffer for simple numeric->string conversion
-# define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable
+#define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable
char tmp[TMP_LEN];
// string address in case of string argument
@@ -832,15 +840,22 @@ int vim_vsnprintf_typval(
// parse flags
while (true) {
switch (*p) {
- case '0': zero_padding = 1; p++; continue;
- case '-': justify_left = 1; p++; continue;
- // if both '0' and '-' flags appear, '0' should be ignored
- case '+': force_sign = 1; space_for_positive = 0; p++; continue;
- case ' ': force_sign = 1; p++; continue;
- // if both ' ' and '+' flags appear, ' ' should be ignored
- case '#': alternate_form = 1; p++; continue;
- case '\'': p++; continue;
- default: break;
+ case '0':
+ zero_padding = 1; p++; continue;
+ case '-':
+ justify_left = 1; p++; continue;
+ // if both '0' and '-' flags appear, '0' should be ignored
+ case '+':
+ force_sign = 1; space_for_positive = 0; p++; continue;
+ case ' ':
+ force_sign = 1; p++; continue;
+ // if both ' ' and '+' flags appear, ' ' should be ignored
+ case '#':
+ alternate_form = 1; p++; continue;
+ case '\'':
+ p++; continue;
+ default:
+ break;
}
break;
}
@@ -905,444 +920,447 @@ int vim_vsnprintf_typval(
// common synonyms
switch (fmt_spec) {
- case 'i': fmt_spec = 'd'; break;
- case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
- case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
- case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
- default: break;
+ case 'i':
+ fmt_spec = 'd'; break;
+ case 'D':
+ fmt_spec = 'd'; length_modifier = 'l'; break;
+ case 'U':
+ fmt_spec = 'u'; length_modifier = 'l'; break;
+ case 'O':
+ fmt_spec = 'o'; length_modifier = 'l'; break;
+ default:
+ break;
}
switch (fmt_spec) {
- case 'b': case 'B':
- case 'd': case 'u': case 'o': case 'x': case 'X':
- if (tvs && length_modifier == '\0') {
- length_modifier = '2';
- }
+ case 'b':
+ case 'B':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (tvs && length_modifier == '\0') {
+ length_modifier = '2';
+ }
}
// get parameter value, do initial processing
switch (fmt_spec) {
- // '%' and 'c' behave similar to 's' regarding flags and field widths
- case '%': case 'c': case 's': case 'S':
- str_arg_l = 1;
- switch (fmt_spec) {
- case '%':
- str_arg = p;
- break;
-
- case 'c': {
- const int j = tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int);
- // standard demands unsigned char
- uchar_arg = (unsigned char)j;
- str_arg = (char *)&uchar_arg;
- break;
- }
+ // '%' and 'c' behave similar to 's' regarding flags and field widths
+ case '%':
+ case 'c':
+ case 's':
+ case 'S':
+ str_arg_l = 1;
+ switch (fmt_spec) {
+ case '%':
+ str_arg = p;
+ break;
- case 's':
- case 'S':
- str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree)
- : va_arg(ap, const char *);
- if (!str_arg) {
- str_arg = "[NULL]";
- str_arg_l = 6;
- } else if (!precision_specified) {
- // make sure not to address string beyond the specified
- // precision
- str_arg_l = strlen(str_arg);
- } else if (precision == 0) {
- // truncate string if necessary as requested by precision
- str_arg_l = 0;
- } else {
- // memchr on HP does not like n > 2^31
- // TODO(elmart): check if this still holds / is relevant
- str_arg_l = (size_t)((char *)xmemscan(str_arg,
- NUL,
- MIN(precision,
- 0x7fffffff))
- - str_arg);
- }
- if (fmt_spec == 'S') {
- if (min_field_width != 0) {
- min_field_width += (strlen(str_arg)
- - mb_string2cells((char_u *)str_arg));
- }
- if (precision) {
- char_u *p1;
- size_t i = 0;
-
- for (p1 = (char_u *)str_arg; *p1;
- p1 += mb_ptr2len(p1)) {
- i += (size_t)utf_ptr2cells(p1);
- if (i > precision) {
- break;
- }
- }
- str_arg_l = (size_t)(p1 - (char_u *)str_arg);
+ case 'c': {
+ const int j = tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int);
+ // standard demands unsigned char
+ uchar_arg = (unsigned char)j;
+ str_arg = (char *)&uchar_arg;
+ break;
+ }
+
+ case 's':
+ case 'S':
+ str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree)
+ : va_arg(ap, const char *);
+ if (!str_arg) {
+ str_arg = "[NULL]";
+ str_arg_l = 6;
+ } else if (!precision_specified) {
+ // make sure not to address string beyond the specified
+ // precision
+ str_arg_l = strlen(str_arg);
+ } else if (precision == 0) {
+ // truncate string if necessary as requested by precision
+ str_arg_l = 0;
+ } else {
+ // memchr on HP does not like n > 2^31
+ // TODO(elmart): check if this still holds / is relevant
+ str_arg_l = (size_t)((char *)xmemscan(str_arg,
+ NUL,
+ MIN(precision,
+ 0x7fffffff))
+ - str_arg);
+ }
+ if (fmt_spec == 'S') {
+ if (min_field_width != 0) {
+ min_field_width += (strlen(str_arg)
+ - mb_string2cells((char_u *)str_arg));
+ }
+ if (precision) {
+ char_u *p1;
+ size_t i = 0;
+
+ for (p1 = (char_u *)str_arg; *p1;
+ p1 += mb_ptr2len(p1)) {
+ i += (size_t)utf_ptr2cells(p1);
+ if (i > precision) {
+ break;
}
}
- break;
-
- default:
- break;
+ str_arg_l = (size_t)(p1 - (char_u *)str_arg);
+ }
}
break;
- case 'd':
- case 'u':
- case 'b': case 'B':
- case 'o':
- case 'x': case 'X':
- case 'p': {
- // u, b, B, o, x, X and p conversion specifiers imply
- // the value is unsigned; d implies a signed value
-
- // 0 if numeric argument is zero (or if pointer is NULL for 'p'),
- // +1 if greater than zero (or non NULL for 'p'),
- // -1 if negative (unsigned argument is never negative)
- int arg_sign = 0;
-
- intmax_t arg = 0;
- uintmax_t uarg = 0;
-
- // only defined for p conversion
- const void *ptr_arg = NULL;
-
- if (fmt_spec == 'p') {
- ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *);
- if (ptr_arg) {
- arg_sign = 1;
- }
- } else if (fmt_spec == 'd') {
- // signed
- switch (length_modifier) {
- case '\0': {
- arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
- break;
- }
- case 'h': {
- // char and short arguments are passed as int16_t
- arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
- break;
- }
- case 'l': {
- arg = (tvs ? (long)tv_nr(tvs, &arg_idx) : va_arg(ap, long));
- break;
- }
- case '2': {
- arg = (
- tvs
+ default:
+ break;
+ }
+ break;
+
+ case 'd':
+ case 'u':
+ case 'b':
+ case 'B':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'p': {
+ // u, b, B, o, x, X and p conversion specifiers imply
+ // the value is unsigned; d implies a signed value
+
+ // 0 if numeric argument is zero (or if pointer is NULL for 'p'),
+ // +1 if greater than zero (or non NULL for 'p'),
+ // -1 if negative (unsigned argument is never negative)
+ int arg_sign = 0;
+
+ intmax_t arg = 0;
+ uintmax_t uarg = 0;
+
+ // only defined for p conversion
+ const void *ptr_arg = NULL;
+
+ if (fmt_spec == 'p') {
+ ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *);
+ if (ptr_arg) {
+ arg_sign = 1;
+ }
+ } else if (fmt_spec == 'd') {
+ // signed
+ switch (length_modifier) {
+ case '\0':
+ arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
+ break;
+ case 'h':
+ // char and short arguments are passed as int16_t
+ arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
+ break;
+ case 'l':
+ arg = (tvs ? (long)tv_nr(tvs, &arg_idx) : va_arg(ap, long));
+ break;
+ case '2':
+ arg = (
+ tvs
? (long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int)
: va_arg(ap, long long)); // NOLINT (runtime/int)
- break;
- }
- case 'z': {
- arg = (tvs
+ break;
+ case 'z':
+ arg = (tvs
? (ptrdiff_t)tv_nr(tvs, &arg_idx)
: va_arg(ap, ptrdiff_t));
- break;
- }
- }
- if (arg > 0) {
- arg_sign = 1;
- } else if (arg < 0) {
- arg_sign = -1;
- }
- } else {
- // unsigned
- switch (length_modifier) {
- case '\0': {
- uarg = (unsigned int)(tvs
+ break;
+ }
+ if (arg > 0) {
+ arg_sign = 1;
+ } else if (arg < 0) {
+ arg_sign = -1;
+ }
+ } else {
+ // unsigned
+ switch (length_modifier) {
+ case '\0':
+ uarg = (unsigned int)(tvs
? tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned int));
- break;
- }
- case 'h': {
- uarg = (uint16_t)(tvs
+ break;
+ case 'h':
+ uarg = (uint16_t)(tvs
? tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned int));
- break;
- }
- case 'l': {
- uarg = (tvs
+ break;
+ case 'l':
+ uarg = (tvs
? (unsigned long)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned long));
- break;
- }
- case '2': {
- uarg = (uintmax_t)(unsigned long long)( // NOLINT (runtime/int)
- tvs
+ break;
+ case '2':
+ uarg = (uintmax_t)(unsigned long long)( // NOLINT (runtime/int)
+ tvs
? ((unsigned long long) // NOLINT (runtime/int)
tv_nr(tvs, &arg_idx))
: va_arg(ap, unsigned long long)); // NOLINT (runtime/int)
- break;
- }
- case 'z': {
- uarg = (tvs
+ break;
+ case 'z':
+ uarg = (tvs
? (size_t)tv_nr(tvs, &arg_idx)
: va_arg(ap, size_t));
- break;
- }
- }
- arg_sign = (uarg != 0);
+ break;
}
+ arg_sign = (uarg != 0);
+ }
- str_arg = tmp;
- str_arg_l = 0;
+ str_arg = tmp;
+ str_arg_l = 0;
- // For d, i, u, o, x, and X conversions, if precision is specified,
- // '0' flag should be ignored. This is so with Solaris 2.6, Digital
- // UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
- if (precision_specified) {
- zero_padding = 0;
- }
+ // For d, i, u, o, x, and X conversions, if precision is specified,
+ // '0' flag should be ignored. This is so with Solaris 2.6, Digital
+ // UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
+ if (precision_specified) {
+ zero_padding = 0;
+ }
- if (fmt_spec == 'd') {
- if (force_sign && arg_sign >= 0) {
- tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
- }
- // leave negative numbers for snprintf to handle, to
- // avoid handling tricky cases like (short int)-32768
- } else if (alternate_form) {
- if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X'
- || fmt_spec == 'b' || fmt_spec == 'B')) {
- tmp[str_arg_l++] = '0';
- tmp[str_arg_l++] = fmt_spec;
- }
- // alternate form should have no effect for p * conversion, but ...
+ if (fmt_spec == 'd') {
+ if (force_sign && arg_sign >= 0) {
+ tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
}
-
- zero_padding_insertion_ind = str_arg_l;
- if (!precision_specified) {
- precision = 1; // default precision is 1
+ // leave negative numbers for snprintf to handle, to
+ // avoid handling tricky cases like (short int)-32768
+ } else if (alternate_form) {
+ if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X'
+ || fmt_spec == 'b' || fmt_spec == 'B')) {
+ tmp[str_arg_l++] = '0';
+ tmp[str_arg_l++] = fmt_spec;
}
- if (precision == 0 && arg_sign == 0) {
- // when zero value is formatted with an explicit precision 0,
- // resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
- } else {
- switch (fmt_spec) {
- case 'p': { // pointer
- str_arg_l += (size_t)snprintf(tmp + str_arg_l,
- sizeof(tmp) - str_arg_l,
- "%p", ptr_arg);
- break;
- }
- case 'd': { // signed
- str_arg_l += (size_t)snprintf(tmp + str_arg_l,
- sizeof(tmp) - str_arg_l,
- "%" PRIdMAX, arg);
- break;
- }
- case 'b': case 'B': { // binary
- size_t bits = 0;
- for (bits = sizeof(uintmax_t) * 8; bits > 0; bits--) {
- if ((uarg >> (bits - 1)) & 0x1) {
- break;
- }
- }
+ // alternate form should have no effect for p * conversion, but ...
+ }
- while (bits > 0) {
- tmp[str_arg_l++] = ((uarg >> --bits) & 0x1) ? '1' : '0';
- }
- break;
- }
- default: { // unsigned
- // construct a simple format string for snprintf
- char f[] = "%" PRIuMAX;
- f[sizeof("%" PRIuMAX) - 1 - 1] = fmt_spec;
- assert(PRIuMAX[sizeof(PRIuMAX) - 1 - 1] == 'u');
- str_arg_l += (size_t)snprintf(tmp + str_arg_l,
- sizeof(tmp) - str_arg_l,
- f, uarg);
+ zero_padding_insertion_ind = str_arg_l;
+ if (!precision_specified) {
+ precision = 1; // default precision is 1
+ }
+ if (precision == 0 && arg_sign == 0) {
+ // when zero value is formatted with an explicit precision 0,
+ // resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
+ } else {
+ switch (fmt_spec) {
+ case 'p': // pointer
+ str_arg_l += (size_t)snprintf(tmp + str_arg_l,
+ sizeof(tmp) - str_arg_l,
+ "%p", ptr_arg);
+ break;
+ case 'd': // signed
+ str_arg_l += (size_t)snprintf(tmp + str_arg_l,
+ sizeof(tmp) - str_arg_l,
+ "%" PRIdMAX, arg);
+ break;
+ case 'b':
+ case 'B': { // binary
+ size_t bits = 0;
+ for (bits = sizeof(uintmax_t) * 8; bits > 0; bits--) {
+ if ((uarg >> (bits - 1)) & 0x1) {
break;
}
}
- assert(str_arg_l < sizeof(tmp));
- // include the optional minus sign and possible "0x" in the region
- // before the zero padding insertion point
- if (zero_padding_insertion_ind < str_arg_l
- && tmp[zero_padding_insertion_ind] == '-') {
- zero_padding_insertion_ind++;
- }
- if (zero_padding_insertion_ind + 1 < str_arg_l
- && tmp[zero_padding_insertion_ind] == '0'
- && (tmp[zero_padding_insertion_ind + 1] == 'x'
- || tmp[zero_padding_insertion_ind + 1] == 'X'
- || tmp[zero_padding_insertion_ind + 1] == 'b'
- || tmp[zero_padding_insertion_ind + 1] == 'B')) {
- zero_padding_insertion_ind += 2;
+ while (bits > 0) {
+ tmp[str_arg_l++] = ((uarg >> --bits) & 0x1) ? '1' : '0';
}
+ break;
+ }
+ default: { // unsigned
+ // construct a simple format string for snprintf
+ char f[] = "%" PRIuMAX;
+ f[sizeof("%" PRIuMAX) - 1 - 1] = fmt_spec;
+ assert(PRIuMAX[sizeof(PRIuMAX) - 1 - 1] == 'u');
+ str_arg_l += (size_t)snprintf(tmp + str_arg_l,
+ sizeof(tmp) - str_arg_l,
+ f, uarg);
+ break;
+ }
}
+ assert(str_arg_l < sizeof(tmp));
- {
- size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
-
- if (alternate_form && fmt_spec == 'o'
- // unless zero is already the first character
- && !(zero_padding_insertion_ind < str_arg_l
- && tmp[zero_padding_insertion_ind] == '0')) {
- // assure leading zero for alternate-form octal numbers
- if (!precision_specified
- || precision < num_of_digits + 1) {
- // precision is increased to force the first character to be
- // zero, except if a zero value is formatted with an explicit
- // precision of zero
- precision = num_of_digits + 1;
- }
- }
- // zero padding to specified precision?
- if (num_of_digits < precision) {
- number_of_zeros_to_pad = precision - num_of_digits;
- }
+ // include the optional minus sign and possible "0x" in the region
+ // before the zero padding insertion point
+ if (zero_padding_insertion_ind < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '-') {
+ zero_padding_insertion_ind++;
}
- // zero padding to specified minimal field width?
- if (!justify_left && zero_padding) {
- const int n = (int)(min_field_width - (str_arg_l
- + number_of_zeros_to_pad));
- if (n > 0) {
- number_of_zeros_to_pad += (size_t)n;
- }
+ if (zero_padding_insertion_ind + 1 < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '0'
+ && (tmp[zero_padding_insertion_ind + 1] == 'x'
+ || tmp[zero_padding_insertion_ind + 1] == 'X'
+ || tmp[zero_padding_insertion_ind + 1] == 'b'
+ || tmp[zero_padding_insertion_ind + 1] == 'B')) {
+ zero_padding_insertion_ind += 2;
}
- break;
}
- case 'f':
- case 'F':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- {
- // floating point
- char format[40];
- int remove_trailing_zeroes = false;
-
- double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
- double abs_f = f < 0 ? -f : f;
-
- if (fmt_spec == 'g' || fmt_spec == 'G') {
- // can't use %g directly, cause it prints "1.0" as "1"
- if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) {
- fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
- } else {
- fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
- }
- remove_trailing_zeroes = true;
+ {
+ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
+
+ if (alternate_form && fmt_spec == 'o'
+ // unless zero is already the first character
+ && !(zero_padding_insertion_ind < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '0')) {
+ // assure leading zero for alternate-form octal numbers
+ if (!precision_specified
+ || precision < num_of_digits + 1) {
+ // precision is increased to force the first character to be
+ // zero, except if a zero value is formatted with an explicit
+ // precision of zero
+ precision = num_of_digits + 1;
}
+ }
+ // zero padding to specified precision?
+ if (num_of_digits < precision) {
+ number_of_zeros_to_pad = precision - num_of_digits;
+ }
+ }
+ // zero padding to specified minimal field width?
+ if (!justify_left && zero_padding) {
+ const int n = (int)(min_field_width - (str_arg_l
+ + number_of_zeros_to_pad));
+ if (n > 0) {
+ number_of_zeros_to_pad += (size_t)n;
+ }
+ }
+ break;
+ }
- if (xisinf(f)
- || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) {
- xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec,
- force_sign, space_for_positive),
- sizeof(tmp));
- str_arg_l = strlen(tmp);
- zero_padding = 0;
- } else if (xisnan(f)) {
- // Not a number: nan or NAN
- memmove(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan", 4);
- str_arg_l = 3;
- zero_padding = 0;
- } else {
- // Regular float number
- format[0] = '%';
- size_t l = 1;
- if (force_sign) {
- format[l++] = space_for_positive ? ' ' : '+';
- }
- if (precision_specified) {
- size_t max_prec = TMP_LEN - 10;
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G': {
+ // floating point
+ char format[40];
+ int remove_trailing_zeroes = false;
+
+ double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
+ double abs_f = f < 0 ? -f : f;
+
+ if (fmt_spec == 'g' || fmt_spec == 'G') {
+ // can't use %g directly, cause it prints "1.0" as "1"
+ if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) {
+ fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
+ } else {
+ fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
+ }
+ remove_trailing_zeroes = true;
+ }
- // make sure we don't get more digits than we have room for
- if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) {
- max_prec -= (size_t)log10(abs_f);
- }
- if (precision > max_prec) {
- precision = max_prec;
- }
- l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d",
- (int)precision);
- }
+ if (xisinf(f)
+ || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) {
+ xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec,
+ force_sign, space_for_positive),
+ sizeof(tmp));
+ str_arg_l = strlen(tmp);
+ zero_padding = 0;
+ } else if (xisnan(f)) {
+ // Not a number: nan or NAN
+ memmove(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan", 4);
+ str_arg_l = 3;
+ zero_padding = 0;
+ } else {
+ // Regular float number
+ format[0] = '%';
+ size_t l = 1;
+ if (force_sign) {
+ format[l++] = space_for_positive ? ' ' : '+';
+ }
+ if (precision_specified) {
+ size_t max_prec = TMP_LEN - 10;
- // Cast to char to avoid a conversion warning on Ubuntu 12.04.
- assert(l + 1 < sizeof(format));
- format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec);
- format[l + 1] = NUL;
+ // make sure we don't get more digits than we have room for
+ if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) {
+ max_prec -= (size_t)log10(abs_f);
+ }
+ if (precision > max_prec) {
+ precision = max_prec;
+ }
+ l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d",
+ (int)precision);
+ }
- str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f);
- assert(str_arg_l < sizeof(tmp));
+ // Cast to char to avoid a conversion warning on Ubuntu 12.04.
+ assert(l + 1 < sizeof(format));
+ format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec);
+ format[l + 1] = NUL;
- if (remove_trailing_zeroes) {
- int i;
- char *tp;
+ str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f);
+ assert(str_arg_l < sizeof(tmp));
- // using %g or %G: remove superfluous zeroes
- if (fmt_spec == 'f' || fmt_spec == 'F') {
- tp = tmp + str_arg_l - 1;
- } else {
- tp = (char *)vim_strchr((char_u *)tmp,
- fmt_spec == 'e' ? 'e' : 'E');
- if (tp) {
- // remove superfluous '+' and leading zeroes from exponent
- if (tp[1] == '+') {
- // change "1.0e+07" to "1.0e07"
- STRMOVE(tp + 1, tp + 2);
- str_arg_l--;
- }
- i = (tp[1] == '-') ? 2 : 1;
- while (tp[i] == '0') {
- // change "1.0e07" to "1.0e7"
- STRMOVE(tp + i, tp + i + 1);
- str_arg_l--;
- }
- tp--;
- }
- }
+ if (remove_trailing_zeroes) {
+ int i;
+ char *tp;
- if (tp != NULL && !precision_specified) {
- // remove trailing zeroes, but keep the one just after a dot
- while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') {
- STRMOVE(tp, tp + 1);
- tp--;
- str_arg_l--;
- }
+ // using %g or %G: remove superfluous zeroes
+ if (fmt_spec == 'f' || fmt_spec == 'F') {
+ tp = tmp + str_arg_l - 1;
+ } else {
+ tp = (char *)vim_strchr((char_u *)tmp,
+ fmt_spec == 'e' ? 'e' : 'E');
+ if (tp) {
+ // remove superfluous '+' and leading zeroes from exponent
+ if (tp[1] == '+') {
+ // change "1.0e+07" to "1.0e07"
+ STRMOVE(tp + 1, tp + 2);
+ str_arg_l--;
}
- } else {
- // Be consistent: some printf("%e") use 1.0e+12 and some
- // 1.0e+012; remove one zero in the last case.
- char *tp = (char *)vim_strchr((char_u *)tmp,
- fmt_spec == 'e' ? 'e' : 'E');
- if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0'
- && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) {
- STRMOVE(tp + 2, tp + 3);
+ i = (tp[1] == '-') ? 2 : 1;
+ while (tp[i] == '0') {
+ // change "1.0e07" to "1.0e7"
+ STRMOVE(tp + i, tp + i + 1);
str_arg_l--;
}
+ tp--;
}
}
- if (zero_padding && min_field_width > str_arg_l
- && (tmp[0] == '-' || force_sign)) {
- // Padding 0's should be inserted after the sign.
- number_of_zeros_to_pad = min_field_width - str_arg_l;
- zero_padding_insertion_ind = 1;
+
+ if (tp != NULL && !precision_specified) {
+ // remove trailing zeroes, but keep the one just after a dot
+ while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') {
+ STRMOVE(tp, tp + 1);
+ tp--;
+ str_arg_l--;
+ }
+ }
+ } else {
+ // Be consistent: some printf("%e") use 1.0e+12 and some
+ // 1.0e+012; remove one zero in the last case.
+ char *tp = (char *)vim_strchr((char_u *)tmp,
+ fmt_spec == 'e' ? 'e' : 'E');
+ if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0'
+ && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) {
+ STRMOVE(tp + 2, tp + 3);
+ str_arg_l--;
}
- str_arg = tmp;
- break;
}
+ }
+ if (zero_padding && min_field_width > str_arg_l
+ && (tmp[0] == '-' || force_sign)) {
+ // Padding 0's should be inserted after the sign.
+ number_of_zeros_to_pad = min_field_width - str_arg_l;
+ zero_padding_insertion_ind = 1;
+ }
+ str_arg = tmp;
+ break;
+ }
- default:
- // unrecognized conversion specifier, keep format string as-is
- zero_padding = 0; // turn zero padding off for non-numeric conversion
- justify_left = 1;
- min_field_width = 0; // reset flags
-
- // discard the unrecognized conversion, just keep
- // the unrecognized conversion character
- str_arg = p;
- str_arg_l = 0;
- if (*p) {
- str_arg_l++; // include invalid conversion specifier
- }
- // unchanged if not at end-of-string
- break;
+ default:
+ // unrecognized conversion specifier, keep format string as-is
+ zero_padding = 0; // turn zero padding off for non-numeric conversion
+ justify_left = 1;
+ min_field_width = 0; // reset flags
+
+ // discard the unrecognized conversion, just keep
+ // the unrecognized conversion character
+ str_arg = p;
+ str_arg_l = 0;
+ if (*p) {
+ str_arg_l++; // include invalid conversion specifier
+ }
+ // unchanged if not at end-of-string
+ break;
}
if (*p) {
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 559a7380eb..d2c94d9fe8 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -383,7 +383,7 @@ static int current_line_id = 0; // unique number for current line
#define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx]
static bool syn_time_on = false;
-# define IF_SYN_TIME(p) (p)
+#define IF_SYN_TIME(p) (p)
// Set the timeout used for syntax highlighting.
// Use NULL to reset, no timeout.
@@ -578,7 +578,7 @@ void syntax_start(win_T *wp, linenr_T lnum)
static void clear_syn_state(synstate_T *p)
{
if (p->sst_stacksize > SST_FIX_STATES) {
-# define UNREF_BUFSTATE_EXTMATCH(bs) unref_extmatch((bs)->bs_extmatch)
+#define UNREF_BUFSTATE_EXTMATCH(bs) unref_extmatch((bs)->bs_extmatch)
GA_DEEP_CLEAR(&(p->sst_union.sst_ga), bufstate_T, UNREF_BUFSTATE_EXTMATCH);
} else {
for (int i = 0; i < p->sst_stacksize; i++) {
@@ -592,7 +592,7 @@ static void clear_syn_state(synstate_T *p)
*/
static void clear_current_state(void)
{
-# define UNREF_STATEITEM_EXTMATCH(si) unref_extmatch((si)->si_extmatch)
+#define UNREF_STATEITEM_EXTMATCH(si) unref_extmatch((si)->si_extmatch)
GA_DEEP_CLEAR(&current_state, stateitem_T, UNREF_STATEITEM_EXTMATCH);
}
@@ -1703,7 +1703,7 @@ static int syn_current_attr(const bool syncing, const bool displaying, bool *con
regmmatch_T regmatch;
lpos_T pos;
reg_extmatch_T *cur_extmatch = NULL;
- char_u buf_chartab[32]; // chartab array for syn iskeyword
+ char_u buf_chartab[32]; // chartab array for syn iskeyword
char_u *line; // current line. NOTE: becomes invalid after
// looking for a pattern match!
@@ -5654,7 +5654,7 @@ static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, in
struct subcommand {
char *name; // subcommand name
- void (*func)(exarg_T *, int); // function to call
+ void (*func)(exarg_T *, int); // function to call
};
static struct subcommand subcommands[] =
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index c63cdad098..768cca284b 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -10,9 +10,7 @@
#include <stdbool.h>
#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/tag.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -22,18 +20,21 @@
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/if_cscope.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/file_search.h"
-#include "nvim/garray.h"
-#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
@@ -41,30 +42,29 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
+#include "nvim/tag.h"
#include "nvim/ui.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
/*
* Structure to hold pointers to various items in a tag line.
*/
typedef struct tag_pointers {
// filled in by parse_tag_line():
- char_u *tagname; // start of tag name (skip "file:")
- char_u *tagname_end; // char after tag name
- char_u *fname; // first char of file name
- char_u *fname_end; // char after file name
- char_u *command; // first char of command
+ char_u *tagname; // start of tag name (skip "file:")
+ char_u *tagname_end; // char after tag name
+ char_u *fname; // first char of file name
+ char_u *fname_end; // char after file name
+ char_u *command; // first char of command
// filled in by parse_match():
- char_u *command_end; // first char after command
- char_u *tag_fname; // file name of the tags file. This is used
+ char_u *command_end; // first char after command
+ char_u *tag_fname; // file name of the tags file. This is used
// when 'tr' is set.
- char_u *tagkind; // "kind:" value
- char_u *tagkind_end; // end of tagkind
- char_u *user_data; // user_data string
- char_u *user_data_end; // end of user_data
+ char_u *tagkind; // "kind:" value
+ char_u *tagkind_end; // end of tagkind
+ char_u *user_data; // user_data string
+ char_u *user_data_end; // end of user_data
linenr_T tagline; // "line:" value
} tagptrs_T;
@@ -72,11 +72,11 @@ typedef struct tag_pointers {
* Structure to hold info about the tag pattern being used.
*/
typedef struct {
- char_u *pat; /* the pattern */
- int len; /* length of pat[] */
- char_u *head; /* start of pattern head */
- int headlen; /* length of head[] */
- regmatch_T regmatch; /* regexp program, may be NULL */
+ char_u *pat; // the pattern
+ int len; // length of pat[]
+ char_u *head; // start of pattern head
+ int headlen; // length of head[]
+ regmatch_T regmatch; // regexp program, may be NULL
} pat_T;
// The matching tags are first stored in one of the hash tables. In
@@ -93,11 +93,11 @@ typedef struct {
#define MT_MASK 7 // mask for printing priority
#define MT_COUNT 16
-static char *mt_names[MT_COUNT/2] =
-{"FSC", "F C", "F ", "FS ", " SC", " C", " ", " S "};
+static char *mt_names[MT_COUNT/2] =
+{ "FSC", "F C", "F ", "FS ", " SC", " C", " ", " S " };
-#define NOTAGFILE 99 /* return value for jumpto_tag */
-static char_u *nofile_fname = NULL; /* fname for NOTAGFILE error */
+#define NOTAGFILE 99 // return value for jumpto_tag
+static char_u *nofile_fname = NULL; // fname for NOTAGFILE error
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -111,7 +111,7 @@ static char_u *recurmsg
static char_u *tfu_inv_ret_msg
= (char_u *)N_("E987: invalid return value from tagfunc");
-static char_u *tagmatchname = NULL; /* name of last used tag */
+static char_u *tagmatchname = NULL; // name of last used tag
/*
* Tag for preview window is remembered separately, to avoid messing up the
@@ -124,36 +124,31 @@ static int tfu_in_use = false; // disallow recursive call of tagfunc
// Used instead of NUL to separate tag fields in the growarrays.
#define TAG_SEP 0x02
-/*
- * Jump to tag; handling of tag commands and tag stack
- *
- * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack
- *
- * type == DT_TAG: ":tag [tag]", jump to newer position or same tag again
- * type == DT_HELP: like DT_TAG, but don't use regexp.
- * type == DT_POP: ":pop" or CTRL-T, jump to old position
- * type == DT_NEXT: jump to next match of same tag
- * type == DT_PREV: jump to previous match of same tag
- * type == DT_FIRST: jump to first match of same tag
- * type == DT_LAST: jump to last match of same tag
- * type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches
- * type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list
- * type == DT_CSCOPE: use cscope to find the tag
- * type == DT_LTAG: use location list for displaying tag matches
- * type == DT_FREE: free cached matches
- *
- * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise
- */
-int
-do_tag(
- char_u *tag, // tag (pattern) to jump to
- int type,
- int count,
- int forceit, // :ta with !
- int verbose // print "tag not found" message
-)
+/// Jump to tag; handling of tag commands and tag stack
+///
+/// *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack
+///
+/// type == DT_TAG: ":tag [tag]", jump to newer position or same tag again
+/// type == DT_HELP: like DT_TAG, but don't use regexp.
+/// type == DT_POP: ":pop" or CTRL-T, jump to old position
+/// type == DT_NEXT: jump to next match of same tag
+/// type == DT_PREV: jump to previous match of same tag
+/// type == DT_FIRST: jump to first match of same tag
+/// type == DT_LAST: jump to last match of same tag
+/// type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches
+/// type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list
+/// type == DT_CSCOPE: use cscope to find the tag
+/// type == DT_LTAG: use location list for displaying tag matches
+/// type == DT_FREE: free cached matches
+///
+/// for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise
+///
+/// @param tag tag (pattern) to jump to
+/// @param forceit :ta with !
+/// @param verbose print "tag not found" message
+int do_tag(char_u *tag, int type, int count, int forceit, int verbose)
{
- taggy_T *tagstack = curwin->w_tagstack;
+ taggy_T *tagstack = curwin->w_tagstack;
int tagstackidx = curwin->w_tagstackidx;
int tagstacklen = curwin->w_tagstacklen;
int cur_match = 0;
@@ -170,16 +165,16 @@ do_tag(
fmark_T saved_fmark;
int jumped_to_tag = false;
int new_num_matches;
- char_u **new_matches;
+ char_u **new_matches;
int use_tagstack;
int skip_msg = false;
char_u *buf_ffname = curbuf->b_ffname; // name for priority computation
int use_tfu = 1;
- /* remember the matches for the last used tag */
+ // remember the matches for the last used tag
static int num_matches = 0;
- static int max_num_matches = 0; /* limit used for match search */
- static char_u **matches = NULL;
+ static int max_num_matches = 0; // limit used for match search
+ static char_u **matches = NULL;
static int flags;
if (tfu_in_use) {
@@ -189,7 +184,7 @@ do_tag(
#ifdef EXITFREE
if (type == DT_FREE) {
- /* remove the list of matches */
+ // remove the list of matches
FreeWild(num_matches, matches);
cs_free_tags();
num_matches = 0;
@@ -207,7 +202,7 @@ do_tag(
free_string_option(nofile_fname);
nofile_fname = NULL;
- clearpos(&saved_fmark.mark); /* shutup gcc 4.0 */
+ clearpos(&saved_fmark.mark); // shutup gcc 4.0
saved_fmark.fnum = 0;
// Don't add a tag to the tagstack if 'tagstack' has been reset.
@@ -226,7 +221,7 @@ do_tag(
use_tagstack = true;
}
- /* new pattern, add to the tag stack */
+ // new pattern, add to the tag stack
if (*tag != NUL
&& (type == DT_TAG || type == DT_SELECT || type == DT_JUMP
|| type == DT_LTAG
@@ -252,7 +247,7 @@ do_tag(
tagstack_clear_entry(&tagstack[--tagstacklen]);
}
- /* if the tagstack is full: remove oldest entry */
+ // if the tagstack is full: remove oldest entry
if (++tagstacklen > TAGSTACKSIZE) {
tagstacklen = TAGSTACKSIZE;
tagstack_clear_entry(&tagstack[0]);
@@ -293,7 +288,7 @@ do_tag(
* way to the bottom now.
*/
tagstackidx = 0;
- } else if (tagstackidx >= tagstacklen) { // count == 0?
+ } else if (tagstackidx >= tagstacklen) { // count == 0?
EMSG(_(topmsg));
goto end_do_tag;
}
@@ -321,8 +316,9 @@ do_tag(
curwin->w_cursor.col = saved_fmark.mark.col;
curwin->w_set_curswant = true;
check_cursor();
- if ((fdo_flags & FDO_TAG) && old_KeyTyped)
+ if ((fdo_flags & FDO_TAG) && old_KeyTyped) {
foldOpenCursor();
+ }
// remove the old list of matches
FreeWild(num_matches, matches);
@@ -333,8 +329,7 @@ do_tag(
}
if (type == DT_TAG
- || type == DT_LTAG
- ) {
+ || type == DT_LTAG) {
if (g_do_tagpreview != 0) {
cur_match = ptag_entry.cur_match;
cur_fnum = ptag_entry.cur_fnum;
@@ -350,7 +345,7 @@ do_tag(
tagstackidx = tagstacklen - 1;
EMSG(_(topmsg));
save_pos = false;
- } else if (tagstackidx < 0) { // must have been count == 0
+ } else if (tagstackidx < 0) { // must have been count == 0
EMSG(_(bottommsg));
tagstackidx = 0;
goto end_do_tag;
@@ -367,23 +362,28 @@ do_tag(
cur_match = ptag_entry.cur_match;
cur_fnum = ptag_entry.cur_fnum;
} else {
- if (--tagstackidx < 0)
+ if (--tagstackidx < 0) {
tagstackidx = 0;
+ }
cur_match = tagstack[tagstackidx].cur_match;
cur_fnum = tagstack[tagstackidx].cur_fnum;
}
switch (type) {
- case DT_FIRST: cur_match = count - 1; break;
+ case DT_FIRST:
+ cur_match = count - 1; break;
case DT_SELECT:
case DT_JUMP:
case DT_CSCOPE:
- case DT_LAST: cur_match = MAXCOL - 1; break;
- case DT_NEXT: cur_match += count; break;
- case DT_PREV: cur_match -= count; break;
+ case DT_LAST:
+ cur_match = MAXCOL - 1; break;
+ case DT_NEXT:
+ cur_match += count; break;
+ case DT_PREV:
+ cur_match -= count; break;
}
- if (cur_match >= MAXCOL)
+ if (cur_match >= MAXCOL) {
cur_match = MAXCOL - 1;
- else if (cur_match < 0) {
+ } else if (cur_match < 0) {
EMSG(_("E425: Cannot go before first matching tag"));
skip_msg = true;
cur_match = 0;
@@ -424,8 +424,9 @@ do_tag(
if (cur_fnum != curbuf->b_fnum) {
buf_T *buf = buflist_findnr(cur_fnum);
- if (buf != NULL)
+ if (buf != NULL) {
buf_ffname = buf->b_ffname;
+ }
}
/*
@@ -433,7 +434,7 @@ do_tag(
*/
for (;; ) {
int other_name;
- char_u *name;
+ char_u *name;
// When desired match not found yet, try to find it (and others).
if (use_tagstack) {
@@ -466,8 +467,9 @@ do_tag(
if (!no_regexp && *name == '/') {
flags = TAG_REGEXP;
++name;
- } else
+ } else {
flags = TAG_NOIC;
+ }
if (type == DT_CSCOPE) {
flags = TAG_CSCOPE;
@@ -490,9 +492,9 @@ do_tag(
* to the start. Avoids that the order changes when using
* ":tnext" and jumping to another file. */
if (!new_tag && !other_name) {
- int j, k;
- int idx = 0;
- tagptrs_T tagp, tagp2;
+ int j, k;
+ int idx = 0;
+ tagptrs_T tagp, tagp2;
// Find the position of each old match in the new list. Need
// to use parse_match() to find the tag line.
@@ -517,8 +519,9 @@ do_tag(
}
if (num_matches <= 0) {
- if (verbose)
+ if (verbose) {
EMSG2(_("E426: tag not found: %s"), name);
+ }
g_do_tagpreview = 0;
} else {
bool ask_for_selection = false;
@@ -533,7 +536,7 @@ do_tag(
} else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1)) {
print_tag_list(new_tag, use_tagstack, num_matches, matches);
ask_for_selection = true;
- } else if (type == DT_LTAG) {
+ } else if (type == DT_LTAG) {
if (add_llist_tags(tag, num_matches, matches) == FAIL) {
goto end_do_tag;
}
@@ -563,16 +566,17 @@ do_tag(
* There will be an EMSG("file doesn't exist") below then. */
if ((type == DT_NEXT || type == DT_FIRST)
&& nofile_fname == NULL) {
- if (num_matches == 1)
+ if (num_matches == 1) {
EMSG(_("E427: There is only one matching tag"));
- else
+ } else {
EMSG(_("E428: Cannot go beyond last matching tag"));
+ }
skip_msg = true;
}
cur_match = num_matches - 1;
}
if (use_tagstack) {
- tagptrs_T tagp2;
+ tagptrs_T tagp2;
tagstack[tagstackidx].cur_match = cur_match;
tagstack[tagstackidx].cur_fnum = cur_fnum;
@@ -581,12 +585,12 @@ do_tag(
if (use_tfu && parse_match(matches[cur_match], &tagp2) == OK
&& tagp2.user_data) {
XFREE_CLEAR(tagstack[tagstackidx].user_data);
- tagstack[tagstackidx].user_data = vim_strnsave(
- tagp2.user_data, tagp2.user_data_end - tagp2.user_data);
+ tagstack[tagstackidx].user_data = vim_strnsave(tagp2.user_data,
+ tagp2.user_data_end - tagp2.user_data);
}
tagstackidx++;
- } else if (g_do_tagpreview != 0) {
+ } else if (g_do_tagpreview != 0) {
ptag_entry.cur_match = cur_match;
ptag_entry.cur_fnum = cur_fnum;
}
@@ -595,8 +599,9 @@ do_tag(
* Only when going to try the next match, report that the previous
* file didn't exist. Otherwise an EMSG() is given below.
*/
- if (nofile_fname != NULL && error_cur_match != cur_match)
+ if (nofile_fname != NULL && error_cur_match != cur_match) {
smsg(_("File \"%s\" does not exist"), nofile_fname);
+ }
ic = (matches[cur_match][0] & MT_IC_OFF);
@@ -631,7 +636,7 @@ do_tag(
// Let the SwapExists event know what tag we are jumping to.
vim_snprintf((char *)IObuff, IOSIZE, ":ta %s\r", name);
- set_vim_var_string(VV_SWAPCOMMAND, (char *) IObuff, -1);
+ set_vim_var_string(VV_SWAPCOMMAND, (char *)IObuff, -1);
/*
* Jump to the desired match.
@@ -648,11 +653,12 @@ do_tag(
&& (max_num_matches != MAXCOL
|| cur_match < num_matches - 1))) {
error_cur_match = cur_match;
- if (use_tagstack)
+ if (use_tagstack) {
--tagstackidx;
- if (type == DT_PREV)
+ }
+ if (type == DT_PREV) {
--cur_match;
- else {
+ } else {
type = DT_NEXT;
++cur_match;
}
@@ -662,8 +668,9 @@ do_tag(
} else {
/* We may have jumped to another window, check that
* tagstackidx is still valid. */
- if (use_tagstack && tagstackidx > curwin->w_tagstacklen)
+ if (use_tagstack && tagstackidx > curwin->w_tagstacklen) {
tagstackidx = curwin->w_tagstackidx;
+ }
jumped_to_tag = true;
}
}
@@ -684,331 +691,322 @@ end_do_tag:
//
// List all the matching tags.
//
-static void
-print_tag_list(
- int new_tag,
- int use_tagstack,
- int num_matches,
- char_u **matches)
+static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_u **matches)
{
- taggy_T *tagstack = curwin->w_tagstack;
- int tagstackidx = curwin->w_tagstackidx;
- int i;
- char_u *p;
- char_u *command_end;
- tagptrs_T tagp;
- int taglen;
- int attr;
-
- // Assume that the first match indicates how long the tags can
- // be, and align the file names to that.
- parse_match(matches[0], &tagp);
- taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
- if (taglen < 18) {
- taglen = 18;
- }
- if (taglen > Columns - 25) {
- taglen = MAXCOL;
- }
- if (msg_col == 0) {
- msg_didout = false; // overwrite previous message
- }
- msg_start();
- msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T));
- msg_clr_eos();
+ taggy_T *tagstack = curwin->w_tagstack;
+ int tagstackidx = curwin->w_tagstackidx;
+ int i;
+ char_u *p;
+ char_u *command_end;
+ tagptrs_T tagp;
+ int taglen;
+ int attr;
+
+ // Assume that the first match indicates how long the tags can
+ // be, and align the file names to that.
+ parse_match(matches[0], &tagp);
+ taglen = (int)(tagp.tagname_end - tagp.tagname + 2);
+ if (taglen < 18) {
+ taglen = 18;
+ }
+ if (taglen > Columns - 25) {
+ taglen = MAXCOL;
+ }
+ if (msg_col == 0) {
+ msg_didout = false; // overwrite previous message
+ }
+ msg_start();
+ msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T));
+ msg_clr_eos();
+ taglen_advance(taglen);
+ msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
+
+ for (i = 0; i < num_matches && !got_int; i++) {
+ parse_match(matches[i], &tagp);
+ if (!new_tag && (
+ (g_do_tagpreview != 0
+ && i == ptag_entry.cur_match)
+ || (use_tagstack
+ && i == tagstack[tagstackidx].cur_match))) {
+ *IObuff = '>';
+ } else {
+ *IObuff = ' ';
+ }
+ vim_snprintf((char *)IObuff + 1, IOSIZE - 1,
+ "%2d %s ", i + 1,
+ mt_names[matches[i][0] & MT_MASK]);
+ msg_puts((char *)IObuff);
+ if (tagp.tagkind != NULL) {
+ msg_outtrans_len(tagp.tagkind,
+ (int)(tagp.tagkind_end - tagp.tagkind));
+ }
+ msg_advance(13);
+ msg_outtrans_len_attr(tagp.tagname,
+ (int)(tagp.tagname_end - tagp.tagname),
+ HL_ATTR(HLF_T));
+ msg_putchar(' ');
taglen_advance(taglen);
- msg_puts_attr(_("file\n"), HL_ATTR(HLF_T));
-
- for (i = 0; i < num_matches && !got_int; i++) {
- parse_match(matches[i], &tagp);
- if (!new_tag && (
- (g_do_tagpreview != 0
- && i == ptag_entry.cur_match)
- || (use_tagstack
- && i == tagstack[tagstackidx].cur_match))) {
- *IObuff = '>';
- } else {
- *IObuff = ' ';
+
+ // Find out the actual file name. If it is long, truncate
+ // it and put "..." in the middle
+ p = tag_full_fname(&tagp);
+ if (p != NULL) {
+ msg_outtrans_attr(p, HL_ATTR(HLF_D));
+ XFREE_CLEAR(p);
+ }
+ if (msg_col > 0) {
+ msg_putchar('\n');
+ }
+ if (got_int) {
+ break;
+ }
+ msg_advance(15);
+
+ // print any extra fields
+ command_end = tagp.command_end;
+ if (command_end != NULL) {
+ p = command_end + 3;
+ while (*p && *p != '\r' && *p != '\n') {
+ while (*p == TAB) {
+ p++;
}
- vim_snprintf((char *)IObuff + 1, IOSIZE - 1,
- "%2d %s ", i + 1,
- mt_names[matches[i][0] & MT_MASK]);
- msg_puts((char *)IObuff);
- if (tagp.tagkind != NULL) {
- msg_outtrans_len(tagp.tagkind,
- (int)(tagp.tagkind_end - tagp.tagkind));
+
+ // skip "file:" without a value (static tag)
+ if (STRNCMP(p, "file:", 5) == 0 && ascii_isspace(p[5])) {
+ p += 5;
+ continue;
}
- msg_advance(13);
- msg_outtrans_len_attr(tagp.tagname,
- (int)(tagp.tagname_end - tagp.tagname),
- HL_ATTR(HLF_T));
- msg_putchar(' ');
- taglen_advance(taglen);
-
- // Find out the actual file name. If it is long, truncate
- // it and put "..." in the middle
- p = tag_full_fname(&tagp);
- if (p != NULL) {
- msg_outtrans_attr(p, HL_ATTR(HLF_D));
- XFREE_CLEAR(p);
+ // skip "kind:<kind>" and "<kind>"
+ if (p == tagp.tagkind
+ || (p + 5 == tagp.tagkind
+ && STRNCMP(p, "kind:", 5) == 0)) {
+ p = tagp.tagkind_end;
+ continue;
}
- if (msg_col > 0) {
+ // print all other extra fields
+ attr = HL_ATTR(HLF_CM);
+ while (*p && *p != '\r' && *p != '\n') {
+ if (msg_col + ptr2cells(p) >= Columns) {
msg_putchar('\n');
+ if (got_int) {
+ break;
+ }
+ msg_advance(15);
+ }
+ p = msg_outtrans_one(p, attr);
+ if (*p == TAB) {
+ msg_puts_attr(" ", attr);
+ break;
+ }
+ if (*p == ':') {
+ attr = 0;
+ }
}
+ }
+ if (msg_col > 15) {
+ msg_putchar('\n');
if (got_int) {
- break;
+ break;
}
msg_advance(15);
+ }
+ } else {
+ for (p = tagp.command;
+ *p && *p != '\r' && *p != '\n';
+ p++) {
+ }
+ command_end = p;
+ }
- // print any extra fields
- command_end = tagp.command_end;
- if (command_end != NULL) {
- p = command_end + 3;
- while (*p && *p != '\r' && *p != '\n') {
- while (*p == TAB) {
- p++;
- }
-
- // skip "file:" without a value (static tag)
- if (STRNCMP(p, "file:", 5) == 0 && ascii_isspace(p[5])) {
- p += 5;
- continue;
- }
- // skip "kind:<kind>" and "<kind>"
- if (p == tagp.tagkind
- || (p + 5 == tagp.tagkind
- && STRNCMP(p, "kind:", 5) == 0)) {
- p = tagp.tagkind_end;
- continue;
- }
- // print all other extra fields
- attr = HL_ATTR(HLF_CM);
- while (*p && *p != '\r' && *p != '\n') {
- if (msg_col + ptr2cells(p) >= Columns) {
- msg_putchar('\n');
- if (got_int) {
- break;
- }
- msg_advance(15);
- }
- p = msg_outtrans_one(p, attr);
- if (*p == TAB) {
- msg_puts_attr(" ", attr);
- break;
- }
- if (*p == ':') {
- attr = 0;
- }
- }
- }
- if (msg_col > 15) {
- msg_putchar('\n');
- if (got_int) {
- break;
- }
- msg_advance(15);
- }
- } else {
- for (p = tagp.command;
- *p && *p != '\r' && *p != '\n';
- p++) {
- }
- command_end = p;
- }
-
- // Put the info (in several lines) at column 15.
- // Don't display "/^" and "?^".
- p = tagp.command;
- if (*p == '/' || *p == '?') {
- p++;
- if (*p == '^') {
- p++;
- }
- }
- // Remove leading whitespace from pattern
- while (p != command_end && ascii_isspace(*p)) {
- p++;
- }
+ // Put the info (in several lines) at column 15.
+ // Don't display "/^" and "?^".
+ p = tagp.command;
+ if (*p == '/' || *p == '?') {
+ p++;
+ if (*p == '^') {
+ p++;
+ }
+ }
+ // Remove leading whitespace from pattern
+ while (p != command_end && ascii_isspace(*p)) {
+ p++;
+ }
- while (p != command_end) {
- if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns) {
- msg_putchar('\n');
- }
- if (got_int) {
- break;
- }
- msg_advance(15);
+ while (p != command_end) {
+ if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns) {
+ msg_putchar('\n');
+ }
+ if (got_int) {
+ break;
+ }
+ msg_advance(15);
- // skip backslash used for escaping a command char or
- // a backslash
- if (*p == '\\' && (*(p + 1) == *tagp.command
- || *(p + 1) == '\\')) {
- p++;
- }
+ // skip backslash used for escaping a command char or
+ // a backslash
+ if (*p == '\\' && (*(p + 1) == *tagp.command
+ || *(p + 1) == '\\')) {
+ p++;
+ }
- if (*p == TAB) {
- msg_putchar(' ');
- p++;
- } else {
- p = msg_outtrans_one(p, 0);
- }
+ if (*p == TAB) {
+ msg_putchar(' ');
+ p++;
+ } else {
+ p = msg_outtrans_one(p, 0);
+ }
- // don't display the "$/;\"" and "$?;\""
- if (p == command_end - 2 && *p == '$'
- && *(p + 1) == *tagp.command) {
- break;
- }
- // don't display matching '/' or '?'
- if (p == command_end - 1 && *p == *tagp.command
- && (*p == '/' || *p == '?')) {
- break;
- }
- }
- if (msg_col) {
- msg_putchar('\n');
- }
- os_breakcheck();
+ // don't display the "$/;\"" and "$?;\""
+ if (p == command_end - 2 && *p == '$'
+ && *(p + 1) == *tagp.command) {
+ break;
+ }
+ // don't display matching '/' or '?'
+ if (p == command_end - 1 && *p == *tagp.command
+ && (*p == '/' || *p == '?')) {
+ break;
+ }
}
- if (got_int) {
- got_int = false; // only stop the listing
+ if (msg_col) {
+ msg_putchar('\n');
}
+ os_breakcheck();
+ }
+ if (got_int) {
+ got_int = false; // only stop the listing
+ }
}
//
// Add the matching tags to the location list for the current
// window.
//
-static int
-add_llist_tags(
- char_u *tag,
- int num_matches,
- char_u **matches)
+static int add_llist_tags(char_u *tag, int num_matches, char_u **matches)
{
- list_T *list;
- char_u tag_name[128 + 1];
- char_u *fname;
- char_u *cmd;
- int i;
- char_u *p;
- tagptrs_T tagp;
-
- fname = xmalloc(MAXPATHL + 1);
- cmd = xmalloc(CMDBUFFSIZE + 1);
- list = tv_list_alloc(0);
-
- for (i = 0; i < num_matches; i++) {
- int len, cmd_len;
- long lnum;
- dict_T *dict;
-
- parse_match(matches[i], &tagp);
-
- // Save the tag name
- len = (int)(tagp.tagname_end - tagp.tagname);
- if (len > 128) {
- len = 128;
- }
- xstrlcpy((char *)tag_name, (const char *)tagp.tagname, len + 1);
- tag_name[len] = NUL;
+ list_T *list;
+ char_u tag_name[128 + 1];
+ char_u *fname;
+ char_u *cmd;
+ int i;
+ char_u *p;
+ tagptrs_T tagp;
- // Save the tag file name
- p = tag_full_fname(&tagp);
- if (p == NULL) {
- continue;
- }
- xstrlcpy((char *)fname, (const char *)p, MAXPATHL);
- XFREE_CLEAR(p);
-
- // Get the line number or the search pattern used to locate
- // the tag.
- lnum = 0;
- if (isdigit(*tagp.command)) {
- // Line number is used to locate the tag
- lnum = atol((char *)tagp.command);
- } else {
- char_u *cmd_start, *cmd_end;
+ fname = xmalloc(MAXPATHL + 1);
+ cmd = xmalloc(CMDBUFFSIZE + 1);
+ list = tv_list_alloc(0);
- // Search pattern is used to locate the tag
+ for (i = 0; i < num_matches; i++) {
+ int len, cmd_len;
+ long lnum;
+ dict_T *dict;
- // Locate the end of the command
- cmd_start = tagp.command;
- cmd_end = tagp.command_end;
- if (cmd_end == NULL) {
- for (p = tagp.command;
- *p && *p != '\r' && *p != '\n'; p++) {
- }
- cmd_end = p;
- }
+ parse_match(matches[i], &tagp);
- // Now, cmd_end points to the character after the
- // command. Adjust it to point to the last
- // character of the command.
- cmd_end--;
+ // Save the tag name
+ len = (int)(tagp.tagname_end - tagp.tagname);
+ if (len > 128) {
+ len = 128;
+ }
+ xstrlcpy((char *)tag_name, (const char *)tagp.tagname, len + 1);
+ tag_name[len] = NUL;
- // Skip the '/' and '?' characters at the
- // beginning and end of the search pattern.
- if (*cmd_start == '/' || *cmd_start == '?') {
- cmd_start++;
- }
+ // Save the tag file name
+ p = tag_full_fname(&tagp);
+ if (p == NULL) {
+ continue;
+ }
+ xstrlcpy((char *)fname, (const char *)p, MAXPATHL);
+ XFREE_CLEAR(p);
+
+ // Get the line number or the search pattern used to locate
+ // the tag.
+ lnum = 0;
+ if (isdigit(*tagp.command)) {
+ // Line number is used to locate the tag
+ lnum = atol((char *)tagp.command);
+ } else {
+ char_u *cmd_start, *cmd_end;
- if (*cmd_end == '/' || *cmd_end == '?') {
- cmd_end--;
- }
+ // Search pattern is used to locate the tag
- len = 0;
- cmd[0] = NUL;
+ // Locate the end of the command
+ cmd_start = tagp.command;
+ cmd_end = tagp.command_end;
+ if (cmd_end == NULL) {
+ for (p = tagp.command;
+ *p && *p != '\r' && *p != '\n'; p++) {
+ }
+ cmd_end = p;
+ }
- // If "^" is present in the tag search pattern, then
- // copy it first.
- if (*cmd_start == '^') {
- STRCPY(cmd, "^");
- cmd_start++;
- len++;
- }
+ // Now, cmd_end points to the character after the
+ // command. Adjust it to point to the last
+ // character of the command.
+ cmd_end--;
- // Precede the tag pattern with \V to make it very
- // nomagic.
- STRCAT(cmd, "\\V");
- len += 2;
+ // Skip the '/' and '?' characters at the
+ // beginning and end of the search pattern.
+ if (*cmd_start == '/' || *cmd_start == '?') {
+ cmd_start++;
+ }
- cmd_len = (int)(cmd_end - cmd_start + 1);
- if (cmd_len > (CMDBUFFSIZE - 5)) {
- cmd_len = CMDBUFFSIZE - 5;
- }
- snprintf((char *)cmd + len, CMDBUFFSIZE + 1 - len,
- "%.*s", cmd_len, cmd_start);
- len += cmd_len;
-
- if (cmd[len - 1] == '$') {
- // Replace '$' at the end of the search pattern
- // with '\$'
- cmd[len - 1] = '\\';
- cmd[len] = '$';
- len++;
- }
+ if (*cmd_end == '/' || *cmd_end == '?') {
+ cmd_end--;
+ }
- cmd[len] = NUL;
- }
+ len = 0;
+ cmd[0] = NUL;
- dict = tv_dict_alloc();
- tv_list_append_dict(list, dict);
+ // If "^" is present in the tag search pattern, then
+ // copy it first.
+ if (*cmd_start == '^') {
+ STRCPY(cmd, "^");
+ cmd_start++;
+ len++;
+ }
- tv_dict_add_str(dict, S_LEN("text"), (const char *)tag_name);
- tv_dict_add_str(dict, S_LEN("filename"), (const char *)fname);
- tv_dict_add_nr(dict, S_LEN("lnum"), lnum);
- if (lnum == 0) {
- tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cmd);
- }
+ // Precede the tag pattern with \V to make it very
+ // nomagic.
+ STRCAT(cmd, "\\V");
+ len += 2;
+
+ cmd_len = (int)(cmd_end - cmd_start + 1);
+ if (cmd_len > (CMDBUFFSIZE - 5)) {
+ cmd_len = CMDBUFFSIZE - 5;
+ }
+ snprintf((char *)cmd + len, CMDBUFFSIZE + 1 - len,
+ "%.*s", cmd_len, cmd_start);
+ len += cmd_len;
+
+ if (cmd[len - 1] == '$') {
+ // Replace '$' at the end of the search pattern
+ // with '\$'
+ cmd[len - 1] = '\\';
+ cmd[len] = '$';
+ len++;
+ }
+
+ cmd[len] = NUL;
}
- vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag);
- set_errorlist(curwin, list, ' ', IObuff, NULL);
+ dict = tv_dict_alloc();
+ tv_list_append_dict(list, dict);
- tv_list_free(list);
- XFREE_CLEAR(fname);
- XFREE_CLEAR(cmd);
+ tv_dict_add_str(dict, S_LEN("text"), (const char *)tag_name);
+ tv_dict_add_str(dict, S_LEN("filename"), (const char *)fname);
+ tv_dict_add_nr(dict, S_LEN("lnum"), lnum);
+ if (lnum == 0) {
+ tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cmd);
+ }
+ }
- return OK;
+ vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag);
+ set_errorlist(curwin, list, ' ', IObuff, NULL);
+
+ tv_list_free(list);
+ XFREE_CLEAR(fname);
+ XFREE_CLEAR(cmd);
+
+ return OK;
}
/*
@@ -1024,8 +1022,9 @@ static void taglen_advance(int l)
if (l == MAXCOL) {
msg_putchar('\n');
msg_advance(24);
- } else
+ } else {
msg_advance(13 + l);
+ }
}
/*
@@ -1034,18 +1033,19 @@ static void taglen_advance(int l)
void do_tags(exarg_T *eap)
{
int i;
- char_u *name;
- taggy_T *tagstack = curwin->w_tagstack;
+ char_u *name;
+ taggy_T *tagstack = curwin->w_tagstack;
int tagstackidx = curwin->w_tagstackidx;
int tagstacklen = curwin->w_tagstacklen;
- /* Highlight title */
+ // Highlight title
MSG_PUTS_TITLE(_("\n # TO tag FROM line in file/text"));
for (i = 0; i < tagstacklen; ++i) {
if (tagstack[i].tagname != NULL) {
name = fm_getname(&(tagstack[i].fmark), 30);
- if (name == NULL) /* file name not available */
+ if (name == NULL) { // file name not available
continue;
+ }
msg_putchar('\n');
vim_snprintf((char *)IObuff, IOSIZE, "%c%2d %2d %-15s %5ld ",
@@ -1059,10 +1059,11 @@ void do_tags(exarg_T *eap)
? HL_ATTR(HLF_D) : 0);
xfree(name);
}
- ui_flush(); /* show one line at a time */
+ ui_flush(); // show one line at a time
}
- if (tagstackidx == tagstacklen) /* idx at top of stack */
+ if (tagstackidx == tagstacklen) { // idx at top of stack
MSG_PUTS("\n>");
+ }
}
@@ -1078,15 +1079,17 @@ static int tag_strnicmp(char_u *s1, char_u *s2, size_t len)
while (len > 0) {
i = TOUPPER_ASC(*s1) - TOUPPER_ASC(*s2);
- if (i != 0)
- return i; /* this character different */
- if (*s1 == NUL)
- break; /* strings match until NUL */
+ if (i != 0) {
+ return i; // this character different
+ }
+ if (*s1 == NUL) {
+ break; // strings match until NUL
+ }
++s1;
++s2;
--len;
}
- return 0; /* strings match */
+ return 0; // strings match
}
@@ -1100,48 +1103,54 @@ static void prepare_pats(pat_T *pats, int has_re)
if (has_re) {
/* When the pattern starts with '^' or "\\<", binary searching can be
* used (much faster). */
- if (pats->pat[0] == '^')
+ if (pats->pat[0] == '^') {
pats->head = pats->pat + 1;
- else if (pats->pat[0] == '\\' && pats->pat[1] == '<')
+ } else if (pats->pat[0] == '\\' && pats->pat[1] == '<') {
pats->head = pats->pat + 2;
- if (pats->head == pats->pat)
+ }
+ if (pats->head == pats->pat) {
pats->headlen = 0;
- else
+ } else {
for (pats->headlen = 0; pats->head[pats->headlen] != NUL;
- ++pats->headlen)
+ ++pats->headlen) {
if (vim_strchr((char_u *)(p_magic ? ".[~*\\$" : "\\$"),
- pats->head[pats->headlen]) != NULL)
+ pats->head[pats->headlen]) != NULL) {
break;
- if (p_tl != 0 && pats->headlen > p_tl) /* adjust for 'taglength' */
+ }
+ }
+ }
+ if (p_tl != 0 && pats->headlen > p_tl) { // adjust for 'taglength'
pats->headlen = p_tl;
+ }
}
- if (has_re)
+ if (has_re) {
pats->regmatch.regprog = vim_regcomp(pats->pat, p_magic ? RE_MAGIC : 0);
- else
+ } else {
pats->regmatch.regprog = NULL;
+ }
}
-//
-// Call the user-defined function to generate a list of tags used by
-// find_tags().
-//
-// Return OK if at least 1 tag has been successfully found,
-// NOTDONE if the function returns v:null, and FAIL otherwise.
-//
-static int find_tagfunc_tags(
- char_u *pat, // pattern supplied to the user-defined function
- garray_T *ga, // the tags will be placed here
- int *match_count, // here the number of tags found will be placed
- int flags, // flags from find_tags (TAG_*)
- char_u *buf_ffname) // name of buffer for priority
+/// Call the user-defined function to generate a list of tags used by
+/// find_tags().
+///
+/// Return OK if at least 1 tag has been successfully found,
+/// NOTDONE if the function returns v:null, and FAIL otherwise.
+///
+/// @param pat pattern supplied to the user-defined function
+/// @param ga the tags will be placed here
+/// @param match_count here the number of tags found will be placed
+/// @param flags flags from find_tags (TAG_*)
+/// @param buf_ffname name of buffer for priority
+static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int flags,
+ char_u *buf_ffname)
{
- pos_T save_pos;
- list_T *taglist;
- int ntags = 0;
- int result = FAIL;
- typval_T args[4];
- typval_T rettv;
+ pos_T save_pos;
+ list_T *taglist;
+ int ntags = 0;
+ int result = FAIL;
+ typval_T args[4];
+ typval_T rettv;
char_u flagString[4];
taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx];
@@ -1195,12 +1204,12 @@ static int find_tagfunc_tags(
taglist = rettv.vval.v_list;
TV_LIST_ITER_CONST(taglist, li, {
- char_u *res_name;
- char_u *res_fname;
- char_u *res_cmd;
- char_u *res_kind;
- int has_extra = 0;
- int name_only = flags & TAG_NAMES;
+ char_u *res_name;
+ char_u *res_fname;
+ char_u *res_cmd;
+ char_u *res_kind;
+ int has_extra = 0;
+ int name_only = flags & TAG_NAMES;
if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) {
EMSG(_(tfu_inv_ret_msg));
@@ -1326,50 +1335,46 @@ static int find_tagfunc_tags(
return result;
}
-/*
- * find_tags() - search for tags in tags files
- *
- * Return FAIL if search completely failed (*num_matches will be 0, *matchesp
- * will be NULL), OK otherwise.
- *
- * There is a priority in which type of tag is recognized.
- *
- * 6. A static or global tag with a full matching tag for the current file.
- * 5. A global tag with a full matching tag for another file.
- * 4. A static tag with a full matching tag for another file.
- * 3. A static or global tag with an ignore-case matching tag for the
- * current file.
- * 2. A global tag with an ignore-case matching tag for another file.
- * 1. A static tag with an ignore-case matching tag for another file.
- *
- * Tags in an emacs-style tags file are always global.
- *
- * flags:
- * TAG_HELP only search for help tags
- * TAG_NAMES only return name of tag
- * TAG_REGEXP use "pat" as a regexp
- * TAG_NOIC don't always ignore case
- * TAG_KEEP_LANG keep language
- * TAG_CSCOPE use cscope results for tags
- * TAG_NO_TAGFUNC do not call the 'tagfunc' function
- */
-int
-find_tags(
- char_u *pat, // pattern to search for
- int *num_matches, // return: number of matches found
- char_u ***matchesp, // return: array of matches found
- int flags,
- int mincount, /* MAXCOL: find all matches
- other: minimal number of matches */
- char_u *buf_ffname /* name of buffer for priority */
-)
+/// find_tags() - search for tags in tags files
+///
+/// Return FAIL if search completely failed (*num_matches will be 0, *matchesp
+/// will be NULL), OK otherwise.
+///
+/// There is a priority in which type of tag is recognized.
+///
+/// 6. A static or global tag with a full matching tag for the current file.
+/// 5. A global tag with a full matching tag for another file.
+/// 4. A static tag with a full matching tag for another file.
+/// 3. A static or global tag with an ignore-case matching tag for the
+/// current file.
+/// 2. A global tag with an ignore-case matching tag for another file.
+/// 1. A static tag with an ignore-case matching tag for another file.
+///
+/// Tags in an emacs-style tags file are always global.
+///
+/// flags:
+/// TAG_HELP only search for help tags
+/// TAG_NAMES only return name of tag
+/// TAG_REGEXP use "pat" as a regexp
+/// TAG_NOIC don't always ignore case
+/// TAG_KEEP_LANG keep language
+/// TAG_CSCOPE use cscope results for tags
+/// TAG_NO_TAGFUNC do not call the 'tagfunc' function
+///
+/// @param pat pattern to search for
+/// @param num_matches return: number of matches found
+/// @param matchesp return: array of matches found
+/// @param mincount MAXCOL: find all matches other: minimal number of matches */
+/// @param buf_ffname name of buffer for priority
+int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int mincount,
+ char_u *buf_ffname)
{
- FILE *fp;
- char_u *lbuf; /* line buffer */
- int lbuf_size = LSIZE; /* length of lbuf */
- char_u *tag_fname; /* name of tag file */
- tagname_T tn; /* info for get_tagfname() */
- int first_file; /* trying first tag file */
+ FILE *fp;
+ char_u *lbuf; // line buffer
+ int lbuf_size = LSIZE; // length of lbuf
+ char_u *tag_fname; // name of tag file
+ tagname_T tn; // info for get_tagfname()
+ int first_file; // trying first tag file
tagptrs_T tagp;
bool did_open = false; // did open a tag file
bool stop_searching = false; // stop when match found or error
@@ -1377,8 +1382,8 @@ find_tags(
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;
+ char_u *p;
+ char_u *s;
int i;
int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value
struct tag_search_info { // Binary search file offsets
@@ -1396,17 +1401,17 @@ find_tags(
off_T offset;
int round;
enum {
- TS_START, /* at start of file */
- TS_LINEAR /* linear searching forward, till EOF */
- , TS_BINARY, /* binary searching */
- TS_SKIP_BACK, /* skipping backwards */
- TS_STEP_FORWARD /* stepping forwards */
- } state; /* Current search state */
+ TS_START, // at start of file
+ TS_LINEAR // linear searching forward, till EOF
+ , TS_BINARY, // binary searching
+ TS_SKIP_BACK, // skipping backwards
+ TS_STEP_FORWARD // stepping forwards
+ } state; // Current search state
int cmplen;
- int match; /* matches */
- int match_no_ic = 0; /* matches with rm_ic == FALSE */
- int match_re; /* match with regexp */
+ int match; // matches
+ int match_no_ic = 0; // matches with rm_ic == FALSE
+ int match_re; // match with regexp
int matchoff = 0;
int save_emsg_off;
@@ -1416,16 +1421,16 @@ find_tags(
hashtab_T ht_match[MT_COUNT]; // stores matches by key
hash_T hash = 0;
int match_count = 0; // number of matches found
- char_u **matches;
+ char_u **matches;
int mtt;
int help_save;
int help_pri = 0;
- char_u *help_lang_find = NULL; // lang to be found
+ char_u *help_lang_find = NULL; // lang to be found
char_u help_lang[3]; // lang of current tags file
- char_u *saved_pat = NULL; // copy of pat[]
+ char_u *saved_pat = NULL; // copy of pat[]
bool is_txt = false;
- pat_T orgpat; /* holds unconverted pattern info */
+ pat_T orgpat; // holds unconverted pattern info
vimconv_T vimconv;
int findall = (mincount == MAXCOL || mincount == TAG_MANY);
@@ -1447,22 +1452,22 @@ find_tags(
// Change the value of 'ignorecase' according to 'tagcase' for the
// duration of this function.
switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) {
- case TC_FOLLOWIC:
- break;
- case TC_IGNORE:
- p_ic = true;
- break;
- case TC_MATCH:
- p_ic = false;
- break;
- case TC_FOLLOWSCS:
- p_ic = ignorecase(pat);
- break;
- case TC_SMART:
- p_ic = ignorecase_opt(pat, true, true);
- break;
- default:
- abort();
+ case TC_FOLLOWIC:
+ break;
+ case TC_IGNORE:
+ p_ic = true;
+ break;
+ case TC_MATCH:
+ p_ic = false;
+ break;
+ case TC_FOLLOWSCS:
+ p_ic = ignorecase(pat);
+ break;
+ case TC_SMART:
+ p_ic = ignorecase_opt(pat, true, true);
+ break;
+ default:
+ abort();
}
help_save = curbuf->b_help;
@@ -1480,7 +1485,7 @@ find_tags(
hash_init(&ht_match[mtt]);
}
- STRCPY(tag_fname, "from cscope"); /* for error messages */
+ STRCPY(tag_fname, "from cscope"); // for error messages
/*
* Initialize a few variables
@@ -1506,15 +1511,17 @@ find_tags(
orgpat.len -= 3;
}
}
- if (p_tl != 0 && orgpat.len > p_tl) /* adjust for 'taglength' */
+ if (p_tl != 0 && orgpat.len > p_tl) { // adjust for 'taglength'
orgpat.len = p_tl;
+ }
save_emsg_off = emsg_off;
- emsg_off = TRUE; /* don't want error for invalid RE here */
+ emsg_off = TRUE; // don't want error for invalid RE here
prepare_pats(&orgpat, has_re);
emsg_off = save_emsg_off;
- if (has_re && orgpat.regmatch.regprog == NULL)
+ if (has_re && orgpat.regmatch.regprog == NULL) {
goto findtag_end;
+ }
// This is only to avoid a compiler warning for using search_info
// uninitialised.
@@ -1580,8 +1587,9 @@ find_tags(
/* When searching for a specific language skip tags files
* for other languages. */
if (help_lang_find != NULL
- && STRICMP(help_lang, help_lang_find) != 0)
+ && STRICMP(help_lang, help_lang_find) != 0) {
continue;
+ }
/* For CTRL-] in a help file prefer a match with the same
* language. */
@@ -1591,23 +1599,26 @@ find_tags(
&& (i = (int)STRLEN(curbuf->b_fname)) > 4
&& curbuf->b_fname[i - 1] == 'x'
&& curbuf->b_fname[i - 4] == '.'
- && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0)
+ && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0) {
help_pri = 0;
- else {
+ } else {
help_pri = 1;
for (s = p_hlg; *s != NUL; ++s) {
- if (STRNICMP(s, help_lang, 2) == 0)
+ if (STRNICMP(s, help_lang, 2) == 0) {
break;
+ }
++help_pri;
- if ((s = vim_strchr(s, ',')) == NULL)
+ if ((s = vim_strchr(s, ',')) == NULL) {
break;
+ }
}
if (s == NULL || *s == NUL) {
/* Language not in 'helplang': use last, prefer English,
* unless found already. */
++help_pri;
- if (STRICMP(help_lang, "en") != 0)
+ if (STRICMP(help_lang, "en") != 0) {
++help_pri;
+ }
}
}
}
@@ -1624,7 +1635,7 @@ find_tags(
}
did_open = true; // remember that we found at least one file
- state = TS_START; /* we're at the start of the file */
+ state = TS_START; // we're at the start of the file
/*
* Read and parse the lines in the file one by one
@@ -1636,8 +1647,9 @@ find_tags(
} else {
fast_breakcheck();
}
- if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */
+ if ((flags & TAG_INS_COMP)) { // Double brackets for gcc
ins_compl_check_keys(30, false);
+ }
if (got_int || compl_interrupted) {
stop_searching = true;
break;
@@ -1649,18 +1661,20 @@ find_tags(
retval = OK;
break;
}
- if (get_it_again)
+ if (get_it_again) {
goto line_read_in;
+ }
/*
* For binary search: compute the next offset to use.
*/
if (state == TS_BINARY) {
offset = search_info.low_offset + ((search_info.high_offset
- search_info.low_offset) / 2);
- if (offset == search_info.curr_offset)
- break; /* End the binary search without a match. */
- else
+ if (offset == search_info.curr_offset) {
+ break; // End the binary search without a match.
+ } else {
search_info.curr_offset = offset;
+ }
} else if (state == TS_SKIP_BACK) {
// Skipping back (after a match during binary search).
search_info.curr_offset -= lbuf_size * 2;
@@ -1676,7 +1690,7 @@ find_tags(
* start of the next line.
*/
if (state == TS_BINARY || state == TS_SKIP_BACK) {
- /* Adjust the search file offset to the correct position */
+ // Adjust the search file offset to the correct position
search_info.curr_offset_used = search_info.curr_offset;
vim_fseek(fp, search_info.curr_offset, SEEK_SET);
eof = vim_fgets(lbuf, lbuf_size, fp);
@@ -1691,13 +1705,13 @@ find_tags(
}
eof = vim_fgets(lbuf, lbuf_size, fp);
}
- /* skip empty and blank lines */
+ // skip empty and blank lines
while (!eof && vim_isblankline(lbuf)) {
search_info.curr_offset = vim_ftell(fp);
eof = vim_fgets(lbuf, lbuf_size, fp);
}
if (eof) {
- /* Hit end of file. Skip backwards. */
+ // Hit end of file. Skip backwards.
state = TS_SKIP_BACK;
search_info.match_offset = vim_ftell(fp);
search_info.curr_offset = search_info.curr_offset_used;
@@ -1708,7 +1722,7 @@ find_tags(
* Not jumping around in the file: Read the next line.
*/
else {
- /* skip empty and blank lines */
+ // skip empty and blank lines
do {
eof = use_cscope
? cs_fgets(lbuf, lbuf_size)
@@ -1716,13 +1730,13 @@ find_tags(
} while (!eof && vim_isblankline(lbuf));
if (eof) {
- break; /* end of file */
+ break; // end of file
}
}
line_read_in:
if (vimconv.vc_type != CONV_NONE) {
- char_u *conv_line;
+ char_u *conv_line;
int len;
/* Convert every line. Converting the pattern from 'enc' to
@@ -1730,7 +1744,7 @@ line_read_in:
* not recognized. */
conv_line = string_convert(&vimconv, lbuf, NULL);
if (conv_line != NULL) {
- /* Copy or swap lbuf and conv_line. */
+ // Copy or swap lbuf and conv_line.
len = (int)STRLEN(conv_line) + 1;
if (len > lbuf_size) {
xfree(lbuf);
@@ -1754,30 +1768,33 @@ line_read_in:
* case is folded lower case letters sort before "_". */
if (STRNCMP(lbuf, "!_TAG_", 6) <= 0
|| (lbuf[0] == '!' && ASCII_ISLOWER(lbuf[1]))) {
- if (STRNCMP(lbuf, "!_TAG_", 6) != 0)
+ if (STRNCMP(lbuf, "!_TAG_", 6) != 0) {
/* Non-header item before the header, e.g. "!" itself.
*/
goto parse_line;
+ }
/*
* Read header line.
*/
- if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0)
+ if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) {
tag_file_sorted = lbuf[18];
+ }
if (STRNCMP(lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) {
/* Prepare to convert every line from the specified
* encoding to 'encoding'. */
- for (p = lbuf + 20; *p > ' ' && *p < 127; ++p)
+ for (p = lbuf + 20; *p > ' ' && *p < 127; ++p) {
;
+ }
*p = NUL;
convert_setup(&vimconv, lbuf + 20, p_enc);
}
- /* Read the next line. Unrecognized flags are ignored. */
+ // Read the next line. Unrecognized flags are ignored.
continue;
}
- /* Headers ends. */
+ // Headers ends.
/*
* When there is no tag head, or ignoring case, need to do a
@@ -1788,18 +1805,19 @@ line_read_in:
* flag set.
* For cscope, it's always linear.
*/
- if (linear || use_cscope)
+ if (linear || use_cscope) {
state = TS_LINEAR;
- else if (tag_file_sorted == NUL)
+ } else if (tag_file_sorted == NUL) {
state = TS_BINARY;
- else if (tag_file_sorted == '1')
+ } else if (tag_file_sorted == '1') {
state = TS_BINARY;
- else if (tag_file_sorted == '2') {
+ } else if (tag_file_sorted == '2') {
state = TS_BINARY;
sortic = true;
orgpat.regmatch.rm_ic = (p_ic || !noic);
- } else
+ } else {
state = TS_LINEAR;
+ }
if (state == TS_BINARY && orgpat.regmatch.rm_ic && !sortic) {
/* Binary search won't work for ignoring case, use linear
@@ -1865,20 +1883,23 @@ parse_line:
* there is no regexp, or the tag is too short.
*/
cmplen = (int)(tagp.tagname_end - tagp.tagname);
- if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */
+ if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength'
cmplen = p_tl;
- if (has_re && orgpat.headlen < cmplen)
+ }
+ if (has_re && orgpat.headlen < cmplen) {
cmplen = orgpat.headlen;
- else if (state == TS_LINEAR && orgpat.headlen != cmplen)
+ } else if (state == TS_LINEAR && orgpat.headlen != cmplen) {
continue;
+ }
if (state == TS_BINARY) {
/*
* Simplistic check for unsorted tags file.
*/
i = (int)tagp.tagname[0];
- if (sortic)
+ if (sortic) {
i = TOUPPER_ASC(tagp.tagname[0]);
+ }
if (i < search_info.low_char || i > search_info.high_char) {
sort_error = true;
}
@@ -1886,21 +1907,23 @@ parse_line:
/*
* Compare the current tag with the searched tag.
*/
- if (sortic)
+ if (sortic) {
tagcmp = tag_strnicmp(tagp.tagname, orgpat.head,
- (size_t)cmplen);
- else
+ (size_t)cmplen);
+ } else {
tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen);
+ }
/*
* A match with a shorter tag means to search forward.
* A match with a longer tag means to search backward.
*/
if (tagcmp == 0) {
- if (cmplen < orgpat.headlen)
+ if (cmplen < orgpat.headlen) {
tagcmp = -1;
- else if (cmplen > orgpat.headlen)
+ } else if (cmplen > orgpat.headlen) {
tagcmp = 1;
+ }
}
if (tagcmp == 0) {
@@ -1915,37 +1938,40 @@ parse_line:
search_info.curr_offset = vim_ftell(fp);
if (search_info.curr_offset < search_info.high_offset) {
search_info.low_offset = search_info.curr_offset;
- if (sortic)
+ if (sortic) {
search_info.low_char =
TOUPPER_ASC(tagp.tagname[0]);
- else
+ } else {
search_info.low_char = tagp.tagname[0];
+ }
continue;
}
}
if (tagcmp > 0
&& search_info.curr_offset != search_info.high_offset) {
search_info.high_offset = search_info.curr_offset;
- if (sortic)
+ if (sortic) {
search_info.high_char =
TOUPPER_ASC(tagp.tagname[0]);
- else
+ } else {
search_info.high_char = tagp.tagname[0];
+ }
continue;
}
- /* No match yet and are at the end of the binary search. */
+ // No match yet and are at the end of the binary search.
break;
- } else if (state == TS_SKIP_BACK) {
+ } else if (state == TS_SKIP_BACK) {
assert(cmplen >= 0);
- if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0)
+ if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) {
state = TS_STEP_FORWARD;
- else
+ } else {
/* Have to skip back more. Restore the curr_offset
* used, otherwise we get stuck at a long line. */
search_info.curr_offset = search_info.curr_offset_used;
+ }
continue;
- } else if (state == TS_STEP_FORWARD) {
+ } else if (state == TS_STEP_FORWARD) {
assert(cmplen >= 0);
if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) {
if ((off_T)vim_ftell(fp) > search_info.match_offset) {
@@ -1954,23 +1980,27 @@ parse_line:
continue; // before first match
}
}
- } else
- /* skip this match if it can't match */
- assert(cmplen >= 0);
- if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0)
+ } else {
+ // skip this match if it can't match
+ assert(cmplen >= 0);
+ }
+ if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) {
continue;
+ }
// Can be a matching tag, isolate the file name and command.
tagp.fname = tagp.tagname_end + 1;
tagp.fname_end = vim_strchr(tagp.fname, TAB);
tagp.command = tagp.fname_end + 1;
- if (tagp.fname_end == NULL)
+ if (tagp.fname_end == NULL) {
i = FAIL;
- else
+ } else {
i = OK;
- } else
+ }
+ } else {
i = parse_tag_line(lbuf,
- &tagp);
+ &tagp);
+ }
if (i == FAIL) {
line_error = true;
break;
@@ -1981,20 +2011,23 @@ parse_line:
* a regexp).
*/
cmplen = (int)(tagp.tagname_end - tagp.tagname);
- if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */
+ if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength'
cmplen = p_tl;
- /* if tag length does not match, don't try comparing */
- if (orgpat.len != cmplen)
+ }
+ // if tag length does not match, don't try comparing
+ if (orgpat.len != cmplen) {
match = FALSE;
- else {
+ } else {
if (orgpat.regmatch.rm_ic) {
assert(cmplen >= 0);
match = mb_strnicmp(tagp.tagname, orgpat.pat, (size_t)cmplen) == 0;
- if (match)
+ if (match) {
match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat,
- cmplen) == 0);
- } else
+ cmplen) == 0);
+ }
+ } else {
match = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0);
+ }
}
/*
@@ -2012,7 +2045,7 @@ parse_line:
if (orgpat.regmatch.rm_ic) {
orgpat.regmatch.rm_ic = FALSE;
match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname,
- (colnr_T)0);
+ (colnr_T)0);
orgpat.regmatch.rm_ic = TRUE;
}
}
@@ -2025,7 +2058,7 @@ parse_line:
int len = 0;
if (use_cscope) {
- /* Don't change the ordering, always use the same table. */
+ // Don't change the ordering, always use the same table.
mtt = MT_GL_OTH;
} else {
// Decide in which array to store this match.
@@ -2035,27 +2068,31 @@ parse_line:
// Decide in which of the sixteen tables to store this match.
if (is_static) {
- if (is_current)
+ if (is_current) {
mtt = MT_ST_CUR;
- else
+ } else {
mtt = MT_ST_OTH;
+ }
} else {
- if (is_current)
+ if (is_current) {
mtt = MT_GL_CUR;
- else
+ } else {
mtt = MT_GL_OTH;
+ }
}
- if (orgpat.regmatch.rm_ic && !match_no_ic)
+ if (orgpat.regmatch.rm_ic && !match_no_ic) {
mtt += MT_IC_OFF;
- if (match_re)
+ }
+ if (match_re) {
mtt += MT_RE_OFF;
+ }
}
// Add the found match in ht_match[mtt] and ga_match[mtt].
// Store the info we need later, which depends on the kind of
// tags we are dealing with.
if (help_only) {
-# define ML_EXTRA 3
+#define ML_EXTRA 3
// Append the help-heuristic number after the tagname, for
// sorting it later. The heuristic is ignored for
// detecting duplicates.
@@ -2074,7 +2111,7 @@ parse_line:
+ help_pri);
*tagp.tagname_end = TAB;
- } else if (name_only) {
+ } else if (name_only) {
if (get_it_again) {
char_u *temp_end = tagp.command;
@@ -2148,7 +2185,7 @@ parse_line:
hash_add_item(&ht_match[mtt], hi, mfp, hash);
ga_grow(&ga_match[mtt], 1);
((char_u **)(ga_match[mtt].ga_data))
- [ga_match[mtt].ga_len++] = mfp;
+ [ga_match[mtt].ga_len++] = mfp;
match_count++;
} else {
// duplicate tag, drop it
@@ -2156,9 +2193,10 @@ parse_line:
}
}
}
- if (use_cscope && eof)
+ if (use_cscope && eof) {
break;
- } /* forever */
+ }
+ } // forever
if (line_error) {
EMSG2(_("E431: Format error in tags file \"%s\""), tag_fname);
@@ -2169,10 +2207,12 @@ parse_line:
line_error = false;
}
- if (!use_cscope)
+ if (!use_cscope) {
fclose(fp);
- if (vimconv.vc_type != CONV_NONE)
+ }
+ if (vimconv.vc_type != CONV_NONE) {
convert_setup(&vimconv, NULL, NULL);
+ }
tag_file_sorted = NUL;
if (sort_error) {
@@ -2188,27 +2228,31 @@ parse_line:
stop_searching = true;
}
- if (stop_searching || use_cscope)
+ if (stop_searching || use_cscope) {
break;
+ }
+ } // end of for-each-file loop
- } /* end of for-each-file loop */
-
- if (!use_cscope)
+ if (!use_cscope) {
tagname_free(&tn);
+ }
/* stop searching when already did a linear search, or when TAG_NOIC
* used, and 'ignorecase' not set or already did case-ignore search */
- if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic)
+ if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic) {
break;
- if (use_cscope)
+ }
+ if (use_cscope) {
break;
- orgpat.regmatch.rm_ic = TRUE; /* try another time while ignoring case */
+ }
+ orgpat.regmatch.rm_ic = TRUE; // try another time while ignoring case
}
if (!stop_searching) {
- if (!did_open && verbose) /* never opened any tags file */
+ if (!did_open && verbose) { // never opened any tags file
EMSG(_("E433: No tags file"));
- retval = OK; /* It's OK even when no tag found */
+ }
+ retval = OK; // It's OK even when no tag found
}
findtag_end:
@@ -2220,13 +2264,15 @@ findtag_end:
* Move the matches from the ga_match[] arrays into one list of
* matches. When retval == FAIL, free the matches.
*/
- if (retval == FAIL)
+ if (retval == FAIL) {
match_count = 0;
+ }
- if (match_count > 0)
+ if (match_count > 0) {
matches = xmalloc(match_count * sizeof(char_u *));
- else
+ } else {
matches = NULL;
+ }
match_count = 0;
for (mtt = 0; mtt < MT_COUNT; mtt++) {
for (i = 0; i < ga_match[mtt].ga_len; i++) {
@@ -2245,7 +2291,7 @@ findtag_end:
}
}
}
- matches[match_count++] = (char_u *)mfp;
+ matches[match_count++] = mfp;
}
}
@@ -2275,7 +2321,7 @@ static void found_tagfile_cb(char_u *fname, void *cookie)
char_u *const tag_fname = vim_strsave(fname);
#ifdef BACKSLASH_IN_FILENAME
- slash_adjust(tag_fname);
+ slash_adjust(tag_fname);
#endif
simplify_filename(tag_fname);
GA_APPEND(char_u *, &tag_fnames, tag_fname);
@@ -2293,24 +2339,22 @@ void free_tag_stuff(void)
#endif
-/*
- * Get the next name of a tag file from the tag file list.
- * For help files, use "tags" file only.
- *
- * Return FAIL if no more tag file names, OK otherwise.
- */
-int
-get_tagfname(
- tagname_T *tnp, // holds status info
- int first, // TRUE when first file name is wanted
- char_u *buf // pointer to buffer of MAXPATHL chars
-)
+/// Get the next name of a tag file from the tag file list.
+/// For help files, use "tags" file only.
+///
+/// @param tnp holds status info
+/// @param first TRUE when first file name is wanted
+/// @param buf pointer to buffer of MAXPATHL chars
+///
+/// @return FAIL if no more tag file names, OK otherwise.
+int get_tagfname(tagname_T *tnp, int first, char_u *buf)
{
- char_u *fname = NULL;
- char_u *r_ptr;
+ char_u *fname = NULL;
+ char_u *r_ptr;
- if (first)
+ if (first) {
memset(tnp, 0, sizeof(tagname_T));
+ }
if (curbuf->b_help) {
/*
@@ -2328,8 +2372,9 @@ get_tagfname(
if (tnp->tn_hf_idx >= tag_fnames.ga_len) {
/* Not found in 'runtimepath', use 'helpfile', if it exists and
* wasn't used yet, replacing "help.txt" with "tags". */
- if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL)
+ if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL) {
return FAIL;
+ }
++tnp->tn_hf_idx;
STRCPY(buf, p_hf);
STRCPY(path_tail(buf), "tags");
@@ -2367,14 +2412,15 @@ get_tagfname(
for (;; ) {
if (tnp->tn_did_filefind_init) {
fname = vim_findfile(tnp->tn_search_ctx);
- if (fname != NULL)
+ if (fname != NULL) {
break;
+ }
tnp->tn_did_filefind_init = FALSE;
} else {
- char_u *filename = NULL;
+ char_u *filename = NULL;
- /* Stop when used all parts of 'tags'. */
+ // Stop when used all parts of 'tags'.
if (*tnp->tn_np == NUL) {
vim_findfile_cleanup(tnp->tn_search_ctx);
tnp->tn_search_ctx = NULL;
@@ -2395,12 +2441,13 @@ get_tagfname(
*filename++ = NUL;
tnp->tn_search_ctx = vim_findfile_init(buf, filename,
- r_ptr, 100,
- FALSE, /* don't free visited list */
- FINDFILE_FILE, /* we search for a file */
- tnp->tn_search_ctx, TRUE, curbuf->b_ffname);
- if (tnp->tn_search_ctx != NULL)
+ r_ptr, 100,
+ FALSE, // don't free visited list
+ FINDFILE_FILE, // we search for a file
+ tnp->tn_search_ctx, TRUE, curbuf->b_ffname);
+ if (tnp->tn_search_ctx != NULL) {
tnp->tn_did_filefind_init = TRUE;
+ }
}
}
@@ -2420,43 +2467,44 @@ void tagname_free(tagname_T *tnp)
ga_clear_strings(&tag_fnames);
}
-/*
- * Parse one line from the tags file. Find start/end of tag name, start/end of
- * file name and start of search pattern.
- *
- * If is_etag is TRUE, tagp->fname and tagp->fname_end are not set.
- *
- * Return FAIL if there is a format error in this line, OK otherwise.
- */
-static int
-parse_tag_line(
- char_u *lbuf, // line to be parsed
- tagptrs_T *tagp
-)
+/// Parse one line from the tags file. Find start/end of tag name, start/end of
+/// file name and start of search pattern.
+///
+/// If is_etag is TRUE, tagp->fname and tagp->fname_end are not set.
+///
+/// @param lbuf line to be parsed
+///
+/// @return FAIL if there is a format error in this line, OK otherwise.
+static int parse_tag_line(char_u *lbuf, tagptrs_T *tagp)
{
- char_u *p;
+ char_u *p;
- /* Isolate the tagname, from lbuf up to the first white */
+ // Isolate the tagname, from lbuf up to the first white
tagp->tagname = lbuf;
p = vim_strchr(lbuf, TAB);
- if (p == NULL)
+ if (p == NULL) {
return FAIL;
+ }
tagp->tagname_end = p;
- /* Isolate file name, from first to second white space */
- if (*p != NUL)
+ // Isolate file name, from first to second white space
+ if (*p != NUL) {
++p;
+ }
tagp->fname = p;
p = vim_strchr(p, TAB);
- if (p == NULL)
+ if (p == NULL) {
return FAIL;
+ }
tagp->fname_end = p;
- /* find start of search command, after second white space */
- if (*p != NUL)
+ // find start of search command, after second white space
+ if (*p != NUL) {
++p;
- if (*p == NUL)
+ }
+ if (*p == NUL) {
return FAIL;
+ }
tagp->command = p;
return OK;
@@ -2466,12 +2514,12 @@ parse_tag_line(
* Check if tagname is a static tag
*
* Static tags produced by the older ctags program have the format:
- * 'file:tag file /pattern'.
+ * 'file:tag file /pattern'.
* This is only recognized when both occurrence of 'file' are the same, to
* avoid recognizing "string::string" or ":exit".
*
* Static tags produced by the new ctags program have the format:
- * 'tag file /pattern/;"<Tab>file:' "
+ * 'tag file /pattern/;"<Tab>file:' "
*
* Return TRUE if it is a static tag and adjust *tagname to the real tag.
* Return FALSE if it is not a static tag.
@@ -2484,8 +2532,9 @@ static bool test_for_static(tagptrs_T *tagp)
p = tagp->command;
while ((p = vim_strchr(p, '\t')) != NULL) {
++p;
- if (STRNCMP(p, "file:", 5) == 0)
+ if (STRNCMP(p, "file:", 5) == 0) {
return TRUE;
+ }
}
return FALSE;
@@ -2501,32 +2550,29 @@ static size_t matching_line_len(const char_u *const lbuf)
return (p - lbuf) + STRLEN(p);
}
-/*
- * Parse a line from a matching tag. Does not change the line itself.
- *
- * The line that we get looks like this:
- * Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf>
- * other tag: <mtt><tag_fname><NUL><NUL><lbuf>
- * without Emacs tags: <mtt><tag_fname><NUL><lbuf>
- *
- * Return OK or FAIL.
- */
-static int
-parse_match(
- char_u *lbuf, // input: matching line
- tagptrs_T *tagp // output: pointers into the line
-)
+/// Parse a line from a matching tag. Does not change the line itself.
+///
+/// The line that we get looks like this:
+/// Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf>
+/// other tag: <mtt><tag_fname><NUL><NUL><lbuf>
+/// without Emacs tags: <mtt><tag_fname><NUL><lbuf>
+///
+/// @param lbuf input: matching line
+/// @param tagp output: pointers into the line
+///
+/// @return OK or FAIL.
+static int parse_match(char_u *lbuf, tagptrs_T *tagp)
{
int retval;
- char_u *p;
- char_u *pc, *pt;
+ char_u *p;
+ char_u *pc, *pt;
tagp->tag_fname = lbuf + 1;
lbuf += STRLEN(tagp->tag_fname) + 2;
- /* Find search pattern and the file name for non-etags. */
+ // Find search pattern and the file name for non-etags.
retval = parse_tag_line(lbuf,
- tagp);
+ tagp);
tagp->tagkind = NULL;
tagp->user_data = NULL;
@@ -2534,7 +2580,7 @@ parse_match(
tagp->command_end = NULL;
if (retval == OK) {
- /* Try to find a kind field: "kind:<kind>" or just "<kind>"*/
+ // Try to find a kind field: "kind:<kind>" or just "<kind>"
p = tagp->command;
if (find_extra(&p) == OK) {
tagp->command_end = p;
@@ -2562,8 +2608,9 @@ parse_match(
if (pc == NULL || (pt != NULL && pc > pt)) {
tagp->tagkind = p;
}
- if (pt == NULL)
+ if (pt == NULL) {
break;
+ }
p = pt;
MB_PTR_ADV(p);
}
@@ -2602,32 +2649,30 @@ static char_u *tag_full_fname(tagptrs_T *tagp)
return fullname;
}
-/*
- * Jump to a tag that has been found in one of the tag files
- *
- * returns OK for success, NOTAGFILE when file not found, FAIL otherwise.
- */
-static int jumpto_tag(
- const char_u *lbuf_arg, // line from the tags file for this tag
- int forceit, // :ta with !
- int keep_help // keep help flag (FALSE for cscope)
-)
+/// Jump to a tag that has been found in one of the tag files
+///
+/// @param lbuf_arg line from the tags file for this tag
+/// @param forceit :ta with !
+/// @param keep_help keep help flag (FALSE for cscope)
+///
+/// @return OK for success, NOTAGFILE when file not found, FAIL otherwise.
+static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
{
int save_magic;
bool save_p_ws;
int save_p_scs, save_p_ic;
linenr_T save_lnum;
- char_u *str;
- char_u *pbuf; /* search pattern buffer */
- char_u *pbuf_end;
- char_u *tofree_fname = NULL;
- char_u *fname;
+ char_u *str;
+ char_u *pbuf; // search pattern buffer
+ char_u *pbuf_end;
+ char_u *tofree_fname = NULL;
+ char_u *fname;
tagptrs_T tagp;
int retval = FAIL;
int getfile_result = GETFILE_UNUSED;
int search_options;
- win_T *curwin_save = NULL;
- char_u *full_fname = NULL;
+ win_T *curwin_save = NULL;
+ char_u *full_fname = NULL;
const bool old_KeyTyped = KeyTyped; // getting the file may reset it
const int l_g_do_tagpreview = g_do_tagpreview;
const size_t len = matching_line_len(lbuf_arg) + 1;
@@ -2636,7 +2681,7 @@ static int jumpto_tag(
pbuf = xmalloc(LSIZE);
- /* parse the match line into the tagp structure */
+ // parse the match line into the tagp structure
if (parse_match(lbuf, &tagp) == FAIL) {
tagp.fname_end = NULL;
goto erret;
@@ -2646,7 +2691,7 @@ static int jumpto_tag(
*tagp.fname_end = NUL;
fname = tagp.fname;
- /* copy the command to pbuf[], remove trailing CR/NL */
+ // copy the command to pbuf[], remove trailing CR/NL
str = tagp.command;
for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; ) {
*pbuf_end++ = *str++;
@@ -2680,8 +2725,8 @@ static int jumpto_tag(
* autocommand event (e.g., http://sys/file).
*/
if (!os_path_exists(fname)
- && !has_autocmd(EVENT_BUFREADCMD, fname, NULL)
- ) {
+ && !has_autocmd(EVENT_BUFREADCMD, fname,
+ NULL)) {
retval = NOTAGFILE;
xfree(nofile_fname);
nofile_fname = vim_strsave(fname);
@@ -2692,8 +2737,8 @@ static int jumpto_tag(
if (l_g_do_tagpreview != 0) {
- postponed_split = 0; /* don't split again below */
- curwin_save = curwin; /* Save current window */
+ postponed_split = 0; // don't split again below
+ curwin_save = curwin; // Save current window
/*
* If we are reusing a window, we may change dir when
@@ -2750,10 +2795,11 @@ static int jumpto_tag(
if (keep_help) {
/* A :ta from a help file will keep the b_help flag set. For ":ptag"
* we need to use the flag from the window where we came from. */
- if (l_g_do_tagpreview != 0)
+ if (l_g_do_tagpreview != 0) {
keep_help_flag = curwin_save->w_buffer->b_help;
- else
+ } else {
keep_help_flag = curbuf->b_help;
+ }
}
if (getfile_result == GETFILE_UNUSED) {
@@ -2777,10 +2823,11 @@ static int jumpto_tag(
* command. If 'cpoptions' does not contain 't', the search pattern
* is not stored.
*/
- if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL)
+ if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL) {
search_options = 0;
- else
+ } else {
search_options = SEARCH_KEEP;
+ }
/*
* If the command is a search, try here.
@@ -2791,14 +2838,15 @@ static int jumpto_tag(
* anything following.
*/
str = pbuf;
- if (pbuf[0] == '/' || pbuf[0] == '?')
+ if (pbuf[0] == '/' || pbuf[0] == '?') {
str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1;
- if (str > pbuf_end - 1) { /* search command with nothing following */
+ }
+ if (str > pbuf_end - 1) { // search command with nothing following
save_p_ws = p_ws;
save_p_ic = p_ic;
save_p_scs = p_scs;
- p_ws = true; /* need 'wrapscan' for backward searches */
- p_ic = FALSE; /* don't ignore case now */
+ p_ws = true; // need 'wrapscan' for backward searches
+ p_ic = FALSE; // don't ignore case now
p_scs = FALSE;
save_lnum = curwin->w_cursor.lnum;
if (tagp.tagline > 0) {
@@ -2898,15 +2946,17 @@ static int jumpto_tag(
* For a help buffer: Put the cursor line at the top of the window,
* the help subject will be below it.
*/
- if (curbuf->b_help)
+ if (curbuf->b_help) {
set_topline(curwin, curwin->w_cursor.lnum);
- if ((fdo_flags & FDO_TAG) && old_KeyTyped)
+ }
+ if ((fdo_flags & FDO_TAG) && old_KeyTyped) {
foldOpenCursor();
+ }
}
if (l_g_do_tagpreview != 0
&& curwin != curwin_save && win_valid(curwin_save)) {
- /* Return cursor to where we were */
+ // Return cursor to where we were
validate_cursor();
redraw_later(curwin, VALID);
win_enter(curwin_save, true);
@@ -2935,11 +2985,10 @@ erret:
// If 'tagrelative' option set, change fname (name of file containing tag)
// according to tag_fname (name of tag file containing fname).
// Returns a pointer to allocated memory.
-static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname,
- const bool expand)
+static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, const bool expand)
{
- char_u *p;
- char_u *expanded_fname = NULL;
+ char_u *p;
+ char_u *expanded_fname = NULL;
expand_T xpc;
/*
@@ -2949,9 +2998,10 @@ static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname,
ExpandInit(&xpc);
xpc.xp_context = EXPAND_FILES;
expanded_fname = ExpandOne(&xpc, fname, NULL,
- WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
- if (expanded_fname != NULL)
+ WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE);
+ if (expanded_fname != NULL) {
fname = expanded_fname;
+ }
}
char_u *retval;
@@ -2961,13 +3011,14 @@ static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname,
retval = xmalloc(MAXPATHL);
STRCPY(retval, tag_fname);
STRLCPY(retval + (p - tag_fname), fname,
- MAXPATHL - (p - tag_fname));
+ MAXPATHL - (p - tag_fname));
/*
* Translate names like "src/a/../b/file.c" into "src/b/file.c".
*/
simplify_filename(retval);
- } else
+ } else {
retval = vim_strsave(fname);
+ }
xfree(expanded_fname);
@@ -2984,9 +3035,9 @@ static int test_for_current(char_u *fname, char_u *fname_end, char_u *tag_fname,
{
int c;
int retval = FALSE;
- char_u *fullname;
+ char_u *fullname;
- if (buf_ffname != NULL) { /* if the buffer has a name */
+ if (buf_ffname != NULL) { // if the buffer has a name
{
c = *fname_end;
*fname_end = NUL;
@@ -3053,13 +3104,8 @@ static void tagstack_clear_entry(taggy_T *item)
XFREE_CLEAR(item->user_data);
}
-int
-expand_tags (
- int tagnames, /* expand tag names */
- char_u *pat,
- int *num_file,
- char_u ***file
-)
+/// @param tagnames expand tag names
+int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file)
{
int i;
int extra_flag;
@@ -3116,17 +3162,13 @@ expand_tags (
}
-/*
- * Add a tag field to the dictionary "dict".
- * Return OK or FAIL.
- */
-static int
-add_tag_field(
- dict_T *dict,
- const char *field_name,
- const char_u *start, // start of the value
- const char_u *end // after the value; can be NULL
-)
+/// Add a tag field to the dictionary "dict".
+/// Return OK or FAIL.
+///
+/// @param start start of the value
+/// @param end after the value; can be NULL
+static int add_tag_field(dict_T *dict, const char *field_name, const char_u *start,
+ const char_u *end)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
int len = 0;
@@ -3145,12 +3187,14 @@ add_tag_field(
if (start != NULL) {
if (end == NULL) {
end = start + STRLEN(start);
- while (end > start && (end[-1] == '\r' || end[-1] == '\n'))
+ while (end > start && (end[-1] == '\r' || end[-1] == '\n')) {
--end;
+ }
}
len = (int)(end - start);
- if (len > MAXPATHL - 1)
+ if (len > MAXPATHL - 1) {
len = MAXPATHL - 1;
+ }
STRLCPY(buf, start, len + 1);
}
buf[len] = NUL;
@@ -3165,9 +3209,9 @@ add_tag_field(
int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
{
int num_matches, i, ret;
- char_u **matches;
- char_u *full_fname;
- dict_T *dict;
+ char_u **matches;
+ char_u *full_fname;
+ dict_T *dict;
tagptrs_T tp;
bool is_static;
@@ -3178,7 +3222,7 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
int parse_result = parse_match(matches[i], &tp);
// Avoid an unused variable warning in release builds.
- (void) parse_result;
+ (void)parse_result;
assert(parse_result == OK);
is_static = test_for_static(&tp);
@@ -3216,29 +3260,35 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname)
// skip "file:" (static tag)
p += 4;
} else if (!ascii_iswhite(*p)) {
- char_u *s, *n;
+ char_u *s, *n;
int len;
/* Add extra field as a dict entry. Fields are
* separated by Tabs. */
n = p;
- while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':')
+ while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') {
++p;
+ }
len = (int)(p - n);
if (*p == ':' && len > 0) {
s = ++p;
- while (*p != NUL && *p >= ' ')
+ while (*p != NUL && *p >= ' ') {
++p;
+ }
n[len] = NUL;
- if (add_tag_field(dict, (char *)n, s, p) == FAIL)
+ if (add_tag_field(dict, (char *)n, s, p) == FAIL) {
ret = FAIL;
+ }
n[len] = ':';
- } else
- /* Skip field without colon. */
- while (*p != NUL && *p >= ' ')
+ } else {
+ // Skip field without colon.
+ while (*p != NUL && *p >= ' ') {
++p;
- if (*p == NUL)
+ }
+ }
+ if (*p == NUL) {
break;
+ }
}
}
}
@@ -3319,14 +3369,8 @@ static void tagstack_shift(win_T *wp)
}
// Push a new item to the tag stack
-static void tagstack_push_item(
- win_T *wp,
- char_u *tagname,
- int cur_fnum,
- int cur_match,
- pos_T mark,
- int fnum,
- char_u *user_data)
+static void tagstack_push_item(win_T *wp, char_u *tagname, int cur_fnum, int cur_match, pos_T mark,
+ int fnum, char_u *user_data)
{
taggy_T *tagstack = wp->w_tagstack;
int idx = wp->w_tagstacklen; // top of the stack
@@ -3382,13 +3426,12 @@ static void tagstack_push_items(win_T *wp, list_T *l)
if (mark.col > 0) {
mark.col--;
}
- tagstack_push_item(
- wp,
- tagname,
- (int)tv_dict_get_number(itemdict, "bufnr"),
- (int)tv_dict_get_number(itemdict, "matchnr") - 1,
- mark, fnum,
- (char_u *)tv_dict_get_string(itemdict, "user_data", true));
+ tagstack_push_item(wp,
+ tagname,
+ (int)tv_dict_get_number(itemdict, "bufnr"),
+ (int)tv_dict_get_number(itemdict, "matchnr") - 1,
+ mark, fnum,
+ (char_u *)tv_dict_get_string(itemdict, "user_data", true));
}
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 3335fa500a..6f19a9209e 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -37,45 +37,44 @@
// Some code from pangoterm http://www.leonerd.org.uk/code/pangoterm
#include <assert.h>
-#include <stdio.h>
-#include <stdint.h>
#include <stdbool.h>
-
+#include <stdint.h>
+#include <stdio.h>
#include <vterm.h>
-#include "nvim/log.h"
-#include "nvim/vim.h"
-#include "nvim/terminal.h"
-#include "nvim/message.h"
-#include "nvim/memory.h"
-#include "nvim/option.h"
-#include "nvim/highlight.h"
-#include "nvim/macros.h"
-#include "nvim/mbyte.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
-#include "nvim/ascii.h"
+#include "nvim/edit.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/time.h"
+#include "nvim/ex_cmds.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/fileio.h"
#include "nvim/getchar.h"
-#include "nvim/ui.h"
-#include "nvim/syntax.h"
-#include "nvim/screen.h"
+#include "nvim/highlight.h"
#include "nvim/keymap.h"
-#include "nvim/edit.h"
-#include "nvim/mouse.h"
-#include "nvim/memline.h"
+#include "nvim/log.h"
+#include "nvim/macros.h"
+#include "nvim/main.h"
#include "nvim/map.h"
+#include "nvim/mbyte.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/misc1.h"
+#include "nvim/mouse.h"
#include "nvim/move.h"
-#include "nvim/main.h"
+#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/ex_cmds.h"
+#include "nvim/syntax.h"
+#include "nvim/terminal.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/fileio.h"
-#include "nvim/event/loop.h"
-#include "nvim/event/time.h"
-#include "nvim/os/input.h"
-#include "nvim/api/private/helpers.h"
typedef struct terminal_state {
VimState state;
@@ -210,7 +209,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
buf->b_p_ma = false; // 'nomodifiable'
buf->b_p_ul = -1; // 'undolevels'
buf->b_p_scbk = // 'scrollback' (initialize local from global)
- (p_scbk < 0) ? 10000 : MAX(1, p_scbk);
+ (p_scbk < 0) ? 10000 : MAX(1, p_scbk);
buf->b_p_tw = 0; // 'textwidth'
set_option_value("wrap", false, NULL, OPT_LOCAL);
set_option_value("list", false, NULL, OPT_LOCAL);
@@ -452,56 +451,56 @@ static int terminal_execute(VimState *state, int key)
TerminalState *s = (TerminalState *)state;
switch (key) {
- case K_LEFTMOUSE:
- case K_LEFTDRAG:
- case K_LEFTRELEASE:
- case K_MOUSEMOVE:
- case K_MIDDLEMOUSE:
- case K_MIDDLEDRAG:
- case K_MIDDLERELEASE:
- case K_RIGHTMOUSE:
- case K_RIGHTDRAG:
- case K_RIGHTRELEASE:
- case K_MOUSEDOWN:
- case K_MOUSEUP:
- if (send_mouse_event(s->term, key)) {
- return 0;
- }
- break;
-
- case K_EVENT:
- // We cannot let an event free the terminal yet. It is still needed.
- s->term->refcount++;
- state_handle_k_event();
- s->term->refcount--;
- if (s->term->buf_handle == 0) {
- s->close = true;
- return 0;
- }
- break;
+ case K_LEFTMOUSE:
+ case K_LEFTDRAG:
+ case K_LEFTRELEASE:
+ case K_MOUSEMOVE:
+ case K_MIDDLEMOUSE:
+ case K_MIDDLEDRAG:
+ case K_MIDDLERELEASE:
+ case K_RIGHTMOUSE:
+ case K_RIGHTDRAG:
+ case K_RIGHTRELEASE:
+ case K_MOUSEDOWN:
+ case K_MOUSEUP:
+ if (send_mouse_event(s->term, key)) {
+ return 0;
+ }
+ break;
+
+ case K_EVENT:
+ // We cannot let an event free the terminal yet. It is still needed.
+ s->term->refcount++;
+ state_handle_k_event();
+ s->term->refcount--;
+ if (s->term->buf_handle == 0) {
+ s->close = true;
+ return 0;
+ }
+ break;
- case K_COMMAND:
- do_cmdline(NULL, getcmdkeycmd, NULL, 0);
- break;
+ case K_COMMAND:
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ break;
- case Ctrl_N:
- if (s->got_bsl) {
- return 0;
- }
- FALLTHROUGH;
+ case Ctrl_N:
+ if (s->got_bsl) {
+ return 0;
+ }
+ FALLTHROUGH;
- default:
- if (key == Ctrl_BSL && !s->got_bsl) {
- s->got_bsl = true;
- break;
- }
- if (s->term->closed) {
- s->close = true;
- return 0;
- }
+ default:
+ if (key == Ctrl_BSL && !s->got_bsl) {
+ s->got_bsl = true;
+ break;
+ }
+ if (s->term->closed) {
+ s->close = true;
+ return 0;
+ }
- s->got_bsl = false;
- terminal_send_key(s->term, key);
+ s->got_bsl = false;
+ terminal_send_key(s->term, key);
}
if (curbuf->terminal == NULL) {
@@ -554,30 +553,30 @@ static bool is_filter_char(int c)
{
unsigned int flag = 0;
switch (c) {
- case 0x08:
- flag = TPF_BS;
- break;
- case 0x09:
- flag = TPF_HT;
- break;
- case 0x0A:
- case 0x0D:
- break;
- case 0x0C:
- flag = TPF_FF;
- break;
- case 0x1b:
- flag = TPF_ESC;
- break;
- case 0x7F:
- flag = TPF_DEL;
- break;
- default:
- if (c < ' ') {
- flag = TPF_C0;
- } else if (c >= 0x80 && c <= 0x9F) {
- flag = TPF_C1;
- }
+ case 0x08:
+ flag = TPF_BS;
+ break;
+ case 0x09:
+ flag = TPF_HT;
+ break;
+ case 0x0A:
+ case 0x0D:
+ break;
+ case 0x0C:
+ flag = TPF_FF;
+ break;
+ case 0x1b:
+ flag = TPF_ESC;
+ break;
+ case 0x7F:
+ flag = TPF_DEL;
+ break;
+ default:
+ if (c < ' ') {
+ flag = TPF_C0;
+ } else if (c >= 0x80 && c <= 0x9F) {
+ flag = TPF_C1;
+ }
}
return !!(tpf_flags & flag);
}
@@ -666,8 +665,7 @@ static int get_rgb(VTermState *state, VTermColor color)
}
-void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
- int *term_attrs)
+void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *term_attrs)
{
int height, width;
vterm_get_size(term->vt, &height, &width);
@@ -701,12 +699,12 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
bool bg_set = vt_bg_idx && vt_bg_idx <= 16 && term->color_set[vt_bg_idx-1];
int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0)
- | (cell.attrs.italic ? HL_ITALIC : 0)
- | (cell.attrs.reverse ? HL_INVERSE : 0)
- | (cell.attrs.underline ? HL_UNDERLINE : 0)
- | (cell.attrs.strike ? HL_STRIKETHROUGH: 0)
- | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0)
- | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0);
+ | (cell.attrs.italic ? HL_ITALIC : 0)
+ | (cell.attrs.reverse ? HL_INVERSE : 0)
+ | (cell.attrs.underline ? HL_UNDERLINE : 0)
+ | (cell.attrs.strike ? HL_STRIKETHROUGH: 0)
+ | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0)
+ | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0);
int attr_id = 0;
@@ -757,12 +755,11 @@ static int term_damage(VTermRect rect, void *data)
static int term_moverect(VTermRect dest, VTermRect src, void *data)
{
invalidate_terminal(data, MIN(dest.start_row, src.start_row),
- MAX(dest.end_row, src.end_row));
+ MAX(dest.end_row, src.end_row));
return 1;
}
-static int term_movecursor(VTermPos new, VTermPos old, int visible,
- void *data)
+static int term_movecursor(VTermPos new, VTermPos old, int visible, void *data)
{
Terminal *term = data;
term->cursor.row = new.row;
@@ -791,26 +788,26 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data)
Terminal *term = data;
switch (prop) {
- case VTERM_PROP_ALTSCREEN:
- break;
-
- case VTERM_PROP_CURSORVISIBLE:
- term->cursor.visible = val->boolean;
- invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
- break;
+ case VTERM_PROP_ALTSCREEN:
+ break;
+
+ case VTERM_PROP_CURSORVISIBLE:
+ term->cursor.visible = val->boolean;
+ invalidate_terminal(term, term->cursor.row, term->cursor.row + 1);
+ break;
+
+ case VTERM_PROP_TITLE: {
+ buf_T *buf = handle_get_buffer(term->buf_handle);
+ buf_set_term_title(buf, val->string);
+ break;
+ }
- case VTERM_PROP_TITLE: {
- buf_T *buf = handle_get_buffer(term->buf_handle);
- buf_set_term_title(buf, val->string);
- break;
- }
+ case VTERM_PROP_MOUSE:
+ term->forward_mouse = (bool)val->number;
+ break;
- case VTERM_PROP_MOUSE:
- term->forward_mouse = (bool)val->number;
- break;
-
- default:
- return 0;
+ default:
+ return 0;
}
return 1;
@@ -844,12 +841,11 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data)
// Make room at the start by shifting to the right.
memmove(term->sb_buffer + 1, term->sb_buffer,
- sizeof(term->sb_buffer[0]) * (term->sb_current - 1));
-
+ sizeof(term->sb_buffer[0]) * (term->sb_current - 1));
} else if (term->sb_current > 0) {
// Make room at the start by shifting to the right.
memmove(term->sb_buffer + 1, term->sb_buffer,
- sizeof(term->sb_buffer[0]) * term->sb_current);
+ sizeof(term->sb_buffer[0]) * term->sb_current);
}
if (!sbrow) {
@@ -894,7 +890,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
term->sb_current--;
// Forget the "popped" row by shifting the rest onto it.
memmove(term->sb_buffer, term->sb_buffer + 1,
- sizeof(term->sb_buffer[0]) * (term->sb_current));
+ sizeof(term->sb_buffer[0]) * (term->sb_current));
size_t cols_to_copy = (size_t)cols;
if (cols_to_copy > sbrow->cols) {
@@ -919,35 +915,41 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
static void convert_modifiers(int key, VTermModifier *statep)
{
- if (mod_mask & MOD_MASK_SHIFT) { *statep |= VTERM_MOD_SHIFT; }
- if (mod_mask & MOD_MASK_CTRL) { *statep |= VTERM_MOD_CTRL; }
- if (mod_mask & MOD_MASK_ALT) { *statep |= VTERM_MOD_ALT; }
+ if (mod_mask & MOD_MASK_SHIFT) {
+ *statep |= VTERM_MOD_SHIFT;
+ }
+ if (mod_mask & MOD_MASK_CTRL) {
+ *statep |= VTERM_MOD_CTRL;
+ }
+ if (mod_mask & MOD_MASK_ALT) {
+ *statep |= VTERM_MOD_ALT;
+ }
switch (key) {
- case K_S_TAB:
- case K_S_UP:
- case K_S_DOWN:
- case K_S_LEFT:
- case K_S_RIGHT:
- case K_S_F1:
- case K_S_F2:
- case K_S_F3:
- case K_S_F4:
- case K_S_F5:
- case K_S_F6:
- case K_S_F7:
- case K_S_F8:
- case K_S_F9:
- case K_S_F10:
- case K_S_F11:
- case K_S_F12:
- *statep |= VTERM_MOD_SHIFT;
- break;
-
- case K_C_LEFT:
- case K_C_RIGHT:
- *statep |= VTERM_MOD_CTRL;
- break;
+ case K_S_TAB:
+ case K_S_UP:
+ case K_S_DOWN:
+ case K_S_LEFT:
+ case K_S_RIGHT:
+ case K_S_F1:
+ case K_S_F2:
+ case K_S_F3:
+ case K_S_F4:
+ case K_S_F5:
+ case K_S_F6:
+ case K_S_F7:
+ case K_S_F8:
+ case K_S_F9:
+ case K_S_F10:
+ case K_S_F11:
+ case K_S_F12:
+ *statep |= VTERM_MOD_SHIFT;
+ break;
+
+ case K_C_LEFT:
+ case K_C_RIGHT:
+ *statep |= VTERM_MOD_CTRL;
+ break;
}
}
@@ -956,115 +958,212 @@ static VTermKey convert_key(int key, VTermModifier *statep)
convert_modifiers(key, statep);
switch (key) {
- case K_BS: return VTERM_KEY_BACKSPACE;
- case K_S_TAB: FALLTHROUGH;
- case TAB: return VTERM_KEY_TAB;
- case Ctrl_M: return VTERM_KEY_ENTER;
- case ESC: return VTERM_KEY_ESCAPE;
-
- case K_S_UP: FALLTHROUGH;
- case K_UP: return VTERM_KEY_UP;
- case K_S_DOWN: FALLTHROUGH;
- case K_DOWN: return VTERM_KEY_DOWN;
- case K_S_LEFT: FALLTHROUGH;
- case K_C_LEFT: FALLTHROUGH;
- case K_LEFT: return VTERM_KEY_LEFT;
- case K_S_RIGHT: FALLTHROUGH;
- case K_C_RIGHT: FALLTHROUGH;
- case K_RIGHT: return VTERM_KEY_RIGHT;
-
- case K_INS: return VTERM_KEY_INS;
- case K_DEL: return VTERM_KEY_DEL;
- case K_HOME: return VTERM_KEY_HOME;
- case K_END: return VTERM_KEY_END;
- case K_PAGEUP: return VTERM_KEY_PAGEUP;
- case K_PAGEDOWN: return VTERM_KEY_PAGEDOWN;
-
- case K_K0: FALLTHROUGH;
- case K_KINS: return VTERM_KEY_KP_0;
- case K_K1: FALLTHROUGH;
- case K_KEND: return VTERM_KEY_KP_1;
- case K_K2: FALLTHROUGH;
- case K_KDOWN: return VTERM_KEY_KP_2;
- case K_K3: FALLTHROUGH;
- case K_KPAGEDOWN: return VTERM_KEY_KP_3;
- case K_K4: FALLTHROUGH;
- case K_KLEFT: return VTERM_KEY_KP_4;
- case K_K5: FALLTHROUGH;
- case K_KORIGIN: return VTERM_KEY_KP_5;
- case K_K6: FALLTHROUGH;
- case K_KRIGHT: return VTERM_KEY_KP_6;
- case K_K7: FALLTHROUGH;
- case K_KHOME: return VTERM_KEY_KP_7;
- case K_K8: FALLTHROUGH;
- case K_KUP: return VTERM_KEY_KP_8;
- case K_K9: FALLTHROUGH;
- case K_KPAGEUP: return VTERM_KEY_KP_9;
- case K_KDEL: FALLTHROUGH;
- case K_KPOINT: return VTERM_KEY_KP_PERIOD;
- case K_KENTER: return VTERM_KEY_KP_ENTER;
- case K_KPLUS: return VTERM_KEY_KP_PLUS;
- case K_KMINUS: return VTERM_KEY_KP_MINUS;
- case K_KMULTIPLY: return VTERM_KEY_KP_MULT;
- case K_KDIVIDE: return VTERM_KEY_KP_DIVIDE;
-
- case K_S_F1: FALLTHROUGH;
- case K_F1: return VTERM_KEY_FUNCTION(1);
- case K_S_F2: FALLTHROUGH;
- case K_F2: return VTERM_KEY_FUNCTION(2);
- case K_S_F3: FALLTHROUGH;
- case K_F3: return VTERM_KEY_FUNCTION(3);
- case K_S_F4: FALLTHROUGH;
- case K_F4: return VTERM_KEY_FUNCTION(4);
- case K_S_F5: FALLTHROUGH;
- case K_F5: return VTERM_KEY_FUNCTION(5);
- case K_S_F6: FALLTHROUGH;
- case K_F6: return VTERM_KEY_FUNCTION(6);
- case K_S_F7: FALLTHROUGH;
- case K_F7: return VTERM_KEY_FUNCTION(7);
- case K_S_F8: FALLTHROUGH;
- case K_F8: return VTERM_KEY_FUNCTION(8);
- case K_S_F9: FALLTHROUGH;
- case K_F9: return VTERM_KEY_FUNCTION(9);
- case K_S_F10: FALLTHROUGH;
- case K_F10: return VTERM_KEY_FUNCTION(10);
- case K_S_F11: FALLTHROUGH;
- case K_F11: return VTERM_KEY_FUNCTION(11);
- case K_S_F12: FALLTHROUGH;
- case K_F12: return VTERM_KEY_FUNCTION(12);
-
- case K_F13: return VTERM_KEY_FUNCTION(13);
- case K_F14: return VTERM_KEY_FUNCTION(14);
- case K_F15: return VTERM_KEY_FUNCTION(15);
- case K_F16: return VTERM_KEY_FUNCTION(16);
- case K_F17: return VTERM_KEY_FUNCTION(17);
- case K_F18: return VTERM_KEY_FUNCTION(18);
- case K_F19: return VTERM_KEY_FUNCTION(19);
- case K_F20: return VTERM_KEY_FUNCTION(20);
- case K_F21: return VTERM_KEY_FUNCTION(21);
- case K_F22: return VTERM_KEY_FUNCTION(22);
- case K_F23: return VTERM_KEY_FUNCTION(23);
- case K_F24: return VTERM_KEY_FUNCTION(24);
- case K_F25: return VTERM_KEY_FUNCTION(25);
- case K_F26: return VTERM_KEY_FUNCTION(26);
- case K_F27: return VTERM_KEY_FUNCTION(27);
- case K_F28: return VTERM_KEY_FUNCTION(28);
- case K_F29: return VTERM_KEY_FUNCTION(29);
- case K_F30: return VTERM_KEY_FUNCTION(30);
- case K_F31: return VTERM_KEY_FUNCTION(31);
- case K_F32: return VTERM_KEY_FUNCTION(32);
- case K_F33: return VTERM_KEY_FUNCTION(33);
- case K_F34: return VTERM_KEY_FUNCTION(34);
- case K_F35: return VTERM_KEY_FUNCTION(35);
- case K_F36: return VTERM_KEY_FUNCTION(36);
- case K_F37: return VTERM_KEY_FUNCTION(37);
-
- default: return VTERM_KEY_NONE;
+ case K_BS:
+ return VTERM_KEY_BACKSPACE;
+ case K_S_TAB:
+ FALLTHROUGH;
+ case TAB:
+ return VTERM_KEY_TAB;
+ case Ctrl_M:
+ return VTERM_KEY_ENTER;
+ case ESC:
+ return VTERM_KEY_ESCAPE;
+
+ case K_S_UP:
+ FALLTHROUGH;
+ case K_UP:
+ return VTERM_KEY_UP;
+ case K_S_DOWN:
+ FALLTHROUGH;
+ case K_DOWN:
+ return VTERM_KEY_DOWN;
+ case K_S_LEFT:
+ FALLTHROUGH;
+ case K_C_LEFT:
+ FALLTHROUGH;
+ case K_LEFT:
+ return VTERM_KEY_LEFT;
+ case K_S_RIGHT:
+ FALLTHROUGH;
+ case K_C_RIGHT:
+ FALLTHROUGH;
+ case K_RIGHT:
+ return VTERM_KEY_RIGHT;
+
+ case K_INS:
+ return VTERM_KEY_INS;
+ case K_DEL:
+ return VTERM_KEY_DEL;
+ case K_HOME:
+ return VTERM_KEY_HOME;
+ case K_END:
+ return VTERM_KEY_END;
+ case K_PAGEUP:
+ return VTERM_KEY_PAGEUP;
+ case K_PAGEDOWN:
+ return VTERM_KEY_PAGEDOWN;
+
+ case K_K0:
+ FALLTHROUGH;
+ case K_KINS:
+ return VTERM_KEY_KP_0;
+ case K_K1:
+ FALLTHROUGH;
+ case K_KEND:
+ return VTERM_KEY_KP_1;
+ case K_K2:
+ FALLTHROUGH;
+ case K_KDOWN:
+ return VTERM_KEY_KP_2;
+ case K_K3:
+ FALLTHROUGH;
+ case K_KPAGEDOWN:
+ return VTERM_KEY_KP_3;
+ case K_K4:
+ FALLTHROUGH;
+ case K_KLEFT:
+ return VTERM_KEY_KP_4;
+ case K_K5:
+ FALLTHROUGH;
+ case K_KORIGIN:
+ return VTERM_KEY_KP_5;
+ case K_K6:
+ FALLTHROUGH;
+ case K_KRIGHT:
+ return VTERM_KEY_KP_6;
+ case K_K7:
+ FALLTHROUGH;
+ case K_KHOME:
+ return VTERM_KEY_KP_7;
+ case K_K8:
+ FALLTHROUGH;
+ case K_KUP:
+ return VTERM_KEY_KP_8;
+ case K_K9:
+ FALLTHROUGH;
+ case K_KPAGEUP:
+ return VTERM_KEY_KP_9;
+ case K_KDEL:
+ FALLTHROUGH;
+ case K_KPOINT:
+ return VTERM_KEY_KP_PERIOD;
+ case K_KENTER:
+ return VTERM_KEY_KP_ENTER;
+ case K_KPLUS:
+ return VTERM_KEY_KP_PLUS;
+ case K_KMINUS:
+ return VTERM_KEY_KP_MINUS;
+ case K_KMULTIPLY:
+ return VTERM_KEY_KP_MULT;
+ case K_KDIVIDE:
+ return VTERM_KEY_KP_DIVIDE;
+
+ case K_S_F1:
+ FALLTHROUGH;
+ case K_F1:
+ return VTERM_KEY_FUNCTION(1);
+ case K_S_F2:
+ FALLTHROUGH;
+ case K_F2:
+ return VTERM_KEY_FUNCTION(2);
+ case K_S_F3:
+ FALLTHROUGH;
+ case K_F3:
+ return VTERM_KEY_FUNCTION(3);
+ case K_S_F4:
+ FALLTHROUGH;
+ case K_F4:
+ return VTERM_KEY_FUNCTION(4);
+ case K_S_F5:
+ FALLTHROUGH;
+ case K_F5:
+ return VTERM_KEY_FUNCTION(5);
+ case K_S_F6:
+ FALLTHROUGH;
+ case K_F6:
+ return VTERM_KEY_FUNCTION(6);
+ case K_S_F7:
+ FALLTHROUGH;
+ case K_F7:
+ return VTERM_KEY_FUNCTION(7);
+ case K_S_F8:
+ FALLTHROUGH;
+ case K_F8:
+ return VTERM_KEY_FUNCTION(8);
+ case K_S_F9:
+ FALLTHROUGH;
+ case K_F9:
+ return VTERM_KEY_FUNCTION(9);
+ case K_S_F10:
+ FALLTHROUGH;
+ case K_F10:
+ return VTERM_KEY_FUNCTION(10);
+ case K_S_F11:
+ FALLTHROUGH;
+ case K_F11:
+ return VTERM_KEY_FUNCTION(11);
+ case K_S_F12:
+ FALLTHROUGH;
+ case K_F12:
+ return VTERM_KEY_FUNCTION(12);
+
+ case K_F13:
+ return VTERM_KEY_FUNCTION(13);
+ case K_F14:
+ return VTERM_KEY_FUNCTION(14);
+ case K_F15:
+ return VTERM_KEY_FUNCTION(15);
+ case K_F16:
+ return VTERM_KEY_FUNCTION(16);
+ case K_F17:
+ return VTERM_KEY_FUNCTION(17);
+ case K_F18:
+ return VTERM_KEY_FUNCTION(18);
+ case K_F19:
+ return VTERM_KEY_FUNCTION(19);
+ case K_F20:
+ return VTERM_KEY_FUNCTION(20);
+ case K_F21:
+ return VTERM_KEY_FUNCTION(21);
+ case K_F22:
+ return VTERM_KEY_FUNCTION(22);
+ case K_F23:
+ return VTERM_KEY_FUNCTION(23);
+ case K_F24:
+ return VTERM_KEY_FUNCTION(24);
+ case K_F25:
+ return VTERM_KEY_FUNCTION(25);
+ case K_F26:
+ return VTERM_KEY_FUNCTION(26);
+ case K_F27:
+ return VTERM_KEY_FUNCTION(27);
+ case K_F28:
+ return VTERM_KEY_FUNCTION(28);
+ case K_F29:
+ return VTERM_KEY_FUNCTION(29);
+ case K_F30:
+ return VTERM_KEY_FUNCTION(30);
+ case K_F31:
+ return VTERM_KEY_FUNCTION(31);
+ case K_F32:
+ return VTERM_KEY_FUNCTION(32);
+ case K_F33:
+ return VTERM_KEY_FUNCTION(33);
+ case K_F34:
+ return VTERM_KEY_FUNCTION(34);
+ case K_F35:
+ return VTERM_KEY_FUNCTION(35);
+ case K_F36:
+ return VTERM_KEY_FUNCTION(36);
+ case K_F37:
+ return VTERM_KEY_FUNCTION(37);
+
+ default:
+ return VTERM_KEY_NONE;
}
}
-static void mouse_action(Terminal *term, int button, int row, int col,
- bool drag, VTermModifier mod)
+static void mouse_action(Terminal *term, int button, int row, int col, bool drag, VTermModifier mod)
{
if (term->pressed_button && (term->pressed_button != button || !drag)) {
// release the previous button
@@ -1100,16 +1199,26 @@ static bool send_mouse_event(Terminal *term, int c)
bool drag = false;
switch (c) {
- case K_LEFTDRAG: drag = true; FALLTHROUGH;
- case K_LEFTMOUSE: button = 1; break;
- case K_MOUSEMOVE: drag = true; button = 0; break;
- case K_MIDDLEDRAG: drag = true; FALLTHROUGH;
- case K_MIDDLEMOUSE: button = 2; break;
- case K_RIGHTDRAG: drag = true; FALLTHROUGH;
- case K_RIGHTMOUSE: button = 3; break;
- case K_MOUSEDOWN: button = 4; break;
- case K_MOUSEUP: button = 5; break;
- default: return false;
+ case K_LEFTDRAG:
+ drag = true; FALLTHROUGH;
+ case K_LEFTMOUSE:
+ button = 1; break;
+ case K_MOUSEMOVE:
+ drag = true; button = 0; break;
+ case K_MIDDLEDRAG:
+ drag = true; FALLTHROUGH;
+ case K_MIDDLEMOUSE:
+ button = 2; break;
+ case K_RIGHTDRAG:
+ drag = true; FALLTHROUGH;
+ case K_RIGHTMOUSE:
+ button = 3; break;
+ case K_MOUSEDOWN:
+ button = 4; break;
+ case K_MOUSEUP:
+ button = 5; break;
+ default:
+ return false;
}
mouse_action(term, button, row, col - offset, drag, 0);
@@ -1162,7 +1271,7 @@ static void fetch_row(Terminal *term, int row, int end_col)
if (cell.chars[0]) {
for (int i = 0; cell.chars[i]; i++) {
cell_len += utf_char2bytes((int)cell.chars[i],
- (uint8_t *)ptr + cell_len);
+ (uint8_t *)ptr + cell_len);
}
} else {
*ptr = ' ';
@@ -1181,8 +1290,7 @@ static void fetch_row(Terminal *term, int row, int end_col)
term->textbuf[line_len] = 0;
}
-static bool fetch_cell(Terminal *term, int row, int col,
- VTermScreenCell *cell)
+static bool fetch_cell(Terminal *term, int row, int col, VTermScreenCell *cell)
{
if (row < 0) {
ScrollbackLine *sbrow = term->sb_buffer[-row - 1];
@@ -1197,8 +1305,8 @@ static bool fetch_cell(Terminal *term, int row, int col,
return false;
}
} else {
- vterm_screen_get_cell(term->vts, (VTermPos){.row = row, .col = col},
- cell);
+ vterm_screen_get_cell(term->vts, (VTermPos){ .row = row, .col = col },
+ cell);
}
return true;
}
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index cc789cb6bd..4a9cb4a8d8 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -259,7 +259,7 @@ let s:filename_checks = {
\ 'jgraph': ['file.jgr'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc'],
\ 'jsonc': ['file.jsonc'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
@@ -344,6 +344,7 @@ let s:filename_checks = {
\ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'],
\ 'ncf': ['file.ncf'],
\ 'netrc': ['.netrc'],
+ \ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'],
\ 'ninja': ['file.ninja'],
\ 'nqc': ['file.nqc'],
\ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'],
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index e82fefc7fc..366615821c 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -585,6 +585,8 @@ func Test_mode()
exe "normal iabc\<C-X>\<C-L>\<F2>\<Esc>u"
call assert_equal('i-ic', g:current_modes)
+ exe "normal R\<F2>\<Esc>"
+ call assert_equal('R-R', g:current_modes)
" R_CTRL-P: Multiple matches
exe "normal RBa\<C-P>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
@@ -619,6 +621,42 @@ func Test_mode()
exe "normal Rabc\<C-X>\<C-L>\<F2>\<Esc>u"
call assert_equal('R-Rc', g:current_modes)
+ exe "normal gR\<F2>\<Esc>"
+ call assert_equal('R-Rv', g:current_modes)
+ " gR_CTRL-P: Multiple matches
+ exe "normal gRBa\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-P: Single match
+ exe "normal gRBro\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X
+ exe "normal gRBa\<C-X>\<F2>\<Esc>u"
+ call assert_equal('R-Rvx', g:current_modes)
+ " gR_CTRL-X CTRL-P: Multiple matches
+ exe "normal gRBa\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X CTRL-P: Single match
+ exe "normal gRBro\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X CTRL-P + CTRL-P: Single match
+ exe "normal gRBro\<C-X>\<C-P>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X CTRL-L: Multiple matches
+ exe "normal gR\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X CTRL-L: Single match
+ exe "normal gRBlu\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-P: No match
+ exe "normal gRCom\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X CTRL-P: No match
+ exe "normal gRCom\<C-X>\<C-P>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+ " gR_CTRL-X CTRL-L: No match
+ exe "normal gRabc\<C-X>\<C-L>\<F2>\<Esc>u"
+ call assert_equal('R-Rvc', g:current_modes)
+
call assert_equal('n', mode(0))
call assert_equal('n', mode(1))
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 710450293c..eb367cfe5c 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -950,6 +950,10 @@ func Test_popup_complete_info_01()
\ ["\<C-X>", 'ctrl_x'],
\ ["\<C-X>\<C-N>", 'keyword'],
\ ["\<C-X>\<C-P>", 'keyword'],
+ \ ["\<C-X>\<C-E>", 'scroll'],
+ \ ["\<C-X>\<C-Y>", 'scroll'],
+ \ ["\<C-X>\<C-E>\<C-E>\<C-Y>", 'scroll'],
+ \ ["\<C-X>\<C-Y>\<C-E>\<C-Y>", 'scroll'],
\ ["\<C-X>\<C-L>", 'whole_line'],
\ ["\<C-X>\<C-F>", 'files'],
\ ["\<C-X>\<C-]>", 'tags'],
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index daebe25466..b140077111 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -27,8 +27,8 @@ func Test_after_comes_later()
set guioptions+=M
let $HOME = "/does/not/exist"
set loadplugins
- set rtp=Xhere,Xafter,Xanother
- set packpath=Xhere,Xafter
+ set rtp=Xhere,Xdir/after,Xanother
+ set packpath=Xhere,Xdir/after
set nomore
let g:sequence = ""
[CODE]
@@ -50,8 +50,8 @@ func Test_after_comes_later()
call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
- call mkdir('Xafter/plugin', 'p')
- call writefile(['let g:sequence .= "after "'], 'Xafter/plugin/later.vim')
+ call mkdir('Xdir/after/plugin', 'p')
+ call writefile(['let g:sequence .= "after "'], 'Xdir/after/plugin/later.vim')
if RunVim(before, after, '')
@@ -74,7 +74,7 @@ func Test_after_comes_later()
call delete('Xsequence')
call delete('Xhere', 'rf')
call delete('Xanother', 'rf')
- call delete('Xafter', 'rf')
+ call delete('Xdir', 'rf')
endfunc
func Test_pack_in_rtp_when_plugins_run()
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index fb5e12c20e..803ff23cea 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -59,12 +59,12 @@
#define LINUXSET1C "\x1b[?1c"
#ifdef NVIM_UNIBI_HAS_VAR_FROM
-#define UNIBI_SET_NUM_VAR(var, num) \
+# define UNIBI_SET_NUM_VAR(var, num) \
do { \
(var) = unibi_var_from_num((num)); \
} while (0)
#else
-#define UNIBI_SET_NUM_VAR(var, num) (var).i = (num);
+# define UNIBI_SET_NUM_VAR(var, num) (var).i = (num);
#endif
typedef struct {
@@ -1483,7 +1483,7 @@ static void tui_guess_size(UI *ui)
height = unibi_get_num(data->ut, unibi_lines);
width = unibi_get_num(data->ut, unibi_columns);
-end:
+ end:
if (width <= 0 || height <= 0) {
// use the defaults
width = DFLT_COLS;
@@ -2111,14 +2111,14 @@ static void flush_buf(UI *ui)
static const char *tui_get_stty_erase(void)
{
static char stty_erase[2] = { 0 };
-#if defined(HAVE_TERMIOS_H)
+# if defined(HAVE_TERMIOS_H)
struct termios t;
if (tcgetattr(input_global_fd(), &t) != -1) {
stty_erase[0] = (char)t.c_cc[VERASE];
stty_erase[1] = '\0';
DLOG("stty/termios:erase=%s", stty_erase);
}
-#endif
+# endif
return stty_erase;
}
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index 9e4aaff878..ef84cdf334 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -2,14 +2,14 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
-#include <limits.h>
#include "nvim/assert.h"
-#include "nvim/vim.h"
-#include "nvim/ui.h"
#include "nvim/ugrid.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ugrid.c.generated.h"
@@ -79,8 +79,7 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count)
}
}
-static void clear_region(UGrid *grid, int top, int bot, int left, int right,
- sattr_T attr)
+static void clear_region(UGrid *grid, int top, int bot, int left, int right, sattr_T attr)
{
for (int row = top; row <= bot; row++) {
UGRID_FOREACH_CELL(grid, row, left, right+1, {
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 09709d0f43..aad72af025 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -3,40 +3,40 @@
#include <assert.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <string.h>
-#include <limits.h>
-#include "nvim/vim.h"
-#include "nvim/log.h"
+#include "nvim/ascii.h"
#include "nvim/aucmd.h"
-#include "nvim/ui.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/cursor_shape.h"
#include "nvim/diff.h"
+#include "nvim/event/loop.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
+#include "nvim/highlight.h"
+#include "nvim/log.h"
#include "nvim/main.h"
-#include "nvim/ascii.h"
-#include "nvim/misc1.h"
#include "nvim/mbyte.h"
-#include "nvim/garray.h"
#include "nvim/memory.h"
+#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
-#include "nvim/os_unix.h"
-#include "nvim/event/loop.h"
-#include "nvim/os/time.h"
#include "nvim/os/input.h"
#include "nvim/os/signal.h"
+#include "nvim/os/time.h"
+#include "nvim/os_unix.h"
#include "nvim/popupmnu.h"
#include "nvim/screen.h"
-#include "nvim/highlight.h"
+#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/cursor_shape.h"
#ifdef FEAT_TUI
# include "nvim/tui/tui.h"
#else
@@ -70,9 +70,9 @@ static int pending_has_mouse = -1;
static size_t uilog_seen = 0;
static char uilog_last_event[1024] = { 0 };
-#ifndef EXITFREE
-#define entered_free_all_mem false
-#endif
+# ifndef EXITFREE
+# define entered_free_all_mem false
+# endif
# define UI_LOG(funname) \
do { \
@@ -95,7 +95,7 @@ static char uilog_last_event[1024] = { 0 };
// UI_CALL invokes a function on all registered UI instances.
// This is called by code generated by generators/gen_api_ui_events.lua
// C code should use ui_call_{funname} instead.
-# define UI_CALL(cond, funname, ...) \
+#define UI_CALL(cond, funname, ...) \
do { \
bool any_call = false; \
for (size_t i = 0; i < ui_count; i++) { \
@@ -115,7 +115,7 @@ static char uilog_last_event[1024] = { 0 };
#endif
#ifndef EXITFREE
-#undef entered_free_all_mem
+# undef entered_free_all_mem
#endif
void ui_init(void)
@@ -382,8 +382,8 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
}
}
-void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
- int clearattr, bool wrap)
+void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, int clearattr,
+ bool wrap)
{
assert(0 <= row && row < grid->Rows);
LineFlags flags = wrap ? kLineFlagWrap : 0;
@@ -515,23 +515,23 @@ void ui_check_mouse(void)
// normal editing mode (not at hit-return message).
for (char_u *p = p_mouse; *p; p++) {
switch (*p) {
- case 'a':
- if (vim_strchr((char_u *)MOUSE_A, checkfor) != NULL) {
- has_mouse = true;
- return;
- }
- break;
- case MOUSE_HELP:
- if (checkfor != MOUSE_RETURN && curbuf->b_help) {
- has_mouse = true;
- return;
- }
- break;
- default:
- if (checkfor == *p) {
- has_mouse = true;
- return;
- }
+ case 'a':
+ if (vim_strchr((char_u *)MOUSE_A, checkfor) != NULL) {
+ has_mouse = true;
+ return;
+ }
+ break;
+ case MOUSE_HELP:
+ if (checkfor != MOUSE_RETURN && curbuf->b_help) {
+ has_mouse = true;
+ return;
+ }
+ break;
+ default:
+ if (checkfor == *p) {
+ has_mouse = true;
+ return;
+ }
}
}
}
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 25f45b8fe6..3402df817a 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -5,18 +5,18 @@
// Used by the built-in TUI and libnvim-based UIs.
#include <assert.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
-#include <limits.h>
+#include "nvim/api/private/helpers.h"
#include "nvim/log.h"
#include "nvim/main.h"
-#include "nvim/vim.h"
-#include "nvim/ui.h"
#include "nvim/memory.h"
-#include "nvim/ui_bridge.h"
#include "nvim/ugrid.h"
-#include "nvim/api/private/helpers.h"
+#include "nvim/ui.h"
+#include "nvim/ui_bridge.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_bridge.c.generated.h"
@@ -26,8 +26,7 @@
// Schedule a function call on the UI bridge thread.
#define UI_BRIDGE_CALL(ui, name, argc, ...) \
- ((UIBridgeData *)ui)->scheduler( \
- event_create(ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui))
+ ((UIBridgeData *)ui)->scheduler(event_create(ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui))
#define INT2PTR(i) ((void *)(intptr_t)i)
#define PTR2INT(p) ((Integer)(intptr_t)p)
@@ -41,6 +40,8 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
UIBridgeData *rv = xcalloc(1, sizeof(UIBridgeData));
rv->ui = ui;
rv->bridge.rgb = ui->rgb;
+ rv->bridge.width = ui->width;
+ rv->bridge.height = ui->height;
rv->bridge.stop = ui_bridge_stop;
rv->bridge.grid_resize = ui_bridge_grid_resize;
rv->bridge.grid_clear = ui_bridge_grid_clear;
@@ -136,8 +137,8 @@ static void ui_bridge_stop_event(void **argv)
ui->stop(ui);
}
-static void ui_bridge_hl_attr_define(UI *ui, Integer id, HlAttrs attrs,
- HlAttrs cterm_attrs, Array info)
+static void ui_bridge_hl_attr_define(UI *ui, Integer id, HlAttrs attrs, HlAttrs cterm_attrs,
+ Array info)
{
HlAttrs *a = xmalloc(sizeof(HlAttrs));
*a = attrs;
@@ -161,11 +162,9 @@ static void ui_bridge_raw_line_event(void **argv)
xfree(argv[8]);
xfree(argv[9]);
}
-static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row,
- Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr,
- LineFlags flags, const schar_T *chunk,
- const sattr_T *attrs)
+static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
+ Integer clearcol, Integer clearattr, LineFlags flags,
+ const schar_T *chunk, const sattr_T *attrs)
{
size_t ncol = (size_t)(endcol-startcol);
schar_T *c = xmemdup(chunk, ncol * sizeof(schar_T));
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 9c9aec1cf5..7a0f68cfeb 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -7,27 +7,27 @@
// Layer-based compositing: https://en.wikipedia.org/wiki/Digital_compositing
#include <assert.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
-#include <limits.h>
+#include "nvim/api/private/helpers.h"
+#include "nvim/ascii.h"
+#include "nvim/highlight.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
+#include "nvim/lua/executor.h"
#include "nvim/main.h"
-#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/ui.h"
-#include "nvim/highlight.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/os/os.h"
#include "nvim/popupmnu.h"
-#include "nvim/ui_compositor.h"
-#include "nvim/ugrid.h"
#include "nvim/screen.h"
#include "nvim/syntax.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/lua/executor.h"
-#include "nvim/os/os.h"
+#include "nvim/ugrid.h"
+#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_compositor.c.generated.h"
@@ -123,8 +123,8 @@ bool ui_comp_should_draw(void)
/// TODO(bfredl): later on the compositor should just use win_float_pos events,
/// though that will require slight event order adjustment: emit the win_pos
/// events in the beginning of update_screen(0), rather than in ui_flush()
-bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width,
- bool valid, bool on_top)
+bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width, bool valid,
+ bool on_top)
{
bool moved;
@@ -257,8 +257,7 @@ static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
}
}
-static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle,
- Integer r, Integer c)
+static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, Integer r, Integer c)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid_handle)) {
return;
@@ -304,8 +303,7 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col)
/// Baseline implementation. This is always correct, but we can sometimes
/// do something more efficient (where efficiency means smaller deltas to
/// the downstream UI.)
-static void compose_line(Integer row, Integer startcol, Integer endcol,
- LineFlags flags)
+static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlags flags)
{
// If rightleft is set, startcol may be -1. In such cases, the assertions
// will fail because no overlap is found. Adjust startcol to prevent it.
@@ -447,8 +445,8 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
(const sattr_T *)attrbuf+skipstart);
}
-static void compose_debug(Integer startrow, Integer endrow, Integer startcol,
- Integer endcol, int syn_id, bool delay)
+static void compose_debug(Integer startrow, Integer endrow, Integer startcol, Integer endcol,
+ int syn_id, bool delay)
{
if (!(rdb_flags & RDB_COMPOSITOR)) {
return;
@@ -479,8 +477,7 @@ static void debug_delay(Integer lines)
}
-static void compose_area(Integer startrow, Integer endrow,
- Integer startcol, Integer endcol)
+static void compose_area(Integer startrow, Integer endrow, Integer startcol, Integer endcol)
{
compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true);
endrow = MIN(endrow, default_grid.Rows);
@@ -505,11 +502,9 @@ void ui_comp_compose_grid(ScreenGrid *grid)
}
}
-static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
- Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr,
- LineFlags flags, const schar_T *chunk,
- const sattr_T *attrs)
+static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
+ Integer clearcol, Integer clearattr, LineFlags flags,
+ const schar_T *chunk, const sattr_T *attrs)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) {
return;
@@ -529,11 +524,11 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
// when resizing nvim, a window will be attempted to be drawn on the older
// and possibly larger global screen size.
if (row >= default_grid.Rows) {
- DLOG("compositor: invalid row %"PRId64" on grid %"PRId64, row, grid);
+ DLOG("compositor: invalid row %" PRId64 " on grid %" PRId64, row, grid);
return;
}
if (clearcol > default_grid.Columns) {
- DLOG("compositor: invalid last column %"PRId64" on grid %"PRId64,
+ DLOG("compositor: invalid last column %" PRId64 " on grid %" PRId64,
clearcol, grid);
if (startcol >= default_grid.Columns) {
return;
@@ -572,8 +567,8 @@ void ui_comp_set_screen_valid(bool valid)
}
}
-static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row,
- Boolean scrolled, String sep_char)
+static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrolled,
+ String sep_char)
{
msg_grid.comp_row = (int)row;
if (scrolled && row > 0) {
@@ -617,9 +612,8 @@ static bool curgrid_covered_above(int row)
return kv_size(layers)-(above_msg?1:0) > curgrid->comp_index+1;
}
-static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
- Integer bot, Integer left, Integer right,
- Integer rows, Integer cols)
+static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left,
+ Integer right, Integer rows, Integer cols)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) {
return;
@@ -653,8 +647,7 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
}
}
-static void ui_comp_grid_resize(UI *ui, Integer grid,
- Integer width, Integer height)
+static void ui_comp_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
{
if (grid == 1) {
ui_composed_call_grid_resize(1, width, height);
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index fb96d7e6ff..af214815f8 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -71,52 +71,51 @@
/* Uncomment the next line for including the u_check() function. This warns
* for errors in the debug information. */
-/* #define U_DEBUG 1 */
-#define UH_MAGIC 0x18dade /* value for uh_magic when in use */
-#define UE_MAGIC 0xabc123 /* value for ue_magic when in use */
+// #define U_DEBUG 1
+#define UH_MAGIC 0x18dade // value for uh_magic when in use
+#define UE_MAGIC 0xabc123 // value for ue_magic when in use
#include <assert.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <string.h>
-#include <fcntl.h>
#include "auto/config.h"
-
-#include "nvim/buffer.h"
#include "nvim/ascii.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/change.h"
-#include "nvim/undo.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
-#include "nvim/buffer_updates.h"
-#include "nvim/pos.h" // MAXLNUM
+#include "nvim/garray.h"
+#include "nvim/lib/kvec.h"
#include "nvim/mark.h"
-#include "nvim/extmark.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/memory.h"
-#include "nvim/garray.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/pos.h" // MAXLNUM
#include "nvim/sha256.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/types.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/lib/kvec.h"
+#include "nvim/undo.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "undo.c.generated.h"
#endif
-/* used in undo_end() to report number of added and deleted lines */
+// used in undo_end() to report number of added and deleted lines
static long u_newcount, u_oldcount;
/*
@@ -136,13 +135,12 @@ static int seen_b_u_curhead;
static int seen_b_u_newhead;
static int header_count;
-static void u_check_tree(u_header_T *uhp,
- u_header_T *exp_uh_next,
- u_header_T *exp_uh_alt_prev) {
+static void u_check_tree(u_header_T *uhp, u_header_T *exp_uh_next, u_header_T *exp_uh_alt_prev) {
u_entry_T *uep;
- if (uhp == NULL)
+ if (uhp == NULL) {
return;
+ }
++header_count;
if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1) {
EMSG("b_u_curhead found twice (looping?)");
@@ -153,22 +151,22 @@ static void u_check_tree(u_header_T *uhp,
return;
}
- if (uhp->uh_magic != UH_MAGIC)
+ if (uhp->uh_magic != UH_MAGIC) {
EMSG("uh_magic wrong (may be using freed memory)");
- else {
- /* Check pointers back are correct. */
+ } else {
+ // Check pointers back are correct.
if (uhp->uh_next.ptr != exp_uh_next) {
EMSG("uh_next wrong");
smsg("expected: 0x%x, actual: 0x%x",
- exp_uh_next, uhp->uh_next.ptr);
+ exp_uh_next, uhp->uh_next.ptr);
}
if (uhp->uh_alt_prev.ptr != exp_uh_alt_prev) {
EMSG("uh_alt_prev wrong");
smsg("expected: 0x%x, actual: 0x%x",
- exp_uh_alt_prev, uhp->uh_alt_prev.ptr);
+ exp_uh_alt_prev, uhp->uh_alt_prev.ptr);
}
- /* Check the undo tree at this header. */
+ // Check the undo tree at this header.
for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) {
if (uep->ue_magic != UE_MAGIC) {
EMSG("ue_magic wrong (may be using freed memory)");
@@ -176,10 +174,10 @@ static void u_check_tree(u_header_T *uhp,
}
}
- /* Check the next alt tree. */
+ // Check the next alt tree.
u_check_tree(uhp->uh_alt_next.ptr, uhp->uh_next.ptr, uhp);
- /* Check the next header in this branch. */
+ // Check the next header in this branch.
u_check_tree(uhp->uh_prev.ptr, uhp, NULL);
}
}
@@ -192,14 +190,16 @@ static void u_check(int newhead_may_be_NULL) {
u_check_tree(curbuf->b_u_oldhead, NULL, NULL);
if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL
- && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL))
+ && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) {
EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead);
- if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0)
+ }
+ if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) {
EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead);
+ }
if (header_count != curbuf->b_u_numhead) {
EMSG("b_u_numhead invalid");
smsg("expected: %" PRId64 ", actual: %" PRId64,
- (int64_t)header_count, (int64_t)curbuf->b_u_numhead);
+ (int64_t)header_count, (int64_t)curbuf->b_u_numhead);
}
}
@@ -228,11 +228,12 @@ int u_save_cursor(void)
int u_save(linenr_T top, linenr_T bot)
{
if (top >= bot || bot > (curbuf->b_ml.ml_line_count + 1)) {
- return FAIL; /* rely on caller to do error messages */
+ return FAIL; // rely on caller to do error messages
}
- if (top + 2 == bot)
+ if (top + 2 == bot) {
u_saveline((linenr_T)(top + 1));
+ }
return u_savecommon(curbuf, top, bot, (linenr_T)0, false);
}
@@ -268,9 +269,8 @@ int u_inssub(linenr_T lnum)
*/
int u_savedel(linenr_T lnum, long nlines)
{
- return u_savecommon(
- curbuf, lnum - 1, lnum + nlines,
- nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false);
+ return u_savecommon(curbuf, lnum - 1, lnum + nlines,
+ nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false);
}
/// Return true when undo is allowed. Otherwise print an error message and
@@ -327,16 +327,14 @@ static inline void zero_fmark_additional_data(fmark_T *fmarks)
* Careful: may trigger autocommands that reload the buffer.
* Returns FAIL when lines could not be saved, OK otherwise.
*/
-int u_savecommon(buf_T *buf,
- linenr_T top, linenr_T bot,
- linenr_T newbot, int reload)
+int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, int reload)
{
linenr_T lnum;
long i;
- u_header_T *uhp;
- u_header_T *old_curhead;
- u_entry_T *uep;
- u_entry_T *prev_uep;
+ u_header_T *uhp;
+ u_header_T *old_curhead;
+ u_entry_T *uep;
+ u_entry_T *prev_uep;
long size;
if (!reload) {
@@ -381,8 +379,9 @@ int u_savecommon(buf_T *buf,
#ifdef U_DEBUG
uhp->uh_magic = UH_MAGIC;
#endif
- } else
+ } else {
uhp = NULL;
+ }
/*
* If we undid more than we redid, move the entry lists before and
@@ -399,7 +398,7 @@ int u_savecommon(buf_T *buf,
*/
while (buf->b_u_numhead > get_undolevel(buf)
&& buf->b_u_oldhead != NULL) {
- u_header_T *uhfree = buf->b_u_oldhead;
+ u_header_T *uhfree = buf->b_u_oldhead;
if (uhfree == old_curhead) {
// Can't reconnect the branch, delete all of it.
@@ -459,11 +458,12 @@ int u_savecommon(buf_T *buf,
uhp->uh_walk = 0;
uhp->uh_entry = NULL;
uhp->uh_getbot_entry = NULL;
- uhp->uh_cursor = curwin->w_cursor; /* save cursor pos. for undo */
- if (virtual_active() && curwin->w_cursor.coladd > 0)
+ uhp->uh_cursor = curwin->w_cursor; // save cursor pos. for undo
+ if (virtual_active() && curwin->w_cursor.coladd > 0) {
uhp->uh_cursor_vcol = getviscol();
- else
+ } else {
uhp->uh_cursor_vcol = -1;
+ }
// save changed and buffer empty flag for undo
uhp->uh_flags = (buf->b_changed ? UH_CHANGED : 0) +
@@ -499,8 +499,9 @@ int u_savecommon(buf_T *buf,
uep = u_get_headentry(buf);
prev_uep = NULL;
for (i = 0; i < 10; ++i) {
- if (uep == NULL)
+ if (uep == NULL) {
break;
+ }
/* If lines have been inserted/deleted we give up.
* Also when the line was included in a multi-line save. */
@@ -509,14 +510,14 @@ int u_savecommon(buf_T *buf,
!= (uep->ue_bot == 0
? buf->b_ml.ml_line_count + 1
: uep->ue_bot))
- : uep->ue_lcount != buf->b_ml.ml_line_count)
+ : uep->ue_lcount != buf->b_ml.ml_line_count)
|| (uep->ue_size > 1
&& top >= uep->ue_top
&& top + 2 <= uep->ue_top + uep->ue_size + 1)) {
break;
}
- /* If it's the same line we can skip saving it again. */
+ // If it's the same line we can skip saving it again.
if (uep->ue_size == 1 && uep->ue_top == top) {
if (i > 0) {
/* It's not the last entry: get ue_bot for the last
@@ -609,25 +610,25 @@ int u_savecommon(buf_T *buf,
// magic at start of undofile
-# define UF_START_MAGIC "Vim\237UnDo\345"
-# define UF_START_MAGIC_LEN 9
+#define UF_START_MAGIC "Vim\237UnDo\345"
+#define UF_START_MAGIC_LEN 9
// magic at start of header
-# define UF_HEADER_MAGIC 0x5fd0
+#define UF_HEADER_MAGIC 0x5fd0
// magic after last header
-# define UF_HEADER_END_MAGIC 0xe7aa
+#define UF_HEADER_END_MAGIC 0xe7aa
// magic at start of entry
-# define UF_ENTRY_MAGIC 0xf518
+#define UF_ENTRY_MAGIC 0xf518
// magic after last entry
-# define UF_ENTRY_END_MAGIC 0x3581
+#define UF_ENTRY_END_MAGIC 0x3581
// 2-byte undofile version number
-# define UF_VERSION 3
+#define UF_VERSION 3
-/* extra fields for header */
-# define UF_LAST_SAVE_NR 1
+// extra fields for header
+#define UF_LAST_SAVE_NR 1
-/* extra fields for uhp */
-# define UHP_SAVE_NR 1
+// extra fields for uhp
+#define UHP_SAVE_NR 1
static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
@@ -640,7 +641,7 @@ void u_compute_hash(buf_T *buf, char_u *hash)
{
context_sha256_T ctx;
linenr_T lnum;
- char_u *p;
+ char_u *p;
sha256_start(&ctx);
for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
@@ -688,7 +689,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
// Loop over 'undodir'. When reading find the first file that exists.
// When not reading use the first directory that exists or ".".
- dirp = (char *) p_udir;
+ dirp = (char *)p_udir;
while (*dirp != NUL) {
size_t dir_len = copy_option_part((char_u **)&dirp, (char_u *)dir_name,
MAXPATHL, ",");
@@ -698,7 +699,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
const size_t ffname_len = strlen(ffname);
undo_file_name = xmalloc(ffname_len + 6);
memmove(undo_file_name, ffname, ffname_len + 1);
- char *const tail = (char *) path_tail((char_u *) undo_file_name);
+ char *const tail = (char *)path_tail((char_u *)undo_file_name);
const size_t tail_len = strlen(tail);
memmove(tail + 1, tail, tail_len + 1);
*tail = '.';
@@ -754,8 +755,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
///
/// @param[in] mesg Identifier of the corruption kind.
/// @param[in] file_name File in which error occurred.
-static void corruption_error(const char *const mesg,
- const char *const file_name)
+static void corruption_error(const char *const mesg, const char *const file_name)
FUNC_ATTR_NONNULL_ALL
{
EMSG3(_("E825: Corrupted undo file (%s): %s"), mesg, file_name);
@@ -763,8 +763,8 @@ static void corruption_error(const char *const mesg,
static void u_free_uhp(u_header_T *uhp)
{
- u_entry_T *nuep;
- u_entry_T *uep;
+ u_entry_T *nuep;
+ u_entry_T *uep;
uep = uhp->uh_entry;
while (uep != NULL) {
@@ -890,8 +890,7 @@ static bool serialize_uhp(bufinfo_T *bi, u_header_T *uhp)
return true;
}
-static u_header_T *unserialize_uhp(bufinfo_T *bi,
- const char *file_name)
+static u_header_T *unserialize_uhp(bufinfo_T *bi, const char *file_name)
{
u_header_T *uhp = xmalloc(sizeof(u_header_T));
memset(uhp, 0, sizeof(u_header_T));
@@ -999,7 +998,7 @@ static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup)
undo_write_bytes(bi, (uintmax_t)extup.type, 4);
if (!undo_write(bi, (uint8_t *)&(extup.data.splice),
sizeof(ExtmarkSplice))) {
- return false;
+ return false;
}
} else if (extup.type == kExtmarkMove) {
undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2);
@@ -1013,8 +1012,7 @@ static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup)
return true;
}
-static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error,
- const char *filename)
+static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error, const char *filename)
{
UndoObjectType type;
uint8_t *buf = NULL;
@@ -1039,7 +1037,7 @@ static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error,
}
extup->data.move = *(ExtmarkMove *)buf;
} else {
- goto error;
+ goto error;
}
xfree(buf);
@@ -1080,8 +1078,7 @@ static bool serialize_uep(bufinfo_T *bi, u_entry_T *uep)
return true;
}
-static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error,
- const char *file_name)
+static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error, const char *file_name)
{
u_entry_T *uep = xmalloc(sizeof(u_entry_T));
memset(uep, 0, sizeof(u_entry_T));
@@ -1171,24 +1168,23 @@ static void unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info)
/// @param[in] buf Buffer for which undo file is written.
/// @param[in] hash Hash value of the buffer text. Must have #UNDO_HASH_SIZE
/// size.
-void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
- char_u *const hash)
+void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, char_u *const hash)
FUNC_ATTR_NONNULL_ARG(3, 4)
{
- u_header_T *uhp;
+ u_header_T *uhp;
char *file_name;
int mark;
#ifdef U_DEBUG
int headers_written = 0;
#endif
int fd;
- FILE *fp = NULL;
+ FILE *fp = NULL;
int perm;
bool write_ok = false;
bufinfo_T bi;
if (name == NULL) {
- file_name = u_get_undo_file_name((char *) buf->b_ffname, false);
+ file_name = u_get_undo_file_name((char *)buf->b_ffname, false);
if (file_name == NULL) {
if (p_verbose > 0) {
verbose_enter();
@@ -1198,7 +1194,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
return;
}
} else {
- file_name = (char *) name;
+ file_name = (char *)name;
}
/*
@@ -1221,16 +1217,18 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
* file, and delete it. */
if (os_path_exists((char_u *)file_name)) {
if (name == NULL || !forceit) {
- /* Check we can read it and it's an undo file. */
+ // Check we can read it and it's an undo file.
fd = os_open(file_name, O_RDONLY, 0);
if (fd < 0) {
if (name != NULL || p_verbose > 0) {
- if (name == NULL)
+ if (name == NULL) {
verbose_enter();
+ }
smsg(_("Will not overwrite with undo file, cannot read: %s"),
file_name);
- if (name == NULL)
+ if (name == NULL) {
verbose_leave();
+ }
}
goto theend;
} else {
@@ -1240,12 +1238,14 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
if (len < UF_START_MAGIC_LEN
|| memcmp(mbuf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) {
if (name != NULL || p_verbose > 0) {
- if (name == NULL)
+ if (name == NULL) {
verbose_enter();
+ }
smsg(_("Will not overwrite, this is not an undo file: %s"),
file_name);
- if (name == NULL)
+ if (name == NULL) {
verbose_leave();
+ }
}
goto theend;
}
@@ -1276,7 +1276,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
}
#ifdef U_DEBUG
- /* Check there is no problem in undo info before writing. */
+ // Check there is no problem in undo info before writing.
u_check(FALSE);
#endif
@@ -1323,7 +1323,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
mark = ++lastmark;
uhp = buf->b_u_oldhead;
while (uhp != NULL) {
- /* Serialize current UHP if we haven't seen it */
+ // Serialize current UHP if we haven't seen it
if (uhp->uh_walk != mark) {
uhp->uh_walk = mark;
#ifdef U_DEBUG
@@ -1334,19 +1334,20 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
}
}
- /* Now walk through the tree - algorithm from undo_time(). */
- if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark)
+ // Now walk through the tree - algorithm from undo_time().
+ if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark) {
uhp = uhp->uh_prev.ptr;
- else if (uhp->uh_alt_next.ptr != NULL
- && uhp->uh_alt_next.ptr->uh_walk != mark)
+ } else if (uhp->uh_alt_next.ptr != NULL
+ && uhp->uh_alt_next.ptr->uh_walk != mark) {
uhp = uhp->uh_alt_next.ptr;
- else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
- && uhp->uh_next.ptr->uh_walk != mark)
+ } else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
+ && uhp->uh_next.ptr->uh_walk != mark) {
uhp = uhp->uh_next.ptr;
- else if (uhp->uh_alt_prev.ptr != NULL)
+ } else if (uhp->uh_alt_prev.ptr != NULL) {
uhp = uhp->uh_alt_prev.ptr;
- else
+ } else {
uhp = uhp->uh_next.ptr;
+ }
}
if (undo_write_bytes(&bi, (uintmax_t)UF_HEADER_END_MAGIC, 2)) {
@@ -1361,14 +1362,15 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
write_error:
fclose(fp);
- if (!write_ok)
+ if (!write_ok) {
EMSG2(_("E829: write error in undo file: %s"), file_name);
+ }
#ifdef HAVE_ACL
if (buf->b_ffname != NULL) {
vim_acl_T acl;
- /* For systems that support ACL: get the ACL from the original file. */
+ // For systems that support ACL: get the ACL from the original file.
acl = mch_get_acl(buf->b_ffname);
mch_set_acl((char_u *)file_name, acl);
mch_free_acl(acl);
@@ -1376,8 +1378,9 @@ write_error:
#endif
theend:
- if (file_name != name)
+ if (file_name != name) {
xfree(file_name);
+ }
}
/// Loads the undo tree from an undo file.
@@ -1385,8 +1388,7 @@ theend:
/// a bit more verbose.
/// Otherwise use curbuf->b_ffname to generate the undo file name.
/// "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text.
-void u_read_undo(char *name, const char_u *hash,
- const char_u *orig_name FUNC_ATTR_UNUSED)
+void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_ATTR_UNUSED)
FUNC_ATTR_NONNULL_ARG(2)
{
u_header_T **uhp_table = NULL;
@@ -1394,7 +1396,7 @@ void u_read_undo(char *name, const char_u *hash,
char *file_name;
if (name == NULL) {
- file_name = u_get_undo_file_name((char *) curbuf->b_ffname, true);
+ file_name = u_get_undo_file_name((char *)curbuf->b_ffname, true);
if (file_name == NULL) {
return;
}
@@ -1418,7 +1420,7 @@ void u_read_undo(char *name, const char_u *hash,
}
#endif
} else {
- file_name = (char *) name;
+ file_name = (char *)name;
}
if (p_verbose > 0) {
@@ -1465,7 +1467,7 @@ void u_read_undo(char *name, const char_u *hash,
verbose_enter();
}
give_warning((char_u *)
- _("File contents changed, cannot use undo info"), true);
+ _("File contents changed, cannot use undo info"), true);
if (name == NULL) {
verbose_leave();
}
@@ -1508,15 +1510,15 @@ void u_read_undo(char *name, const char_u *hash,
}
int what = undo_read_byte(&bi);
switch (what) {
- case UF_LAST_SAVE_NR:
- last_save_nr = undo_read_4c(&bi);
- break;
+ case UF_LAST_SAVE_NR:
+ last_save_nr = undo_read_4c(&bi);
+ break;
- default:
- // field not supported, skip
- while (--len >= 0) {
- (void)undo_read_byte(&bi);
- }
+ default:
+ // field not supported, skip
+ while (--len >= 0) {
+ (void)undo_read_byte(&bi);
+ }
}
}
@@ -1559,7 +1561,7 @@ void u_read_undo(char *name, const char_u *hash,
size_t amount = num_head * sizeof(int) + 1;
int *uhp_table_used = xmalloc(amount);
memset(uhp_table_used, 0, amount);
-# define SET_FLAG(j) ++ uhp_table_used[j]
+# define SET_FLAG(j) ++uhp_table_used[j]
#else
# define SET_FLAG(j)
#endif
@@ -1666,10 +1668,11 @@ void u_read_undo(char *name, const char_u *hash,
error:
xfree(line_ptr);
if (uhp_table != NULL) {
- for (long i = 0; i < num_read_uhps; i++)
+ for (long i = 0; i < num_read_uhps; i++) {
if (uhp_table[i] != NULL) {
u_free_uhp(uhp_table[i]);
}
+ }
xfree(uhp_table);
}
@@ -1844,7 +1847,7 @@ bool u_undo_and_forget(int count)
to_forget->uh_alt_next.ptr = NULL;
curbuf->b_u_curhead->uh_alt_prev.ptr = to_forget->uh_alt_prev.ptr;
curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_next.ptr ?
- curbuf->b_u_curhead->uh_next.ptr->uh_seq : 0;
+ curbuf->b_u_curhead->uh_next.ptr->uh_seq : 0;
} else if (curbuf->b_u_newhead) {
curbuf->b_u_seq_cur = curbuf->b_u_newhead->uh_seq;
}
@@ -1876,8 +1879,9 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
u_newcount = 0;
u_oldcount = 0;
- if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) {
u_oldcount = -1;
+ }
while (count--) {
/* Do the change warning now, so that it triggers FileChangedRO when
* needed. This may cause the file to be reloaded, that must happen
@@ -1894,7 +1898,7 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
}
// nothing to undo
if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) {
- /* stick curbuf->b_u_curhead at end */
+ // stick curbuf->b_u_curhead at end
curbuf->b_u_curhead = curbuf->b_u_oldhead;
beep_flush();
if (count == startcount - 1) {
@@ -1919,8 +1923,9 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
/* Advance for next redo. Set "newhead" when at the end of the
* redoable changes. */
- if (curbuf->b_u_curhead->uh_prev.ptr == NULL)
+ if (curbuf->b_u_curhead->uh_prev.ptr == NULL) {
curbuf->b_u_newhead = curbuf->b_u_curhead;
+ }
curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev.ptr;
}
}
@@ -1941,8 +1946,8 @@ void undo_time(long step, bool sec, bool file, bool absolute)
long closest_start;
long closest_seq = 0;
long val;
- u_header_T *uhp = NULL;
- u_header_T *last;
+ u_header_T *uhp = NULL;
+ u_header_T *last;
int mark;
int nomark = 0; // shut up compiler
int round;
@@ -1958,8 +1963,9 @@ void undo_time(long step, bool sec, bool file, bool absolute)
u_newcount = 0;
u_oldcount = 0;
- if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) {
u_oldcount = -1;
+ }
/* "target" is the node below which we want to be.
* Init "closest" to a value we can't reach. */
@@ -1975,23 +1981,26 @@ void undo_time(long step, bool sec, bool file, bool absolute)
* the last write, count that as moving one file-write, so
* that ":earlier 1f" undoes all changes since the last save. */
uhp = curbuf->b_u_curhead;
- if (uhp != NULL)
+ if (uhp != NULL) {
uhp = uhp->uh_next.ptr;
- else
+ } else {
uhp = curbuf->b_u_newhead;
- if (uhp != NULL && uhp->uh_save_nr != 0)
+ }
+ if (uhp != NULL && uhp->uh_save_nr != 0) {
/* "uh_save_nr" was set in the last block, that means
* there were no changes since the last write */
target = curbuf->b_u_save_nr_cur + step;
- else
- /* count the changes since the last write as one step */
+ } else {
+ // count the changes since the last write as one step
target = curbuf->b_u_save_nr_cur + step + 1;
- if (target <= 0)
+ }
+ if (target <= 0) {
/* Go to before first write: before the oldest change. Use
* the sequence number for that. */
dofile = false;
+ }
} else {
- /* Moving forward to a newer write. */
+ // Moving forward to a newer write.
target = curbuf->b_u_save_nr_cur + step;
if (target > curbuf->b_u_save_nr_last) {
/* Go to after last write: after the latest change. Use
@@ -2000,11 +2009,13 @@ void undo_time(long step, bool sec, bool file, bool absolute)
dofile = false;
}
}
- } else
+ } else {
target = curbuf->b_u_seq_cur + step;
+ }
if (step < 0) {
- if (target < 0)
+ if (target < 0) {
target = 0;
+ }
closest = -1;
} else {
if (dosec) {
@@ -2044,10 +2055,11 @@ void undo_time(long step, bool sec, bool file, bool absolute)
mark = ++lastmark;
nomark = ++lastmark;
- if (curbuf->b_u_curhead == NULL) /* at leaf of the tree */
+ if (curbuf->b_u_curhead == NULL) { // at leaf of the tree
uhp = curbuf->b_u_newhead;
- else
+ } else {
uhp = curbuf->b_u_curhead;
+ }
while (uhp != NULL) {
uhp->uh_walk = mark;
@@ -2065,17 +2077,17 @@ void undo_time(long step, bool sec, bool file, bool absolute)
* "b_u_seq_cur"). When the timestamp is equal find the
* highest/lowest sequence number. */
if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur
- : uhp->uh_seq > curbuf->b_u_seq_cur)
+ : uhp->uh_seq > curbuf->b_u_seq_cur)
&& ((dosec && val == closest)
? (step < 0
? uhp->uh_seq < closest_seq
- : uhp->uh_seq > closest_seq)
- : closest == closest_start
+ : uhp->uh_seq > closest_seq)
+ : closest == closest_start
|| (val > target
? (closest > target
? val - target <= closest - target
: val - target <= target - closest)
- : (closest > target
+ : (closest > target
? target - val <= closest - target
: target - val <= target - closest)))) {
closest = val;
@@ -2090,38 +2102,41 @@ void undo_time(long step, bool sec, bool file, bool absolute)
break;
}
- /* go down in the tree if we haven't been there */
+ // go down in the tree if we haven't been there
if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark
- && uhp->uh_prev.ptr->uh_walk != mark)
+ && uhp->uh_prev.ptr->uh_walk != mark) {
uhp = uhp->uh_prev.ptr;
-
- /* go to alternate branch if we haven't been there */
+ }
+ // go to alternate branch if we haven't been there
else if (uhp->uh_alt_next.ptr != NULL
&& uhp->uh_alt_next.ptr->uh_walk != nomark
- && uhp->uh_alt_next.ptr->uh_walk != mark)
+ && uhp->uh_alt_next.ptr->uh_walk != mark) {
uhp = uhp->uh_alt_next.ptr;
-
+ }
/* go up in the tree if we haven't been there and we are at the
* start of alternate branches */
else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
&& uhp->uh_next.ptr->uh_walk != nomark
&& uhp->uh_next.ptr->uh_walk != mark) {
- /* If still at the start we don't go through this change. */
- if (uhp == curbuf->b_u_curhead)
+ // If still at the start we don't go through this change.
+ if (uhp == curbuf->b_u_curhead) {
uhp->uh_walk = nomark;
+ }
uhp = uhp->uh_next.ptr;
} else {
- /* need to backtrack; mark this node as useless */
+ // need to backtrack; mark this node as useless
uhp->uh_walk = nomark;
- if (uhp->uh_alt_prev.ptr != NULL)
+ if (uhp->uh_alt_prev.ptr != NULL) {
uhp = uhp->uh_alt_prev.ptr;
- else
+ } else {
uhp = uhp->uh_next.ptr;
+ }
}
}
- if (uhp != NULL) /* found it */
+ if (uhp != NULL) { // found it
break;
+ }
if (absolute) {
EMSGN(_("E830: Undo number %" PRId64 " not found"), step);
@@ -2129,10 +2144,11 @@ void undo_time(long step, bool sec, bool file, bool absolute)
}
if (closest == closest_start) {
- if (step < 0)
+ if (step < 0) {
MSG(_("Already at oldest change"));
- else
+ } else {
MSG(_("Already at newest change"));
+ }
return;
}
@@ -2153,10 +2169,11 @@ target_zero:
change_warning(curbuf, 0);
uhp = curbuf->b_u_curhead;
- if (uhp == NULL)
+ if (uhp == NULL) {
uhp = curbuf->b_u_newhead;
- else
+ } else {
uhp = uhp->uh_next.ptr;
+ }
if (uhp == NULL
|| (target > 0 && uhp->uh_walk != mark)
|| (uhp->uh_seq == target && !above)) {
@@ -2264,21 +2281,21 @@ target_zero:
/// @param do_buf_event If `true`, send buffer updates.
static void u_undoredo(int undo, bool do_buf_event)
{
- char_u **newarray = NULL;
+ char_u **newarray = NULL;
linenr_T oldsize;
linenr_T newsize;
linenr_T top, bot;
linenr_T lnum;
linenr_T newlnum = MAXLNUM;
long i;
- u_entry_T *uep, *nuep;
- u_entry_T *newlist = NULL;
+ u_entry_T *uep, *nuep;
+ u_entry_T *newlist = NULL;
int old_flags;
int new_flags;
fmark_T namedm[NMARKS];
visualinfo_T visualinfo;
bool empty_buffer; // buffer became empty
- u_header_T *curhead = curbuf->b_u_curhead;
+ u_header_T *curhead = curbuf->b_u_curhead;
/* Don't want autocommands using the undo structures here, they are
* invalid till the end. */
@@ -2307,8 +2324,9 @@ static void u_undoredo(int undo, bool do_buf_event)
for (uep = curhead->uh_entry; uep != NULL; uep = nuep) {
top = uep->ue_top;
bot = uep->ue_bot;
- if (bot == 0)
+ if (bot == 0) {
bot = curbuf->b_ml.ml_line_count + 1;
+ }
if (top > curbuf->b_ml.ml_line_count || top >= bot
|| bot > curbuf->b_ml.ml_line_count + 1) {
unblock_autocmds();
@@ -2317,8 +2335,8 @@ static void u_undoredo(int undo, bool do_buf_event)
return;
}
- oldsize = bot - top - 1; /* number of lines before undo */
- newsize = uep->ue_size; /* number of lines after undo */
+ oldsize = bot - top - 1; // number of lines before undo
+ newsize = uep->ue_size; // number of lines after undo
if (top < newlnum) {
/* If the saved cursor is somewhere in this undo block, move it to
@@ -2332,13 +2350,15 @@ static void u_undoredo(int undo, bool do_buf_event)
/* Use the first line that actually changed. Avoids that
* undoing auto-formatting puts the cursor in the previous
* line. */
- for (i = 0; i < newsize && i < oldsize; ++i)
- if (STRCMP(uep->ue_array[i], ml_get(top + 1 + i)) != 0)
+ for (i = 0; i < newsize && i < oldsize; ++i) {
+ if (STRCMP(uep->ue_array[i], ml_get(top + 1 + i)) != 0) {
break;
+ }
+ }
if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) {
newlnum = top;
curwin->w_cursor.lnum = newlnum + 1;
- } else if (i < newsize) {
+ } else if (i < newsize) {
newlnum = top + i;
curwin->w_cursor.lnum = newlnum + 1;
}
@@ -2347,12 +2367,12 @@ static void u_undoredo(int undo, bool do_buf_event)
empty_buffer = false;
- /* delete the lines between top and bot and save them in newarray */
+ // delete the lines between top and bot and save them in newarray
if (oldsize > 0) {
newarray = xmalloc(sizeof(char_u *) * (size_t)oldsize);
- /* delete backwards, it goes faster in most cases */
+ // delete backwards, it goes faster in most cases
for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) {
- /* what can we do when we run out of memory? */
+ // what can we do when we run out of memory?
newarray[i] = u_save_line(lnum);
/* remember we deleted the last line in the buffer, and a
* dummy empty line will be inserted */
@@ -2361,10 +2381,11 @@ static void u_undoredo(int undo, bool do_buf_event)
}
ml_delete(lnum, false);
}
- } else
+ } else {
newarray = NULL;
+ }
- /* insert the lines in u_array between top and bot */
+ // insert the lines in u_array between top and bot
if (newsize) {
for (lnum = top, i = 0; i < newsize; ++i, ++lnum) {
/*
@@ -2395,13 +2416,15 @@ static void u_undoredo(int undo, bool do_buf_event)
changed_lines(top + 1, 0, bot, newsize - oldsize, do_buf_event);
- /* set '[ and '] mark */
- if (top + 1 < curbuf->b_op_start.lnum)
+ // set '[ and '] mark
+ if (top + 1 < curbuf->b_op_start.lnum) {
curbuf->b_op_start.lnum = top + 1;
- if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum)
+ }
+ if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) {
curbuf->b_op_end.lnum = top + 1;
- else if (top + newsize > curbuf->b_op_end.lnum)
+ } else if (top + newsize > curbuf->b_op_end.lnum) {
curbuf->b_op_end.lnum = top + newsize;
+ }
u_newcount += newsize;
u_oldcount += oldsize;
@@ -2424,7 +2447,7 @@ static void u_undoredo(int undo, bool do_buf_event)
undo_info = kv_A(curhead->uh_extmark, i);
extmark_apply_undo(undo_info, undo);
}
- // redo
+ // redo
} else {
for (i = 0; i < (int)kv_size(curhead->uh_extmark); i++) {
undo_info = kv_A(curhead->uh_extmark, i);
@@ -2482,17 +2505,20 @@ static void u_undoredo(int undo, bool do_buf_event)
* Otherwise the cursor should go to the first undone line.
*/
if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum
- && curwin->w_cursor.lnum > 1)
+ && curwin->w_cursor.lnum > 1) {
--curwin->w_cursor.lnum;
+ }
if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) {
if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum) {
curwin->w_cursor.col = curhead->uh_cursor.col;
- if (virtual_active() && curhead->uh_cursor_vcol >= 0)
+ if (virtual_active() && curhead->uh_cursor_vcol >= 0) {
coladvance((colnr_T)curhead->uh_cursor_vcol);
- else
+ } else {
curwin->w_cursor.coladd = 0;
- } else
+ }
+ } else {
beginline(BL_SOL | BL_FIX);
+ }
} else {
/* We get here with the current cursor line being past the end (eg
* after adding lines at the end of the file, and then undoing it).
@@ -2502,23 +2528,25 @@ static void u_undoredo(int undo, bool do_buf_event)
curwin->w_cursor.coladd = 0;
}
- /* Make sure the cursor is on an existing line and column. */
+ // Make sure the cursor is on an existing line and column.
check_cursor();
- /* Remember where we are for "g-" and ":earlier 10s". */
+ // Remember where we are for "g-" and ":earlier 10s".
curbuf->b_u_seq_cur = curhead->uh_seq;
- if (undo)
+ if (undo) {
/* We are below the previous undo. However, to make ":earlier 1s"
* work we compute this as being just above the just undone change. */
curbuf->b_u_seq_cur = curhead->uh_next.ptr ?
- curhead->uh_next.ptr->uh_seq : 0;
+ curhead->uh_next.ptr->uh_seq : 0;
+ }
- /* Remember where we are for ":earlier 1f" and ":later 1f". */
+ // Remember where we are for ":earlier 1f" and ":later 1f".
if (curhead->uh_save_nr != 0) {
- if (undo)
+ if (undo) {
curbuf->b_u_save_nr_cur = curhead->uh_save_nr - 1;
- else
+ } else {
curbuf->b_u_save_nr_cur = curhead->uh_save_nr;
+ }
}
/* The timestamp can be the same for multiple changes, just use the one of
@@ -2534,17 +2562,18 @@ static void u_undoredo(int undo, bool do_buf_event)
/// If we deleted or added lines, report the number of less/more lines.
/// Otherwise, report the number of changes (this may be incorrect
/// in some cases, but it's better than nothing).
-static void u_undo_end(
- bool did_undo, ///< just did an undo
- bool absolute, ///< used ":undo N"
- bool quiet)
+///
+/// @param did_undo just did an undo
+/// @param absolute used ":undo N"
+static void u_undo_end(bool did_undo, bool absolute, bool quiet)
{
- char *msgstr;
- u_header_T *uhp;
+ char *msgstr;
+ u_header_T *uhp;
char_u msgbuf[80];
- if ((fdo_flags & FDO_UNDO) && KeyTyped)
+ if ((fdo_flags & FDO_UNDO) && KeyTyped) {
foldOpenCursor();
+ }
if (quiet
|| global_busy // no messages until global is finished
@@ -2552,28 +2581,30 @@ static void u_undo_end(
return;
}
- if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) {
--u_newcount;
+ }
u_oldcount -= u_newcount;
- if (u_oldcount == -1)
+ if (u_oldcount == -1) {
msgstr = N_("more line");
- else if (u_oldcount < 0)
+ } else if (u_oldcount < 0) {
msgstr = N_("more lines");
- else if (u_oldcount == 1)
+ } else if (u_oldcount == 1) {
msgstr = N_("line less");
- else if (u_oldcount > 1)
+ } else if (u_oldcount > 1) {
msgstr = N_("fewer lines");
- else {
+ } else {
u_oldcount = u_newcount;
- if (u_newcount == 1)
+ if (u_newcount == 1) {
msgstr = N_("change");
- else
+ } else {
msgstr = N_("changes");
+ }
}
if (curbuf->b_u_curhead != NULL) {
- /* For ":undo N" we prefer a "after #N" message. */
+ // For ":undo N" we prefer a "after #N" message.
if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) {
uhp = curbuf->b_u_curhead->uh_next.ptr;
did_undo = false;
@@ -2600,14 +2631,13 @@ static void u_undo_end(
}
}
- smsg_attr_keep(
- 0,
- _("%" PRId64 " %s; %s #%" PRId64 " %s"),
- u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount,
- _(msgstr),
- did_undo ? _("before") : _("after"),
- uhp == NULL ? (int64_t)0L : (int64_t)uhp->uh_seq,
- msgbuf);
+ smsg_attr_keep(0,
+ _("%" PRId64 " %s; %s #%" PRId64 " %s"),
+ u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount,
+ _(msgstr),
+ did_undo ? _("before") : _("after"),
+ uhp == NULL ? (int64_t)0L : (int64_t)uhp->uh_seq,
+ msgbuf);
}
/// u_sync: stop adding to the current entry list
@@ -2634,7 +2664,7 @@ void u_sync(bool force)
void ex_undolist(exarg_T *eap)
{
garray_T ga;
- u_header_T *uhp;
+ u_header_T *uhp;
int mark;
int nomark;
int changes = 1;
@@ -2657,28 +2687,29 @@ void ex_undolist(exarg_T *eap)
add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
uhp->uh_time);
if (uhp->uh_save_nr > 0) {
- while (STRLEN(IObuff) < 33)
+ while (STRLEN(IObuff) < 33) {
STRCAT(IObuff, " ");
+ }
vim_snprintf_add((char *)IObuff, IOSIZE,
- " %3ld", uhp->uh_save_nr);
+ " %3ld", uhp->uh_save_nr);
}
GA_APPEND(char_u *, &ga, vim_strsave(IObuff));
}
uhp->uh_walk = mark;
- /* go down in the tree if we haven't been there */
+ // go down in the tree if we haven't been there
if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark
&& uhp->uh_prev.ptr->uh_walk != mark) {
uhp = uhp->uh_prev.ptr;
++changes;
}
- /* go to alternate branch if we haven't been there */
+ // go to alternate branch if we haven't been there
else if (uhp->uh_alt_next.ptr != NULL
&& uhp->uh_alt_next.ptr->uh_walk != nomark
- && uhp->uh_alt_next.ptr->uh_walk != mark)
+ && uhp->uh_alt_next.ptr->uh_walk != mark) {
uhp = uhp->uh_alt_next.ptr;
-
+ }
/* go up in the tree if we haven't been there and we are at the
* start of alternate branches */
else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL
@@ -2687,20 +2718,20 @@ void ex_undolist(exarg_T *eap)
uhp = uhp->uh_next.ptr;
--changes;
} else {
- /* need to backtrack; mark this node as done */
+ // need to backtrack; mark this node as done
uhp->uh_walk = nomark;
- if (uhp->uh_alt_prev.ptr != NULL)
+ if (uhp->uh_alt_prev.ptr != NULL) {
uhp = uhp->uh_alt_prev.ptr;
- else {
+ } else {
uhp = uhp->uh_next.ptr;
--changes;
}
}
}
- if (GA_EMPTY(&ga))
+ if (GA_EMPTY(&ga)) {
MSG(_("Nothing to undo"));
- else {
+ } else {
sort_strings((char_u **)ga.ga_data, ga.ga_len);
msg_start();
@@ -2757,17 +2788,18 @@ void u_unchanged(buf_T *buf)
*/
void u_find_first_changed(void)
{
- u_header_T *uhp = curbuf->b_u_newhead;
- u_entry_T *uep;
+ u_header_T *uhp = curbuf->b_u_newhead;
+ u_entry_T *uep;
linenr_T lnum;
- if (curbuf->b_u_curhead != NULL || uhp == NULL)
- return; /* undid something in an autocmd? */
-
- /* Check that the last undo block was for the whole file. */
+ if (curbuf->b_u_curhead != NULL || uhp == NULL) {
+ return; // undid something in an autocmd?
+ }
+ // Check that the last undo block was for the whole file.
uep = uhp->uh_entry;
- if (uep->ue_top != 0 || uep->ue_bot != 0)
+ if (uep->ue_top != 0 || uep->ue_bot != 0) {
return;
+ }
for (lnum = 1; lnum < curbuf->b_ml.ml_line_count
&& lnum <= uep->ue_size; lnum++) {
@@ -2778,7 +2810,7 @@ void u_find_first_changed(void)
}
}
if (curbuf->b_ml.ml_line_count != uep->ue_size) {
- /* lines added or deleted at the end, put the cursor there */
+ // lines added or deleted at the end, put the cursor there
clearpos(&(uhp->uh_cursor));
uhp->uh_cursor.lnum = lnum;
}
@@ -2790,27 +2822,30 @@ void u_find_first_changed(void)
*/
void u_update_save_nr(buf_T *buf)
{
- u_header_T *uhp;
+ u_header_T *uhp;
++buf->b_u_save_nr_last;
buf->b_u_save_nr_cur = buf->b_u_save_nr_last;
uhp = buf->b_u_curhead;
- if (uhp != NULL)
+ if (uhp != NULL) {
uhp = uhp->uh_next.ptr;
- else
+ } else {
uhp = buf->b_u_newhead;
- if (uhp != NULL)
+ }
+ if (uhp != NULL) {
uhp->uh_save_nr = buf->b_u_save_nr_last;
+ }
}
static void u_unch_branch(u_header_T *uhp)
{
- u_header_T *uh;
+ u_header_T *uh;
for (uh = uhp; uh != NULL; uh = uh->uh_prev.ptr) {
uh->uh_flags |= UH_CHANGED;
- if (uh->uh_alt_next.ptr != NULL)
- u_unch_branch(uh->uh_alt_next.ptr); /* recursive */
+ if (uh->uh_alt_next.ptr != NULL) {
+ u_unch_branch(uh->uh_alt_next.ptr); // recursive
+ }
}
}
@@ -2829,11 +2864,11 @@ static u_entry_T *u_get_headentry(buf_T *buf)
/*
* u_getbot(): compute the line number of the previous u_save
- * It is called only when b_u_synced is false.
+ * It is called only when b_u_synced is false.
*/
static void u_getbot(buf_T *buf)
{
- u_entry_T *uep;
+ u_entry_T *uep;
linenr_T extra;
uep = u_get_headentry(buf); // check for corrupt undo list
@@ -2864,95 +2899,91 @@ static void u_getbot(buf_T *buf)
buf->b_u_synced = true;
}
-/*
- * Free one header "uhp" and its entry list and adjust the pointers.
- */
-static void
-u_freeheader(
- buf_T *buf,
- u_header_T *uhp,
- u_header_T **uhpp // if not NULL reset when freeing this header
-)
+/// Free one header "uhp" and its entry list and adjust the pointers.
+///
+/// @param uhpp if not NULL reset when freeing this header
+static void u_freeheader(buf_T *buf, u_header_T *uhp, u_header_T **uhpp)
{
- u_header_T *uhap;
+ u_header_T *uhap;
/* When there is an alternate redo list free that branch completely,
* because we can never go there. */
- if (uhp->uh_alt_next.ptr != NULL)
+ if (uhp->uh_alt_next.ptr != NULL) {
u_freebranch(buf, uhp->uh_alt_next.ptr, uhpp);
+ }
- if (uhp->uh_alt_prev.ptr != NULL)
+ if (uhp->uh_alt_prev.ptr != NULL) {
uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL;
+ }
- /* Update the links in the list to remove the header. */
- if (uhp->uh_next.ptr == NULL)
+ // Update the links in the list to remove the header.
+ if (uhp->uh_next.ptr == NULL) {
buf->b_u_oldhead = uhp->uh_prev.ptr;
- else
+ } else {
uhp->uh_next.ptr->uh_prev.ptr = uhp->uh_prev.ptr;
+ }
- if (uhp->uh_prev.ptr == NULL)
+ if (uhp->uh_prev.ptr == NULL) {
buf->b_u_newhead = uhp->uh_next.ptr;
- else
+ } else {
for (uhap = uhp->uh_prev.ptr; uhap != NULL;
- uhap = uhap->uh_alt_next.ptr)
+ uhap = uhap->uh_alt_next.ptr) {
uhap->uh_next.ptr = uhp->uh_next.ptr;
+ }
+ }
u_freeentries(buf, uhp, uhpp);
}
-/*
- * Free an alternate branch and any following alternate branches.
- */
-static void
-u_freebranch(
- buf_T *buf,
- u_header_T *uhp,
- u_header_T **uhpp // if not NULL reset when freeing this header
-)
+/// Free an alternate branch and any following alternate branches.
+///
+/// @param uhpp if not NULL reset when freeing this header
+static void u_freebranch(buf_T *buf, u_header_T *uhp, u_header_T **uhpp)
{
- u_header_T *tofree, *next;
+ u_header_T *tofree, *next;
/* If this is the top branch we may need to use u_freeheader() to update
* all the pointers. */
if (uhp == buf->b_u_oldhead) {
- while (buf->b_u_oldhead != NULL)
+ while (buf->b_u_oldhead != NULL) {
u_freeheader(buf, buf->b_u_oldhead, uhpp);
+ }
return;
}
- if (uhp->uh_alt_prev.ptr != NULL)
+ if (uhp->uh_alt_prev.ptr != NULL) {
uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL;
+ }
next = uhp;
while (next != NULL) {
tofree = next;
- if (tofree->uh_alt_next.ptr != NULL)
- u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp); /* recursive */
+ if (tofree->uh_alt_next.ptr != NULL) {
+ u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp); // recursive
+ }
next = tofree->uh_prev.ptr;
u_freeentries(buf, tofree, uhpp);
}
}
-/*
- * Free all the undo entries for one header and the header itself.
- * This means that "uhp" is invalid when returning.
- */
-static void
-u_freeentries(
- buf_T *buf,
- u_header_T *uhp,
- u_header_T **uhpp // if not NULL reset when freeing this header
-)
+/// Free all the undo entries for one header and the header itself.
+/// This means that "uhp" is invalid when returning.
+///
+/// @param uhpp if not NULL reset when freeing this header
+static void u_freeentries(buf_T *buf, u_header_T *uhp, u_header_T **uhpp)
{
- u_entry_T *uep, *nuep;
+ u_entry_T *uep, *nuep;
- /* Check for pointers to the header that become invalid now. */
- if (buf->b_u_curhead == uhp)
+ // Check for pointers to the header that become invalid now.
+ if (buf->b_u_curhead == uhp) {
buf->b_u_curhead = NULL;
- if (buf->b_u_newhead == uhp)
- buf->b_u_newhead = NULL; /* freeing the newest entry */
- if (uhpp != NULL && uhp == *uhpp)
+ }
+ if (buf->b_u_newhead == uhp) {
+ buf->b_u_newhead = NULL; // freeing the newest entry
+ }
+ if (uhpp != NULL && uhp == *uhpp) {
*uhpp = NULL;
+ }
for (uep = uhp->uh_entry; uep != NULL; uep = nuep) {
nuep = uep->ue_next;
@@ -2973,8 +3004,9 @@ u_freeentries(
*/
static void u_freeentry(u_entry_T *uep, long n)
{
- while (n > 0)
+ while (n > 0) {
xfree(uep->ue_array[--n]);
+ }
xfree((char_u *)uep->ue_array);
#ifdef U_DEBUG
uep->ue_magic = 0;
@@ -2999,16 +3031,19 @@ void u_clearall(buf_T *buf)
*/
void u_saveline(linenr_T lnum)
{
- if (lnum == curbuf->b_u_line_lnum) /* line is already saved */
+ if (lnum == curbuf->b_u_line_lnum) { // line is already saved
return;
- if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) /* should never happen */
+ }
+ if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { // should never happen
return;
+ }
u_clearline();
curbuf->b_u_line_lnum = lnum;
- if (curwin->w_cursor.lnum == lnum)
+ if (curwin->w_cursor.lnum == lnum) {
curbuf->b_u_line_colnr = curwin->w_cursor.col;
- else
+ } else {
curbuf->b_u_line_colnr = 0;
+ }
curbuf->b_u_line_ptr = u_save_line(lnum);
}
@@ -3033,7 +3068,7 @@ void u_clearline(void)
void u_undoline(void)
{
colnr_T t;
- char_u *oldp;
+ char_u *oldp;
if (curbuf->b_u_line_ptr == NULL
|| curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count) {
@@ -3054,8 +3089,9 @@ void u_undoline(void)
curbuf->b_u_line_ptr = oldp;
t = curbuf->b_u_line_colnr;
- if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum)
+ if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) {
curbuf->b_u_line_colnr = curwin->w_cursor.col;
+ }
curwin->w_cursor.col = t;
curwin->w_cursor.lnum = curbuf->b_u_line_lnum;
check_cursor_col();
@@ -3106,8 +3142,8 @@ bool bufIsChanged(buf_T *buf)
{
// In a "prompt" buffer we do respect 'modified', so that we can control
// closing the window by setting or resetting that option.
- return (!bt_dontwrite(buf) || bt_prompt(buf))
- && (buf->b_changed || file_ff_differs(buf, true));
+ return (!bt_dontwrite(buf) || bt_prompt(buf))
+ && (buf->b_changed || file_ff_differs(buf, true));
}
// Return true if any buffer has changes. Also buffers that are not written.
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 7c197f1b7f..bc06ef0b98 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -6,32 +6,32 @@
/// Nvim was forked from Vim 7.4.160.
/// Vim originated from Stevie version 3.6 (Fish disk 217) by GRWalter (Fred).
-#include <inttypes.h>
#include <assert.h>
+#include <inttypes.h>
#include <limits.h>
#include "nvim/api/private/helpers.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
-#include "nvim/iconv.h"
-#include "nvim/version.h"
#include "nvim/charset.h"
+#include "nvim/iconv.h"
+#include "nvim/lua/executor.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
-#include "nvim/lua/executor.h"
+#include "nvim/version.h"
+#include "nvim/vim.h"
// version info generated by the build system
#include "auto/versiondef.h"
// for ":version", ":intro", and "nvim --version"
#ifndef NVIM_VERSION_MEDIUM
-#define NVIM_VERSION_MEDIUM "v" STR(NVIM_VERSION_MAJOR)\
-"." STR(NVIM_VERSION_MINOR) "." STR(NVIM_VERSION_PATCH)\
-NVIM_VERSION_PRERELEASE
+# define NVIM_VERSION_MEDIUM "v" STR(NVIM_VERSION_MAJOR)\
+ "." STR(NVIM_VERSION_MINOR) "." STR(NVIM_VERSION_PATCH)\
+ NVIM_VERSION_PRERELEASE
#endif
#define NVIM_VERSION_LONG "NVIM " NVIM_VERSION_MEDIUM
@@ -50,23 +50,23 @@ char *version_cflags = "Compilation: " NVIM_VERSION_CFLAGS;
static char *features[] = {
#ifdef HAVE_ACL
-"+acl",
+ "+acl",
#else
-"-acl",
+ "-acl",
#endif
#if defined(HAVE_ICONV)
-"+iconv",
+ "+iconv",
#else
-"-iconv",
+ "-iconv",
#endif
#ifdef FEAT_TUI
-"+tui",
+ "+tui",
#else
-"-tui",
+ "-tui",
#endif
-NULL
+ NULL
};
// clang-format off
@@ -2019,7 +2019,7 @@ void ex_version(exarg_T *eap)
/// @param wrap
static void version_msg_wrap(char_u *s, int wrap)
{
- int len = (int)vim_strsize(s) + (wrap ? 2 : 0);
+ int len = vim_strsize(s) + (wrap ? 2 : 0);
if (!got_int
&& (len < Columns)
@@ -2070,7 +2070,7 @@ void list_in_columns(char_u **items, int size, int current)
// Find the length of the longest item, use that + 1 as the column width.
int i;
for (i = 0; size < 0 ? items[i] != NULL : i < size; i++) {
- int l = (int)vim_strsize(items[i]) + (i == current ? 2 : 0);
+ int l = vim_strsize(items[i]) + (i == current ? 2 : 0);
if (l > width) {
width = l;
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index f61f9a5e01..62536a0600 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -305,18 +305,6 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
#include "nvim/buffer_defs.h" // buffer and windows
#include "nvim/ex_cmds_defs.h" // Ex command defines
-// Used for flags in do_in_path()
-#define DIP_ALL 0x01 // all matches, not just the first one
-#define DIP_DIR 0x02 // find directories instead of files
-#define DIP_ERR 0x04 // give an error message when none found
-#define DIP_START 0x08 // also use "start" directory in 'packpath'
-#define DIP_OPT 0x10 // also use "opt" directory in 'packpath'
-#define DIP_NORTP 0x20 // do not use 'runtimepath'
-#define DIP_NOAFTER 0x40 // skip "after" directories
-#define DIP_AFTER 0x80 // only use "after" directories
-#define DIP_LUA 0x100 // also use ".lua" files
-#define DIP_DIRFILE 0x200 // find both files and directories
-
// Lowest number used for window ID. Cannot have this many windows per tab.
#define LOWEST_WIN_ID 1000
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index c2aa923c49..39687a8e8d 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -936,7 +936,7 @@ static const char *intchar2str(const int ch)
}
#ifdef UNIT_TESTING
-#include <stdio.h>
+# include <stdio.h>
REAL_FATTR_UNUSED
static inline void viml_pexpr_debug_print_ast_node(const ExprASTNode *const *const eastnode_p,
@@ -971,14 +971,14 @@ static inline void viml_pexpr_debug_print_token(const ParserState *const pstate,
{
fprintf(stderr, "\ntkn: %s\n", viml_pexpr_repr_token(pstate, token, NULL));
}
-#define PSTACK(msg) \
+# define PSTACK(msg) \
viml_pexpr_debug_print_ast_stack(&ast_stack, #msg)
-#define PSTACK_P(msg) \
+# define PSTACK_P(msg) \
viml_pexpr_debug_print_ast_stack(ast_stack, #msg)
-#define PNODE_P(eastnode_p, msg) \
+# define PNODE_P(eastnode_p, msg) \
viml_pexpr_debug_print_ast_node((const ExprASTNode *const *)eastnode_p, \
(#msg))
-#define PTOKEN(tkn) \
+# define PTOKEN(tkn) \
viml_pexpr_debug_print_token(pstate, tkn)
#endif
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 400962f993..ff97eaa757 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -62,7 +62,7 @@
#define NOWIN (win_T *)-1 // non-existing window
-# define ROWS_AVAIL (Rows - p_ch - tabline_height())
+#define ROWS_AVAIL (Rows - p_ch - tabline_height())
/// flags for win_enter_ext()
typedef enum {
@@ -90,7 +90,7 @@ void do_window(int nchar, long Prenum, int xchar)
Prenum1 = Prenum == 0 ? 1 : Prenum;
-# define CHECK_CMDWIN \
+#define CHECK_CMDWIN \
do { \
if (cmdwin_type != 0) { \
EMSG(_(e_cmdwin)); \
@@ -853,12 +853,12 @@ void ui_ext_win_position(win_T *wp)
bool east = c.anchor & kFloatAnchorEast;
bool south = c.anchor & kFloatAnchorSouth;
- int comp_row = (int)row - (south ? wp->w_height : 0);
- int comp_col = (int)col - (east ? wp->w_width : 0);
+ int comp_row = (int)row - (south ? wp->w_height_outer : 0);
+ int comp_col = (int)col - (east ? wp->w_width_outer : 0);
comp_row += grid->comp_row;
comp_col += grid->comp_col;
- comp_row = MAX(MIN(comp_row, Rows-wp->w_height_outer-1), 0);
- comp_col = MAX(MIN(comp_col, Columns-wp->w_width_outer), 0);
+ comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - 1), 0);
+ comp_col = MAX(MIN(comp_col, Columns - wp->w_width_outer), 0);
wp->w_winrow = comp_row;
wp->w_wincol = comp_col;
bool valid = (wp->w_redr_type == 0);
diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg
index 08296a644a..db0c50ff22 100644
--- a/src/uncrustify.cfg
+++ b/src/uncrustify.cfg
@@ -1,4 +1,4 @@
-# Uncrustify-0.73.0-168-f20a083e
+# Uncrustify-0.73.0-195-1f883c691
#
# General options
@@ -259,7 +259,7 @@ sp_before_byref_func = ignore # ignore/add/remove/force/not_defined
# following word.
#
# Default: force
-sp_after_type = ignore # ignore/add/remove/force/not_defined
+sp_after_type = force # ignore/add/remove/force/not_defined
# Add or remove space between 'decltype(...)' and word,
# brace or function call.
@@ -447,12 +447,18 @@ sp_before_ellipsis = ignore # ignore/add/remove/force/not_defined
# Add or remove space between a type and '...'.
sp_type_ellipsis = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between a '*' and '...'.
+sp_ptr_type_ellipsis = ignore # ignore/add/remove/force/not_defined
+
# (D) Add or remove space between a type and '?'.
sp_type_question = ignore # ignore/add/remove/force/not_defined
# Add or remove space between ')' and '...'.
sp_paren_ellipsis = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between '&&' and '...'.
+sp_byref_ellipsis = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space between ')' and a qualifier such as 'const'.
sp_paren_qualifier = ignore # ignore/add/remove/force/not_defined
@@ -507,6 +513,12 @@ sp_sizeof_ellipsis = ignore # ignore/add/remove/force/not_defined
# Add or remove space between 'sizeof...' and '('.
sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force/not_defined
+# Add or remove space between '...' and a parameter pack.
+sp_ellipsis_parameter_pack = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a parameter pack and '...'.
+sp_parameter_pack_ellipsis = ignore # ignore/add/remove/force/not_defined
+
# Add or remove space between 'decltype' and '('.
sp_decltype_paren = ignore # ignore/add/remove/force/not_defined
@@ -523,14 +535,21 @@ sp_inside_braces_struct = ignore # ignore/add/remove/force/not_defined
sp_inside_braces_oc_dict = ignore # ignore/add/remove/force/not_defined
# Add or remove space after open brace in an unnamed temporary
-# direct-list-initialization.
+# direct-list-initialization
+# if statement is a brace_init_lst
+# works only if sp_brace_brace is set to ignore.
sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined
# Add or remove space before close brace in an unnamed temporary
-# direct-list-initialization.
+# direct-list-initialization
+# if statement is a brace_init_lst
+# works only if sp_brace_brace is set to ignore.
sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined
-# Add or remove space inside an unnamed temporary direct-list-initialization.
+# Add or remove space inside an unnamed temporary direct-list-initialization
+# if statement is a brace_init_lst
+# works only if sp_brace_brace is set to ignore
+# works only if sp_before_type_brace_init_lst_close is set to ignore.
sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined
# Add or remove space inside '{' and '}'.
@@ -775,7 +794,7 @@ sp_sign = ignore # ignore/add/remove/force/not_defined
# applied, as in '(--x)' or 'y++;'.
#
# Default: remove
-sp_incdec = ignore # ignore/add/remove/force/not_defined
+sp_incdec = remove # ignore/add/remove/force/not_defined
# Add or remove space before a backslash-newline at the end of a line.
#
@@ -2020,7 +2039,7 @@ nl_constr_colon = ignore # ignore/add/remove/force/not_defined
# Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }'
# into a single line. If true, prevents other brace newline rules from turning
-# such code into four lines.
+# such code into four lines. If true, it also preserves one-liner namespaces.
nl_namespace_two_to_one_liner = false # true/false
# Whether to remove a newline in simple unbraced if statements, turning them
@@ -3029,7 +3048,7 @@ mod_sort_oc_property_nullability_weight = 0 # number
# Add or remove indentation of preprocessor directives inside #if blocks
# at brace level 0 (file-level).
-pp_indent = ignore # ignore/add/remove/force/not_defined
+pp_indent = remove # ignore/add/remove/force/not_defined
# Whether to indent #if/#else/#endif at the brace level. If false, these are
# indented from column 1.
@@ -3044,7 +3063,7 @@ pp_indent_at_level = false # true/false
pp_indent_count = 1 # unsigned number
# Add or remove space after # based on pp_level of #if blocks.
-pp_space = ignore # ignore/add/remove/force/not_defined
+pp_space = force # ignore/add/remove/force/not_defined
# Sets the number of spaces per level added with pp_space.
pp_space_count = 0 # unsigned number
@@ -3255,29 +3274,29 @@ debug_truncate = 0 # unsigned number
# `macro-close END_MESSAGE_MAP`
#
#
-set PREPROC FUNC_API_CHECK_TEXTLOCK
-set PREPROC FUNC_API_DEPRECATED_SINCE
-set PREPROC FUNC_API_FAST
-set PREPROC FUNC_API_LUA_ONLY
-set PREPROC FUNC_API_NOEXPORT
-set PREPROC FUNC_API_REMOTE_ONLY
-set PREPROC FUNC_API_SINCE
-set PREPROC FUNC_ATTR_ALWAYS_INLINE
-set PREPROC FUNC_ATTR_CONST
-set PREPROC FUNC_ATTR_MALLOC
-set PREPROC FUNC_ATTR_NONNULL_ALL
-set PREPROC FUNC_ATTR_NONNULL_ARG
-set PREPROC FUNC_ATTR_NONNULL_RET
-set PREPROC FUNC_ATTR_NORETURN
-set PREPROC FUNC_ATTR_NO_SANITIZE_UNDEFINED
-set PREPROC FUNC_ATTR_PRINTF
-set PREPROC FUNC_ATTR_PURE
-set PREPROC FUNC_ATTR_UNUSED
-set PREPROC FUNC_ATTR_WARN_UNUSED_RESULT
-set PREPROC REAL_FATTR_ALWAYS_INLINE
-set PREPROC REAL_FATTR_CONST
-set PREPROC REAL_FATTR_NONNULL_ALL
-set PREPROC REAL_FATTR_PURE
-set PREPROC REAL_FATTR_WARN_UNUSED_RESULT
+set QUESTION FUNC_API_CHECK_TEXTLOCK
+set QUESTION FUNC_API_DEPRECATED_SINCE
+set QUESTION FUNC_API_FAST
+set QUESTION FUNC_API_LUA_ONLY
+set QUESTION FUNC_API_NOEXPORT
+set QUESTION FUNC_API_REMOTE_ONLY
+set QUESTION FUNC_API_SINCE
+set QUESTION FUNC_ATTR_ALWAYS_INLINE
+set QUESTION FUNC_ATTR_CONST
+set QUESTION FUNC_ATTR_MALLOC
+set QUESTION FUNC_ATTR_NONNULL_ALL
+set QUESTION FUNC_ATTR_NONNULL_ARG
+set QUESTION FUNC_ATTR_NONNULL_RET
+set QUESTION FUNC_ATTR_NORETURN
+set QUESTION FUNC_ATTR_NO_SANITIZE_UNDEFINED
+set QUESTION FUNC_ATTR_PRINTF
+set QUESTION FUNC_ATTR_PURE
+set QUESTION FUNC_ATTR_UNUSED
+set QUESTION FUNC_ATTR_WARN_UNUSED_RESULT
+set QUESTION REAL_FATTR_ALWAYS_INLINE
+set QUESTION REAL_FATTR_CONST
+set QUESTION REAL_FATTR_NONNULL_ALL
+set QUESTION REAL_FATTR_PURE
+set QUESTION REAL_FATTR_WARN_UNUSED_RESULT
# option(s) with 'not default' value: 62
#
diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c
index f35ac5d0b0..cfcbb5d982 100644
--- a/src/xdiff/xdiffi.c
+++ b/src/xdiff/xdiffi.c
@@ -1,6 +1,3 @@
-// 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
-
/*
* LibXDiff by Davide Libenzi ( File Differential Library )
* Copyright (C) 2003 Davide Libenzi
diff --git a/src/xdiff/xemit.c b/src/xdiff/xemit.c
index 23c6e2d993..b578e7a9d5 100644
--- a/src/xdiff/xemit.c
+++ b/src/xdiff/xemit.c
@@ -1,6 +1,3 @@
-// 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
-
/*
* LibXDiff by Davide Libenzi ( File Differential Library )
* Copyright (C) 2003 Davide Libenzi
diff --git a/src/xdiff/xhistogram.c b/src/xdiff/xhistogram.c
index 3c84f35626..8598a8550d 100644
--- a/src/xdiff/xhistogram.c
+++ b/src/xdiff/xhistogram.c
@@ -1,6 +1,3 @@
-// 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
-
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in JGit's IP log.
diff --git a/src/xdiff/xpatience.c b/src/xdiff/xpatience.c
index 5f547ca5c0..f78c897ad8 100644
--- a/src/xdiff/xpatience.c
+++ b/src/xdiff/xpatience.c
@@ -1,6 +1,3 @@
-// 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
-
/*
* LibXDiff by Davide Libenzi ( File Differential Library )
* Copyright (C) 2003-2016 Davide Libenzi, Johannes E. Schindelin
diff --git a/src/xdiff/xprepare.c b/src/xdiff/xprepare.c
index f13822e4fa..abeb8fb84e 100644
--- a/src/xdiff/xprepare.c
+++ b/src/xdiff/xprepare.c
@@ -1,6 +1,3 @@
-// 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
-
/*
* LibXDiff by Davide Libenzi ( File Differential Library )
* Copyright (C) 2003 Davide Libenzi
diff --git a/src/xdiff/xutils.c b/src/xdiff/xutils.c
index 65aa50497d..f13a854536 100644
--- a/src/xdiff/xutils.c
+++ b/src/xdiff/xutils.c
@@ -1,6 +1,3 @@
-// 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
-
/*
* LibXDiff by Davide Libenzi ( File Differential Library )
* Copyright (C) 2003 Davide Libenzi
diff --git a/test/config/paths.lua.in b/test/config/paths.lua.in
index 7fe5d8ad80..e3979981ba 100644
--- a/test/config/paths.lua.in
+++ b/test/config/paths.lua.in
@@ -19,5 +19,6 @@ if module.test_luajit_prg == '' then
end
end
table.insert(module.include_paths, "${CMAKE_BINARY_DIR}/include")
+table.insert(module.include_paths, "${CMAKE_BINARY_DIR}/src/nvim/auto")
return module
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index 37331d11c7..6f929ad1ca 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -21,7 +21,7 @@ describe('nvim_get_commands', function()
it('validates input', function()
eq('builtin=true not implemented', pcall_err(meths.get_commands,
{builtin=true}))
- eq('unexpected key: foo', pcall_err(meths.get_commands,
+ eq("Invalid key: 'foo'", pcall_err(meths.get_commands,
{foo='blah'}))
end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 4194945645..dd8eef7ca0 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -436,16 +436,16 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end)
it('error on invalid optnames', function()
- eq('Invalid key: silentt',
+ eq("Invalid key: 'silentt'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {silentt = true}))
- eq('Invalid key: sidd',
+ eq("Invalid key: 'sidd'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {sidd = false}))
- eq('Invalid key: nowaiT',
+ eq("Invalid key: 'nowaiT'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {nowaiT = false}))
end)
it('error on <buffer> option key', function()
- eq('Invalid key: buffer',
+ eq("Invalid key: 'buffer'",
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', {buffer = true}))
end)
@@ -454,8 +454,8 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
-- note: need '%' to escape hyphens, which have special meaning in lua
it('throws an error when given non-boolean value for '..opt, function()
local opts = {}
- opts[opt] = 2
- eq('Gave non-boolean value for an opt: '..opt,
+ opts[opt] = 'fooo'
+ eq(opt..' is not a boolean',
pcall_err(meths.set_keymap, 'n', 'lhs', 'rhs', opts))
end)
end
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index ffef6a6066..6bcf8dd91f 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -12,10 +12,12 @@ local funcs = helpers.funcs
local iswin = helpers.iswin
local meths = helpers.meths
local matches = helpers.matches
+local mkdir_p = helpers.mkdir_p
local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
local is_os = helpers.is_os
local parse_context = helpers.parse_context
local request = helpers.request
+local rmdir = helpers.rmdir
local source = helpers.source
local next_msg = helpers.next_msg
local tmpname = helpers.tmpname
@@ -1117,7 +1119,7 @@ describe('API', function()
describe('nvim_get_context', function()
it('validates args', function()
- eq('unexpected key: blah',
+ eq("Invalid key: 'blah'",
pcall_err(nvim, 'get_context', {blah={}}))
eq('invalid value for key: types',
pcall_err(nvim, 'get_context', {types=42}))
@@ -1574,6 +1576,18 @@ describe('API', function()
end)
describe('nvim_list_runtime_paths', function()
+ setup(function()
+ local pathsep = helpers.get_pathsep()
+ mkdir_p('Xtest'..pathsep..'a')
+ mkdir_p('Xtest'..pathsep..'b')
+ end)
+ teardown(function()
+ rmdir 'Xtest'
+ end)
+ before_each(function()
+ meths.set_current_dir 'Xtest'
+ end)
+
it('returns nothing with empty &runtimepath', function()
meths.set_option('runtimepath', '')
eq({}, meths.list_runtime_paths())
@@ -1601,8 +1615,7 @@ describe('API', function()
local long_path = ('/a'):rep(8192)
meths.set_option('runtimepath', long_path)
local paths_list = meths.list_runtime_paths()
- neq({long_path}, paths_list)
- eq({long_path:sub(1, #(paths_list[1]))}, paths_list)
+ eq({}, paths_list)
end)
end)
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index c49d6405f4..11755a9d97 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -1,8 +1,9 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
- ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf,
+ ok, feed, insert, eval, tabpage = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
- helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval
+ helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval,
+ helpers.tabpage
local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths
local funcs = helpers.funcs
@@ -11,6 +12,7 @@ local NIL = helpers.NIL
local meths = helpers.meths
local command = helpers.command
local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
-- check if str is visible at the beginning of some line
local function is_visible(str)
@@ -206,7 +208,7 @@ describe('API/win', function()
end)
end)
- describe('{get,set}_option', function()
+ describe('nvim_win_get_option, nvim_win_set_option', function()
it('works', function()
curwin('set_option', 'colorcolumn', '4,3')
eq('4,3', curwin('get_option', 'colorcolumn'))
@@ -224,6 +226,18 @@ describe('API/win', function()
pcall_err(curwin, 'get_option', 'statusline'))
eq('', eval('&l:statusline')) -- confirm local value was not copied
end)
+
+ it('after switching windows #15390', function()
+ nvim('command', 'tabnew')
+ local tab1 = unpack(nvim('list_tabpages'))
+ local win1 = unpack(tabpage('list_wins', tab1))
+ window('set_option', win1, 'statusline', 'window-status')
+ nvim('command', 'split')
+ nvim('command', 'wincmd J')
+ nvim('command', 'wincmd j')
+ eq('window-status', window('get_option', win1, 'statusline'))
+ assert_alive()
+ end)
end)
describe('get_position', function()
@@ -354,13 +368,13 @@ describe('API/win', function()
local win = meths.open_win(0, true, {
relative='editor', row=10, col=10, width=50, height=10
})
- local tabpage = eval('tabpagenr()')
+ local tab = eval('tabpagenr()')
command('tabprevious')
eq(1, eval('tabpagenr()'))
meths.win_close(win, false)
- eq(1001, meths.tabpage_get_win(tabpage).id)
- helpers.assert_alive()
+ eq(1001, meths.tabpage_get_win(tab).id)
+ assert_alive()
end)
end)
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index ff93f88a2d..bf2559f8d7 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -20,6 +20,7 @@ local retry = helpers.retry
local rmdir = helpers.rmdir
local sleep = helpers.sleep
local iswin = helpers.iswin
+local startswith = helpers.startswith
local write_file = helpers.write_file
local meths = helpers.meths
@@ -310,7 +311,8 @@ describe('startup', function()
end)
local function pack_clear(cmd)
- clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
+ -- add packages after config dir in rtp but before config/after
+ clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
end
@@ -351,12 +353,57 @@ describe('startup', function()
it("handles the correct order with start packages and after/", function()
pack_clear [[ lua _G.test_loadorder = {} vim.cmd "runtime! filen.lua" ]]
- eq({'ordinary', 'FANCY', 'ordinary after', 'FANCY after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with start packages and after/ after startup", function()
+ pack_clear [[ lua _G.test_loadorder = {} ]]
+ command [[ runtime! filen.lua ]]
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with globpath(&rtp, ...)", function()
+ pack_clear [[ set loadplugins | lua _G.test_loadorder = {} ]]
+ command [[
+ for x in globpath(&rtp, "filen.lua",1,1)
+ call v:lua.dofile(x)
+ endfor
+ ]]
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+
+ local rtp = meths.get_option'rtp'
+ ok(startswith(rtp, 'test/functional/fixtures/nvim,test/functional/fixtures/pack/*/start/*,test/functional/fixtures/start/*,test/functional/fixtures,test/functional/fixtures/middle,'), 'rtp='..rtp)
end)
it("handles the correct order with opt packages and after/", function()
pack_clear [[ lua _G.test_loadorder = {} vim.cmd "packadd! superspecial\nruntime! filen.lua" ]]
- eq({'ordinary', 'SuperSpecial', 'FANCY', 'SuperSpecial after', 'ordinary after', 'FANCY after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'FANCY after', 'SuperSpecial after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with opt packages and after/ after startup", function()
+ pack_clear [[ lua _G.test_loadorder = {} ]]
+ command [[
+ packadd! superspecial
+ runtime! filen.lua
+ ]]
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'FANCY after', 'SuperSpecial after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with opt packages and globpath(&rtp, ...)", function()
+ pack_clear [[ set loadplugins | lua _G.test_loadorder = {} ]]
+ command [[
+ packadd! superspecial
+ for x in globpath(&rtp, "filen.lua",1,1)
+ call v:lua.dofile(x)
+ endfor
+ ]]
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'SuperSpecial after', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with a package that changes packpath", function()
+ pack_clear [[ lua _G.test_loadorder = {} vim.cmd "packadd! funky\nruntime! filen.lua" ]]
+ eq({'ordinary', 'funky!', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'funky!', 'mittel', 'ordinary after'}, exec_lua [[ return _G.nested_order ]])
end)
end)
diff --git a/test/functional/editor/meta_key_spec.lua b/test/functional/editor/meta_key_spec.lua
index 2a9541ba96..c219204409 100644
--- a/test/functional/editor/meta_key_spec.lua
+++ b/test/functional/editor/meta_key_spec.lua
@@ -11,15 +11,20 @@ describe('meta-keys #8226 #13042', function()
end)
it('ALT/META, normal-mode', function()
- -- Unmapped ALT-chords behave as ESC+c
+ -- Unmapped ALT-chord behaves as ESC+c.
insert('hello')
feed('0<A-x><M-x>')
expect('llo')
+ -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869
+ command('nnoremap <ESC> A<lt>ESC><Esc>')
+ command('nnoremap ; A;<Esc>')
+ feed('<A-;><M-;>')
+ expect('llo<ESC>;<ESC>;')
-- Mapped ALT-chord behaves as mapped.
command('nnoremap <M-l> Ameta-l<Esc>')
command('nnoremap <A-j> Aalt-j<Esc>')
feed('<A-j><M-l>')
- expect('lloalt-jmeta-l')
+ expect('llo<ESC>;<ESC>;alt-jmeta-l')
end)
it('ALT/META, visual-mode', function()
@@ -27,11 +32,15 @@ describe('meta-keys #8226 #13042', function()
insert('peaches')
feed('viw<A-x>viw<M-x>')
expect('peach')
+ -- Unmapped ALT-chord resolves isolated (non-ALT) ESC mapping. #13086 #15869
+ command('vnoremap <ESC> A<lt>ESC>')
+ feed('viw<A-;><ESC>viw<M-;><ESC>')
+ expect('peach<ESC>;<ESC>;')
-- Mapped ALT-chord behaves as mapped.
command('vnoremap <M-l> Ameta-l<Esc>')
command('vnoremap <A-j> Aalt-j<Esc>')
feed('viw<A-j>viw<M-l>')
- expect('peachalt-jmeta-l')
+ expect('peach<ESC>;<ESC>;alt-jmeta-l')
end)
it('ALT/META insert-mode', function()
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index 9579525502..8e03d9a46e 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -43,11 +43,11 @@ end
local function read_message()
local line = io.read("*l")
local length = line:lower():match("content%-length:%s*(%d+)")
- return vim.fn.json_decode(io.read(2 + length):sub(2))
+ return vim.json.decode(io.read(2 + length):sub(2))
end
local function send(payload)
- io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload)))
+ io.stdout:write(format_message_with_content_length(vim.json.encode(payload)))
end
local function respond(id, err, result)
@@ -564,6 +564,35 @@ function tests.decode_nil()
}
end
+
+function tests.code_action_with_resolve()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ codeActionProvider = {
+ resolveProvider = true
+ }
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ local cmd = {
+ title = 'Command 1',
+ command = 'dummy1'
+ }
+ expect_request('textDocument/codeAction', function()
+ return nil, { cmd, }
+ end)
+ expect_request('codeAction/resolve', function()
+ return nil, cmd
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
-- Tests will be indexed by TEST_NAME
local kill_timer = vim.loop.new_timer()
diff --git a/test/functional/fixtures/middle/filen.lua b/test/functional/fixtures/middle/filen.lua
new file mode 100644
index 0000000000..fce50cc776
--- /dev/null
+++ b/test/functional/fixtures/middle/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "mittel")
diff --git a/test/functional/fixtures/pack/foo/opt/funky/filen.lua b/test/functional/fixtures/pack/foo/opt/funky/filen.lua
new file mode 100644
index 0000000000..a33b83c2a7
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/funky/filen.lua
@@ -0,0 +1,12 @@
+table.insert(_G.test_loadorder, "funky!")
+
+if not _G.nesty then
+ _G.nesty = true
+ local save_order = _G.test_loadorder
+ _G.test_loadorder = {}
+ _G.vim.o.pp = "" -- funky!
+ vim.cmd [[runtime! filen.lua ]]
+ _G.nested_order = _G.test_loadorder
+ _G.test_loadorder = save_order
+ _G.nesty = nil
+end
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index 9397af9d9f..45aa4915cd 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -874,6 +874,26 @@ describe('vim.diagnostic', function()
return count_extmarks(diagnostic_bufnr, diagnostic_ns)
]])
end)
+
+ it('sets signs', function()
+ local result = exec_lua [[
+ vim.diagnostic.config({
+ signs = true,
+ })
+
+ local diagnostics = {
+ make_error('Error', 1, 1, 1, 2),
+ make_warning('Warning', 3, 3, 3, 3),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+
+ return vim.fn.sign_getplaced(diagnostic_bufnr, {group = '*'})[1].signs
+ ]]
+
+ eq({2, 'DiagnosticSignError'}, {result[1].lnum, result[1].name})
+ eq({4, 'DiagnosticSignWarn'}, {result[2].lnum, result[2].name})
+ end)
end)
describe('show_line_diagnostics()', function()
@@ -995,37 +1015,6 @@ describe('vim.diagnostic', function()
end)
end)
- describe('set_signs()', function()
- -- TODO(tjdevries): Find out why signs are not displayed when set from Lua...??
- pending('sets signs by default', function()
- exec_lua [[
- vim.diagnostic.config({
- update_in_insert = true,
- signs = true,
- })
-
- local diagnostics = {
- make_error('Delayed Diagnostic', 1, 1, 1, 2),
- make_error('Delayed Diagnostic', 3, 3, 3, 3),
- }
-
- vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
-
- vim.diagnostic._set_signs(diagnostic_ns, diagnostic_bufnr, diagnostics)
- -- return vim.fn.sign_getplaced()
- ]]
-
- nvim("input", "o")
- nvim("input", "<esc>")
-
- -- TODO(tjdevries): Find a way to get the signs to display in the test...
- eq(nil, exec_lua [[
- return im.fn.sign_getplaced()[1].signs
- ]])
- end)
- end)
-
describe('setloclist()', function()
it('sets diagnostics in lnum order', function()
local loc_list = exec_lua [[
diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua
new file mode 100644
index 0000000000..fbb21bfd57
--- /dev/null
+++ b/test/functional/lua/json_spec.lua
@@ -0,0 +1,133 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local NIL = helpers.NIL
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+
+describe('vim.json.decode function', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('parses null, true, false', function()
+ eq(NIL, exec_lua([[return vim.json.decode('null')]]))
+ eq(true, exec_lua([[return vim.json.decode('true')]]))
+ eq(false, exec_lua([[return vim.json.decode('false')]]))
+ end)
+
+ it('parses integer numbers', function()
+ eq(100000, exec_lua([[return vim.json.decode('100000')]]))
+ eq(-100000, exec_lua([[return vim.json.decode('-100000')]]))
+ eq(100000, exec_lua([[return vim.json.decode(' 100000 ')]]))
+ eq(-100000, exec_lua([[return vim.json.decode(' -100000 ')]]))
+ eq(0, exec_lua([[return vim.json.decode('0')]]))
+ eq(0, exec_lua([[return vim.json.decode('-0')]]))
+ end)
+
+ it('parses floating-point numbers', function()
+ -- This behavior differs from vim.fn.json_decode, which return '100000.0'
+ eq('100000', exec_lua([[return tostring(vim.json.decode('100000.0'))]]))
+ eq(100000.5, exec_lua([[return vim.json.decode('100000.5')]]))
+ eq(-100000.5, exec_lua([[return vim.json.decode('-100000.5')]]))
+ eq(-100000.5e50, exec_lua([[return vim.json.decode('-100000.5e50')]]))
+ eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e50')]]))
+ eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e+50')]]))
+ eq(-100000.5e-50, exec_lua([[return vim.json.decode('-100000.5e-50')]]))
+ eq(100000.5e-50, exec_lua([[return vim.json.decode('100000.5e-50')]]))
+ eq(100000e-50, exec_lua([[return vim.json.decode('100000e-50')]]))
+ eq(0.5, exec_lua([[return vim.json.decode('0.5')]]))
+ eq(0.005, exec_lua([[return vim.json.decode('0.005')]]))
+ eq(0.005, exec_lua([[return vim.json.decode('0.00500')]]))
+ eq(0.5, exec_lua([[return vim.json.decode('0.00500e+002')]]))
+ eq(0.00005, exec_lua([[return vim.json.decode('0.00500e-002')]]))
+
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e+0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e-0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e-0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e-2')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e+2')]]))
+
+ eq(0.0, exec_lua([[return vim.json.decode('0.0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e+0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e-0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e-0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e-2')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e+2')]]))
+ end)
+
+ it('parses containers', function()
+ eq({1}, exec_lua([[return vim.json.decode('[1]')]]))
+ eq({NIL, 1}, exec_lua([[return vim.json.decode('[null, 1]')]]))
+ eq({['1']=2}, exec_lua([[return vim.json.decode('{"1": 2}')]]))
+ eq({['1']=2, ['3']={{['4']={['5']={{}, 1}}}}},
+ exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]]))
+ end)
+
+ it('parses strings properly', function()
+ eq('\n', exec_lua([=[return vim.json.decode([["\n"]])]=]))
+ eq('', exec_lua([=[return vim.json.decode([[""]])]=]))
+ eq('\\/"\t\b\n\r\f', exec_lua([=[return vim.json.decode([["\\\/\"\t\b\n\r\f"]])]=]))
+ eq('/a', exec_lua([=[return vim.json.decode([["\/a"]])]=]))
+ -- Unicode characters: 2-byte, 3-byte
+ eq('«',exec_lua([=[return vim.json.decode([["«"]])]=]))
+ eq('ફ',exec_lua([=[return vim.json.decode([["ફ"]])]=]))
+ end)
+
+ it('parses surrogate pairs properly', function()
+ eq('\240\144\128\128', exec_lua([[return vim.json.decode('"\\uD800\\uDC00"')]]))
+ end)
+
+ it('accepts all spaces in every position where space may be put', function()
+ local s = ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t'
+ local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s)
+ eq({key={'val', 'val2'}, key2=1}, exec_lua([[return vim.json.decode(...)]], str))
+ end)
+
+end)
+
+describe('vim.json.encode function', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('dumps strings', function()
+ eq('"Test"', exec_lua([[return vim.json.encode('Test')]]))
+ eq('""', exec_lua([[return vim.json.encode('')]]))
+ eq('"\\t"', exec_lua([[return vim.json.encode('\t')]]))
+ eq('"\\n"', exec_lua([[return vim.json.encode('\n')]]))
+ -- vim.fn.json_encode return \\u001B
+ eq('"\\u001b"', exec_lua([[return vim.json.encode('\27')]]))
+ eq('"þÿþ"', exec_lua([[return vim.json.encode('þÿþ')]]))
+ end)
+
+ it('dumps numbers', function()
+ eq('0', exec_lua([[return vim.json.encode(0)]]))
+ eq('10', exec_lua([[return vim.json.encode(10)]]))
+ eq('-10', exec_lua([[return vim.json.encode(-10)]]))
+ end)
+
+ it('dumps floats', function()
+ eq('10.5', exec_lua([[return vim.json.encode(10.5)]]))
+ eq('-10.5', exec_lua([[return vim.json.encode(-10.5)]]))
+ eq('-1e-05', exec_lua([[return vim.json.encode(-1e-5)]]))
+ end)
+
+ it('dumps lists', function()
+ eq('[]', exec_lua([[return vim.json.encode({})]]))
+ eq('[[]]', exec_lua([[return vim.json.encode({{}})]]))
+ eq('[[],[]]', exec_lua([[return vim.json.encode({{}, {}})]]))
+ end)
+
+ it('dumps dictionaries', function()
+ eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]]))
+ eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]]))
+ end)
+
+ it('dumps vim.NIL', function()
+ eq('null', exec_lua([[return vim.json.encode(vim.NIL)]]))
+ end)
+
+end)
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
new file mode 100644
index 0000000000..94f1b5840b
--- /dev/null
+++ b/test/functional/lua/ui_spec.lua
@@ -0,0 +1,46 @@
+local helpers = require('test.functional.helpers')(after_each)
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local clear = helpers.clear
+
+describe('vim.ui', function()
+ before_each(function()
+ clear()
+ end)
+
+
+ describe('select', function()
+ it('can select an item', function()
+ local result = exec_lua[[
+ local items = {
+ { name = 'Item 1' },
+ { name = 'Item 2' },
+ }
+ local opts = {
+ format_item = function(entry)
+ return entry.name
+ end
+ }
+ local selected
+ local cb = function(item)
+ selected = item
+ end
+ -- inputlist would require input and block the test;
+ local choices
+ vim.fn.inputlist = function(x)
+ choices = x
+ return 1
+ end
+ vim.ui.select(items, opts, cb)
+ vim.wait(100, function() return selected ~= nil end)
+ return {selected, choices}
+ ]]
+ eq({ name = 'Item 1' }, result[1])
+ eq({
+ 'Select one of:',
+ '1: Item 1',
+ '2: Item 2',
+ }, result[2])
+ end)
+ end)
+end)
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
index e48a0ad260..c8b75e65fc 100644
--- a/test/functional/plugin/lsp/codelens_spec.lua
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -58,5 +58,33 @@ describe('vim.lsp.codelens', function()
]], bufnr)
eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks)
+
+ end)
+ it('codelens uses client commands', function()
+ local fake_uri = "file:///fake/uri"
+ local cmd = exec_lua([[
+ fake_uri = ...
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ vim.fn.bufload(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 8 }
+ },
+ command = { title = 'Lens1', command = 'Dummy' }
+ },
+ }
+ vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ local cmd_called = nil
+ vim.lsp.commands['Dummy'] = function(command)
+ cmd_called = command
+ end
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.lsp.codelens.run()
+ return cmd_called
+ ]], fake_uri)
+ eq({ command = 'Dummy', title = 'Lens1' }, cmd)
end)
end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 27f2d2536f..8f9b194690 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -132,37 +132,38 @@ local function test_rpc_server(config)
end
describe('LSP', function()
- describe('server_name specified', function()
- before_each(function()
- clear_notrace()
- -- Run an instance of nvim on the file which contains our "scripts".
- -- Pass TEST_NAME to pick the script.
- local test_name = "basic_init"
- exec_lua([=[
- lsp = require('vim.lsp')
- local test_name, fixture_filename, logfile = ...
- function test__start_client()
- return lsp.start_client {
- cmd_env = {
- NVIM_LOG_FILE = logfile;
- };
- cmd = {
- vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
- "-c", string.format("lua TEST_NAME = %q", test_name),
- "-c", "luafile "..fixture_filename;
- };
- root_dir = vim.loop.cwd();
- }
- end
- TEST_CLIENT1 = test__start_client()
- ]=], test_name, fake_lsp_code, fake_lsp_logfile)
- end)
+ before_each(function()
+ clear_notrace()
- after_each(function()
- exec_lua("lsp._vim_exit_handler()")
- -- exec_lua("lsp.stop_all_clients(true)")
- end)
+ -- Run an instance of nvim on the file which contains our "scripts".
+ -- Pass TEST_NAME to pick the script.
+ local test_name = "basic_init"
+ exec_lua([=[
+ lsp = require('vim.lsp')
+ local test_name, fixture_filename, logfile = ...
+ function test__start_client()
+ return lsp.start_client {
+ cmd_env = {
+ NVIM_LOG_FILE = logfile;
+ };
+ cmd = {
+ vim.v.progpath, '-Es', '-u', 'NONE', '--headless',
+ "-c", string.format("lua TEST_NAME = %q", test_name),
+ "-c", "luafile "..fixture_filename;
+ };
+ root_dir = vim.loop.cwd();
+ }
+ end
+ TEST_CLIENT1 = test__start_client()
+ ]=], test_name, fake_lsp_code, fake_lsp_logfile)
+ end)
+ after_each(function()
+ exec_lua("lsp._vim_exit_handler()")
+ -- exec_lua("lsp.stop_all_clients(true)")
+ end)
+
+ describe('server_name specified', function()
it('start_client(), stop_client()', function()
retry(nil, 4000, function()
eq(1, exec_lua('return #lsp.get_active_clients()'))
@@ -334,7 +335,6 @@ describe('LSP', function()
}
end)
it('workspace/configuration returns NIL per section if client was started without config.settings', function()
- clear_notrace()
fake_lsp_server_setup('workspace/configuration no settings')
eq({ NIL, NIL, }, exec_lua [[
local result = {
@@ -2022,83 +2022,6 @@ describe('LSP', function()
end)
end)
- describe('lsp.util.make_floating_popup_options', function()
- before_each(function()
- exec_lua [[
- local bufnr = vim.uri_to_bufnr("file:///fake/uri")
- local winheight = vim.fn.winheight(0)
- for i = 1, winheight do
- vim.api.nvim_buf_set_lines(bufnr, 0, 0, false, {''})
- end
- vim.api.nvim_win_set_buf(0, bufnr)
- vim.api.nvim_win_set_cursor(0, {winheight, 0})
- ]]
- end)
-
- local function popup_row(opts)
- return exec_lua([[
- return vim.lsp.util.make_floating_popup_options(...).row
- ]], 2, 2, opts)
- end
-
- local err_pattern = "^Error executing lua: %.%.%./util%.lua:0: invalid floating preview border: .*%. :help vim%.api%.nvim_open_win%(%)$"
-
- it('calculates default border height correctly', function()
- eq(0, popup_row())
- end)
-
- it('calculates string border height correctly', function()
- eq(0, popup_row({border = 'none'}))
- eq(-2, popup_row({border = 'single'}))
- eq(-2, popup_row({border = 'double'}))
- eq(-2, popup_row({border = 'rounded'}))
- eq(-2, popup_row({border = 'solid'}))
- eq(-1, popup_row({border = 'shadow'}))
- end)
-
- it('error on invalid string border', function()
- matches(err_pattern, pcall_err(popup_row, {border = ''}))
- matches(err_pattern, pcall_err(popup_row, {border = 'invalid'}))
- end)
-
- it('error on invalid array border length', function()
- matches(err_pattern, pcall_err(popup_row, {border = {}}))
- matches(err_pattern, pcall_err(popup_row, {border = {'', '', ''}}))
- matches(err_pattern, pcall_err(popup_row, {border = {'', '', '', '', ''}}))
- end)
-
- it('error on invalid array border member type', function()
- matches(err_pattern, pcall_err(popup_row, {border = {0}}))
- end)
-
- it('calculates 8-array border height correctly', function()
- eq(0, popup_row({border = {'', '', '', '', '', '', '', ''}}))
- eq(-2, popup_row({border = {'', '~', '', '~', '', '~', '', '~'}}))
- eq(-1, popup_row({border = {'', '', '', '~', '', '~', '', ''}}))
- eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}}}))
- eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}, '', ''}}))
- end)
-
- it('calculates 4-array border height correctly', function()
- eq(0, popup_row({border = {'', '', '', ''}}))
- eq(-2, popup_row({border = {'', '~', '', '~'}}))
- eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}}}))
- eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', ''}}))
- end)
-
- it('calculates 2-array border height correctly', function()
- eq(0, popup_row({border = {'', ''}}))
- eq(-2, popup_row({border = {'', '~'}}))
- eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}}}))
- end)
-
- it('calculates 1-array border height correctly', function()
- eq(0, popup_row({border = {''}}))
- eq(-2, popup_row({border = {'~'}}))
- eq(-2, popup_row({border = {{'~', 'NormalFloat'}}}))
- end)
- end)
-
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
exec_lua [[ contents =
@@ -2376,26 +2299,43 @@ describe('LSP', function()
describe('vim.lsp.buf.code_action', function()
it('Calls client side command if available', function()
- eq(1, exec_lua [[
- local dummy_calls = 0
- vim.lsp.commands.dummy = function()
- dummy_calls = dummy_calls + 1
- end
- local actions = {
- {
- title = 'Dummy command',
- command = 'dummy',
- },
- }
- -- inputlist would require input and block the test;
- vim.fn.inputlist = function()
- return 1
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'code_action_with_resolve',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end,
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx})
+ if ctx.method == 'start' then
+ exec_lua([[
+ vim.lsp.commands['dummy1'] = function(cmd)
+ vim.lsp.commands['dummy2'] = function()
+ end
+ end
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.fn.inputlist = function()
+ return 1
+ end
+ vim.lsp.buf.code_action()
+ ]])
+ elseif ctx.method == 'shutdown' then
+ eq('function', exec_lua[[return type(vim.lsp.commands['dummy2'])]])
+ client.stop()
+ end
end
- local params = {}
- local handler = require'vim.lsp.handlers'['textDocument/codeAction']
- handler(nil, actions, { method = 'textDocument/codeAction', params = params }, nil)
- return dummy_calls
- ]])
+ }
end)
end)
describe('vim.lsp.commands', function()
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 4373d17890..8074f91215 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -790,3 +790,511 @@ end]]
helpers.assert_alive()
end)
end)
+
+describe('decorations: virtual lines', function()
+ local screen, ns
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 12)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {foreground = Screen.colors.Cyan4};
+ [3] = {background = Screen.colors.Yellow1};
+ [4] = {bold = true};
+ [5] = {background = Screen.colors.Yellow, foreground = Screen.colors.Blue};
+ [6] = {foreground = Screen.colors.Blue};
+ [7] = {foreground = Screen.colors.SlateBlue};
+ [8] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
+ [9] = {foreground = Screen.colors.Brown};
+ }
+
+ ns = meths.create_namespace 'test'
+ end)
+
+ local example_text = [[
+if (h->n_buckets < new_n_buckets) { // expand
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t));
+ h->keys = new_keys;
+ if (kh_is_map && val_size) {
+ char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size);
+ h->vals_buf = new_vals;
+ }
+}]]
+
+ it('works with one line', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 33, {
+ virt_lines={ {{">> ", "NonText"}, {"krealloc", "Identifier"}, {": change the size of an allocation"}}};
+ virt_lines_above=true;
+ })
+
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+
+ feed '/krealloc<cr>'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ khkey_t *new_keys = (khkey_t *){3:^krealloc}((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ /krealloc |
+ ]]}
+
+ -- virtual line remains anchored to the extmark
+ feed 'i<cr>'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ {3:^krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ {4:-- INSERT --} |
+ ]]}
+
+ feed '<esc>3+'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 5, 0, {
+ virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unneccesary?", "Comment"}} };
+ })
+ -- TODO: what about the cursor??
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buck^ets * val_size); |
+ {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+
+ meths.buf_clear_namespace(0, ns, 0, -1)
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buck^ets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+ end)
+
+
+ it('works with text at the beginning of the buffer', function()
+ insert(example_text)
+ feed 'gg'
+
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ {1:~ }|
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 0, 0, {
+ virt_lines={
+ {{"refactor(khash): ", "Special"}, {"take size of values as parameter"}};
+ {{"Author: Dev Devsson, "}, {"Tue Aug 31 10:13:37 2021", "Comment"}};
+ };
+ virt_lines_above=true;
+ right_gravity=false;
+ })
+
+ -- placing virt_text on topline does not automatically cause a scroll
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ {1:~ }|
+ |
+ ]], unchanged=true}
+
+ feed '<c-b>'
+ screen:expect{grid=[[
+ {7:refactor(khash): }take size of values as parameter |
+ Author: Dev Devsson, {6:Tue Aug 31 10:13:37 2021} |
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+ end)
+
+ it('works with text et the end of the buffer', function()
+ insert(example_text)
+ feed 'G'
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+
+ local id = meths.buf_set_extmark(0, ns, 7, 0, {
+ virt_lines={{{"Grugg"}}};
+ right_gravity=false;
+ })
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ Grugg |
+ |
+ ]]}
+
+ meths.buf_del_extmark(0, ns, id)
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with a block scrolling up', function()
+ screen:try_resize(30, 7)
+ insert("aa\nbb\ncc\ndd\nee\nff\ngg\nhh")
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 6, 0, {
+ virt_lines={
+ {{"they see me"}};
+ {{"scrolling", "Special"}};
+ {{"they"}};
+ {{"hatin'", "Special"}};
+ };
+ })
+
+ screen:expect{grid=[[
+ ^aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ they see me |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^dd |
+ ee |
+ ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^ee |
+ ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ hh |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with sign and numbercolumns', function()
+ insert(example_text)
+ feed 'gg'
+ command 'set number signcolumn=yes'
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ {8: }{9: 6 } h->vals_buf = new_vals; |
+ {8: }{9: 7 } } |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_lines={
+ {{"Some special", "Special"}};
+ {{"remark about codes", "Comment"}};
+ };
+ })
+
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {8: }{9: }{7:Some special} |
+ {8: }{9: }{6:remark about codes} |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_lines={
+ {{"Some special", "Special"}};
+ {{"remark about codes", "Comment"}};
+ };
+ virt_lines_leftcol=true;
+ })
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {7:Some special} |
+ {6:remark about codes} |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ |
+ ]]}
+ end)
+
+
+ it('works with hard tabs', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 0, {
+ virt_lines={ {{">>", "NonText"}, {"\tvery\ttabby", "Identifier"}, {"text\twith\ttabs"}}};
+ })
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ {1:>>}{2: very tabby}text with tabs |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+
+ command 'set tabstop=4'
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ {1:>>}{2: very tabby}text with tabs |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+ end)
+
+end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index ccf5f963d1..e57c63bb0f 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -109,6 +109,21 @@ describe('float window', function()
assert_alive()
end)
+ it('closed immediately by autocmd after win_enter #15548', function()
+ eq('Error executing lua: [string "<nvim>"]:0: Window was closed immediately',
+ pcall_err(exec_lua, [[
+ vim.cmd "autocmd BufLeave * ++once quit!"
+ local buf = vim.api.nvim_create_buf(true, true)
+ vim.api.nvim_open_win(buf, true, {
+ relative = "win",
+ row = 0, col = 0,
+ width = 1, height = 1,
+ noautocmd = false,
+ })
+ ]]))
+ assert_alive()
+ end)
+
it('opened with correct height', function()
local height = exec_lua([[
vim.api.nvim_set_option("winheight", 20)
@@ -1514,7 +1529,7 @@ describe('float window', function()
it('API has proper error messages', function()
local buf = meths.create_buf(false,false)
- eq("Invalid key 'bork'",
+ eq("Invalid key: 'bork'",
pcall_err(meths.open_win,buf, false, {width=20,height=2,bork=true}))
eq("'win' key is only valid with relative='win'",
pcall_err(meths.open_win,buf, false, {width=20,height=2,relative='editor',row=0,col=0,win=0}))
@@ -1527,13 +1542,15 @@ describe('float window', function()
eq("'relative' requires 'row'/'col' or 'bufpos'",
pcall_err(meths.open_win,buf, false, {width=20,height=2,relative='editor'}))
eq("'width' key must be a positive Integer",
- pcall_err(meths.open_win,buf, false, {width=-1,height=2,relative='editor'}))
+ pcall_err(meths.open_win,buf, false, {width=-1,height=2,relative='editor', row=0, col=0}))
eq("'height' key must be a positive Integer",
- pcall_err(meths.open_win,buf, false, {width=20,height=-1,relative='editor'}))
+ pcall_err(meths.open_win,buf, false, {width=20,height=-1,relative='editor', row=0, col=0}))
eq("'height' key must be a positive Integer",
- pcall_err(meths.open_win,buf, false, {width=20,height=0,relative='editor'}))
- eq("Must specify 'width' and 'height'",
- pcall_err(meths.open_win,buf, false, {relative='editor'}))
+ pcall_err(meths.open_win,buf, false, {width=20,height=0,relative='editor', row=0, col=0}))
+ eq("Must specify 'width'",
+ pcall_err(meths.open_win,buf, false, {relative='editor', row=0, col=0}))
+ eq("Must specify 'height'",
+ pcall_err(meths.open_win,buf, false, {relative='editor', row=0, col=0, width=2}))
end)
it('can be placed relative window or cursor', function()
@@ -1866,6 +1883,293 @@ describe('float window', function()
end
end)
+ it('always anchor to corner including border', function()
+ screen:try_resize(40,13)
+ meths.buf_set_lines(0, 0, -1, true, {'just some example text', 'some more example text'})
+ feed('ggeee')
+ command('below split')
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:[No Name] [+] }|
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ local buf = meths.create_buf(false, false)
+ meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',
+ ' BORDAA '})
+ local win = meths.open_win(buf, false, {relative='cursor', width=9, height=2, row=1, col=-2, border="double"})
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "NW", 4, 1, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:[No Name] [+] }|
+ just some exampl^e text |
+ some more exam{5:╔═════════╗} |
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='cursor', row=0, col=-2, anchor='NE'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "NE", 4, 0, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {5:[No Name] [+] }|
+ jus{5:╔═════════╗}pl^e text |
+ som{5:║}{1: halloj! }{5:║}ple text |
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {0:~ }{5:╚═════════╝}{0: }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='cursor', row=1, col=-2, anchor='SE'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "SE", 4, 1, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }{5:╔═════════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {5:[No║}{1: BORDAA }{5:║ }|
+ jus{5:╚═════════╝}pl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='cursor', row=0, col=-2, anchor='SW'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ {5:[No Name] [+] }|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ [4:----------------------------------------]|
+ {4:[No Name] [+] }|
+ [3:----------------------------------------]|
+ ## grid 2
+ just some example text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 6
+ {5:╔═════════╗}|
+ {5:║}{1: halloj! }{5:║}|
+ {5:║}{1: BORDAA }{5:║}|
+ {5:╚═════════╝}|
+ ]], float_pos={
+ [6] = {{id = 1003}, "SW", 4, 0, 14, true}
+ }}
+ else
+ screen:expect([[
+ just some example text |
+ some more example text |
+ {0:~ }{5:╔═════════╗}{0: }|
+ {0:~ }{5:║}{1: halloj! }{5:║}{0: }|
+ {0:~ }{5:║}{1: BORDAA }{5:║}{0: }|
+ {5:[No Name] [+] ╚═════════╝ }|
+ just some exampl^e text |
+ some more example text |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {4:[No Name] [+] }|
+ |
+ ]])
+ end
+ end)
+
it('can be placed relative text in a window', function()
screen:try_resize(30,5)
local firstwin = meths.get_current_win().id
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 7bca741ae3..d3fe38ef52 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1384,4 +1384,128 @@ describe('ui/mouse/input', function()
end) -- level 3 - wrapped
end)
+
+ it('getmousepos works correctly', function()
+ local winwidth = meths.get_option('winwidth')
+ -- Set winwidth=1 so that window sizes don't change.
+ meths.set_option('winwidth', 1)
+ command('tabedit')
+ local tabpage = meths.get_current_tabpage()
+ insert('hello')
+ command('vsplit')
+ local opts = {
+ relative='editor',
+ width=12,
+ height=1,
+ col=8,
+ row=1,
+ anchor='NW',
+ style='minimal',
+ border='single',
+ focusable=1
+ }
+ local float = meths.open_win(meths.get_current_buf(), false, opts)
+ command('redraw')
+ local lines = meths.get_option('lines')
+ local columns = meths.get_option('columns')
+
+ -- Test that screenrow and screencol are set properly for all positions.
+ for row = 0, lines - 1 do
+ for col = 0, columns - 1 do
+ -- Skip the X button that would close the tab.
+ if row ~= 0 or col ~= columns - 1 then
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ meths.set_current_tabpage(tabpage)
+ local mousepos = funcs.getmousepos()
+ eq(row + 1, mousepos.screenrow)
+ eq(col + 1, mousepos.screencol)
+ -- All other values should be 0 when clicking on the command line.
+ if row == lines - 1 then
+ eq(0, mousepos.winid)
+ eq(0, mousepos.winrow)
+ eq(0, mousepos.wincol)
+ eq(0, mousepos.line)
+ eq(0, mousepos.column)
+ end
+ end
+ end
+ end
+
+ -- Test that mouse position values are properly set for the floating window
+ -- with a border. 1 is added to the height and width to account for the
+ -- border.
+ for win_row = 0, opts.height + 1 do
+ for win_col = 0, opts.width + 1 do
+ local row = win_row + opts.row
+ local col = win_col + opts.col
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(float.id, mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = 0
+ local column = 0
+ if win_row > 0 and win_row < opts.height + 1
+ and win_col > 0 and win_col < opts.width + 1 then
+ -- Because of border, win_row and win_col don't need to be
+ -- incremented by 1.
+ line = math.min(win_row, funcs.line('$'))
+ column = math.min(win_col, #funcs.getline(line) + 1)
+ end
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+
+ -- Test that mouse position values are properly set for the floating
+ -- window, after removing the border.
+ opts.border = 'none'
+ meths.win_set_config(float, opts)
+ command('redraw')
+ for win_row = 0, opts.height - 1 do
+ for win_col = 0, opts.width - 1 do
+ local row = win_row + opts.row
+ local col = win_col + opts.col
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(float.id, mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = math.min(win_row + 1, funcs.line('$'))
+ local column = math.min(win_col + 1, #funcs.getline(line) + 1)
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+
+ -- Test that mouse position values are properly set for ordinary windows.
+ -- Set the float to be unfocusable instead of closing, to additionally test
+ -- that getmousepos does not consider unfocusable floats. (see discussion
+ -- in PR #14937 for details).
+ opts.focusable = false
+ meths.win_set_config(float, opts)
+ command('redraw')
+ for nr = 1, 2 do
+ for win_row = 0, funcs.winheight(nr) - 1 do
+ for win_col = 0, funcs.winwidth(nr) - 1 do
+ local row = win_row + funcs.win_screenpos(nr)[1] - 1
+ local col = win_col + funcs.win_screenpos(nr)[2] - 1
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(funcs.win_getid(nr), mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = math.min(win_row + 1, funcs.line('$'))
+ local column = math.min(win_col + 1, #funcs.getline(line) + 1)
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+ end
+
+ -- Restore state and release mouse.
+ command('tabclose!')
+ meths.set_option('winwidth', winwidth)
+ meths.input_mouse('left', 'release', '', 0, 0, 0)
+ end)
end)