aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml8
-rwxr-xr-x.github/scripts/install_deps.sh27
-rw-r--r--.github/workflows/lintcommit.yml16
-rw-r--r--.github/workflows/release.yml5
-rw-r--r--.github/workflows/test.yml47
-rw-r--r--CMakeLists.txt2
-rw-r--r--cmake.deps/CMakePresets.json25
-rw-r--r--runtime/doc/filetype.txt14
-rw-r--r--runtime/doc/if_perl.txt2
-rw-r--r--runtime/doc/if_pyth.txt11
-rw-r--r--runtime/doc/if_ruby.txt8
-rw-r--r--runtime/doc/lua.txt8
-rw-r--r--runtime/doc/news.txt6
-rw-r--r--runtime/doc/treesitter.txt22
-rw-r--r--runtime/ftplugin/query.lua26
-rw-r--r--runtime/lua/vim/treesitter/_query_linter.lua302
-rw-r--r--runtime/lua/vim/treesitter/playground.lua1
-rw-r--r--runtime/lua/vim/treesitter/query.lua29
-rw-r--r--src/nvim/buffer.c23
-rw-r--r--src/nvim/eval/funcs.c4
-rw-r--r--src/nvim/eval/userfunc.c9
-rw-r--r--src/nvim/eval/vars.c32
-rw-r--r--src/nvim/ex_cmds.c2
-rw-r--r--src/nvim/ex_getln.c29
-rw-r--r--src/nvim/generators/gen_options.lua3
-rw-r--r--src/nvim/insexpand.c19
-rw-r--r--src/nvim/lua/executor.c2
-rw-r--r--src/nvim/lua/spell.c2
-rw-r--r--src/nvim/mapping.c17
-rw-r--r--src/nvim/normal.c4
-rw-r--r--src/nvim/ops.c5
-rw-r--r--src/nvim/option.c515
-rw-r--r--src/nvim/option_defs.h64
-rw-r--r--src/nvim/options.lua512
-rw-r--r--src/nvim/optionstr.c1269
-rw-r--r--src/nvim/quickfix.c11
-rw-r--r--src/nvim/runtime.c3
-rw-r--r--src/nvim/search.c6
-rw-r--r--src/nvim/spell.c6
-rw-r--r--src/nvim/spellfile.c2
-rw-r--r--src/nvim/spellsuggest.c2
-rw-r--r--src/nvim/tag.c17
-rw-r--r--src/nvim/window.c6
-rw-r--r--test/functional/lua/commands_spec.lua18
-rw-r--r--test/old/testdir/test_matchfuzzy.vim27
-rw-r--r--test/old/testdir/test_options.vim224
-rw-r--r--test/old/testdir/test_perl.vim15
-rw-r--r--test/old/testdir/test_python2.vim24
-rw-r--r--test/old/testdir/test_python3.vim102
-rw-r--r--test/old/testdir/test_pyx2.vim30
-rw-r--r--test/old/testdir/test_pyx3.vim30
-rw-r--r--test/old/testdir/test_ruby.vim30
-rw-r--r--test/old/testdir/test_undo.vim5
-rw-r--r--test/old/testdir/test_vimscript.vim5
54 files changed, 2552 insertions, 1081 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 92507f6d50..d9067b05e3 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -27,15 +27,11 @@ freebsd_task:
oldtest_script:
- sudo -u cirrus gmake oldtest
-with_external_deps_task:
+external_deps_task:
container:
dockerfile: ci/Dockerfile.external_deps
deps_script:
- # Ideally all dependencies should external for this job, but some
- # dependencies don't have the required version available. We use the
- # bundled versions for these with the hopes of being able to remove them
- # later on.
- - cmake -S cmake.deps -B .deps -G Ninja -D USE_BUNDLED=OFF -D USE_BUNDLED_LIBVTERM=ON -D USE_BUNDLED_TS=ON
+ - cmake -S cmake.deps --preset external_deps
- cmake --build .deps
build_script:
- cmake --preset ci
diff --git a/.github/scripts/install_deps.sh b/.github/scripts/install_deps.sh
index 29f4d73a7f..bb99873267 100755
--- a/.github/scripts/install_deps.sh
+++ b/.github/scripts/install_deps.sh
@@ -1,10 +1,31 @@
#!/bin/bash
+SUDO="sudo"
+
+while (($# > 0)); do
+ case $1 in
+ --test) # install test dependencies
+ TEST=1
+ shift
+ ;;
+ --container) # don't use sudo
+ SUDO=""
+ shift
+ ;;
+ esac
+done
+
os=$(uname -s)
if [[ $os == Linux ]]; then
- sudo apt-get update
- sudo apt-get install -y build-essential cmake curl gettext locales-all ninja-build pkg-config unzip "$@"
+ $SUDO apt-get update
+ $SUDO apt-get install -y build-essential cmake curl gettext ninja-build pkg-config unzip
+ if [[ -n $TEST ]]; then
+ $SUDO apt-get install -y locales-all cpanminus
+ fi
elif [[ $os == Darwin ]]; then
brew update --quiet
- brew install ninja "$@"
+ brew install ninja
+ if [[ -n $TEST ]]; then
+ brew install cpanminus
+ fi
fi
diff --git a/.github/workflows/lintcommit.yml b/.github/workflows/lintcommit.yml
index 0bd92c05ec..e56211c29b 100644
--- a/.github/workflows/lintcommit.yml
+++ b/.github/workflows/lintcommit.yml
@@ -13,7 +13,15 @@ jobs:
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- - uses: rhysd/action-setup-vim@v1
- with:
- neovim: true
- - run: nvim --clean -l scripts/lintcommit.lua main
+
+ - run: ./.github/scripts/install_deps.sh
+ - uses: ./.github/actions/cache
+ - name: Build
+ run: |
+ cmake -S cmake.deps -B .deps -G Ninja
+ cmake --build .deps
+ cmake --preset ci
+ cmake --build build
+
+ - name: lintcommit
+ run: cmake --build build --target lintcommit
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ebf5df7aac..a07e1a098a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -39,10 +39,7 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- - name: Install dependencies
- run: |
- apt-get update
- apt-get install -y build-essential cmake gettext ninja-build unzip
+ - run: ./.github/scripts/install_deps.sh --container
- if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly')
run: |
echo 'NVIM_BUILD_TYPE=Release' >> $GITHUB_ENV
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 2b0b9ff20a..5249b36f9a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -33,39 +33,16 @@ jobs:
if: (github.event_name == 'pull_request' && github.base_ref == 'master') || (github.event_name == 'push' && github.ref == 'refs/heads/master')
runs-on: ubuntu-22.04
timeout-minutes: 10
- env:
- CACHE_UNCRUSTIFY: ${{ github.workspace }}/.cache/uncrustify
- UNCRUSTIFY_VERSION: uncrustify-0.76.0
steps:
- uses: actions/checkout@v3
- - name: Install dependencies
- run: ./.github/scripts/install_deps.sh lua-check
+ - name: Set up Homebrew
+ uses: Homebrew/actions/setup-homebrew@master
- - name: Cache uncrustify
- id: cache-uncrustify
- uses: actions/cache@v3
- with:
- path: ${{ env.CACHE_UNCRUSTIFY }}
- key: ${{ env.UNCRUSTIFY_VERSION }}
-
- - name: Clone uncrustify
- if: steps.cache-uncrustify.outputs.cache-hit != 'true'
- uses: actions/checkout@v3
- with:
- repository: uncrustify/uncrustify
- ref: ${{ env.UNCRUSTIFY_VERSION }}
- path: uncrustify
-
- - name: Install uncrustify
- if: steps.cache-uncrustify.outputs.cache-hit != 'true'
+ - name: Install dependencies
run: |
- source_dir=uncrustify
- build_dir=uncrustify/build
- cmake -S $source_dir -B $build_dir -G Ninja -D CMAKE_BUILD_TYPE=Release
- cmake --build $build_dir
- mkdir -p .cache
- cp $build_dir/uncrustify ${{ env.CACHE_UNCRUSTIFY }}
+ ./.github/scripts/install_deps.sh
+ brew install stylua uncrustify
- uses: ./.github/actions/cache
@@ -75,7 +52,6 @@ jobs:
cmake --build .deps
- if: success() || failure() && steps.abort_job.outputs.status == 'success'
- name: configure
run: cmake -B build -G Ninja
- if: "!cancelled()"
@@ -84,12 +60,8 @@ jobs:
run: echo "status=${{ job.status }}" >> $GITHUB_OUTPUT
- if: success() || failure() && steps.abort_job.outputs.status == 'success'
- name: lintstylua
- uses: JohnnyMorganz/stylua-action@v2
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- version: latest
- args: --check runtime/
+ name: stylua
+ run: cmake --build build --target lintlua-stylua
- if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: luacheck
@@ -108,8 +80,7 @@ jobs:
- if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: uncrustify
- run: |
- ${{ env.CACHE_UNCRUSTIFY }} -c ./src/uncrustify.cfg -q --replace --no-backup $(find ./src/nvim -name "*.[ch]")
+ run: cmake --build build --target lintc-uncrustify
- if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: suggester / uncrustify
@@ -170,7 +141,7 @@ jobs:
run: mkdir -p "$LOG_DIR"
- name: Install dependencies
- run: ./.github/scripts/install_deps.sh cpanminus
+ run: ./.github/scripts/install_deps.sh --test
- name: Setup interpreter packages
run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dad8f4b745..731bf09e2e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -236,6 +236,8 @@ add_glob_target(
FLAGS --color=always --check
GLOB_DIRS runtime/
GLOB_PAT *.lua
+ EXCLUDE
+ /runtime/lua/vim/re.lua
TOUCH_STRATEGY SINGLE)
add_custom_target(lintlua)
diff --git a/cmake.deps/CMakePresets.json b/cmake.deps/CMakePresets.json
new file mode 100644
index 0000000000..f399dad217
--- /dev/null
+++ b/cmake.deps/CMakePresets.json
@@ -0,0 +1,25 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "base",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/../.deps",
+ "hidden": true
+ },
+ {
+ "name": "ci",
+ "inherits": ["base"]
+ },
+ {
+ "name": "external_deps",
+ "description": "Build neovim with external deps on ubuntu",
+ "cacheVariables": {
+ "USE_BUNDLED":"OFF",
+ "USE_BUNDLED_LIBVTERM":"ON",
+ "USE_BUNDLED_TS":"ON"
+ },
+ "inherits": ["base"]
+ }
+ ]
+}
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index f69ffeabfe..175c531950 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -663,6 +663,20 @@ To disable this behavior, set the following variable in your vimrc: >
let g:python_recommended_style = 0
+QUERY *ft-query-plugin*
+
+
+Linting of tree-sitter queries for installed parsers using
+|lua-treesitter-query_linter| is enabled by default on
+`BufEnter` and `BufWrite`. To change the events that
+trigger linting, use >lua
+
+ vim.g.query_lint_on = { 'InsertLeave', 'TextChanged' }
+<
+To disable linting completely, set >lua
+
+ vim.g.query_lint_on = {}
+<
QF QUICKFIX *qf.vim* *ft-qf-plugin*
diff --git a/runtime/doc/if_perl.txt b/runtime/doc/if_perl.txt
index e4ec6dcf45..c3b49dc5bb 100644
--- a/runtime/doc/if_perl.txt
+++ b/runtime/doc/if_perl.txt
@@ -19,7 +19,7 @@ See |provider-perl| for more information.
working: >
:perl print "Hello"
-:[range]perl << [endmarker]
+:[range]perl << [trim] [{endmarker}]
{script}
{endmarker}
Execute perl script {script}.
diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt
index 45accc2e03..415a58ec71 100644
--- a/runtime/doc/if_pyth.txt
+++ b/runtime/doc/if_pyth.txt
@@ -19,17 +19,16 @@ Commands *python-commands*
the `:python` command is working: >vim
:python print "Hello"
-:[range]py[thon] << [endmarker]
+:[range]py[thon] << [trim] [{endmarker}]
{script}
{endmarker}
Execute Python script {script}. Useful for including
python code in Vim scripts. Requires Python, see
|script-here|.
-The {endmarker} below the {script} must NOT be preceded by any white space.
-
If [endmarker] is omitted from after the "<<", a dot '.' must be used after
-{script}, like for the |:append| and |:insert| commands.
+{script}, like for the |:append| and |:insert| commands. Refer to
+|:let-heredoc| for more information.
Example: >vim
function! IcecreamInitialize()
@@ -597,12 +596,12 @@ variants explicitly if Python 3 is required.
*:py3* *:python3*
:[range]py3 {stmt}
-:[range]py3 << [endmarker]
+:[range]py3 << [trim] [{endmarker}]
{script}
{endmarker}
:[range]python3 {stmt}
-:[range]python3 << [endmarker]
+:[range]python3 << [trim] [{endmarker}]
{script}
{endmarker}
The `:py3` and `:python3` commands work similar to `:python`. A
diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt
index d88f59eb73..a5aaac1a5f 100644
--- a/runtime/doc/if_ruby.txt
+++ b/runtime/doc/if_ruby.txt
@@ -19,15 +19,15 @@ downloading Ruby there.
:rub[y] {cmd} Execute Ruby command {cmd}. A command to try it out: >
:ruby print "Hello"
-:rub[y] << [endmarker]
+:rub[y] << [trim] [{endmarker}]
{script}
{endmarker}
Execute Ruby script {script}.
- The {endmarker} after {script} must NOT be preceded by
- any white space.
If [endmarker] is omitted, it defaults to a dot '.'
- like for the |:append| and |:insert| commands.
+ like for the |:append| and |:insert| commands. Refer
+ to |:let-heredoc| for more information.
+
This form of the |:ruby| command is mainly useful for
including ruby code in vim scripts.
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index e36ff9d8d8..820bd0eb35 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -247,12 +247,12 @@ arguments separated by " " (space) instead of "\t" (tab).
:lua =jit.version
<
*:lua-heredoc*
-:lua << [endmarker]
+:lua << [trim] [{endmarker}]
{script}
{endmarker}
- Executes Lua script {script} from within Vimscript. {endmarker} must NOT
- be preceded by whitespace. You can omit [endmarker] after the "<<" and use
- a dot "." after {script} (similar to |:append|, |:insert|).
+ Executes Lua script {script} from within Vimscript. You can omit
+ [endmarker] after the "<<" and use a dot "." after {script} (similar to
+ |:append|, |:insert|). Refer to |let-heredoc| for more information.
Example: >vim
function! CurrentLineInfo()
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 2a776ea30a..c343525a09 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -39,6 +39,12 @@ The following new APIs or features were added.
iterators |luaref-in|.
• Added |vim.keycode()| for translating keycodes in a string.
+• Added automatic linting of treesitter query files (see |ft-query-plugin|).
+ Automatic linting can be turned off via >lua
+ vim.g.query_lint_on = {}
+<
+• Enabled treesitter highlighting for treesitter query files by default.
+
==============================================================================
CHANGED FEATURES *news-changed*
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index dc1afe89f8..32c97ce3ad 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -841,6 +841,28 @@ get_files({lang}, {query_name}, {is_included})
string[] query_files List of files to load for given query and
language
+lint({buf}, {opts}) *vim.treesitter.query.lint()*
+ Lint treesitter queries using installed parser, or clear lint errors.
+
+ Use |treesitter-parsers| in runtimepath to check the query file in {buf}
+ for errors:
+
+ • verify that used nodes are valid identifiers in the grammar.
+ • verify that predicates and directives are valid.
+ • verify that top-level s-expressions are valid.
+
+ The found diagnostics are reported using |diagnostic-api|. By default, the
+ parser used for verification is determined by the containing folder of the
+ query file, e.g., if the path is `**/lua/highlights.scm` , the parser for the `lua` language will be used.
+
+ Parameters: ~
+ • {buf} (integer) Buffer handle
+ • {opts} (QueryLinterOpts|nil) Optional keyword arguments:
+ • langs (string|string[]|nil) Language(s) to use for checking
+ the query. If multiple languages are specified, queries are
+ validated for all of them
+ • clear (boolean) if `true`, just clear current lint errors
+
list_directives() *vim.treesitter.query.list_directives()*
Lists the currently available directives to use in queries.
diff --git a/runtime/ftplugin/query.lua b/runtime/ftplugin/query.lua
index 3b99d67247..842d338fd9 100644
--- a/runtime/ftplugin/query.lua
+++ b/runtime/ftplugin/query.lua
@@ -1,6 +1,30 @@
-- Neovim filetype plugin file
-- Language: Tree-sitter query
--- Last Change: 2022 Mar 29
+-- Last Change: 2022 Apr 25
+
+if vim.b.did_ftplugin == 1 then
+ return
+end
+
+-- Do not set vim.b.did_ftplugin = 1 to allow loading of ftplugin/lisp.vim
+
+-- use treesitter over syntax
+vim.treesitter.start()
+
+-- query linter
+local buf = vim.api.nvim_get_current_buf()
+local query_lint_on = vim.g.query_lint_on or { 'BufEnter', 'BufWrite' }
+
+if not vim.b.disable_query_linter and #query_lint_on > 0 then
+ vim.api.nvim_create_autocmd(query_lint_on, {
+ group = vim.api.nvim_create_augroup('querylint', { clear = false }),
+ buffer = buf,
+ callback = function()
+ vim.treesitter.query.lint(buf)
+ end,
+ desc = 'Query linter',
+ })
+end
-- it's a lisp!
vim.cmd([[ runtime! ftplugin/lisp.vim ]])
diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua
new file mode 100644
index 0000000000..62f28d3097
--- /dev/null
+++ b/runtime/lua/vim/treesitter/_query_linter.lua
@@ -0,0 +1,302 @@
+local namespace = vim.api.nvim_create_namespace('vim.treesitter.query_linter')
+-- those node names exist for every language
+local BUILT_IN_NODE_NAMES = { '_', 'ERROR' }
+
+local M = {}
+
+--- @class QueryLinterNormalizedOpts
+--- @field langs string[]
+--- @field clear boolean
+
+--- @private
+--- Caches parse results for queries for each language.
+--- Entries of parse_cache[lang][query_text] will either be true for successful parse or contain the
+--- error message of the parse
+--- @type table<string,table<string,string|true>>
+local parse_cache = {}
+
+--- Contains language dependent context for the query linter
+--- @class QueryLinterLanguageContext
+--- @field lang string? Current `lang` of the targeted parser
+--- @field parser_info table? Parser info returned by vim.treesitter.language.inspect
+--- @field is_first_lang boolean Whether this is the first language of a linter run checking queries for multiple `langs`
+
+--- @private
+--- Adds a diagnostic for node in the query buffer
+--- @param diagnostics Diagnostic[]
+--- @param node TSNode
+--- @param buf integer
+--- @param lint string
+--- @param lang string?
+local function add_lint_for_node(diagnostics, node, buf, lint, lang)
+ local node_text = vim.treesitter.get_node_text(node, buf):gsub('\n', ' ')
+ --- @type string
+ local message = lint .. ': ' .. node_text
+ local error_range = { node:range() }
+ diagnostics[#diagnostics + 1] = {
+ lnum = error_range[1],
+ end_lnum = error_range[3],
+ col = error_range[2],
+ end_col = error_range[4],
+ severity = vim.diagnostic.ERROR,
+ message = message,
+ source = lang,
+ }
+end
+
+--- @private
+--- Determines the target language of a query file by its path: <lang>/<query_type>.scm
+--- @param buf integer
+--- @return string?
+local function guess_query_lang(buf)
+ local filename = vim.api.nvim_buf_get_name(buf)
+ if filename ~= '' then
+ local ok, query_lang = pcall(vim.fn.fnamemodify, filename, ':p:h:t')
+ if ok then
+ return query_lang
+ end
+ end
+end
+
+--- @private
+--- @param buf integer
+--- @param opts QueryLinterOpts|QueryLinterNormalizedOpts|nil
+--- @return QueryLinterNormalizedOpts
+local function normalize_opts(buf, opts)
+ opts = opts or {}
+ if not opts.langs then
+ opts.langs = guess_query_lang(buf)
+ end
+
+ if type(opts.langs) ~= 'table' then
+ --- @diagnostic disable-next-line:assign-type-mismatch
+ opts.langs = { opts.langs }
+ end
+
+ --- @cast opts QueryLinterNormalizedOpts
+ opts.langs = opts.langs or {}
+ return opts
+end
+
+local lint_query = [[;; query
+ (program [(named_node) (list) (grouping)] @toplevel)
+ (named_node
+ name: _ @node.named)
+ (anonymous_node
+ name: _ @node.anonymous)
+ (field_definition
+ name: (identifier) @field)
+ (predicate
+ name: (identifier) @predicate.name
+ type: (predicate_type) @predicate.type)
+ (ERROR) @error
+]]
+
+--- @private
+--- @param node TSNode
+--- @param buf integer
+--- @param lang string
+--- @param diagnostics Diagnostic[]
+local function check_toplevel(node, buf, lang, diagnostics)
+ local query_text = vim.treesitter.get_node_text(node, buf)
+
+ if not parse_cache[lang] then
+ parse_cache[lang] = {}
+ end
+
+ local lang_cache = parse_cache[lang]
+
+ if lang_cache[query_text] == nil then
+ local ok, err = pcall(vim.treesitter.query.parse, lang, query_text)
+
+ if not ok and type(err) == 'string' then
+ err = err:match('.-:%d+: (.+)')
+ end
+
+ lang_cache[query_text] = ok or err
+ end
+
+ local cache_entry = lang_cache[query_text]
+
+ if type(cache_entry) == 'string' then
+ add_lint_for_node(diagnostics, node, buf, cache_entry, lang)
+ end
+end
+
+--- @private
+--- @param node TSNode
+--- @param buf integer
+--- @param lang string
+--- @param parser_info table
+--- @param diagnostics Diagnostic[]
+local function check_field(node, buf, lang, parser_info, diagnostics)
+ local field_name = vim.treesitter.get_node_text(node, buf)
+ if not vim.tbl_contains(parser_info.fields, field_name) then
+ add_lint_for_node(diagnostics, node, buf, 'Invalid field', lang)
+ end
+end
+
+--- @private
+--- @param node TSNode
+--- @param buf integer
+--- @param lang string
+--- @param parser_info (table)
+--- @param diagnostics Diagnostic[]
+local function check_node(node, buf, lang, parser_info, diagnostics)
+ local node_type = vim.treesitter.get_node_text(node, buf)
+ local is_named = node_type:sub(1, 1) ~= '"'
+
+ if not is_named then
+ node_type = node_type:gsub('"(.*)".*$', '%1'):gsub('\\(.)', '%1')
+ end
+
+ local found = vim.tbl_contains(BUILT_IN_NODE_NAMES, node_type)
+ or vim.tbl_contains(parser_info.symbols, function(s)
+ return vim.deep_equal(s, { node_type, is_named })
+ end, { predicate = true })
+
+ if not found then
+ add_lint_for_node(diagnostics, node, buf, 'Invalid node type', lang)
+ end
+end
+
+--- @private
+--- @param node TSNode
+--- @param buf integer
+--- @param is_predicate boolean
+--- @return string
+local function get_predicate_name(node, buf, is_predicate)
+ local name = vim.treesitter.get_node_text(node, buf)
+ if is_predicate then
+ if vim.startswith(name, 'not-') then
+ --- @type string
+ name = name:sub(string.len('not-') + 1)
+ end
+ return name .. '?'
+ end
+ return name .. '!'
+end
+
+--- @private
+--- @param predicate_node TSNode
+--- @param predicate_type_node TSNode
+--- @param buf integer
+--- @param lang string?
+--- @param diagnostics Diagnostic[]
+local function check_predicate(predicate_node, predicate_type_node, buf, lang, diagnostics)
+ local type_string = vim.treesitter.get_node_text(predicate_type_node, buf)
+
+ -- Quirk of the query grammar that directives are also predicates!
+ if type_string == '?' then
+ if
+ not vim.tbl_contains(
+ vim.treesitter.query.list_predicates(),
+ get_predicate_name(predicate_node, buf, true)
+ )
+ then
+ add_lint_for_node(diagnostics, predicate_node, buf, 'Unknown predicate', lang)
+ end
+ elseif type_string == '!' then
+ if
+ not vim.tbl_contains(
+ vim.treesitter.query.list_directives(),
+ get_predicate_name(predicate_node, buf, false)
+ )
+ then
+ add_lint_for_node(diagnostics, predicate_node, buf, 'Unknown directive', lang)
+ end
+ end
+end
+
+--- @private
+--- @param buf integer
+--- @param match table<integer,TSNode>
+--- @param query Query
+--- @param lang_context QueryLinterLanguageContext
+--- @param diagnostics Diagnostic[]
+local function lint_match(buf, match, query, lang_context, diagnostics)
+ local predicate --- @type TSNode
+ local predicate_type --- @type TSNode
+ local lang = lang_context.lang
+ local parser_info = lang_context.parser_info
+
+ for id, node in pairs(match) do
+ local cap_id = query.captures[id]
+
+ -- perform language-independent checks only for first lang
+ if lang_context.is_first_lang then
+ if cap_id == 'error' then
+ add_lint_for_node(diagnostics, node, buf, 'Syntax error')
+ elseif cap_id == 'predicate.name' then
+ predicate = node
+ elseif cap_id == 'predicate.type' then
+ predicate_type = node
+ end
+ end
+
+ -- other checks rely on Neovim parser introspection
+ if lang and parser_info then
+ if cap_id == 'toplevel' then
+ check_toplevel(node, buf, lang, diagnostics)
+ elseif cap_id == 'field' then
+ check_field(node, buf, lang, parser_info, diagnostics)
+ elseif cap_id == 'node.named' or cap_id == 'node.anonymous' then
+ check_node(node, buf, lang, parser_info, diagnostics)
+ end
+ end
+ end
+
+ if predicate and predicate_type then
+ check_predicate(predicate, predicate_type, buf, lang, diagnostics)
+ end
+end
+
+--- @private
+--- @param buf integer Buffer to lint
+--- @param opts QueryLinterOpts|QueryLinterNormalizedOpts|nil Options for linting
+function M.lint(buf, opts)
+ if buf == 0 then
+ buf = vim.api.nvim_get_current_buf()
+ end
+
+ local diagnostics = {}
+ local query = vim.treesitter.query.parse('query', lint_query)
+
+ opts = normalize_opts(buf, opts)
+
+ -- perform at least one iteration even with no langs to perform language independent checks
+ for i = 1, math.max(1, #opts.langs) do
+ local lang = opts.langs[i]
+
+ --- @type boolean, (table|nil)
+ local ok, parser_info = pcall(vim.treesitter.language.inspect, lang)
+ if not ok then
+ parser_info = nil
+ end
+
+ local parser = vim.treesitter.get_parser(buf)
+ parser:parse()
+ parser:for_each_tree(function(tree, ltree)
+ if ltree:lang() == 'query' then
+ for _, match, _ in query:iter_matches(tree:root(), buf, 0, -1) do
+ local lang_context = {
+ lang = lang,
+ parser_info = parser_info,
+ is_first_lang = i == 1,
+ }
+ lint_match(buf, match, query, lang_context, diagnostics)
+ end
+ end
+ end)
+ end
+
+ vim.diagnostic.set(namespace, buf, diagnostics)
+end
+
+--- @private
+--- @param buf integer
+function M.clear(buf)
+ vim.diagnostic.reset(namespace, buf)
+end
+
+return M
diff --git a/runtime/lua/vim/treesitter/playground.lua b/runtime/lua/vim/treesitter/playground.lua
index c512710810..8293c1bd0a 100644
--- a/runtime/lua/vim/treesitter/playground.lua
+++ b/runtime/lua/vim/treesitter/playground.lua
@@ -269,6 +269,7 @@ function M.inspect_tree(opts)
vim.bo[b].buflisted = false
vim.bo[b].buftype = 'nofile'
vim.bo[b].bufhidden = 'wipe'
+ vim.b[b].disable_query_linter = true
vim.bo[b].filetype = 'query'
local title --- @type string?
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index 8a747ba14c..492bfd1ffb 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -714,4 +714,33 @@ function Query:iter_matches(node, source, start, stop)
return iter
end
+---@class QueryLinterOpts
+---@field langs (string|string[]|nil)
+---@field clear (boolean)
+
+--- Lint treesitter queries using installed parser, or clear lint errors.
+---
+--- Use |treesitter-parsers| in runtimepath to check the query file in {buf} for errors:
+---
+--- - verify that used nodes are valid identifiers in the grammar.
+--- - verify that predicates and directives are valid.
+--- - verify that top-level s-expressions are valid.
+---
+--- The found diagnostics are reported using |diagnostic-api|.
+--- By default, the parser used for verification is determined by the containing folder
+--- of the query file, e.g., if the path is `**/lua/highlights.scm`, the parser for the
+--- `lua` language will be used.
+---@param buf (integer) Buffer handle
+---@param opts (QueryLinterOpts|nil) Optional keyword arguments:
+--- - langs (string|string[]|nil) Language(s) to use for checking the query.
+--- If multiple languages are specified, queries are validated for all of them
+--- - clear (boolean) if `true`, just clear current lint errors
+function M.lint(buf, opts)
+ if opts and opts.clear then
+ require('vim.treesitter._query_linter').clear(buf)
+ else
+ require('vim.treesitter._query_linter').lint(buf, opts)
+ end
+end
+
return M
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index c63ab804af..8d730733d0 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1687,7 +1687,7 @@ void enter_buffer(buf_T *buf)
// May need to set the spell language. Can only do this after the buffer
// has been properly setup.
if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
- (void)did_set_spelllang(curwin);
+ (void)parse_spelllang(curwin);
}
curbuf->b_last_used = time(NULL);
@@ -3470,8 +3470,8 @@ void free_titles(void)
#endif
-/// Get relative cursor position in window into "buf[buflen]", in the form 99%,
-/// using "Top", "Bot" or "All" when appropriate.
+/// Get relative cursor position in window into "buf[buflen]", in the localized
+/// percentage form like %99, 99%; using "Top", "Bot" or "All" when appropriate.
void get_rel_pos(win_T *wp, char *buf, int buflen)
{
// Need at least 3 chars for writing.
@@ -3495,9 +3495,20 @@ void get_rel_pos(win_T *wp, char *buf, int buflen)
} else if (above <= 0) {
xstrlcpy(buf, _("Top"), (size_t)buflen);
} else {
- vim_snprintf(buf, (size_t)buflen, "%2d%%", above > 1000000L
- ? (int)(above / ((above + below) / 100L))
- : (int)(above * 100L / (above + below)));
+ int perc = (above > 1000000L
+ ? (int)(above / ((above + below) / 100L))
+ : (int)(above * 100L / (above + below)));
+
+ char *p = buf;
+ size_t l = (size_t)buflen;
+ if (perc < 10) {
+ // prepend one space
+ buf[0] = ' ';
+ p++;
+ l--;
+ }
+ // localized percentage value
+ vim_snprintf(p, l, _("%d%%"), perc);
}
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index ebc34564e2..f898063fb0 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -7711,7 +7711,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
const int wo_spell_save = curwin->w_p_spell;
if (!curwin->w_p_spell) {
- did_set_spelllang(curwin);
+ parse_spelllang(curwin);
curwin->w_p_spell = true;
}
@@ -7768,7 +7768,7 @@ static void f_spellsuggest(typval_T *argvars, typval_T *rettv, EvalFuncData fptr
const int wo_spell_save = curwin->w_p_spell;
if (!curwin->w_p_spell) {
- did_set_spelllang(curwin);
+ parse_spelllang(curwin);
curwin->w_p_spell = true;
}
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 0e22cf54cf..1f5a6eaec4 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -2571,11 +2571,18 @@ void ex_function(exarg_T *eap)
&& (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) {
// ":python <<" continues until a dot, like ":append"
p = skipwhite(arg + 2);
+ if (strncmp(p, "trim", 4) == 0) {
+ // Ignore leading white space.
+ p = skipwhite(p + 4);
+ heredoc_trimmed = xstrnsave(theline, (size_t)(skipwhite(theline) - theline));
+ }
if (*p == NUL) {
skip_until = xstrdup(".");
} else {
- skip_until = xstrdup(p);
+ skip_until = xstrnsave(p, (size_t)(skiptowhite(p) - p));
}
+ do_concat = false;
+ is_heredoc = true;
}
// Check for ":let v =<< [trim] EOF"
diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c
index 593ba9f6c3..de6c4bab60 100644
--- a/src/nvim/eval/vars.c
+++ b/src/nvim/eval/vars.c
@@ -155,14 +155,18 @@ char *eval_all_expr_in_str(char *str)
/// marker, then the leading indentation before the lines (matching the
/// indentation in the 'cmd' line) is stripped.
///
+/// When getting lines for an embedded script (e.g. python, lua, perl, ruby,
+/// tcl, mzscheme), "script_get" is set to true. In this case, if the marker is
+/// missing, then '.' is accepted as a marker.
+///
/// @return a List with {lines} or NULL on failure.
-static list_T *heredoc_get(exarg_T *eap, char *cmd)
+list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get)
{
char *marker;
- char *p;
int marker_indent_len = 0;
int text_indent_len = 0;
char *text_indent = NULL;
+ char dot[] = ".";
if (eap->getline == NULL) {
emsg(_("E991: cannot use =<< here"));
@@ -182,7 +186,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// The amount of indentation trimmed is the same as the indentation
// of the first line after the :let command line. To find the end
// marker the indent of the :let command line is trimmed.
- p = *eap->cmdlinep;
+ char *p = *eap->cmdlinep;
while (ascii_iswhite(*p)) {
p++;
marker_indent_len++;
@@ -203,19 +207,25 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
// The marker is the next word.
if (*cmd != NUL && *cmd != '"') {
marker = skipwhite(cmd);
- p = skiptowhite(marker);
+ char *p = skiptowhite(marker);
if (*skipwhite(p) != NUL && *skipwhite(p) != '"') {
semsg(_(e_trailing_arg), p);
return NULL;
}
*p = NUL;
- if (islower((uint8_t)(*marker))) {
+ if (!script_get && islower((uint8_t)(*marker))) {
emsg(_("E221: Marker cannot start with lower case letter"));
return NULL;
}
} else {
- emsg(_("E172: Missing marker"));
- return NULL;
+ // When getting lines for an embedded script, if the marker is missing,
+ // accept '.' as the marker.
+ if (script_get) {
+ marker = dot;
+ } else {
+ emsg(_("E172: Missing marker"));
+ return NULL;
+ }
}
char *theline = NULL;
@@ -227,7 +237,9 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
xfree(theline);
theline = eap->getline(NUL, eap->cookie, 0, false);
if (theline == NULL) {
- semsg(_("E990: Missing end marker '%s'"), marker);
+ if (!script_get) {
+ semsg(_("E990: Missing end marker '%s'"), marker);
+ }
break;
}
@@ -249,7 +261,7 @@ static list_T *heredoc_get(exarg_T *eap, char *cmd)
if (text_indent_len == -1 && *theline != NUL) {
// set the text indent from the first line.
- p = theline;
+ char *p = theline;
text_indent_len = 0;
while (ascii_iswhite(*p)) {
p++;
@@ -353,7 +365,7 @@ void ex_let(exarg_T *eap)
if (expr[0] == '=' && expr[1] == '<' && expr[2] == '<') {
// HERE document
- list_T *l = heredoc_get(eap, expr + 3);
+ list_T *l = heredoc_get(eap, expr + 3, false);
if (l != NULL) {
tv_list_set_ret(&rettv, l);
if (!eap->skip) {
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 7a77ffb4da..f276e8ae24 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -2640,7 +2640,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
// If the window options were changed may need to set the spell language.
// Can only do this after the buffer has been properly setup.
if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
- (void)did_set_spelllang(curwin);
+ (void)parse_spelllang(curwin);
}
if (command == NULL) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 33a8dcafc2..5018c9268b 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -29,6 +29,7 @@
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/vars.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
@@ -4277,7 +4278,7 @@ void cmdline_init(void)
/// Check value of 'cedit' and set cedit_key.
/// Returns NULL if value is OK, error message otherwise.
-const char *check_cedit(void)
+const char *did_set_cedit(optset_T *args)
{
if (*p_cedit == NUL) {
cedit_key = -1;
@@ -4561,39 +4562,37 @@ bool is_in_cmdwin(void)
char *script_get(exarg_T *const eap, size_t *const lenp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
- const char *const cmd = eap->arg;
+ char *cmd = eap->arg;
if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL) {
*lenp = strlen(eap->arg);
return eap->skip ? NULL : xmemdupz(eap->arg, *lenp);
}
+ cmd += 2;
garray_T ga = { .ga_data = NULL, .ga_len = 0 };
+
+ list_T *const l = heredoc_get(eap, cmd, true);
+ if (l == NULL) {
+ return NULL;
+ }
+
if (!eap->skip) {
ga_init(&ga, 1, 0x400);
}
- const char *const end_pattern = (cmd[2] != NUL ? skipwhite(cmd + 2) : ".");
- while (true) {
- char *const theline = eap->getline(eap->cstack->cs_looplevel > 0 ? -1 : NUL, eap->cookie, 0,
- true);
-
- if (theline == NULL || strcmp(end_pattern, theline) == 0) {
- xfree(theline);
- break;
- }
-
+ TV_LIST_ITER_CONST(l, li, {
if (!eap->skip) {
- ga_concat(&ga, theline);
+ ga_concat(&ga, tv_get_string(TV_LIST_ITEM_TV(li)));
ga_append(&ga, '\n');
}
- xfree(theline);
- }
+ });
*lenp = (size_t)ga.ga_len; // Set length without trailing NUL.
if (!eap->skip) {
ga_append(&ga, NUL);
}
+ tv_list_free(l);
return (char *)ga.ga_data;
}
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 35302e1222..ecb1a0c11b 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -154,6 +154,9 @@ local dump_option = function(i, o)
table.insert(defines, { 'PV_' .. varname:sub(3):upper() , pv_name})
w(' .indir=' .. pv_name)
end
+ if o.cb then
+ w(' .opt_did_set_cb=' .. o.cb)
+ end
if o.enable_if then
w('#else')
w(' .var=NULL')
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
index 6624b39d0c..d6860fff30 100644
--- a/src/nvim/insexpand.c
+++ b/src/nvim/insexpand.c
@@ -2257,14 +2257,14 @@ static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb)
/// Invoked when the 'completefunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-void set_completefunc_option(const char **errmsg)
+const char *did_set_completefunc(optset_T *args FUNC_ATTR_UNUSED)
{
if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
set_buflocal_cfu_callback(curbuf);
+ return NULL;
}
/// Copy the global 'completefunc' callback function to the buffer-local
@@ -2278,13 +2278,14 @@ void set_buflocal_cfu_callback(buf_T *buf)
/// Invoked when the 'omnifunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-void set_omnifunc_option(buf_T *buf, const char **errmsg)
+const char *did_set_omnifunc(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
if (option_set_callback_func(buf->b_p_ofu, &ofu_cb) == FAIL) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
set_buflocal_ofu_callback(buf);
+ return NULL;
}
/// Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc'
@@ -2298,7 +2299,7 @@ void set_buflocal_ofu_callback(buf_T *buf)
/// Invoked when the 'thesaurusfunc' option is set. The option value can be a
/// name of a function (string), or function(<name>) or funcref(<name>) or a
/// lambda expression.
-void set_thesaurusfunc_option(const char **errmsg)
+const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED)
{
int retval;
@@ -2310,9 +2311,7 @@ void set_thesaurusfunc_option(const char **errmsg)
retval = option_set_callback_func(p_tsrfu, &tsrfu_cb);
}
- if (retval == FAIL) {
- *errmsg = e_invarg;
- }
+ return retval == FAIL ? e_invarg : NULL;
}
/// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 1c1f68b68d..9586b56f3c 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1619,7 +1619,7 @@ void ex_lua(exarg_T *const eap)
{
size_t len;
char *code = script_get(eap, &len);
- if (eap->skip) {
+ if (eap->skip || code == NULL) {
xfree(code);
return;
}
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
index 742e8720f9..37f1c5216d 100644
--- a/src/nvim/lua/spell.c
+++ b/src/nvim/lua/spell.c
@@ -39,7 +39,7 @@ int nlua_spell_check(lua_State *lstate)
const int wo_spell_save = curwin->w_p_spell;
if (!curwin->w_p_spell) {
- did_set_spelllang(curwin);
+ parse_spelllang(curwin);
curwin->w_p_spell = true;
}
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 9a835e0eb8..c1d02e89b8 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -2386,7 +2386,7 @@ void langmap_init(void)
/// Called when langmap option is set; the language map can be
/// changed at any time!
-void langmap_set(void)
+const char *did_set_langmap(optset_T *args)
{
char *p;
char *p2;
@@ -2434,9 +2434,10 @@ void langmap_set(void)
}
}
if (to == NUL) {
- semsg(_("E357: 'langmap': Matching character missing for %s"),
- transchar(from));
- return;
+ snprintf(args->os_errbuf, args->os_errbuflen,
+ _("E357: 'langmap': Matching character missing for %s"),
+ transchar(from));
+ return args->os_errbuf;
}
if (from >= 256) {
@@ -2454,8 +2455,10 @@ void langmap_set(void)
p = p2;
if (p[0] != NUL) {
if (p[0] != ',') {
- semsg(_("E358: 'langmap': Extra characters after semicolon: %s"), p);
- return;
+ snprintf(args->os_errbuf, args->os_errbuflen,
+ _("E358: 'langmap': Extra characters after semicolon: %s"),
+ p);
+ return args->os_errbuf;
}
p++;
}
@@ -2464,6 +2467,8 @@ void langmap_set(void)
}
}
}
+
+ return NULL;
}
static void do_exmap(exarg_T *eap, int isabbrev)
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index da693371f3..5a5286905f 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -956,7 +956,7 @@ normal_end:
set_reg_var(get_default_register_name());
}
- s->c = finish_op;
+ const bool prev_finish_op = finish_op;
if (s->oa.op_type == OP_NOP) {
// Reset finish_op, in case it was set
finish_op = false;
@@ -964,7 +964,7 @@ normal_end:
}
// Redraw the cursor with another shape, if we were in Operator-pending
// mode or did a replace command.
- if (s->c || s->ca.cmdchar == 'r'
+ if (prev_finish_op || s->ca.cmdchar == 'r'
|| (s->ca.cmdchar == 'g' && s->ca.nchar == 'r')) {
ui_cursor_shape(); // may show different cursor shape
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 2919b94d41..89fe9b464d 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -5628,11 +5628,12 @@ static void op_colon(oparg_T *oap)
static Callback opfunc_cb;
/// Process the 'operatorfunc' option value.
-void set_operatorfunc_option(const char **errmsg)
+const char *did_set_operatorfunc(optset_T *args FUNC_ATTR_UNUSED)
{
if (option_set_callback_func(p_opfunc, &opfunc_cb) == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
#if defined(EXITFREE)
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 040ab1b847..3264d80a2f 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -84,6 +84,7 @@
#include "nvim/path.h"
#include "nvim/popupmenu.h"
#include "nvim/pos.h"
+#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
#include "nvim/search.h"
@@ -135,17 +136,6 @@ static long p_tw_nopaste;
static long p_wm_nopaste;
static char *p_vsts_nopaste;
-// options[] is initialized here.
-// The order of the options MUST be alphabetic for ":set all" and findoption().
-// All option names MUST start with a lowercase letter (for findoption()).
-// Exception: "t_" options are at the end.
-// The options with a NULL variable are 'hidden': a set command for them is
-// ignored and they are not printed.
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "options.generated.h"
-#endif
-
#define OPTION_COUNT ARRAY_SIZE(options)
typedef enum {
@@ -159,6 +149,17 @@ typedef enum {
# include "option.c.generated.h"
#endif
+// options[] is initialized here.
+// The order of the options MUST be alphabetic for ":set all" and findoption().
+// All option names MUST start with a lowercase letter (for findoption()).
+// Exception: "t_" options are at the end.
+// The options with a NULL variable are 'hidden': a set command for them is
+// ignored and they are not printed.
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "options.generated.h"
+#endif
+
void set_init_tablocal(void)
{
// susy baka: cmdheight calls itself OPT_GLOBAL but is really tablocal!
@@ -1237,7 +1238,7 @@ static void do_set_option_string(int opt_idx, int opt_flags, char **argp, int ne
// Handle side effects, and set the global value for ":set" on local
// options. Note: when setting 'syntax' or 'filetype' autocommands may
// be triggered that can cause havoc.
- *errmsg = did_set_string_option(opt_idx, (char **)varp, oldval,
+ *errmsg = did_set_string_option(opt_idx, (char **)varp, oldval, newval,
errbuf, errbuflen,
opt_flags, value_checked);
@@ -1840,9 +1841,9 @@ static void didset_options(void)
(void)compile_cap_prog(curwin->w_s);
(void)did_set_spell_option(true);
// set cedit_key
- (void)check_cedit();
+ (void)did_set_cedit(NULL);
// initialize the table for 'breakat'.
- fill_breakat_flags();
+ (void)did_set_breakat(NULL);
didset_window_options(curwin, true);
}
@@ -1853,10 +1854,10 @@ static void didset_options2(void)
highlight_changed();
// Parse default for 'fillchars'.
- (void)set_chars_option(curwin, &curwin->w_p_fcs, true);
+ (void)set_fillchars_option(curwin, curwin->w_p_fcs, true);
// Parse default for 'listchars'.
- (void)set_chars_option(curwin, &curwin->w_p_lcs, true);
+ (void)set_listchars_option(curwin, curwin->w_p_lcs, true);
// Parse default for 'wildmode'.
check_opt_wim();
@@ -2101,25 +2102,27 @@ static const char *did_set_force_off(bool *doskip)
}
/// Process the updated 'langremap' option value.
-static void did_set_langremap(void)
+static const char *did_set_langremap(optset_T *args FUNC_ATTR_UNUSED)
{
// 'langremap' -> !'langnoremap'
p_lnr = !p_lrm;
+ return NULL;
}
/// Process the updated 'langnoremap' option value.
-static void did_set_langnoremap(void)
+static const char *did_set_langnoremap(optset_T *args FUNC_ATTR_UNUSED)
{
// 'langnoremap' -> !'langremap'
p_lrm = !p_lnr;
+ return NULL;
}
/// Process the updated 'undofile' option value.
-static void did_set_undofile(int opt_flags)
+static const char *did_set_undofile(optset_T *args)
{
// Only take action when the option was set.
if (!curbuf->b_p_udf && !p_udf) {
- return;
+ return NULL;
}
// When reset we do not delete the undo file, the option may be set again
@@ -2132,19 +2135,21 @@ static void did_set_undofile(int opt_flags)
// if one exists, the buffer wasn't changed and the buffer was
// loaded
if ((curbuf == bp
- || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
+ || (args->os_flags & OPT_GLOBAL) || args->os_flags == 0)
&& !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) {
u_compute_hash(bp, hash);
u_read_undo(NULL, hash, bp->b_fname);
}
}
+
+ return NULL;
}
/// Process the updated 'readonly' option value.
-static void did_set_readonly(int opt_flags)
+static const char *did_set_readonly(optset_T *args)
{
// when 'readonly' is reset globally, also reset readonlymode
- if (!curbuf->b_p_ro && (opt_flags & OPT_LOCAL) == 0) {
+ if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0) {
readonlymode = false;
}
@@ -2154,10 +2159,12 @@ static void did_set_readonly(int opt_flags)
}
redraw_titles();
+
+ return NULL;
}
/// Process the updated 'modifiable' option value.
-static char *did_set_modifiable(void)
+static const char *did_set_modifiable(optset_T *args FUNC_ATTR_UNUSED)
{
// when 'modifiable' is changed, redraw the window title
redraw_titles();
@@ -2167,90 +2174,108 @@ static char *did_set_modifiable(void)
/// Process the updated 'endoffile' or 'endofline' or 'fixendofline' or 'bomb'
/// option value.
-static void did_set_eof_eol_fixeol_bomb(void)
+static const char *did_set_eof_eol_fixeol_bomb(optset_T *args FUNC_ATTR_UNUSED)
{
// redraw the window title and tab page text
redraw_titles();
+ return NULL;
}
/// Process the updated 'binary' option value.
-static void did_set_binary(int opt_flags, long old_value)
+static const char *did_set_binary(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+
// when 'bin' is set also set some other options
- set_options_bin((int)old_value, curbuf->b_p_bin, opt_flags);
+ set_options_bin((int)args->os_oldval.boolean, buf->b_p_bin, args->os_flags);
redraw_titles();
+
+ return NULL;
}
/// Process the updated 'buflisted' option value.
-static void did_set_buflisted(long old_value)
+static const char *did_set_buflisted(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+
// when 'buflisted' changes, trigger autocommands
- if (old_value != curbuf->b_p_bl) {
- apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE,
- NULL, NULL, true, curbuf);
+ if (args->os_oldval.boolean != buf->b_p_bl) {
+ apply_autocmds(buf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE,
+ NULL, NULL, true, buf);
}
+ return NULL;
}
/// Process the updated 'swapfile' option value.
-static void did_set_swapfile(void)
+static const char *did_set_swapfile(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
// when 'swf' is set, create swapfile, when reset remove swapfile
- if (curbuf->b_p_swf && p_uc) {
- ml_open_file(curbuf); // create the swap file
+ if (buf->b_p_swf && p_uc) {
+ ml_open_file(buf); // create the swap file
} else {
// no need to reset curbuf->b_may_swap, ml_open_file() will check
// buf->b_p_swf
- mf_close_file(curbuf, true); // remove the swap file
+ mf_close_file(buf, true); // remove the swap file
}
+ return NULL;
}
/// Process the updated 'paste' option value.
-static void did_set_paste(void)
+static const char *did_set_paste(optset_T *args FUNC_ATTR_UNUSED)
{
// when 'paste' is set or reset also change other options
paste_option_changed();
+ return NULL;
}
/// Process the updated 'ignorecase' option value.
-static void did_set_ignorecase(void)
+static const char *did_set_ignorecase(optset_T *args FUNC_ATTR_UNUSED)
{
// when 'ignorecase' is set or reset and 'hlsearch' is set, redraw
if (p_hls) {
redraw_all_later(UPD_SOME_VALID);
}
+ return NULL;
}
/// Process the updated 'hlsearch' option value.
-static void did_set_hlsearch(void)
+static const char *did_set_hlsearch(optset_T *args FUNC_ATTR_UNUSED)
{
// when 'hlsearch' is set or reset: reset no_hlsearch
set_no_hlsearch(false);
+ return NULL;
}
/// Process the updated 'scrollbind' option value.
-static void did_set_scrollbind(void)
+static const char *did_set_scrollbind(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+
// when 'scrollbind' is set: snapshot the current position to avoid a jump
// at the end of normal_cmd()
- if (!curwin->w_p_scb) {
- return;
+ if (!win->w_p_scb) {
+ return NULL;
}
do_check_scrollbind(false);
- curwin->w_scbind_pos = curwin->w_topline;
+ win->w_scbind_pos = win->w_topline;
+ return NULL;
}
/// Process the updated 'previewwindow' option value.
-static const char *did_set_previewwindow(bool *doskip)
+static const char *did_set_previewwindow(optset_T *args)
{
- if (!curwin->w_p_pvw) {
+ win_T *win = (win_T *)args->os_win;
+
+ if (!win->w_p_pvw) {
return NULL;
}
// There can be only one window with 'previewwindow' set.
- FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
- if (win->w_p_pvw && win != curwin) {
- curwin->w_p_pvw = false;
- *doskip = true;
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_p_pvw && wp != win) {
+ win->w_p_pvw = false;
+ args->os_doskip = true;
return e_preview_window_already_exists;
}
}
@@ -2259,32 +2284,37 @@ static const char *did_set_previewwindow(bool *doskip)
}
/// Process the updated 'lisp' option value.
-static void did_set_lisp(void)
+static const char *did_set_lisp(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
// When 'lisp' option changes include/exclude '-' in keyword characters.
- (void)buf_init_chartab(curbuf, false); // ignore errors
+ (void)buf_init_chartab(buf, false); // ignore errors
+ return NULL;
}
/// Process the updated 'title' or the 'icon' option value.
-static void did_set_title_icon(void)
+static const char *did_set_title_icon(optset_T *args FUNC_ATTR_UNUSED)
{
// when 'title' changed, may need to change the title; same for 'icon'
did_set_title();
+ return NULL;
}
/// Process the updated 'modified' option value.
-static void did_set_modified(long value)
+static const char *did_set_modified(optset_T *args)
{
- if (!value) {
- save_file_ff(curbuf); // Buffer is unchanged
+ buf_T *buf = (buf_T *)args->os_buf;
+ if (!args->os_newval.boolean) {
+ save_file_ff(buf); // Buffer is unchanged
}
redraw_titles();
- modified_was_set = (int)value;
+ modified_was_set = (int)args->os_newval.boolean;
+ return NULL;
}
#ifdef BACKSLASH_IN_FILENAME
/// Process the updated 'shellslash' option value.
-static void did_set_shellslash(void)
+static const char *did_set_shellslash(optset_T *args FUNC_ATTR_UNUSED)
{
if (p_ssl) {
psepc = '/';
@@ -2300,63 +2330,76 @@ static void did_set_shellslash(void)
buflist_slash_adjust();
alist_slash_adjust();
scriptnames_slash_adjust();
+ return NULL;
}
#endif
/// Process the updated 'wrap' option value.
-static void did_set_wrap(void)
+static const char *did_set_wrap(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+
// If 'wrap' is set, set w_leftcol to zero.
- if (curwin->w_p_wrap) {
- curwin->w_leftcol = 0;
+ if (win->w_p_wrap) {
+ win->w_leftcol = 0;
}
+ return NULL;
}
/// Process the updated 'equalalways' option value.
-static void did_set_equalalways(long old_value)
+static const char *did_set_equalalways(optset_T *args)
{
- if (p_ea && !old_value) {
- win_equal(curwin, false, 0);
+ win_T *win = (win_T *)args->os_win;
+ if (p_ea && !args->os_oldval.boolean) {
+ win_equal(win, false, 0);
}
+
+ return NULL;
}
/// Process the updated 'autochdir' option value.
-static void did_set_autochdir(void)
+static const char *did_set_autochdir(optset_T *args FUNC_ATTR_UNUSED)
{
// Change directories when the 'acd' option is set now.
do_autochdir();
+ return NULL;
}
/// Process the updated 'diff' option value.
-static void did_set_diff(void)
+static const char *did_set_diff(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
// May add or remove the buffer from the list of diff buffers.
- diff_buf_adjust(curwin);
- if (foldmethodIsDiff(curwin)) {
- foldUpdateAll(curwin);
+ diff_buf_adjust(win);
+ if (foldmethodIsDiff(win)) {
+ foldUpdateAll(win);
}
+ return NULL;
}
/// Process the updated 'spell' option value.
-static char *did_set_spell(void)
+static const char *did_set_spell(optset_T *args)
{
- if (curwin->w_p_spell) {
- return did_set_spelllang(curwin);
+ win_T *win = (win_T *)args->os_win;
+ if (win->w_p_spell) {
+ return parse_spelllang(win);
}
return NULL;
}
/// Process the updated 'arabic' option value.
-static const char *did_set_arabic(void)
+static const char *did_set_arabic(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
const char *errmsg = NULL;
- if (curwin->w_p_arab) {
+
+ if (win->w_p_arab) {
// 'arabic' is set, handle various sub-settings.
if (!p_tbidi) {
// set rightleft mode
- if (!curwin->w_p_rl) {
- curwin->w_p_rl = true;
+ if (!win->w_p_rl) {
+ win->w_p_rl = true;
changed_window_setting();
}
@@ -2386,8 +2429,8 @@ static const char *did_set_arabic(void)
// 'arabic' is reset, handle various sub-settings.
if (!p_tbidi) {
// reset rightleft mode
- if (curwin->w_p_rl) {
- curwin->w_p_rl = false;
+ if (win->w_p_rl) {
+ win->w_p_rl = false;
changed_window_setting();
}
@@ -2406,85 +2449,15 @@ static const char *did_set_arabic(void)
return errmsg;
}
-static void did_set_number_relativenumber(void)
+/// Process the updated 'number' or 'relativenumber' option value.
+static const char *did_set_number_relativenumber(optset_T *args)
{
- if (*curwin->w_p_stc != NUL) {
+ win_T *win = (win_T *)args->os_win;
+ if (*win->w_p_stc != NUL) {
// When 'relativenumber'/'number' is changed and 'statuscolumn' is set, reset width.
- curwin->w_nrwidth_line_count = 0;
+ win->w_nrwidth_line_count = 0;
}
-}
-
-/// When some boolean options are changed, need to take some action.
-static const char *did_set_bool_option(const char *varp, int opt_flags, long value, long old_value,
- bool *doskip)
-{
- const char *errmsg = NULL;
-
- if ((int *)varp == &p_force_on) {
- errmsg = did_set_force_on(doskip);
- } else if ((int *)varp == &p_force_off) {
- errmsg = did_set_force_off(doskip);
- } else if ((int *)varp == &p_lrm) { // 'langremap'
- did_set_langremap();
- } else if ((int *)varp == &p_lnr) { // 'langnoremap'
- did_set_langnoremap();
- } else if ((int *)varp == &curbuf->b_p_udf // buffer local 'undofile'
- || (int *)varp == &p_udf) { // 'undofile'
- did_set_undofile(opt_flags);
- } else if ((int *)varp == &curbuf->b_p_ro) { // 'readonly'
- did_set_readonly(opt_flags);
- } else if ((int *)varp == &curbuf->b_p_ma) {
- errmsg = did_set_modifiable(); // 'modifiable'
- } else if ((int *)varp == &curbuf->b_p_eof // 'endoffile'
- || (int *)varp == &curbuf->b_p_eol // 'endofline'
- || (int *)varp == &curbuf->b_p_fixeol // 'fixendofline'
- || (int *)varp == &curbuf->b_p_bomb) { // 'bomb'
- did_set_eof_eol_fixeol_bomb();
- } else if ((int *)varp == &curbuf->b_p_bin) { // 'binary'
- did_set_binary(opt_flags, old_value);
- } else if ((int *)varp == &curbuf->b_p_bl) { // 'buflisted'
- did_set_buflisted(old_value);
- } else if ((int *)varp == &curbuf->b_p_swf) { // 'swapfile'
- did_set_swapfile();
- } else if ((int *)varp == &p_paste) { // 'paste'
- did_set_paste();
- } else if ((int *)varp == &p_ic) { // 'ignorecase'
- did_set_ignorecase();
- } else if ((int *)varp == &p_hls) { // 'hlsearch'
- did_set_hlsearch();
- } else if ((int *)varp == &curwin->w_p_scb) { // 'scrollbind'
- did_set_scrollbind();
- } else if ((int *)varp == &curwin->w_p_pvw) { // 'previewwindow'
- errmsg = did_set_previewwindow(doskip);
- } else if (varp == (char *)&(curbuf->b_p_lisp)) { // 'lisp'
- did_set_lisp();
- } else if ((int *)varp == &p_title // 'title'
- || (int *)varp == &p_icon) { // 'icon'
- did_set_title_icon();
- } else if ((int *)varp == &curbuf->b_changed) { // 'modified'
- did_set_modified(value);
-#ifdef BACKSLASH_IN_FILENAME
- } else if ((int *)varp == &p_ssl) { // 'shellslash'
- did_set_shellslash();
-#endif
- } else if ((int *)varp == &curwin->w_p_wrap) { // 'wrap'
- did_set_wrap();
- } else if ((int *)varp == &p_ea) { // 'equalalways'
- did_set_equalalways(old_value);
- } else if ((int *)varp == &p_acd) { // 'autochdir'
- did_set_autochdir();
- } else if ((int *)varp == &curwin->w_p_diff) { // 'diff'
- did_set_diff();
- } else if ((int *)varp == &curwin->w_p_spell) { // 'spell'
- errmsg = did_set_spell();
- } else if ((int *)varp == &curwin->w_p_arab) { // 'arabic'
- errmsg = did_set_arabic();
- } else if ((int *)varp == &curwin->w_p_nu // 'number'
- || (int *)varp == &curwin->w_p_rnu) { // 'relativenumber'
- did_set_number_relativenumber();
- }
-
- return errmsg;
+ return NULL;
}
/// Set the value of a boolean option, taking care of side effects
@@ -2524,8 +2497,28 @@ static const char *set_bool_option(const int opt_idx, char *const varp, const in
}
// Handle side effects for changing a bool option.
+ const char *errmsg = NULL;
bool doskip = false;
- const char *errmsg = did_set_bool_option(varp, opt_flags, value, old_value, &doskip);
+ if ((int *)varp == &p_force_on) {
+ errmsg = did_set_force_on(&doskip);
+ } else if ((int *)varp == &p_force_off) {
+ errmsg = did_set_force_off(&doskip);
+ } else if (options[opt_idx].opt_did_set_cb != NULL) {
+ optset_T args = {
+ .os_varp = varp,
+ .os_flags = opt_flags,
+ .os_oldval.boolean = old_value,
+ .os_newval.boolean = value,
+ .os_doskip = false,
+ .os_errbuf = NULL,
+ .os_errbuflen = 0,
+ .os_buf = curbuf,
+ .os_win = curwin
+ };
+
+ errmsg = options[opt_idx].opt_did_set_cb(&args);
+ doskip = args.os_doskip;
+ }
if (doskip) {
return errmsg;
}
@@ -2557,38 +2550,51 @@ static const char *set_bool_option(const int opt_idx, char *const varp, const in
}
/// Process the new 'winheight' value.
-static void did_set_winheight(win_T *win, long value)
+static const char *did_set_winheight(optset_T *args)
{
// Change window height NOW
if (!ONE_WINDOW) {
- if (win->w_height < value) {
- win_setheight((int)value);
+ win_T *win = (win_T *)args->os_win;
+ if (win->w_height < p_wh) {
+ win_setheight((int)p_wh);
}
}
+
+ return NULL;
}
/// Process the new 'helpheight' option value.
-static void did_set_helpheight(buf_T *buf, win_T *win, long value)
+static const char *did_set_helpheight(optset_T *args)
{
// Change window height NOW
if (!ONE_WINDOW) {
- if (buf->b_help && win->w_height < value) {
- win_setheight((int)value);
+ buf_T *buf = (buf_T *)args->os_buf;
+ win_T *win = (win_T *)args->os_win;
+ if (buf->b_help && win->w_height < p_hh) {
+ win_setheight((int)p_hh);
}
}
+
+ return NULL;
}
/// Process the new 'winwidth' option value.
-static void did_set_winwidth(win_T *win, long value)
+static const char *did_set_winwidth(optset_T *args)
{
- if (!ONE_WINDOW && win->w_width < value) {
- win_setwidth((int)value);
+ win_T *win = (win_T *)args->os_win;
+
+ if (!ONE_WINDOW && win->w_width < p_wiw) {
+ win_setwidth((int)p_wiw);
}
+ return NULL;
}
/// Process the new 'laststatus' option value.
-static void did_set_laststatus(long value, long old_value)
+static const char *did_set_laststatus(optset_T *args)
{
+ long old_value = args->os_oldval.number;
+ long value = args->os_newval.number;
+
// When switching to global statusline, decrease topframe height
// Also clear the cmdline to remove the ruler if there is one
if (value == 3 && old_value != 3) {
@@ -2604,38 +2610,49 @@ static void did_set_laststatus(long value, long old_value)
}
last_status(false); // (re)set last window status line.
+ return NULL;
}
/// Process the new 'showtabline' option value.
-static void did_set_showtabline(void)
+static const char *did_set_showtabline(optset_T *args FUNC_ATTR_UNUSED)
{
// (re)set tab page line
win_new_screen_rows(); // recompute window positions and heights
+ return NULL;
}
/// Process the new 'foldlevel' option value.
-static void did_set_foldlevel(void)
+static const char *did_set_foldlevel(optset_T *args FUNC_ATTR_UNUSED)
{
newFoldLevel();
+ return NULL;
}
/// Process the new 'foldminlines' option value.
-static void did_set_foldminlines(win_T *win)
+static const char *did_set_foldminlines(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
foldUpdateAll(win);
+ return NULL;
}
/// Process the new 'foldnestmax' option value.
-static void did_set_foldnestmax(win_T *win)
+static const char *did_set_foldnestmax(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
if (foldmethodIsSyntax(win) || foldmethodIsIndent(win)) {
foldUpdateAll(win);
}
+ return NULL;
}
/// Process the new 'shiftwidth' or the 'tabstop' option value.
-static void did_set_shiftwidth_tabstop(buf_T *buf, win_T *win, const long *pp)
+static const char *did_set_shiftwidth_tabstop(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ win_T *win = (win_T *)args->os_win;
+ long *pp = (long *)args->os_varp;
+
if (foldmethodIsIndent(win)) {
foldUpdateAll(win);
}
@@ -2644,38 +2661,49 @@ static void did_set_shiftwidth_tabstop(buf_T *buf, win_T *win, const long *pp)
if (pp == &buf->b_p_sw || buf->b_p_sw == 0) {
parse_cino(buf);
}
+
+ return NULL;
}
/// Process the new 'iminset' option value.
-static void did_set_iminsert(void)
+static const char *did_set_iminsert(optset_T *args FUNC_ATTR_UNUSED)
{
showmode();
// Show/unshow value of 'keymap' in status lines.
status_redraw_curbuf();
+
+ return NULL;
}
/// Process the new 'window' option value.
-static void did_set_window(void)
+static const char *did_set_window(optset_T *args FUNC_ATTR_UNUSED)
{
if (p_window < 1) {
p_window = Rows - 1;
} else if (p_window >= Rows) {
p_window = Rows - 1;
}
+ return NULL;
}
/// Process the new 'titlelen' option value.
-static void did_set_titlelen(long old_value)
+static const char *did_set_titlelen(optset_T *args)
{
+ long old_value = args->os_oldval.number;
+
// if 'titlelen' has changed, redraw the title
if (starting != NO_SCREEN && old_value != p_titlelen) {
need_maketitle = true;
}
+
+ return NULL;
}
/// Process the new 'cmdheight' option value.
-static void did_set_cmdheight(long old_value)
+static const char *did_set_cmdheight(optset_T *args)
{
+ long old_value = args->os_oldval.number;
+
if (ui_has(kUIMessages)) {
p_ch = 0;
}
@@ -2691,19 +2719,25 @@ static void did_set_cmdheight(long old_value)
&& full_screen) {
command_height();
}
+
+ return NULL;
}
/// Process the new 'updatecount' option value.
-static void did_set_updatecount(long old_value)
+static const char *did_set_updatecount(optset_T *args)
{
+ long old_value = args->os_oldval.number;
+
// when 'updatecount' changes from zero to non-zero, open swap files
if (p_uc && !old_value) {
ml_open_files();
}
+
+ return NULL;
}
/// Process the new 'pumblend' option value.
-static void did_set_pumblend(void)
+static const char *did_set_pumblend(optset_T *args FUNC_ATTR_UNUSED)
{
p_pb = MAX(MIN(p_pb, 100), 0);
hl_invalidate_blends();
@@ -2711,113 +2745,93 @@ static void did_set_pumblend(void)
if (pum_drawn()) {
pum_redraw();
}
+
+ return NULL;
}
/// Process the new global 'undolevels' option value.
-static void did_set_global_undolevels(long value, long old_value)
+const char *did_set_global_undolevels(long value, long old_value)
{
// sync undo before 'undolevels' changes
// use the old value, otherwise u_sync() may not work properly
p_ul = old_value;
u_sync(true);
p_ul = value;
+ return NULL;
}
/// Process the new buffer local 'undolevels' option value.
-static void did_set_buflocal_undolevels(buf_T *buf, long value, long old_value)
+const char *did_set_buflocal_undolevels(buf_T *buf, long value, long old_value)
{
// use the old value, otherwise u_sync() may not work properly
buf->b_p_ul = old_value;
u_sync(true);
buf->b_p_ul = value;
+ return NULL;
}
/// Process the new 'scrollback' option value.
-static void did_set_scrollback(buf_T *buf, long value, long old_value)
+static const char *did_set_scrollback(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ long old_value = args->os_oldval.number;
+ long value = args->os_newval.number;
+
if (buf->terminal && value < old_value) {
// Force the scrollback to take immediate effect only when decreasing it.
on_scrollback_option_changed(buf->terminal);
}
+ return NULL;
}
/// Process the new 'numberwidth' option value.
-static void did_set_numberwidth(void)
+static const char *did_set_numberwidth(optset_T *args)
{
- curwin->w_nrwidth_line_count = 0; // trigger a redraw
+ win_T *win = (win_T *)args->os_win;
+ win->w_nrwidth_line_count = 0; // trigger a redraw
+
+ return NULL;
}
/// Process the new 'textwidth' option value.
-static void did_set_textwidth(void)
+static const char *did_set_textwidth(optset_T *args FUNC_ATTR_UNUSED)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
check_colorcolumn(wp);
}
+
+ return NULL;
}
/// Process the new 'winblend' option value.
-static void did_set_winblend(win_T *win, long value, long old_value)
+static const char *did_set_winblend(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+ long old_value = args->os_oldval.number;
+ long value = args->os_newval.number;
+
if (value != old_value) {
win->w_p_winbl = MAX(MIN(win->w_p_winbl, 100), 0);
win->w_hl_needs_update = true;
check_blending(curwin);
}
+
+ return NULL;
}
-/// When some number options are changed, need to take some action.
-static const char *did_set_num_option(long *pp, long value, long old_value, const char *errmsg)
-{
- if (pp == &p_wh) { // 'winheight'
- did_set_winheight(curwin, value);
- } else if (pp == &p_hh) { // 'helpheight'
- did_set_helpheight(curbuf, curwin, value);
- } else if (pp == &p_wmh) { // 'winminheight'
- did_set_winminheight();
- } else if (pp == &p_wiw) { // 'winwidth'
- did_set_winwidth(curwin, value);
- } else if (pp == &p_wmw) { // 'winminwidth'
- did_set_winminwidth();
- } else if (pp == &p_window) { // 'window'
- did_set_window();
- } else if (pp == &p_ls) { // 'laststatus'
- did_set_laststatus(value, old_value);
- } else if (pp == &p_stal) {
- did_set_showtabline(); // 'showtabline'
- } else if (pp == &curwin->w_p_fdl) {
- did_set_foldlevel();
- } else if (pp == &curwin->w_p_fml) {
- did_set_foldminlines(curwin);
- } else if (pp == &curwin->w_p_fdn) {
- did_set_foldnestmax(curwin);
- } else if (pp == &curbuf->b_p_sw // 'shiftwidth'
- || pp == &curbuf->b_p_ts) { // 'tabstop'
- did_set_shiftwidth_tabstop(curbuf, curwin, pp);
- } else if (pp == &curbuf->b_p_iminsert) { // 'iminsert'
- did_set_iminsert();
- } else if (pp == &p_titlelen) { // 'titlelen'
- did_set_titlelen(old_value);
- } else if (pp == &p_ch) { // 'cmdheight'
- did_set_cmdheight(old_value);
- } else if (pp == &p_uc) { // 'updatecount'
- did_set_updatecount(old_value);
- } else if (pp == &p_pb) { // 'pumblend
- did_set_pumblend();
- } else if (pp == &p_ul) { // global 'undolevels'
- did_set_global_undolevels(value, old_value);
- } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels'
- did_set_buflocal_undolevels(curbuf, value, old_value);
- } else if (pp == &curbuf->b_p_scbk || pp == &p_scbk) {
- did_set_scrollback(curbuf, value, old_value);
- } else if (pp == &curwin->w_p_nuw) { // 'numberwidth'
- did_set_numberwidth();
- } else if (pp == &curbuf->b_p_tw) { // 'textwidth'
- did_set_textwidth();
- } else if (pp == &curwin->w_p_winbl) {
- did_set_winblend(curwin, value, old_value);
+/// Process the new 'undolevels' option value.
+static const char *did_set_undolevels(optset_T *args)
+{
+ buf_T *buf = (buf_T *)args->os_buf;
+ long *pp = (long *)args->os_varp;
+
+ if (pp == &p_ul) { // global 'undolevels'
+ did_set_global_undolevels(args->os_newval.number, args->os_oldval.number);
+ } else if (pp == &curbuf->b_p_ul) { // buffer local 'undolevels'
+ did_set_buflocal_undolevels(buf, args->os_newval.number, args->os_oldval.number);
}
- return errmsg;
+ return NULL;
}
/// Check the bounds of numeric options.
@@ -3080,8 +3094,21 @@ static const char *set_num_option(int opt_idx, char *varp, long value, char *err
// Remember where the option was set.
set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
- // Number options that need some action when changed
- errmsg = did_set_num_option(pp, value, old_value, errmsg);
+ // Invoke the option specific callback function to validate and apply the
+ // new value.
+ if (options[opt_idx].opt_did_set_cb != NULL) {
+ optset_T args = {
+ .os_varp = varp,
+ .os_flags = opt_flags,
+ .os_oldval.number = old_value,
+ .os_newval.number = value,
+ .os_errbuf = NULL,
+ .os_errbuflen = 0,
+ .os_buf = curbuf,
+ .os_win = curwin
+ };
+ errmsg = options[opt_idx].opt_did_set_cb(&args);
+ }
// Check the bounds for numeric options here
errmsg = check_num_option_bounds(pp, old_value, old_Rows, errbuf, errbuflen, errmsg);
@@ -4137,12 +4164,12 @@ void unset_global_local_option(char *name, void *from)
break;
case PV_LCS:
clear_string_option(&((win_T *)from)->w_p_lcs);
- set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true);
+ set_listchars_option((win_T *)from, ((win_T *)from)->w_p_lcs, true);
redraw_later((win_T *)from, UPD_NOT_VALID);
break;
case PV_FCS:
clear_string_option(&((win_T *)from)->w_p_fcs);
- set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true);
+ set_fillchars_option((win_T *)from, ((win_T *)from)->w_p_fcs, true);
redraw_later((win_T *)from, UPD_NOT_VALID);
break;
case PV_VE:
@@ -4562,6 +4589,12 @@ static inline char *get_varp(vimoption_T *p)
return get_varp_from(p, curbuf, curwin);
}
+/// Return the did_set callback function for the option at 'opt_idx'
+opt_did_set_cb_T get_option_did_set_cb(int opt_idx)
+{
+ return options[opt_idx].opt_did_set_cb;
+}
+
/// Get the value of 'equalprg', either the buffer-local one or the global one.
char *get_equalprg(void)
{
@@ -4716,8 +4749,8 @@ void didset_window_options(win_T *wp, bool valid_cursor)
check_colorcolumn(wp);
briopt_check(wp);
fill_culopt_flags(NULL, wp);
- set_chars_option(wp, &wp->w_p_fcs, true);
- set_chars_option(wp, &wp->w_p_lcs, true);
+ set_fillchars_option(wp, wp->w_p_fcs, true);
+ set_listchars_option(wp, wp->w_p_lcs, true);
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
check_blending(wp);
set_winbar_win(wp, false, valid_cursor);
@@ -5621,8 +5654,8 @@ void reset_option_was_set(const char *name)
options[idx].flags &= ~P_WAS_SET;
}
-/// fill_breakat_flags() -- called when 'breakat' changes value.
-void fill_breakat_flags(void)
+/// Called when the 'breakat' option changes value.
+static const char *did_set_breakat(optset_T *args FUNC_ATTR_UNUSED)
{
for (int i = 0; i < 256; i++) {
breakat_flags[i] = false;
@@ -5633,6 +5666,8 @@ void fill_breakat_flags(void)
breakat_flags[(uint8_t)(*p)] = true;
}
}
+
+ return NULL;
}
/// fill_culopt_flags() -- called when 'culopt' changes value
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index 0715177bba..40e77550aa 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -7,7 +7,7 @@
// option_defs.h: definition of global variables for settable options
-// Flags
+// Option Flags
#define P_BOOL 0x01U ///< the option is boolean
#define P_NUM 0x02U ///< the option is numeric
#define P_STRING 0x04U ///< the option is a string
@@ -290,7 +290,7 @@ enum {
#define GO_FOOTER 'F' // add footer
#define GO_VERTICAL 'v' // arrange dialog buttons vertically
#define GO_KEEPWINSIZE 'k' // keep GUI window size
-#define GO_ALL "aAbcdefFghilmMprTvk" // all possible flags for 'go'
+#define GO_ALL "!aAbcdefFghilLmMpPrRtTvk" // all possible flags for 'go'
// flags for 'comments' option
#define COM_NEST 'n' // comments strings nest
@@ -978,6 +978,61 @@ enum {
#define TABSTOP_MAX 9999
+// Argument for the callback function (opt_did_set_cb_T) invoked after an
+// option value is modified.
+typedef struct {
+ // Pointer to the option variable. The variable can be a long (numeric
+ // option), an int (boolean option) or a char pointer (string option).
+ char *os_varp;
+ int os_idx;
+ int os_flags;
+
+ // old value of the option (can be a string, number or a boolean)
+ union {
+ const long number;
+ const bool boolean;
+ const char *string;
+ } os_oldval;
+
+ // new value of the option (can be a string, number or a boolean)
+ union {
+ const long number;
+ const bool boolean;
+ const char *string;
+ } os_newval;
+
+ // When set by the called function: Stop processing the option further.
+ // Currently only used for boolean options.
+ int os_doskip;
+
+ // Option value was checked to be safe, no need to set P_INSECURE
+ // Used for the 'keymap', 'filetype' and 'syntax' options.
+ int os_value_checked;
+ // Option value changed. Used for the 'filetype' and 'syntax' options.
+ int os_value_changed;
+
+ // Used by the 'isident', 'iskeyword', 'isprint' and 'isfname' options.
+ // Set to true if the character table is modified when processing the
+ // option and need to be restored because of a failure.
+ int os_restore_chartab;
+
+ // If the value specified for an option is not valid and the error message
+ // is parameterized, then the "os_errbuf" buffer is used to store the error
+ // message (when it is not NULL).
+ char *os_errbuf;
+ size_t os_errbuflen;
+
+ void *os_win;
+ void *os_buf;
+} optset_T;
+
+/// Type for the callback function that is invoked after an option value is
+/// changed to validate and apply the new value.
+///
+/// Returns NULL if the option value is valid and successfully applied.
+/// Otherwise returns an error message.
+typedef const char *(*opt_did_set_cb_T)(optset_T *args);
+
/// Stores an identifier of a script or channel that last set an option.
typedef struct {
sctx_T script_ctx; /// script context where the option was last set
@@ -993,12 +1048,15 @@ typedef enum {
typedef struct vimoption {
char *fullname; // full option name
char *shortname; // permissible abbreviation
- uint32_t flags; // see below
+ uint32_t flags; // see above
char *var; // global option: pointer to variable;
// window-local option: VAR_WIN;
// buffer-local option: global value
idopt_T indir; // global option: PV_NONE;
// local option: indirect option index
+ // callback function to invoke after an option is modified to validate and
+ // apply the new value.
+ opt_did_set_cb_T opt_did_set_cb;
char *def_val; // default values for variable (neovim!!)
LastSet last_set; // script in which the option was last set
} vimoption_T;
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index dffebcf14e..e028fbb6a6 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -62,7 +62,8 @@ return {
short_desc=N_("Arabic as a default second language"),
type='bool', scope={'window'},
redraw={'curswant'},
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_arabic'
},
{
full_name='arabicshape', abbreviation='arshape',
@@ -86,14 +87,16 @@ return {
type='string', scope={'global'},
redraw={'all_windows', 'ui_option'},
varname='p_ambw',
- defaults={if_true="single"}
+ defaults={if_true="single"},
+ cb='did_set_ambiwidth'
},
{
full_name='autochdir', abbreviation='acd',
short_desc=N_("change directory to the file in the current window"),
type='bool', scope={'global'},
varname='p_acd',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_autochdir'
},
{
full_name='autoindent', abbreviation='ai',
@@ -128,7 +131,8 @@ return {
short_desc=N_("\"dark\" or \"light\", used for highlight colors"),
type='string', scope={'global'},
varname='p_bg',
- defaults={if_true="dark"}
+ defaults={if_true="dark"},
+ cb='did_set_background'
},
{
full_name='backspace', abbreviation='bs',
@@ -136,7 +140,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_bs',
- defaults={if_true="indent,eol,start"}
+ defaults={if_true="indent,eol,start"},
+ cb='did_set_backspace'
},
{
full_name='backup', abbreviation='bk',
@@ -156,6 +161,7 @@ return {
if_true="auto",
if_false="auto"
},
+ cb='did_set_backupcopy'
},
{
full_name='backupdir', abbreviation='bdir',
@@ -173,7 +179,8 @@ return {
type='string', scope={'global'},
normal_fname_chars=true,
varname='p_bex',
- defaults={if_true="~"}
+ defaults={if_true="~"},
+ cb='did_set_backupext_or_patchmode'
},
{
full_name='backupskip', abbreviation='bsk',
@@ -189,7 +196,8 @@ return {
type='string', list='comma', scope={'global'},
deny_duplicates=true,
varname='p_bo',
- defaults={if_true="all"}
+ defaults={if_true="all"},
+ cb='did_set_belloff'
},
{
full_name='binary', abbreviation='bin',
@@ -197,7 +205,8 @@ return {
type='bool', scope={'buffer'},
redraw={'statuslines'},
varname='p_bin',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_binary'
},
{
full_name='bomb',
@@ -206,7 +215,8 @@ return {
no_mkrc=true,
redraw={'statuslines'},
varname='p_bomb',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_eof_eol_fixeol_bomb'
},
{
full_name='breakat', abbreviation='brk',
@@ -214,7 +224,8 @@ return {
type='string', list='flags', scope={'global'},
redraw={'all_windows'},
varname='p_breakat',
- defaults={if_true=" \t!@*-+;:,./?"}
+ defaults={if_true=" \t!@*-+;:,./?"},
+ cb='did_set_breakat'
},
{
full_name='breakindent', abbreviation='bri',
@@ -231,6 +242,7 @@ return {
alloced=true,
redraw={'current_buffer'},
defaults={if_true=""},
+ cb='did_set_breakindentopt'
},
{
full_name='browsedir', abbreviation='bsdir',
@@ -245,7 +257,8 @@ return {
noglob=true,
alloced=true,
varname='p_bh',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_bufhidden'
},
{
full_name='buflisted', abbreviation='bl',
@@ -253,7 +266,8 @@ return {
type='bool', scope={'buffer'},
noglob=true,
varname='p_bl',
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_buflisted'
},
{
full_name='buftype', abbreviation='bt',
@@ -262,7 +276,8 @@ return {
noglob=true,
alloced=true,
varname='p_bt',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_buftype'
},
{
full_name='casemap', abbreviation='cmp',
@@ -270,7 +285,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_cmp',
- defaults={if_true="internal,keepascii"}
+ defaults={if_true="internal,keepascii"},
+ cb='did_set_casemap'
},
{
full_name='cdhome', abbreviation='cdh',
@@ -295,7 +311,8 @@ return {
short_desc=N_("used to open the command-line window"),
type='string', scope={'global'},
varname='p_cedit',
- defaults={if_true=macros('CTRL_F_STR')}
+ defaults={if_true=macros('CTRL_F_STR')},
+ cb='did_set_cedit'
},
{
full_name='channel',
@@ -312,7 +329,8 @@ return {
type='string', scope={'global'},
secure=true,
varname='p_ccv',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_optexpr'
},
{
full_name='cindent', abbreviation='cin',
@@ -337,7 +355,8 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_cino',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_cinoptions'
},
{
full_name='cinwords', abbreviation='cinw',
@@ -363,7 +382,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_cb',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_clipboard'
},
{
full_name='cmdheight', abbreviation='ch',
@@ -371,7 +391,8 @@ return {
type='number', scope={'global'},
redraw={'all_windows'},
varname='p_ch',
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_cmdheight'
},
{
full_name='cmdwinheight', abbreviation='cwh',
@@ -386,7 +407,8 @@ return {
type='string', list='onecomma', scope={'window'},
deny_duplicates=true,
redraw={'current_window'},
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_colorcolumn'
},
{
full_name='columns', abbreviation='co',
@@ -404,7 +426,8 @@ return {
alloced=true,
redraw={'curswant'},
varname='p_com',
- defaults={if_true="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"}
+ defaults={if_true="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"},
+ cb='did_set_comments'
},
{
full_name='commentstring', abbreviation='cms',
@@ -413,7 +436,8 @@ return {
alloced=true,
redraw={'curswant'},
varname='p_cms',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_commentstring'
},
{
full_name='compatible', abbreviation='cp',
@@ -431,7 +455,8 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_cpt',
- defaults={if_true=".,w,b,u,t"}
+ defaults={if_true=".,w,b,u,t"},
+ cb='did_set_complete'
},
{
full_name='concealcursor', abbreviation='cocu',
@@ -439,7 +464,8 @@ return {
type='string', scope={'window'},
alloced=true,
redraw={'current_window'},
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_concealcursor'
},
{
full_name='conceallevel', abbreviation='cole',
@@ -456,7 +482,8 @@ return {
alloced=true,
func=true,
varname='p_cfu',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_completefunc'
},
{
full_name='completeopt', abbreviation='cot',
@@ -464,14 +491,16 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_cot',
- defaults={if_true="menu,preview"}
+ defaults={if_true="menu,preview"},
+ cb='did_set_completeopt'
},
{
full_name='completeslash', abbreviation='csl',
type='string', scope={'buffer'},
varname='p_csl',
enable_if='BACKSLASH_IN_FILENAME',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_completeslash'
},
{
full_name='confirm', abbreviation='cf',
@@ -493,7 +522,8 @@ return {
type='string', list='flags', scope={'global'},
redraw={'all_windows'},
varname='p_cpo',
- defaults={if_true=macros('CPO_VIM')}
+ defaults={if_true=macros('CPO_VIM')},
+ cb='did_set_cpoptions'
},
{
full_name='cursorbind', abbreviation='crb',
@@ -522,14 +552,16 @@ return {
type='string', list='onecomma', scope={'window'},
deny_duplicates=true,
redraw={'current_window_only'},
- defaults={if_true="both"}
+ defaults={if_true="both"},
+ cb='did_set_cursorlineopt'
},
{
full_name='debug',
short_desc=N_("to \"msg\" to see all error messages"),
type='string', scope={'global'},
varname='p_debug',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_debug'
},
{
full_name='define', abbreviation='def',
@@ -563,7 +595,8 @@ return {
type='bool', scope={'window'},
noglob=true,
redraw={'current_window'},
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_diff'
},
{
full_name='diffexpr', abbreviation='dex',
@@ -572,7 +605,8 @@ return {
secure=true,
redraw={'curswant'},
varname='p_dex',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_optexpr'
},
{
full_name='diffopt', abbreviation='dip',
@@ -582,7 +616,8 @@ return {
alloced=true,
redraw={'current_window'},
varname='p_dip',
- defaults={if_true="internal,filler,closeoff"}
+ defaults={if_true="internal,filler,closeoff"},
+ cb='did_set_diffopt'
},
{
full_name='digraph', abbreviation='dg',
@@ -608,14 +643,16 @@ return {
deny_duplicates=true,
redraw={'all_windows'},
varname='p_dy',
- defaults={if_true="lastline"}
+ defaults={if_true="lastline"},
+ cb='did_set_display'
},
{
full_name='eadirection', abbreviation='ead',
short_desc=N_("in which direction 'equalalways' works"),
type='string', scope={'global'},
varname='p_ead',
- defaults={if_true="both"}
+ defaults={if_true="both"},
+ cb='did_set_eadirection'
},
{
full_name='edcompatible', abbreviation='ed',
@@ -630,7 +667,8 @@ return {
type='bool', scope={'global'},
redraw={'all_windows', 'ui_option'},
varname='p_emoji',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_ambiwidth'
},
{
full_name='encoding', abbreviation='enc',
@@ -638,7 +676,8 @@ return {
type='string', scope={'global'},
deny_in_modelines=true,
varname='p_enc',
- defaults={if_true=macros('ENC_DFLT')}
+ defaults={if_true=macros('ENC_DFLT')},
+ cb='did_set_encoding'
},
{
full_name='endoffile', abbreviation='eof',
@@ -647,7 +686,8 @@ return {
no_mkrc=true,
redraw={'statuslines'},
varname='p_eof',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_eof_eol_fixeol_bomb'
},
{
full_name='endofline', abbreviation='eol',
@@ -656,14 +696,16 @@ return {
no_mkrc=true,
redraw={'statuslines'},
varname='p_eol',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_eof_eol_fixeol_bomb'
},
{
full_name='equalalways', abbreviation='ea',
short_desc=N_("windows are automatically made the same size"),
type='bool', scope={'global'},
varname='p_ea',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_equalalways'
},
{
full_name='equalprg', abbreviation='ep',
@@ -704,7 +746,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_ei',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_eventignore'
},
{
full_name='expandtab', abbreviation='et',
@@ -729,7 +772,8 @@ return {
alloced=true,
redraw={'statuslines', 'current_buffer'},
varname='p_fenc',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_encoding'
},
{
full_name='fileencodings', abbreviation='fencs',
@@ -747,7 +791,8 @@ return {
alloced=true,
redraw={'curswant', 'statuslines'},
varname='p_ff',
- defaults={if_true=macros('DFLT_FF')}
+ defaults={if_true=macros('DFLT_FF')},
+ cb='did_set_fileformat'
},
{
full_name='fileformats', abbreviation='ffs',
@@ -755,7 +800,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_ffs',
- defaults={if_true=macros('DFLT_FFS_VIM')}
+ defaults={if_true=macros('DFLT_FFS_VIM')},
+ cb='did_set_fileformats'
},
{
full_name='fileignorecase', abbreviation='fic',
@@ -777,7 +823,8 @@ return {
alloced=true,
expand=true,
varname='p_ft',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_filetype_or_syntax'
},
{
full_name='fillchars', abbreviation='fcs',
@@ -787,7 +834,8 @@ return {
alloced=true,
redraw={'current_window'},
varname='p_fcs',
- defaults={if_true=''}
+ defaults={if_true=''},
+ cb='did_set_chars_option'
},
{
full_name='fixendofline', abbreviation='fixeol',
@@ -795,7 +843,8 @@ return {
type='bool', scope={'buffer'},
redraw={'statuslines'},
varname='p_fixeol',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_eof_eol_fixeol_bomb'
},
{
full_name='foldclose', abbreviation='fcl',
@@ -804,7 +853,8 @@ return {
deny_duplicates=true,
redraw={'current_window'},
varname='p_fcl',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_foldclose'
},
{
full_name='foldcolumn', abbreviation='fdc',
@@ -812,7 +862,8 @@ return {
type='string', scope={'window'},
alloced=true,
redraw={'current_window'},
- defaults={if_true="0"}
+ defaults={if_true="0"},
+ cb='did_set_foldcolumn'
},
{
full_name='foldenable', abbreviation='fen',
@@ -828,7 +879,8 @@ return {
modelineexpr=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true="0"}
+ defaults={if_true="0"},
+ cb='did_set_foldexpr'
},
{
full_name='foldignore', abbreviation='fdi',
@@ -836,14 +888,16 @@ return {
type='string', scope={'window'},
alloced=true,
redraw={'current_window'},
- defaults={if_true="#"}
+ defaults={if_true="#"},
+ cb='did_set_foldignore'
},
{
full_name='foldlevel', abbreviation='fdl',
short_desc=N_("close folds with a level higher than this"),
type='number', scope={'window'},
redraw={'current_window'},
- defaults={if_true=0}
+ defaults={if_true=0},
+ cb='did_set_foldlevel'
},
{
full_name='foldlevelstart', abbreviation='fdls',
@@ -860,7 +914,8 @@ return {
deny_duplicates=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true="{{{,}}}"}
+ defaults={if_true="{{{,}}}"},
+ cb='did_set_foldmarker'
},
{
full_name='foldmethod', abbreviation='fdm',
@@ -868,21 +923,24 @@ return {
type='string', scope={'window'},
alloced=true,
redraw={'current_window'},
- defaults={if_true="manual"}
+ defaults={if_true="manual"},
+ cb='did_set_foldmethod'
},
{
full_name='foldminlines', abbreviation='fml',
short_desc=N_("minimum number of lines for a fold to be closed"),
type='number', scope={'window'},
redraw={'current_window'},
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_foldminlines'
},
{
full_name='foldnestmax', abbreviation='fdn',
short_desc=N_("maximum fold depth"),
type='number', scope={'window'},
redraw={'current_window'},
- defaults={if_true=20}
+ defaults={if_true=20},
+ cb='did_set_foldnestmax'
},
{
full_name='foldopen', abbreviation='fdo',
@@ -891,7 +949,8 @@ return {
deny_duplicates=true,
redraw={'curswant'},
varname='p_fdo',
- defaults={if_true="block,hor,mark,percent,quickfix,search,tag,undo"}
+ defaults={if_true="block,hor,mark,percent,quickfix,search,tag,undo"},
+ cb='did_set_foldopen'
},
{
full_name='foldtext', abbreviation='fdt',
@@ -900,7 +959,8 @@ return {
modelineexpr=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true="foldtext()"}
+ defaults={if_true="foldtext()"},
+ cb='did_set_optexpr'
},
{
full_name='formatexpr', abbreviation='fex',
@@ -909,7 +969,8 @@ return {
modelineexpr=true,
alloced=true,
varname='p_fex',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_optexpr'
},
{
full_name='formatoptions', abbreviation='fo',
@@ -917,7 +978,8 @@ return {
type='string', list='flags', scope={'buffer'},
alloced=true,
varname='p_fo',
- defaults={if_true=macros('DFLT_FO_VIM')}
+ defaults={if_true=macros('DFLT_FO_VIM')},
+ cb='did_set_formatoptions'
},
{
full_name='formatlistpat', abbreviation='flp',
@@ -980,7 +1042,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_guicursor',
- defaults={if_true="n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"}
+ defaults={if_true="n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"},
+ cb='did_set_guicursor'
},
{
full_name='guifont', abbreviation='gfn',
@@ -1028,14 +1091,16 @@ return {
secure=true,
expand=true,
varname='p_hf',
- defaults={if_true=macros('DFLT_HELPFILE')}
+ defaults={if_true=macros('DFLT_HELPFILE')},
+ cb='did_set_helpfile'
},
{
full_name='helpheight', abbreviation='hh',
short_desc=N_("minimum height of a new help window"),
type='number', scope={'global'},
varname='p_hh',
- defaults={if_true=20}
+ defaults={if_true=20},
+ cb='did_set_helpheight'
},
{
full_name='helplang', abbreviation='hlg',
@@ -1043,7 +1108,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_hlg',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_helplang'
},
{
full_name='hidden', abbreviation='hid',
@@ -1058,7 +1124,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_hl',
- defaults={if_true=macros('HIGHLIGHT_INIT')}
+ defaults={if_true=macros('HIGHLIGHT_INIT')},
+ cb='did_set_highlight'
},
{
full_name='history', abbreviation='hi',
@@ -1087,14 +1154,16 @@ return {
type='bool', scope={'global'},
redraw={'all_windows'},
varname='p_hls',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_hlsearch'
},
{
full_name='icon',
short_desc=N_("Vim set the text of the window icon"),
type='bool', scope={'global'},
varname='p_icon',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_title_icon'
},
{
full_name='iconstring',
@@ -1102,14 +1171,16 @@ return {
type='string', scope={'global'},
modelineexpr=true,
varname='p_iconstring',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_iconstring'
},
{
full_name='ignorecase', abbreviation='ic',
short_desc=N_("ignore case in search patterns"),
type='bool', scope={'global'},
varname='p_ic',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_ignorecase'
},
{
full_name='imcmdline', abbreviation='imc',
@@ -1130,9 +1201,8 @@ return {
short_desc=N_("use :lmap or IM in Insert mode"),
type='number', scope={'buffer'},
varname='p_iminsert', pv_name='p_imi',
- defaults={
- if_true=macros('B_IMODE_NONE'),
- }
+ defaults={if_true=macros('B_IMODE_NONE')},
+ cb='did_set_iminsert'
},
{
full_name='imsearch', abbreviation='ims',
@@ -1148,7 +1218,8 @@ return {
short_desc=N_("Live preview of substitution"),
type='string', scope={'global'},
varname='p_icm',
- defaults={if_true="nosplit"}
+ defaults={if_true="nosplit"},
+ cb='did_set_inccommand'
},
{
full_name='include', abbreviation='inc',
@@ -1165,7 +1236,8 @@ return {
modelineexpr=true,
alloced=true,
varname='p_inex',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_optexpr'
},
{
full_name='incsearch', abbreviation='is',
@@ -1181,7 +1253,8 @@ return {
modelineexpr=true,
alloced=true,
varname='p_inde',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_optexpr'
},
{
full_name='indentkeys', abbreviation='indk',
@@ -1218,7 +1291,8 @@ return {
-- ( and ) are used in text separating fnames */
if_true="@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,=",
if_false="@,48-57,/,.,-,_,+,,,#,$,%,~,="
- }
+ },
+ cb='did_set_isopt'
},
{
full_name='isident', abbreviation='isi',
@@ -1230,7 +1304,8 @@ return {
condition='MSWIN',
if_true="@,48-57,_,128-167,224-235",
if_false="@,48-57,_,192-255"
- }
+ },
+ cb='did_set_isopt'
},
{
full_name='iskeyword', abbreviation='isk',
@@ -1239,7 +1314,8 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_isk',
- defaults={if_true="@,48-57,_,192-255"}
+ defaults={if_true="@,48-57,_,192-255"},
+ cb='did_set_isopt'
},
{
full_name='isprint', abbreviation='isp',
@@ -1248,8 +1324,8 @@ return {
deny_duplicates=true,
redraw={'all_windows'},
varname='p_isp',
- defaults={if_true="@,161-255"
- }
+ defaults={if_true="@,161-255"},
+ cb='did_set_isopt'
},
{
full_name='joinspaces', abbreviation='js',
@@ -1264,7 +1340,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_jop',
- defaults={if_true=''}
+ defaults={if_true=''},
+ cb='did_set_jumpoptions'
},
{
full_name='keymap', abbreviation='kmp',
@@ -1275,7 +1352,8 @@ return {
alloced=true,
redraw={'statuslines', 'current_buffer'},
varname='p_keymap', pv_name='p_kmap',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_keymap'
},
{
full_name='keymodel', abbreviation='km',
@@ -1283,7 +1361,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_km',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_keymodel'
},
{
full_name='keywordprg', abbreviation='kp',
@@ -1303,7 +1382,8 @@ return {
deny_duplicates=true,
secure=true,
varname='p_langmap',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_langmap'
},
{
full_name='langmenu', abbreviation='lm',
@@ -1318,14 +1398,16 @@ return {
short_desc=N_("do not apply 'langmap' to mapped characters"),
type='bool', scope={'global'},
varname='p_lnr',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_langnoremap'
},
{
full_name='langremap', abbreviation='lrm',
short_desc=N_('No description'),
type='bool', scope={'global'},
varname='p_lrm',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_langremap'
},
{
full_name='laststatus', abbreviation='ls',
@@ -1333,7 +1415,8 @@ return {
type='number', scope={'global'},
redraw={'all_windows'},
varname='p_ls',
- defaults={if_true=2}
+ defaults={if_true=2},
+ cb='did_set_laststatus'
},
{
full_name='lazyredraw', abbreviation='lz',
@@ -1370,7 +1453,8 @@ return {
short_desc=N_("indenting for Lisp"),
type='bool', scope={'buffer'},
varname='p_lisp',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_lisp'
},
{
full_name='lispoptions', abbreviation='lop',
@@ -1378,7 +1462,8 @@ return {
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
varname='p_lop', pv_name='p_lop',
- defaults={if_true=''}
+ defaults={if_true=''},
+ cb='did_set_lispoptions'
},
{
full_name='lispwords', abbreviation='lw',
@@ -1403,7 +1488,8 @@ return {
alloced=true,
redraw={'current_window'},
varname='p_lcs',
- defaults={if_true="tab:> ,trail:-,nbsp:+"}
+ defaults={if_true="tab:> ,trail:-,nbsp:+"},
+ cb='did_set_chars_option'
},
{
full_name='loadplugins', abbreviation='lpl',
@@ -1433,7 +1519,8 @@ return {
short_desc=N_("Converts the output of external commands"),
type='string', scope={'global', 'buffer'},
varname='p_menc',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_encoding'
},
{
full_name='makeprg', abbreviation='mp',
@@ -1451,7 +1538,8 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_mps',
- defaults={if_true="(:),{:},[:]"}
+ defaults={if_true="(:),{:},[:]"},
+ cb='did_set_matchpairs'
},
{
full_name='matchtime', abbreviation='mat',
@@ -1502,7 +1590,8 @@ return {
secure=true,
expand=true,
varname='p_msm',
- defaults={if_true="460000,2000,500"}
+ defaults={if_true="460000,2000,500"},
+ cb='did_set_mkspellmem'
},
{
full_name='modeline', abbreviation='ml',
@@ -1532,7 +1621,8 @@ return {
type='bool', scope={'buffer'},
noglob=true,
varname='p_ma',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_modifiable'
},
{
full_name='modified', abbreviation='mod',
@@ -1541,7 +1631,8 @@ return {
no_mkrc=true,
redraw={'statuslines'},
varname='p_mod',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_modified'
},
{
full_name='more',
@@ -1555,7 +1646,8 @@ return {
short_desc=N_("the use of mouse clicks"),
type='string', list='flags', scope={'global'},
varname='p_mouse',
- defaults={if_true="nvi"}
+ defaults={if_true="nvi"},
+ cb='did_set_mouse'
},
{
full_name='mousefocus', abbreviation='mousef',
@@ -1577,7 +1669,8 @@ return {
short_desc=N_("changes meaning of mouse buttons"),
type='string', scope={'global'},
varname='p_mousem',
- defaults={if_true="popup_setpos"}
+ defaults={if_true="popup_setpos"},
+ cb='did_set_mousemodel'
},
{
full_name='mousemoveevent', abbreviation='mousemev',
@@ -1593,7 +1686,8 @@ return {
type='string', list='comma', scope={'global'},
vi_def=true,
varname='p_mousescroll',
- defaults={if_true="ver:3,hor:6"}
+ defaults={if_true="ver:3,hor:6"},
+ cb='did_set_mousescroll'
},
{
full_name='mouseshape', abbreviation='mouses',
@@ -1616,21 +1710,24 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_nf',
- defaults={if_true="bin,hex"}
+ defaults={if_true="bin,hex"},
+ cb='did_set_nrformats'
},
{
full_name='number', abbreviation='nu',
short_desc=N_("print the line number in front of each line"),
type='bool', scope={'window'},
redraw={'current_window'},
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_number_relativenumber'
},
{
full_name='numberwidth', abbreviation='nuw',
short_desc=N_("number of columns used for the line number"),
type='number', scope={'window'},
redraw={'current_window'},
- defaults={if_true=4}
+ defaults={if_true=4},
+ cb='did_set_numberwidth'
},
{
full_name='omnifunc', abbreviation='ofu',
@@ -1640,7 +1737,8 @@ return {
alloced=true,
func=true,
varname='p_ofu',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_omnifunc'
},
{
full_name='opendevice', abbreviation='odev',
@@ -1656,7 +1754,8 @@ return {
secure=true,
func=true,
varname='p_opfunc',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_operatorfunc'
},
{
full_name='packpath', abbreviation='pp',
@@ -1666,7 +1765,8 @@ return {
secure=true,
expand=true,
varname='p_pp',
- defaults={if_true=''}
+ defaults={if_true=''},
+ cb='did_set_runtimepackpath'
},
{
full_name='paragraphs', abbreviation='para',
@@ -1681,7 +1781,8 @@ return {
type='bool', scope={'global'},
pri_mkrc=true,
varname='p_paste',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_paste'
},
{
full_name='pastetoggle', abbreviation='pt',
@@ -1695,7 +1796,8 @@ return {
type='string', scope={'global'},
secure=true,
varname='p_pex',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_optexpr'
},
{
full_name='patchmode', abbreviation='pm',
@@ -1703,7 +1805,8 @@ return {
type='string', scope={'global'},
normal_fname_chars=true,
varname='p_pm',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_backupext_or_patchmode'
},
{
full_name='path', abbreviation='pa',
@@ -1734,7 +1837,8 @@ return {
type='bool', scope={'window'},
noglob=true,
redraw={'statuslines'},
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_previewwindow'
},
{
full_name='prompt',
@@ -1749,7 +1853,8 @@ return {
type='number', scope={'global'},
redraw={'ui_option'},
varname='p_pb',
- defaults={if_true=0}
+ defaults={if_true=0},
+ cb='did_set_pumblend'
},
{
full_name='pumheight', abbreviation='ph',
@@ -1780,7 +1885,8 @@ return {
secure=true,
func=true,
varname='p_qftf',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_quickfixtextfunc'
},
{
full_name='quoteescape', abbreviation='qe',
@@ -1797,14 +1903,16 @@ return {
noglob=true,
redraw={'statuslines'},
varname='p_ro',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_readonly'
},
{
full_name='redrawdebug', abbreviation='rdb',
short_desc=N_("Changes the way redrawing works (debug)"),
type='string', list='onecomma', scope={'global'},
varname='p_rdb',
- defaults={if_true=''}
+ defaults={if_true=''},
+ cb='did_set_redrawdebug'
},
{
full_name='redrawtime', abbreviation='rdt',
@@ -1825,7 +1933,8 @@ return {
short_desc=N_("show relative line number in front of each line"),
type='bool', scope={'window'},
redraw={'current_window'},
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_number_relativenumber'
},
{
full_name='remap',
@@ -1861,7 +1970,8 @@ return {
type='string', scope={'window'},
alloced=true,
redraw={'current_window'},
- defaults={if_true="search"}
+ defaults={if_true="search"},
+ cb='did_set_rightleftcmd'
},
{
full_name='ruler', abbreviation='ru',
@@ -1879,7 +1989,8 @@ return {
modelineexpr=true,
redraw={'statuslines'},
varname='p_ruf',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_rulerformat'
},
{
full_name='runtimepath', abbreviation='rtp',
@@ -1889,7 +2000,8 @@ return {
secure=true,
expand='nodefault',
varname='p_rtp',
- defaults={if_true=''}
+ defaults={if_true=''},
+ cb='did_set_runtimepackpath'
},
{
full_name='scroll', abbreviation='scr',
@@ -1905,14 +2017,16 @@ return {
type='number', scope={'buffer'},
varname='p_scbk',
redraw={'current_buffer'},
- defaults={if_true=-1}
+ defaults={if_true=-1},
+ cb='did_set_scrollback'
},
{
full_name='scrollbind', abbreviation='scb',
short_desc=N_("scroll in window as other windows scroll"),
type='bool', scope={'window'},
pv_name='p_scbind',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_scrollbind'
},
{
full_name='scrolljump', abbreviation='sj',
@@ -1934,7 +2048,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_sbo',
- defaults={if_true="ver,jump"}
+ defaults={if_true="ver,jump"},
+ cb='did_set_scrollopt'
},
{
full_name='sections', abbreviation='sect',
@@ -1956,7 +2071,8 @@ return {
short_desc=N_("what type of selection to use"),
type='string', scope={'global'},
varname='p_sel',
- defaults={if_true="inclusive"}
+ defaults={if_true="inclusive"},
+ cb='did_set_selection'
},
{
full_name='selectmode', abbreviation='slm',
@@ -1964,7 +2080,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_slm',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_selectmode'
},
{
full_name='sessionoptions', abbreviation='ssop',
@@ -1972,7 +2089,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_ssop',
- defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize,terminal"}
+ defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize,terminal"},
+ cb='did_set_sessionoptions',
},
{
full_name='shada', abbreviation='sd',
@@ -2056,7 +2174,8 @@ return {
type='bool', scope={'global'},
varname='p_ssl',
enable_if='BACKSLASH_IN_FILENAME',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_shellslash'
},
{
full_name='shelltemp', abbreviation='stmp',
@@ -2097,14 +2216,16 @@ return {
short_desc=N_("number of spaces to use for (auto)indent step"),
type='number', scope={'buffer'},
varname='p_sw',
- defaults={if_true=8}
+ defaults={if_true=8},
+ cb='did_set_shiftwidth_tabstop'
},
{
full_name='shortmess', abbreviation='shm',
short_desc=N_("list of flags, reduce length of messages"),
type='string', list='flags', scope={'global'},
varname='p_shm',
- defaults={if_true="filnxtToOF"}
+ defaults={if_true="filnxtToOF"},
+ cb='did_set_shortmess'
},
{
full_name='showbreak', abbreviation='sbr',
@@ -2112,7 +2233,8 @@ return {
type='string', scope={'global', 'window'},
redraw={'all_windows'},
varname='p_sbr',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_showbreak'
},
{
full_name='showcmd', abbreviation='sc',
@@ -2126,7 +2248,8 @@ return {
short_desc=N_("change location of partial command"),
type='string', scope={'global'},
varname='p_sloc',
- defaults={if_true="last"}
+ defaults={if_true="last"},
+ cb='did_set_showcmdloc'
},
{
full_name='showfulltag', abbreviation='sft',
@@ -2155,7 +2278,8 @@ return {
type='number', scope={'global'},
redraw={'all_windows', 'ui_option'},
varname='p_stal',
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_showtabline'
},
{
full_name='sidescroll', abbreviation='ss',
@@ -2177,7 +2301,8 @@ return {
type='string', scope={'window'},
alloced=true,
redraw={'current_window'},
- defaults={if_true="auto"}
+ defaults={if_true="auto"},
+ cb='did_set_signcolumn'
},
{
full_name='smartcase', abbreviation='scs',
@@ -2212,7 +2337,8 @@ return {
short_desc=N_("spell checking"),
type='bool', scope={'window'},
redraw={'current_window'},
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_spell'
},
{
full_name='spellcapcheck', abbreviation='spc',
@@ -2221,7 +2347,8 @@ return {
alloced=true,
redraw={'current_buffer'},
varname='p_spc',
- defaults={if_true="[.?!]\\_[\\])'\" ]\\+"}
+ defaults={if_true="[.?!]\\_[\\])'\" ]\\+"},
+ cb='did_set_spellcapcheck'
},
{
full_name='spellfile', abbreviation='spf',
@@ -2232,7 +2359,8 @@ return {
alloced=true,
expand=true,
varname='p_spf',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_spellfile'
},
{
full_name='spelllang', abbreviation='spl',
@@ -2243,7 +2371,8 @@ return {
expand=true,
redraw={'current_buffer'},
varname='p_spl',
- defaults={if_true="en"}
+ defaults={if_true="en"},
+ cb='did_set_spelllang'
},
{
full_name='spellsuggest', abbreviation='sps',
@@ -2253,7 +2382,8 @@ return {
secure=true,
expand=true,
varname='p_sps',
- defaults={if_true="best"}
+ defaults={if_true="best"},
+ cb='did_set_spellsuggest'
},
{
full_name='spelloptions', abbreviation='spo',
@@ -2263,7 +2393,8 @@ return {
expand=true,
varname='p_spo',
redraw={'current_buffer'},
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_spelloptions'
},
{
full_name='splitbelow', abbreviation='sb',
@@ -2277,7 +2408,8 @@ return {
short_desc=N_("determines scroll behavior for split windows"),
type='string', scope={'global'},
varname='p_spk',
- defaults={if_true='cursor'}
+ defaults={if_true='cursor'},
+ cb='did_set_splitkeep'
},
{
full_name='splitright', abbreviation='spr',
@@ -2301,7 +2433,8 @@ return {
redraw={'current_window'},
secure=true,
alloced=true,
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_statuscolumn'
},
{
full_name='statusline', abbreviation='stl',
@@ -2311,7 +2444,8 @@ return {
modelineexpr=true,
redraw={'statuslines'},
varname='p_stl',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_statusline'
},
{
full_name='suffixes', abbreviation='su',
@@ -2336,7 +2470,8 @@ return {
type='bool', scope={'buffer'},
redraw={'statuslines'},
varname='p_swf',
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_swapfile'
},
{
full_name='switchbuf', abbreviation='swb',
@@ -2344,7 +2479,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_swb',
- defaults={if_true="uselast"}
+ defaults={if_true="uselast"},
+ cb='did_set_switchbuf'
},
{
full_name='synmaxcol', abbreviation='smc',
@@ -2362,7 +2498,8 @@ return {
normal_fname_chars=true,
alloced=true,
varname='p_syn',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_filetype_or_syntax'
},
{
full_name='tagfunc', abbreviation='tfu',
@@ -2371,7 +2508,8 @@ return {
secure=true,
func=true,
varname='p_tfu',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_tagfunc'
},
{
full_name='tabline', abbreviation='tal',
@@ -2380,7 +2518,8 @@ return {
modelineexpr=true,
redraw={'tabline'},
varname='p_tal',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_tabline'
},
{
full_name='tabpagemax', abbreviation='tpm',
@@ -2395,7 +2534,8 @@ return {
type='number', scope={'buffer'},
redraw={'current_buffer'},
varname='p_ts',
- defaults={if_true=8}
+ defaults={if_true=8},
+ cb='did_set_shiftwidth_tabstop'
},
{
full_name='tagbsearch', abbreviation='tbs',
@@ -2409,7 +2549,8 @@ return {
short_desc=N_("how to handle case when searching in tags files"),
type='string', scope={'global', 'buffer'},
varname='p_tc',
- defaults={if_true="followic"}
+ defaults={if_true="followic"},
+ cb='did_set_tagcase'
},
{
full_name='taglength', abbreviation='tl',
@@ -2467,7 +2608,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_tpf',
- defaults={if_true="BS,HT,ESC,DEL"}
+ defaults={if_true="BS,HT,ESC,DEL"},
+ cb='did_set_termpastefilter'
},
{
full_name='terse',
@@ -2482,7 +2624,8 @@ return {
type='number', scope={'buffer'},
redraw={'current_buffer'},
varname='p_tw',
- defaults={if_true=0}
+ defaults={if_true=0},
+ cb='did_set_textwidth'
},
{
full_name='thesaurus', abbreviation='tsr',
@@ -2502,7 +2645,8 @@ return {
alloced=true,
func=true,
varname='p_tsrfu',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_thesaurusfunc'
},
{
full_name='tildeop', abbreviation='top',
@@ -2530,14 +2674,16 @@ return {
short_desc=N_("Vim set the title of the window"),
type='bool', scope={'global'},
varname='p_title',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_title_icon'
},
{
full_name='titlelen',
short_desc=N_("of 'columns' used for window title"),
type='number', scope={'global'},
varname='p_titlelen',
- defaults={if_true=85}
+ defaults={if_true=85},
+ cb='did_set_titlelen'
},
{
full_name='titleold',
@@ -2554,7 +2700,8 @@ return {
type='string', scope={'global'},
modelineexpr=true,
varname='p_titlestring',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_titlestring'
},
{
full_name='ttimeout',
@@ -2595,14 +2742,16 @@ return {
short_desc=N_("save undo information in a file"),
type='bool', scope={'buffer'},
varname='p_udf',
- defaults={if_true=false}
+ defaults={if_true=false},
+ cb='did_set_undofile'
},
{
full_name='undolevels', abbreviation='ul',
short_desc=N_("maximum number of changes that can be undone"),
type='number', scope={'global', 'buffer'},
varname='p_ul',
- defaults={if_true=1000}
+ defaults={if_true=1000},
+ cb='did_set_undolevels'
},
{
full_name='undoreload', abbreviation='ur',
@@ -2616,7 +2765,8 @@ return {
short_desc=N_("after this many characters flush swap file"),
type='number', scope={'global'},
varname='p_uc',
- defaults={if_true=200}
+ defaults={if_true=200},
+ cb='did_set_updatecount'
},
{
full_name='updatetime', abbreviation='ut',
@@ -2630,7 +2780,8 @@ return {
short_desc=N_("list of numbers of spaces that <Tab> uses while editing"),
type='string', list='comma', scope={'buffer'},
varname='p_vsts',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_varsofttabstop'
},
{
full_name='vartabstop', abbreviation='vts',
@@ -2638,7 +2789,8 @@ return {
type='string', list='comma', scope={'buffer'},
varname='p_vts',
redraw={'current_buffer'},
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_vartabstop'
},
{
full_name='verbose', abbreviation='vbs',
@@ -2654,7 +2806,8 @@ return {
secure=true,
expand=true,
varname='p_vfile',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_verbosefile'
},
{
full_name='viewdir', abbreviation='vdir',
@@ -2671,7 +2824,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_vop',
- defaults={if_true="folds,cursor,curdir"}
+ defaults={if_true="folds,cursor,curdir"},
+ cb='did_set_viewoptions'
},
{
-- Alias for "shada".
@@ -2692,7 +2846,8 @@ return {
deny_duplicates=true,
redraw={'curswant'},
varname='p_ve',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_virtualedit'
},
{
full_name='visualbell', abbreviation='vb',
@@ -2713,7 +2868,8 @@ return {
short_desc=N_("allow specified keys to cross line boundaries"),
type='string', list='flagscomma', scope={'global'},
varname='p_ww',
- defaults={if_true="b,s"}
+ defaults={if_true="b,s"},
+ cb='did_set_whichwrap'
},
{
full_name='wildchar', abbreviation='wc',
@@ -2757,7 +2913,8 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=false,
varname='p_wim',
- defaults={if_true="full"}
+ defaults={if_true="full"},
+ cb='did_set_wildmode'
},
{
full_name='wildoptions', abbreviation='wop',
@@ -2765,14 +2922,16 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_wop',
- defaults={if_true='pum,tagfile'}
+ defaults={if_true='pum,tagfile'},
+ cb='did_set_wildoptions'
},
{
full_name='winaltkeys', abbreviation='wak',
short_desc=N_("when the windows system handles ALT keys"),
type='string', scope={'global'},
varname='p_wak',
- defaults={if_true="menu"}
+ defaults={if_true="menu"},
+ cb='did_set_winaltkeys'
},
{
full_name='winbar', abbreviation='wbr',
@@ -2782,14 +2941,16 @@ return {
modelineexpr=true,
redraw={'statuslines'},
varname='p_wbr',
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_winbar'
},
{
full_name='winblend', abbreviation='winbl',
short_desc=N_("Controls transparency level for floating windows"),
type='number', scope={'window'},
redraw={'current_window'},
- defaults={if_true=0}
+ defaults={if_true=0},
+ cb='did_set_winblend'
},
{
full_name='winhighlight', abbreviation='winhl',
@@ -2798,21 +2959,24 @@ return {
deny_duplicates=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true=""}
+ defaults={if_true=""},
+ cb='did_set_winhl'
},
{
full_name='window', abbreviation='wi',
short_desc=N_("nr of lines to scroll for CTRL-F and CTRL-B"),
type='number', scope={'global'},
varname='p_window',
- defaults={if_true=0}
+ defaults={if_true=0},
+ cb='did_set_window'
},
{
full_name='winheight', abbreviation='wh',
short_desc=N_("minimum number of lines for the current window"),
type='number', scope={'global'},
varname='p_wh',
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_winheight'
},
{
full_name='winfixheight', abbreviation='wfh',
@@ -2833,28 +2997,32 @@ return {
short_desc=N_("minimum number of lines for any window"),
type='number', scope={'global'},
varname='p_wmh',
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_winminheight'
},
{
full_name='winminwidth', abbreviation='wmw',
short_desc=N_("minimal number of columns for any window"),
type='number', scope={'global'},
varname='p_wmw',
- defaults={if_true=1}
+ defaults={if_true=1},
+ cb='did_set_winminwidth'
},
{
full_name='winwidth', abbreviation='wiw',
short_desc=N_("minimal number of columns for current window"),
type='number', scope={'global'},
varname='p_wiw',
- defaults={if_true=20}
+ defaults={if_true=20},
+ cb='did_set_winwidth'
},
{
full_name='wrap',
short_desc=N_("lines wrap and continue on the next line"),
type='bool', scope={'window'},
redraw={'current_window'},
- defaults={if_true=true}
+ defaults={if_true=true},
+ cb='did_set_wrap'
},
{
full_name='wrapmargin', abbreviation='wm',
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index ece7a90b4a..96d383bbb1 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -444,7 +444,7 @@ const char *set_string_option(const int opt_idx, const char *const value, const
char *const saved_newval = xstrdup(s);
int value_checked = false;
- const char *const errmsg = did_set_string_option(opt_idx, varp, oldval, errbuf, errbuflen,
+ const char *const errmsg = did_set_string_option(opt_idx, varp, oldval, s, errbuf, errbuflen,
opt_flags, &value_checked);
if (errmsg == NULL) {
did_set_option(opt_idx, opt_flags, true, value_checked);
@@ -479,11 +479,13 @@ static bool valid_filetype(const char *val)
/// Handle setting 'mousescroll'.
/// @return error message, NULL if it's OK.
-static const char *check_mousescroll(char *string)
+const char *did_set_mousescroll(optset_T *args FUNC_ATTR_UNUSED)
{
long vertical = -1;
long horizontal = -1;
+ char *string = p_mousescroll;
+
while (true) {
char *end = vim_strchr(string, ',');
size_t length = end ? (size_t)(end - string) : strlen(string);
@@ -651,8 +653,12 @@ static bool check_illegal_path_names(char *val, uint32_t flags)
&& strpbrk(val, "*?[|;&<>\r\n") != NULL));
}
-static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, const char **errmsg)
+/// The 'backupcopy' option is changed.
+const char *did_set_backupcopy(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ const char *oldval = args->os_oldval.string;
+ int opt_flags = args->os_flags;
char *bkc = p_bkc;
unsigned *flags = &bkc_flags;
@@ -666,7 +672,7 @@ static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, const ch
*flags = 0;
} else {
if (opt_strings_flags(bkc, p_bkc_values, flags, true) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
if (((*flags & BKC_AUTO) != 0)
@@ -674,42 +680,68 @@ static void did_set_backupcopy(buf_T *buf, char *oldval, int opt_flags, const ch
+ ((*flags & BKC_NO) != 0) != 1) {
// Must have exactly one of "auto", "yes" and "no".
(void)opt_strings_flags(oldval, p_bkc_values, flags, true);
- *errmsg = e_invarg;
+ return e_invarg;
}
}
+
+ return NULL;
}
-static void did_set_backupext_or_patchmode(const char **errmsg)
+/// The 'backupext' or the 'patchmode' option is changed.
+const char *did_set_backupext_or_patchmode(optset_T *args FUNC_ATTR_UNUSED)
{
if (strcmp(*p_bex == '.' ? p_bex + 1 : p_bex,
*p_pm == '.' ? p_pm + 1 : p_pm) == 0) {
- *errmsg = e_backupext_and_patchmode_are_equal;
+ return e_backupext_and_patchmode_are_equal;
}
+
+ return NULL;
+}
+
+/// The 'belloff' option is changed.
+const char *did_set_belloff(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true);
}
-static void did_set_breakindentopt(win_T *win, const char **errmsg)
+/// The 'termpastefilter' option is changed.
+const char *did_set_termpastefilter(optset_T *args FUNC_ATTR_UNUSED)
{
+ return did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true);
+}
+
+/// The 'breakindentopt' option is changed.
+const char *did_set_breakindentopt(optset_T *args)
+{
+ win_T *win = (win_T *)args->os_win;
if (briopt_check(win) == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
// list setting requires a redraw
if (win == curwin && win->w_briopt_list) {
redraw_all_later(UPD_NOT_VALID);
}
+
+ return NULL;
}
-static void did_set_isopt(buf_T *buf, bool *did_chartab, const char **errmsg)
+/// The 'isident' or the 'iskeyword' or the 'isprint' or the 'isfname' option is
+/// changed.
+const char *did_set_isopt(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
// 'isident', 'iskeyword', 'isprint or 'isfname' option: refill g_chartab[]
// If the new option is invalid, use old value.
// 'lisp' option: refill g_chartab[] for '-' char
if (buf_init_chartab(buf, true) == FAIL) {
- *did_chartab = true; // need to restore it below
- *errmsg = e_invarg; // error in value
+ args->os_restore_chartab = true; // need to restore it below
+ return e_invarg; // error in value
}
+ return NULL;
}
-static void did_set_helpfile(void)
+/// The 'helpfile' option is changed.
+const char *did_set_helpfile(optset_T *args FUNC_ATTR_UNUSED)
{
// May compute new values for $VIM and $VIMRUNTIME
if (didset_vim) {
@@ -718,75 +750,102 @@ static void did_set_helpfile(void)
if (didset_vimruntime) {
vim_unsetenv_ext("VIMRUNTIME");
}
+ return NULL;
}
-static void did_set_cursorlineopt(win_T *win, char **varp, const char **errmsg)
+/// The 'cursorlineopt' option is changed.
+const char *did_set_cursorlineopt(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
+
if (**varp == NUL || fill_culopt_flags(*varp, win) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+
+ return NULL;
}
-static void did_set_helplang(const char **errmsg)
+/// The 'helplang' option is changed.
+const char *did_set_helplang(optset_T *args FUNC_ATTR_UNUSED)
{
// Check for "", "ab", "ab,cd", etc.
for (char *s = p_hlg; *s != NUL; s += 3) {
if (s[1] == NUL || ((s[2] != ',' || s[3] == NUL) && s[2] != NUL)) {
- *errmsg = e_invarg;
- break;
+ return e_invarg;
}
if (s[2] == NUL) {
break;
}
}
+ return NULL;
}
-static void did_set_highlight(char **varp, const char **errmsg)
+/// The 'highlight' option is changed.
+const char *did_set_highlight(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
if (strcmp(*varp, HIGHLIGHT_INIT) != 0) {
- *errmsg = e_unsupportedoption;
+ return e_unsupportedoption;
}
+ return NULL;
}
-static void did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list,
- const char **errmsg)
+static const char *did_set_opt_flags(char *val, char **values, unsigned *flagp, bool list)
{
if (opt_strings_flags(val, values, flagp, list) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
+}
+
+static const char *did_set_opt_strings(char *val, char **values, bool list)
+{
+ return did_set_opt_flags(val, values, NULL, list);
+}
+
+/// The 'selectmode' option is changed.
+const char *did_set_selectmode(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_strings(p_slm, p_slm_values, true);
}
-static void did_set_opt_strings(char *val, char **values, bool list, const char **errmsg)
+/// The 'inccommand' option is changed.
+const char *did_set_inccommand(optset_T *args FUNC_ATTR_UNUSED)
{
- did_set_opt_flags(val, values, NULL, list, errmsg);
+ return did_set_opt_strings(p_icm, p_icm_values, false);
}
-static void did_set_sessionoptions(char *oldval, const char **errmsg)
+/// The 'sessionoptions' option is changed.
+const char *did_set_sessionoptions(optset_T *args)
{
if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, true) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR)) {
// Don't allow both "sesdir" and "curdir".
+ const char *oldval = args->os_oldval.string;
(void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, true);
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_ambiwidth(const char **errmsg)
+/// The 'ambiwidth' option is changed.
+const char *did_set_ambiwidth(optset_T *args FUNC_ATTR_UNUSED)
{
if (check_opt_strings(p_ambw, p_ambw_values, false) != OK) {
- *errmsg = e_invarg;
- } else {
- *errmsg = check_chars_options();
+ return e_invarg;
}
+ return check_chars_options();
}
-static void did_set_background(const char **errmsg)
+/// The 'background' option is changed.
+const char *did_set_background(optset_T *args FUNC_ATTR_UNUSED)
{
if (check_opt_strings(p_bg, p_bg_values, false) != OK) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
int dark = (*p_bg == 'd');
@@ -803,44 +862,122 @@ static void did_set_background(const char **errmsg)
check_string_option(&p_bg);
init_highlight(false, false);
}
+ return NULL;
+}
+
+/// The 'whichwrap' option is changed.
+const char *did_set_whichwrap(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_option_listflag(*varp, WW_ALL, args->os_errbuf, args->os_errbuflen);
}
-static void did_set_wildmode(const char **errmsg)
+/// The 'shortmess' option is changed.
+const char *did_set_shortmess(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_option_listflag(*varp, SHM_ALL, args->os_errbuf, args->os_errbuflen);
+}
+
+/// The 'cpoptions' option is changed.
+const char *did_set_cpoptions(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_option_listflag(*varp, CPO_VI, args->os_errbuf, args->os_errbuflen);
+}
+
+/// The 'clipboard' option is changed.
+const char *did_set_clipboard(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true);
+}
+
+/// The 'foldopen' option is changed.
+const char *did_set_foldopen(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true);
+}
+
+/// The 'formatoptions' option is changed.
+const char *did_set_formatoptions(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_option_listflag(*varp, FO_ALL, args->os_errbuf, args->os_errbuflen);
+}
+
+/// The 'concealcursor' option is changed.
+const char *did_set_concealcursor(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_option_listflag(*varp, COCU_ALL, args->os_errbuf, args->os_errbuflen);
+}
+
+/// The 'mouse' option is changed.
+const char *did_set_mouse(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_option_listflag(*varp, MOUSE_ALL, args->os_errbuf, args->os_errbuflen);
+}
+
+/// The 'wildmode' option is changed.
+const char *did_set_wildmode(optset_T *args FUNC_ATTR_UNUSED)
{
if (check_opt_wim() == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_winaltkeys(const char **errmsg)
+/// The 'winaltkeys' option is changed.
+const char *did_set_winaltkeys(optset_T *args FUNC_ATTR_UNUSED)
{
if (*p_wak == NUL || check_opt_strings(p_wak, p_wak_values, false) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_eventignore(const char **errmsg)
+/// The 'eventignore' option is changed.
+const char *did_set_eventignore(optset_T *args FUNC_ATTR_UNUSED)
{
if (check_ei() == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
+}
+
+/// The 'eadirection' option is changed.
+const char *did_set_eadirection(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_strings(p_ead, p_ead_values, false);
}
-// 'encoding', 'fileencoding' and 'makeencoding'
-static void did_set_encoding(buf_T *buf, char **varp, char **gvarp, int opt_flags,
- const char **errmsg)
+/// One of the 'encoding', 'fileencoding' or 'makeencoding'
+/// options is changed.
+const char *did_set_encoding(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ char **varp = (char **)args->os_varp;
+ int opt_flags = args->os_flags;
+ // Get the global option to compare with, otherwise we would have to check
+ // two values for all local options.
+ char **gvarp = (char **)get_option_varp_scope_from(args->os_idx, OPT_GLOBAL, buf, NULL);
+
if (gvarp == &p_fenc) {
if (!MODIFIABLE(buf) && opt_flags != OPT_GLOBAL) {
- *errmsg = e_modifiable;
- return;
+ return e_modifiable;
}
if (vim_strchr(*varp, ',') != NULL) {
// No comma allowed in 'fileencoding'; catches confusing it
// with 'fileencodings'.
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
// May show a "+" in the title now.
@@ -856,19 +993,22 @@ static void did_set_encoding(buf_T *buf, char **varp, char **gvarp, int opt_flag
if (varp == &p_enc) {
// only encoding=utf-8 allowed
if (strcmp(p_enc, "utf-8") != 0) {
- *errmsg = e_unsupportedoption;
- return;
+ return e_unsupportedoption;
}
spell_reload();
}
+ return NULL;
}
-static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_checked,
- const char **errmsg)
+/// The 'keymap' option has changed.
+const char *did_set_keymap(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ char **varp = (char **)args->os_varp;
+ int opt_flags = args->os_flags;
+
if (!valid_filetype(*varp)) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
int secure_save = secure;
@@ -878,15 +1018,15 @@ static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_ch
secure = 0;
// load or unload key mapping tables
- *errmsg = keymap_init();
+ const char *errmsg = keymap_init();
secure = secure_save;
// Since we check the value, there is no need to set P_INSECURE,
// even when the value comes from a modeline.
- *value_checked = true;
+ args->os_value_checked = true;
- if (*errmsg == NULL) {
+ if (errmsg == NULL) {
if (*buf->b_p_keymap != NUL) {
// Installed a new keymap, switch on using it.
buf->b_p_iminsert = B_IMODE_LMAP;
@@ -908,29 +1048,44 @@ static void did_set_keymap(buf_T *buf, char **varp, int opt_flags, int *value_ch
}
status_redraw_buf(buf);
}
+
+ return errmsg;
}
-static void did_set_fileformat(buf_T *buf, char **varp, const char *oldval, int opt_flags,
- const char **errmsg)
+/// The 'fileformat' option is changed.
+const char *did_set_fileformat(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ char **varp = (char **)args->os_varp;
+ const char *oldval = args->os_oldval.string;
+ int opt_flags = args->os_flags;
if (!MODIFIABLE(buf) && !(opt_flags & OPT_GLOBAL)) {
- *errmsg = e_modifiable;
+ return e_modifiable;
} else if (check_opt_strings(*varp, p_ff_values, false) != OK) {
- *errmsg = e_invarg;
- } else {
- redraw_titles();
- // update flag in swap file
- ml_setflags(buf);
- // Redraw needed when switching to/from "mac": a CR in the text
- // will be displayed differently.
- if (get_fileformat(buf) == EOL_MAC || *oldval == 'm') {
- redraw_buf_later(buf, UPD_NOT_VALID);
- }
+ return e_invarg;
+ }
+ redraw_titles();
+ // update flag in swap file
+ ml_setflags(buf);
+ // Redraw needed when switching to/from "mac": a CR in the text
+ // will be displayed differently.
+ if (get_fileformat(buf) == EOL_MAC || *oldval == 'm') {
+ redraw_buf_later(buf, UPD_NOT_VALID);
}
+ return NULL;
}
-static void did_set_matchpairs(char **varp, const char **errmsg)
+/// The 'fileformats' option is changed.
+const char *did_set_fileformats(optset_T *args)
{
+ return did_set_opt_strings(p_ffs, p_ff_values, true);
+}
+
+/// The 'matchpairs' option is changed.
+const char *did_set_matchpairs(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
for (char *p = *varp; *p != NUL; p++) {
int x2 = -1;
int x3 = -1;
@@ -944,32 +1099,50 @@ static void did_set_matchpairs(char **varp, const char **errmsg)
p += utfc_ptr2len(p);
}
if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) {
- *errmsg = e_invarg;
- break;
+ return e_invarg;
}
if (*p == NUL) {
break;
}
}
+ return NULL;
+}
+
+/// The 'cinoptions' option is changed.
+const char *did_set_cinoptions(optset_T *args FUNC_ATTR_UNUSED)
+{
+ // TODO(vim): recognize errors
+ parse_cino(curbuf);
+
+ return NULL;
+}
+
+/// The 'colorcolumn' option is changed.
+const char *did_set_colorcolumn(optset_T *args)
+{
+ win_T *win = (win_T *)args->os_win;
+ return check_colorcolumn(win);
}
-static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, const char **errmsg)
+const char *did_set_comments(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+ char *errmsg = NULL;
for (char *s = *varp; *s;) {
while (*s && *s != ':') {
if (vim_strchr(COM_ALL, (uint8_t)(*s)) == NULL
&& !ascii_isdigit(*s) && *s != '-') {
- *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
+ errmsg = illegal_char(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s));
break;
}
s++;
}
if (*s++ == NUL) {
- *errmsg = N_("E524: Missing colon");
+ errmsg = N_("E524: Missing colon");
} else if (*s == ',' || *s == NUL) {
- *errmsg = N_("E525: Zero length string");
+ errmsg = N_("E525: Zero length string");
}
- if (*errmsg != NULL) {
+ if (errmsg != NULL) {
break;
}
while (*s && *s != ',') {
@@ -980,46 +1153,104 @@ static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, const
}
s = skip_to_option_part(s);
}
+ return errmsg;
}
-static void did_set_global_listfillchars(win_T *win, char **varp, int opt_flags,
- const char **errmsg)
+/// The global 'listchars' or 'fillchars' option is changed.
+static const char *did_set_global_listfillchars(win_T *win, char *val, bool opt_lcs, int opt_flags)
{
- char **local_ptr = varp == &p_lcs ? &win->w_p_lcs : &win->w_p_fcs;
- // only apply the global value to "win" when it does not have a local value
- *errmsg = set_chars_option(win, varp, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
- if (*errmsg == NULL) {
- // If the current window is set to use the global
- // 'listchars'/'fillchars' value, clear the window-local value.
- if (!(opt_flags & OPT_GLOBAL)) {
- clear_string_option(local_ptr);
- }
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- // If the current window has a local value need to apply it
- // again, it was changed when setting the global value.
- // If no error was returned above, we don't expect an error
- // here, so ignore the return value.
- local_ptr = varp == &p_lcs ? &wp->w_p_lcs : &wp->w_p_fcs;
- if (**local_ptr == NUL) {
- (void)set_chars_option(wp, local_ptr, true);
+ const char *errmsg = NULL;
+ char **local_ptr = opt_lcs ? &win->w_p_lcs : &win->w_p_fcs;
+
+ // only apply the global value to "win" when it does not have a
+ // local value
+ if (opt_lcs) {
+ errmsg = set_listchars_option(win, val, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
+ } else {
+ errmsg = set_fillchars_option(win, val, **local_ptr == NUL || !(opt_flags & OPT_GLOBAL));
+ }
+ if (errmsg != NULL) {
+ return errmsg;
+ }
+
+ // If the current window is set to use the global
+ // 'listchars'/'fillchars' value, clear the window-local value.
+ if (!(opt_flags & OPT_GLOBAL)) {
+ clear_string_option(local_ptr);
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ // If the current window has a local value need to apply it
+ // again, it was changed when setting the global value.
+ // If no error was returned above, we don't expect an error
+ // here, so ignore the return value.
+ if (opt_lcs) {
+ if (*wp->w_p_lcs == NUL) {
+ (void)set_listchars_option(wp, wp->w_p_lcs, true);
+ }
+ } else {
+ if (*wp->w_p_fcs == NUL) {
+ (void)set_fillchars_option(wp, wp->w_p_fcs, true);
}
}
- redraw_all_later(UPD_NOT_VALID);
}
+
+ redraw_all_later(UPD_NOT_VALID);
+
+ return NULL;
+}
+
+/// Handle the new value of 'fillchars'.
+const char *set_fillchars_option(win_T *wp, char *val, int apply)
+{
+ return set_chars_option(wp, val, false, apply);
+}
+
+/// Handle the new value of 'listchars'.
+const char *set_listchars_option(win_T *wp, char *val, int apply)
+{
+ return set_chars_option(wp, val, true, apply);
+}
+
+/// The 'fillchars' option or the 'listchars' option is changed.
+const char *did_set_chars_option(optset_T *args)
+{
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
+ const char *errmsg = NULL;
+
+ if (varp == &p_lcs // global 'listchars'
+ || varp == &p_fcs) { // global 'fillchars'
+ errmsg = did_set_global_listfillchars(win, *varp, varp == &p_lcs, args->os_flags);
+ } else if (varp == &win->w_p_lcs) { // local 'listchars'
+ errmsg = set_listchars_option(win, *varp, true);
+ } else if (varp == &win->w_p_fcs) { // local 'fillchars'
+ errmsg = set_fillchars_option(win, *varp, true);
+ }
+
+ return errmsg;
}
-static void did_set_verbosefile(const char **errmsg)
+/// The 'verbosefile' option is changed.
+const char *did_set_verbosefile(optset_T *args)
{
verbose_stop();
if (*p_vfile != NUL && verbose_open() == FAIL) {
- *errmsg = e_invarg;
+ return (char *)e_invarg;
}
+ return NULL;
+}
+
+/// The 'viewoptions' option is changed.
+const char *did_set_viewoptions(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true);
}
static int shada_idx = -1;
-static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf,
- size_t errbuflen, const char **errmsg)
+static const char *did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, char *errbuf,
+ size_t errbuflen)
{
// TODO(ZyX-I): Remove this code in the future, alongside with &viminfo
// option.
@@ -1034,8 +1265,7 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch
for (char *s = p_shada; *s;) {
// Check it's a valid character
if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
- break;
+ return illegal_char(errbuf, errbuflen, (uint8_t)(*s));
}
if (*s == 'n') { // name is always last one
break;
@@ -1054,43 +1284,46 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch
vim_snprintf(errbuf, errbuflen,
_("E526: Missing number after <%s>"),
transchar_byte((uint8_t)(*(s - 1))));
- *errmsg = errbuf;
+ return errbuf;
} else {
- *errmsg = "";
+ return "";
}
- break;
}
}
if (*s == ',') {
s++;
} else if (*s) {
if (errbuf != NULL) {
- *errmsg = N_("E527: Missing comma");
+ return N_("E527: Missing comma");
} else {
- *errmsg = "";
+ return "";
}
- break;
}
}
- if (*p_shada && *errmsg == NULL && get_shada_parameter('\'') < 0) {
- *errmsg = N_("E528: Must specify a ' value");
+ if (*p_shada && get_shada_parameter('\'') < 0) {
+ return N_("E528: Must specify a ' value");
}
+ return NULL;
}
-static void did_set_showbreak(char **varp, const char **errmsg)
+/// The 'showbreak' option is changed.
+const char *did_set_showbreak(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
for (char *s = *varp; *s;) {
if (ptr2cells(s) != 1) {
- *errmsg = e_showbreak_contains_unprintable_or_wide_character;
+ return e_showbreak_contains_unprintable_or_wide_character;
}
MB_PTR_ADV(s);
}
+ return NULL;
}
-static void did_set_titleiconstring(char **varp)
+/// The 'titlestring' or the 'iconstring' option is changed.
+static const char *did_set_titleiconstring(optset_T *args, int flagval)
{
- // 'titlestring' and 'iconstring'
- int flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON;
+ char **varp = (char **)args->os_varp;
// NULL => statusline syntax
if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL) {
@@ -1099,140 +1332,240 @@ static void did_set_titleiconstring(char **varp)
stl_syntax &= ~flagval;
}
did_set_title();
+
+ return NULL;
}
-static void did_set_selection(const char **errmsg)
+/// The 'titlestring' option is changed.
+const char *did_set_titlestring(optset_T *args)
+{
+ return did_set_titleiconstring(args, STL_IN_TITLE);
+}
+
+/// The 'iconstring' option is changed.
+const char *did_set_iconstring(optset_T *args)
+{
+ return did_set_titleiconstring(args, STL_IN_ICON);
+}
+
+/// The 'selection' option is changed.
+const char *did_set_selection(optset_T *args FUNC_ATTR_UNUSED)
{
if (*p_sel == NUL || check_opt_strings(p_sel, p_sel_values, false) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_keymodel(const char **errmsg)
+/// The 'keymodel' option is changed.
+const char *did_set_keymodel(optset_T *args FUNC_ATTR_UNUSED)
{
if (check_opt_strings(p_km, p_km_values, true) != OK) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
km_stopsel = (vim_strchr(p_km, 'o') != NULL);
km_startsel = (vim_strchr(p_km, 'a') != NULL);
+ return NULL;
}
-static void did_set_display(const char **errmsg)
+/// The 'display' option is changed.
+const char *did_set_display(optset_T *args FUNC_ATTR_UNUSED)
{
if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, true) != OK) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
(void)init_chartab();
msg_grid_validate();
+ return NULL;
}
-static void did_set_spellfile(char **varp, const char **errmsg)
+/// The 'spellfile' option is changed.
+const char *did_set_spellfile(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
// When there is a window for this buffer in which 'spell'
// is set load the wordlists.
-
if ((!valid_spellfile(*varp))) {
- *errmsg = e_invarg;
- } else {
- *errmsg = did_set_spell_option(true);
+ return e_invarg;
}
+ return did_set_spell_option(true);
}
-static void did_set_spell(char **varp, const char **errmsg)
+const char *did_set_spelllang(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
// When there is a window for this buffer in which 'spell'
// is set load the wordlists.
if (!valid_spelllang(*varp)) {
- *errmsg = e_invarg;
- } else {
- *errmsg = did_set_spell_option(false);
+ return e_invarg;
}
+ return did_set_spell_option(false);
}
-static void did_set_spellcapcheck(win_T *win, const char **errmsg)
+/// The 'spellcapcheck' option is changed.
+const char *did_set_spellcapcheck(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
// When 'spellcapcheck' is set compile the regexp program.
- *errmsg = compile_cap_prog(win->w_s);
+ return compile_cap_prog(win->w_s);
}
-static void did_set_spelloptions(win_T *win, const char **errmsg)
+/// The 'spelloptions' option is changed.
+const char *did_set_spelloptions(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
if (opt_strings_flags(win->w_s->b_p_spo, p_spo_values, &(win->w_s->b_p_spo_flags),
true) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_spellsuggest(const char **errmsg)
+/// The 'spellsuggest' option is changed.
+const char *did_set_spellsuggest(optset_T *args FUNC_ATTR_UNUSED)
{
if (spell_check_sps() != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
+}
+
+/// The 'splitkeep' option is changed.
+const char *did_set_splitkeep(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_strings(p_spk, p_spk_values, false);
}
-static void did_set_mkspellmem(const char **errmsg)
+/// The 'mkspellmem' option is changed.
+const char *did_set_mkspellmem(optset_T *args FUNC_ATTR_UNUSED)
{
if (spell_check_msm() != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
+}
+
+/// The 'mousemodel' option is changed.
+const char *did_set_mousemodel(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_strings(p_mousem, p_mousem_values, false);
}
-static void did_set_buftype(buf_T *buf, win_T *win, const char **errmsg)
+/// The 'bufhidden' option is changed.
+const char *did_set_bufhidden(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ return did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false);
+}
+
+/// The 'buftype' option is changed.
+const char *did_set_buftype(optset_T *args)
+{
+ buf_T *buf = (buf_T *)args->os_buf;
+ win_T *win = (win_T *)args->os_win;
// When 'buftype' is set, check for valid value.
if ((buf->terminal && buf->b_p_bt[0] != 't')
|| (!buf->terminal && buf->b_p_bt[0] == 't')
|| check_opt_strings(buf->b_p_bt, p_buftype_values, false) != OK) {
- *errmsg = e_invarg;
- } else {
- if (win->w_status_height || global_stl_height()) {
- win->w_redr_status = true;
- redraw_later(win, UPD_VALID);
- }
- buf->b_help = (buf->b_p_bt[0] == 'h');
- redraw_titles();
+ return e_invarg;
+ }
+ if (win->w_status_height || global_stl_height()) {
+ win->w_redr_status = true;
+ redraw_later(win, UPD_VALID);
}
+ buf->b_help = (buf->b_p_bt[0] == 'h');
+ redraw_titles();
+ return NULL;
}
-// 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn'
-static void did_set_statusline(win_T *win, char **varp, char **gvarp, const char **errmsg)
+/// The 'casemap' option is changed.
+const char *did_set_casemap(optset_T *args FUNC_ATTR_UNUSED)
{
- if (varp == &p_ruf) { // reset ru_wid first
+ return did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true);
+}
+
+/// The 'statusline', 'winbar', 'tabline', 'rulerformat' or 'statuscolumn' option is changed.
+///
+/// @param rulerformat true if the 'rulerformat' option is changed
+/// @param statuscolumn true if the 'statuscolumn' option is changed
+static const char *did_set_statustabline_rulerformat(optset_T *args, bool rulerformat,
+ bool statuscolumn)
+{
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
+ if (rulerformat) { // reset ru_wid first
ru_wid = 0;
- } else if (varp == &win->w_p_stc) {
+ } else if (statuscolumn) {
// reset 'statuscolumn' width
win->w_nrwidth_line_count = 0;
}
+ const char *errmsg = NULL;
char *s = *varp;
- if (varp == &p_ruf && *s == '%') {
+ if (rulerformat && *s == '%') {
// set ru_wid if 'ruf' starts with "%99("
if (*++s == '-') { // ignore a '-'
s++;
}
int wid = getdigits_int(&s, true, 0);
- if (wid && *s == '(' && (*errmsg = check_stl_option(p_ruf)) == NULL) {
+ if (wid && *s == '(' && (errmsg = check_stl_option(p_ruf)) == NULL) {
ru_wid = wid;
} else {
- *errmsg = check_stl_option(p_ruf);
+ errmsg = check_stl_option(p_ruf);
}
- } else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') {
+ } else if (rulerformat || s[0] != '%' || s[1] != '!') {
// check 'statusline', 'winbar', 'tabline' or 'statuscolumn'
// only if it doesn't start with "%!"
- *errmsg = check_stl_option(s);
+ errmsg = check_stl_option(s);
}
- if (varp == &p_ruf && *errmsg == NULL) {
+ if (rulerformat && errmsg == NULL) {
comp_col();
}
- // add / remove window bars for 'winbar'
- if (gvarp == &p_wbr) {
- set_winbar(true);
- }
+ return errmsg;
+}
+
+/// The 'statusline' option is changed.
+const char *did_set_statusline(optset_T *args)
+{
+ return did_set_statustabline_rulerformat(args, false, false);
+}
+
+/// The 'tabline' option is changed.
+const char *did_set_tabline(optset_T *args)
+{
+ return did_set_statustabline_rulerformat(args, false, false);
+}
+
+/// The 'rulerformat' option is changed.
+const char *did_set_rulerformat(optset_T *args)
+{
+ return did_set_statustabline_rulerformat(args, true, false);
+}
+
+/// The 'winbar' option is changed.
+const char *did_set_winbar(optset_T *args)
+{
+ return did_set_statustabline_rulerformat(args, false, false);
+}
+
+/// The 'statuscolumn' option is changed.
+const char *did_set_statuscolumn(optset_T *args)
+{
+ return did_set_statustabline_rulerformat(args, false, true);
}
-static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, const char **errmsg)
+/// The 'scrollopt' option is changed.
+const char *did_set_scrollopt(optset_T *args FUNC_ATTR_UNUSED)
{
+ return did_set_opt_strings(p_sbo, p_scbopt_values, true);
+}
+
+/// The 'complete' option is changed.
+const char *did_set_complete(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
// check if it is a valid value for 'complete' -- Acevedo
for (char *s = *varp; *s;) {
while (*s == ',' || *s == ' ') {
@@ -1242,8 +1575,7 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, const
break;
}
if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
- break;
+ return illegal_char(args->os_errbuf, args->os_errbuflen, (uint8_t)(*s));
}
if (*++s != NUL && *s != ',' && *s != ' ') {
if (s[-1] == 'k' || s[-1] == 's') {
@@ -1255,43 +1587,56 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, const
s++;
}
} else {
- if (errbuf != NULL) {
- vim_snprintf(errbuf, errbuflen,
+ if (args->os_errbuf != NULL) {
+ vim_snprintf(args->os_errbuf, args->os_errbuflen,
_("E535: Illegal character after <%c>"),
*--s);
- *errmsg = errbuf;
- } else {
- *errmsg = "";
+ return args->os_errbuf;
}
- break;
+ return "";
}
}
}
+ return NULL;
}
-static void did_set_completeopt(const char **errmsg)
+/// The 'completeopt' option is changed.
+const char *did_set_completeopt(optset_T *args FUNC_ATTR_UNUSED)
{
if (check_opt_strings(p_cot, p_cot_values, true) != OK) {
- *errmsg = e_invarg;
- } else {
- completeopt_was_set();
+ return e_invarg;
}
+ completeopt_was_set();
+ return NULL;
}
#ifdef BACKSLASH_IN_FILENAME
-static void did_set_completeslash(buf_T *buf, const char **errmsg)
+/// The 'completeslash' option is changed.
+const char *did_set_completeslash(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
if (check_opt_strings(p_csl, p_csl_values, false) != OK
|| check_opt_strings(buf->b_p_csl, p_csl_values, false) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
#endif
-static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, const char **errmsg)
+/// The 'showcmdloc' option is changed.
+const char *did_set_showcmdloc(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_strings(p_sloc, p_sloc_values, true);
+}
+
+/// The 'signcolumn' option is changed.
+const char *did_set_signcolumn(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
+ const char *oldval = args->os_oldval.string;
if (check_signcolumn(*varp) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
// When changing the 'signcolumn' to or from 'number', recompute the
// width of the number column if 'number' or 'relativenumber' is set.
@@ -1300,28 +1645,44 @@ static void did_set_signcolumn(win_T *win, char **varp, const char *oldval, cons
&& (win->w_p_nu || win->w_p_rnu)) {
win->w_nrwidth_line_count = 0;
}
+ return NULL;
}
-static void did_set_foldcolumn(char **varp, const char **errmsg)
+/// The 'foldcolumn' option is changed.
+const char *did_set_foldcolumn(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
if (**varp == NUL || check_opt_strings(*varp, p_fdc_values, false) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_backspace(const char **errmsg)
+/// The 'backspace' option is changed.
+const char *did_set_backspace(optset_T *args FUNC_ATTR_UNUSED)
{
if (ascii_isdigit(*p_bs)) {
if (*p_bs > '3' || p_bs[1] != NUL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
} else if (check_opt_strings(p_bs, p_bs_values, true) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_tagcase(buf_T *buf, int opt_flags, const char **errmsg)
+/// The 'switchbuf' option is changed.
+const char *did_set_switchbuf(optset_T *args FUNC_ATTR_UNUSED)
{
+ return did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true);
+}
+
+/// The 'tagcase' option is changed.
+const char *did_set_tagcase(optset_T *args)
+{
+ buf_T *buf = (buf_T *)args->os_buf;
+ int opt_flags = args->os_flags;
+
unsigned *flags;
char *p;
@@ -1338,73 +1699,105 @@ static void did_set_tagcase(buf_T *buf, int opt_flags, const char **errmsg)
*flags = 0;
} else if (*p == NUL
|| opt_strings_flags(p, p_tc_values, flags, false) != OK) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_diffopt(const char **errmsg)
+/// The 'debug' option is changed.
+const char *did_set_debug(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_strings(p_debug, p_debug_values, false);
+}
+
+/// The 'diffopt' option is changed.
+const char *did_set_diffopt(optset_T *args FUNC_ATTR_UNUSED)
{
if (diffopt_changed() == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_foldmethod(win_T *win, char **varp, const char **errmsg)
+/// The 'foldmethod' option is changed.
+const char *did_set_foldmethod(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
if (check_opt_strings(*varp, p_fdm_values, false) != OK
|| *win->w_p_fdm == NUL) {
- *errmsg = e_invarg;
- } else {
- foldUpdateAll(win);
- if (foldmethodIsDiff(win)) {
- newFoldLevel();
- }
+ return e_invarg;
+ }
+ foldUpdateAll(win);
+ if (foldmethodIsDiff(win)) {
+ newFoldLevel();
}
+ return NULL;
}
-static void did_set_foldmarker(win_T *win, char **varp, const char **errmsg)
+/// The 'foldmarker' option is changed.
+const char *did_set_foldmarker(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
char *p = vim_strchr(*varp, ',');
+
if (p == NULL) {
- *errmsg = N_("E536: comma required");
- } else if (p == *varp || p[1] == NUL) {
- *errmsg = e_invarg;
- } else if (foldmethodIsMarker(win)) {
+ return N_("E536: comma required");
+ }
+
+ if (p == *varp || p[1] == NUL) {
+ return e_invarg;
+ }
+
+ if (foldmethodIsMarker(win)) {
foldUpdateAll(win);
}
+
+ return NULL;
}
-static void did_set_commentstring(char **varp, const char **errmsg)
+/// The 'commentstring' option is changed.
+const char *did_set_commentstring(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
if (**varp != NUL && strstr(*varp, "%s") == NULL) {
- *errmsg = N_("E537: 'commentstring' must be empty or contain %s");
+ return N_("E537: 'commentstring' must be empty or contain %s");
}
+ return NULL;
}
-static void did_set_foldignore(win_T *win)
+/// The 'foldignore' option is changed.
+const char *did_set_foldignore(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
if (foldmethodIsIndent(win)) {
foldUpdateAll(win);
}
+ return NULL;
}
-static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, const char **errmsg)
+/// The 'virtualedit' option is changed.
+const char *did_set_virtualedit(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
+
char *ve = p_ve;
unsigned *flags = &ve_flags;
- if (opt_flags & OPT_LOCAL) {
+ if (args->os_flags & OPT_LOCAL) {
ve = win->w_p_ve;
flags = &win->w_ve_flags;
}
- if ((opt_flags & OPT_LOCAL) && *ve == NUL) {
+ if ((args->os_flags & OPT_LOCAL) && *ve == NUL) {
// make the local value empty: use the global value
*flags = 0;
} else {
if (opt_strings_flags(ve, p_ve_values, flags, true) != OK) {
- *errmsg = e_invarg;
- } else if (strcmp(ve, oldval) != 0) {
+ return e_invarg;
+ } else if (strcmp(ve, args->os_oldval.string) != 0) {
// Recompute cursor position in case the new 've' setting
// changes something.
validate_virtcol_win(win);
@@ -1412,42 +1805,87 @@ static void did_set_virtualedit(win_T *win, int opt_flags, char *oldval, const c
coladvance(win->w_virtcol);
}
}
+ return NULL;
+}
+
+/// The 'jumpoptions' option is changed.
+const char *did_set_jumpoptions(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true);
+}
+
+/// The 'redrawdebug' option is changed.
+const char *did_set_redrawdebug(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true);
+}
+
+/// The 'wildoptions' option is changed.
+const char *did_set_wildoptions(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true);
}
-static void did_set_lispoptions(char **varp, const char **errmsg)
+/// The 'lispoptions' option is changed.
+const char *did_set_lispoptions(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
if (**varp != NUL && strcmp(*varp, "expr:0") != 0 && strcmp(*varp, "expr:1") != 0) {
- *errmsg = e_invarg;
+ return e_invarg;
+ }
+ return NULL;
+}
+
+/// The 'rightleftcmd' option is changed.
+const char *did_set_rightleftcmd(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ // Currently only "search" is a supported value.
+ if (**varp != NUL && strcmp(*varp, "search") != 0) {
+ return e_invarg;
}
+
+ return NULL;
}
-static void did_set_filetype_or_syntax(char **varp, char *oldval, int *value_checked,
- bool *value_changed, const char **errmsg)
+/// The 'filetype' or the 'syntax' option is changed.
+const char *did_set_filetype_or_syntax(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
if (!valid_filetype(*varp)) {
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
- *value_changed = strcmp(oldval, *varp) != 0;
+ args->os_value_changed = strcmp(args->os_oldval.string, *varp) != 0;
// Since we check the value, there is no need to set P_INSECURE,
// even when the value comes from a modeline.
- *value_checked = true;
+ args->os_value_checked = true;
+
+ return NULL;
}
-static void did_set_winhl(win_T *win, const char **errmsg)
+const char *did_set_winhl(optset_T *args)
{
+ win_T *win = (win_T *)args->os_win;
if (!parse_winhl_opt(win)) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_varsoftabstop(buf_T *buf, char **varp, const char **errmsg)
+/// The 'varsofttabstop' option is changed.
+const char *did_set_varsofttabstop(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ char **varp = (char **)args->os_varp;
+
if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
XFREE_CLEAR(buf->b_p_vsts_array);
- return;
+ return NULL;
}
for (char *cp = *varp; *cp; cp++) {
@@ -1457,23 +1895,28 @@ static void did_set_varsoftabstop(buf_T *buf, char **varp, const char **errmsg)
if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
continue;
}
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
long *oldarray = buf->b_p_vsts_array;
if (tabstop_set(*varp, &(buf->b_p_vsts_array))) {
xfree(oldarray);
} else {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
-static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, const char **errmsg)
+/// The 'varstabstop' option is changed.
+const char *did_set_vartabstop(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+ win_T *win = (win_T *)args->os_win;
+ char **varp = (char **)args->os_varp;
+
if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1])) {
XFREE_CLEAR(buf->b_p_vts_array);
- return;
+ return NULL;
}
for (char *cp = *varp; *cp; cp++) {
@@ -1483,8 +1926,7 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, const char *
if (*cp == ',' && cp > *varp && *(cp - 1) != ',') {
continue;
}
- *errmsg = e_invarg;
- return;
+ return e_invarg;
}
long *oldarray = buf->b_p_vts_array;
@@ -1494,29 +1936,67 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, const char *
foldUpdateAll(win);
}
} else {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
+}
+
+/// The 'nrformats' option is changed.
+const char *did_set_nrformats(optset_T *args)
+{
+ char **varp = (char **)args->os_varp;
+
+ return did_set_opt_strings(*varp, p_nf_values, true);
}
-static void did_set_optexpr(char **varp)
+/// One of the '*expr' options is changed:, 'diffexpr', 'foldexpr', 'foldtext',
+/// 'formatexpr', 'includeexpr', 'indentexpr', 'patchexpr' and 'charconvert'.
+const char *did_set_optexpr(optset_T *args)
{
+ char **varp = (char **)args->os_varp;
+
+ // If the option value starts with <SID> or s:, then replace that with
+ // the script identifier.
char *name = get_scriptlocal_funcname(*varp);
if (name != NULL) {
free_string_option(*varp);
*varp = name;
}
+ return NULL;
+}
+
+/// The 'foldexpr' option is changed.
+const char *did_set_foldexpr(optset_T *args)
+{
+ win_T *win = (win_T *)args->os_win;
+ (void)did_set_optexpr(args);
+ if (foldmethodIsExpr(win)) {
+ foldUpdateAll(win);
+ }
+ return NULL;
}
-// handle option that is a list of flags.
-static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size_t errbuflen,
- const char **errmsg)
+/// The 'foldclose' option is changed.
+const char *did_set_foldclose(optset_T *args FUNC_ATTR_UNUSED)
{
- for (char *s = *varp; *s; s++) {
+ return did_set_opt_strings(p_fcl, p_fcl_values, true);
+}
+
+/// An option which is a list of flags is set. Valid values are in 'flags'.
+static const char *did_set_option_listflag(char *val, char *flags, char *errbuf, size_t errbuflen)
+{
+ for (char *s = val; *s; s++) {
if (vim_strchr(flags, (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
- break;
+ return illegal_char(errbuf, errbuflen, (uint8_t)(*s));
}
}
+
+ return NULL;
+}
+
+const char *did_set_guicursor(optset_T *args FUNC_ATTR_UNUSED)
+{
+ return parse_shape_opt(SHAPE_CURSOR);
}
// When 'syntax' is set, load the syntax of that name
@@ -1574,18 +2054,30 @@ static void do_spelllang_source(win_T *win)
///
/// @return NULL for success, or an untranslated error message for an error
static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char **varp,
- char *oldval, char *errbuf, size_t errbuflen,
- int opt_flags, int *value_checked)
+ char *oldval, const char *value, char *errbuf,
+ size_t errbuflen, int opt_flags, int *value_checked)
{
const char *errmsg = NULL;
- bool did_chartab = false;
+ int restore_chartab = false;
vimoption_T *opt = get_option(opt_idx);
bool free_oldval = (opt->flags & P_ALLOCED);
+ opt_did_set_cb_T did_set_cb = get_option_did_set_cb(opt_idx);
bool value_changed = false;
- // Get the global option to compare with, otherwise we would have to check
- // two values for all local options.
- char **gvarp = (char **)get_varp_scope(opt, OPT_GLOBAL);
+ optset_T args = {
+ .os_varp = (char *)varp,
+ .os_idx = opt_idx,
+ .os_flags = opt_flags,
+ .os_oldval.string = oldval,
+ .os_newval.string = value,
+ .os_value_checked = false,
+ .os_value_changed = false,
+ .os_restore_chartab = false,
+ .os_errbuf = errbuf,
+ .os_errbuflen = errbuflen,
+ .os_win = curwin,
+ .os_buf = curbuf,
+ };
// Disallow changing some options from secure mode
if ((secure || sandbox != 0) && (opt->flags & P_SECURE)) {
@@ -1593,236 +2085,22 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx
// Check for a "normal" directory or file name in some options.
} else if (check_illegal_path_names(*varp, opt->flags)) {
errmsg = e_invarg;
- } else if (gvarp == &p_bkc) { // 'backupcopy'
- did_set_backupcopy(buf, oldval, opt_flags, &errmsg);
- } else if (varp == &p_bex // 'backupext'
- || varp == &p_pm) { // 'patchmode'
- did_set_backupext_or_patchmode(&errmsg);
- } else if (varp == &win->w_p_briopt) { // 'breakindentopt'
- did_set_breakindentopt(win, &errmsg);
- } else if (varp == &p_isi // 'isident'
- || varp == &buf->b_p_isk // 'iskeyword'
- || varp == &p_isp // 'isprint'
- || varp == &p_isf) { // 'isfname'
- did_set_isopt(buf, &did_chartab, &errmsg);
- } else if (varp == &p_hf) { // 'helpfile'
- did_set_helpfile();
- } else if (varp == &p_rtp // 'runtimepath'
- || varp == &p_pp) { // 'packpath'
- runtime_search_path_invalidate();
- } else if (gvarp == &win->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
- did_set_cursorlineopt(win, varp, &errmsg);
- } else if (varp == &win->w_p_cc) { // 'colorcolumn'
- errmsg = check_colorcolumn(win);
- } else if (varp == &p_hlg) { // 'helplang'
- did_set_helplang(&errmsg);
- } else if (varp == &p_hl) { // 'highlight'
- did_set_highlight(varp, &errmsg);
- } else if (varp == &p_jop) { // 'jumpoptions'
- did_set_opt_flags(p_jop, p_jop_values, &jop_flags, true, &errmsg);
- } else if (gvarp == &p_nf) { // 'nrformats'
- did_set_opt_strings(*varp, p_nf_values, true, &errmsg);
- } else if (varp == &p_ssop) { // 'sessionoptions'
- did_set_sessionoptions(oldval, &errmsg);
- } else if (varp == &p_vop) { // 'viewoptions'
- did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, true, &errmsg);
- } else if (varp == &p_rdb) { // 'redrawdebug'
- did_set_opt_flags(p_rdb, p_rdb_values, &rdb_flags, true, &errmsg);
- } else if (varp == &p_sbo) { // 'scrollopt'
- did_set_opt_strings(p_sbo, p_scbopt_values, true, &errmsg);
- } else if (varp == &p_ambw // 'ambiwidth'
- || (int *)varp == &p_emoji) { // 'emoji'
- did_set_ambiwidth(&errmsg);
- } else if (varp == &p_bg) { // 'background'
- did_set_background(&errmsg);
- } else if (varp == &p_wim) { // 'wildmode'
- did_set_wildmode(&errmsg);
- } else if (varp == &p_wop) { // 'wildoptions'
- did_set_opt_flags(p_wop, p_wop_values, &wop_flags, true, &errmsg);
- } else if (varp == &p_wak) { // 'winaltkeys'
- did_set_winaltkeys(&errmsg);
- } else if (varp == &p_ei) { // 'eventignore'
- did_set_eventignore(&errmsg);
- } else if (varp == &p_enc // 'encoding'
- || gvarp == &p_fenc // 'fileencoding'
- || gvarp == &p_menc) { // 'makeencoding'
- did_set_encoding(buf, varp, gvarp, opt_flags, &errmsg);
- } else if (varp == &buf->b_p_keymap) { // 'keymap'
- did_set_keymap(buf, varp, opt_flags, value_checked, &errmsg);
- } else if (gvarp == &p_ff) { // 'fileformat'
- did_set_fileformat(buf, varp, oldval, opt_flags, &errmsg);
- } else if (varp == &p_ffs) { // 'fileformats'
- did_set_opt_strings(p_ffs, p_ff_values, true, &errmsg);
- } else if (gvarp == &p_mps) { // 'matchpairs'
- did_set_matchpairs(varp, &errmsg);
- } else if (gvarp == &p_com) { // 'comments'
- did_set_comments(varp, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_lcs // global 'listchars'
- || varp == &p_fcs) { // global 'fillchars'
- did_set_global_listfillchars(win, varp, opt_flags, &errmsg);
- } else if (varp == &win->w_p_lcs) { // local 'listchars'
- errmsg = set_chars_option(win, varp, true);
- } else if (varp == &win->w_p_fcs) { // local 'fillchars'
- errmsg = set_chars_option(win, varp, true);
- } else if (varp == &p_cedit) { // 'cedit'
- errmsg = check_cedit();
- } else if (varp == &p_vfile) { // 'verbosefile'
- did_set_verbosefile(&errmsg);
+ } else if (did_set_cb != NULL) {
+ // Invoke the option specific callback function to validate and apply
+ // the new option value.
+ errmsg = did_set_cb(&args);
+
+ // The 'filetype' and 'syntax' option callback functions may change
+ // the os_value_changed field.
+ value_changed = args.os_value_changed;
+ // The 'keymap', 'filetype' and 'syntax' option callback functions
+ // may change the os_value_checked field.
+ *value_checked = args.os_value_checked;
+ // The 'isident', 'iskeyword', 'isprint' and 'isfname' options may
+ // change the character table. On failure, this needs to be restored.
+ restore_chartab = args.os_restore_chartab;
} else if (varp == &p_shada) { // 'shada'
- did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen, &errmsg);
- } else if (gvarp == &p_sbr) { // 'showbreak'
- did_set_showbreak(varp, &errmsg);
- } else if (varp == &p_guicursor) { // 'guicursor'
- errmsg = parse_shape_opt(SHAPE_CURSOR);
- } else if (varp == &p_langmap) { // 'langmap'
- langmap_set();
- } else if (varp == &p_breakat) { // 'breakat'
- fill_breakat_flags();
- } else if (varp == &p_titlestring // 'titlestring'
- || varp == &p_iconstring) { // 'iconstring'
- did_set_titleiconstring(varp);
- } else if (varp == &p_sel) { // 'selection'
- did_set_selection(&errmsg);
- } else if (varp == &p_slm) { // 'selectmode'
- did_set_opt_strings(p_slm, p_slm_values, true, &errmsg);
- } else if (varp == &p_km) { // 'keymodel'
- did_set_keymodel(&errmsg);
- } else if (varp == &p_mousem) { // 'mousemodel'
- did_set_opt_strings(p_mousem, p_mousem_values, false, &errmsg);
- } else if (varp == &p_mousescroll) { // 'mousescroll'
- errmsg = check_mousescroll(p_mousescroll);
- } else if (varp == &p_swb) { // 'switchbuf'
- did_set_opt_flags(p_swb, p_swb_values, &swb_flags, true, &errmsg);
- } else if (varp == &p_spk) { // 'splitkeep'
- did_set_opt_strings(p_spk, p_spk_values, false, &errmsg);
- } else if (varp == &p_debug) { // 'debug'
- did_set_opt_strings(p_debug, p_debug_values, true, &errmsg);
- } else if (varp == &p_dy) { // 'display'
- did_set_display(&errmsg);
- } else if (varp == &p_ead) { // 'eadirection'
- did_set_opt_strings(p_ead, p_ead_values, false, &errmsg);
- } else if (varp == &p_cb) { // 'clipboard'
- did_set_opt_flags(p_cb, p_cb_values, &cb_flags, true, &errmsg);
- } else if (varp == &win->w_s->b_p_spf) { // 'spellfile'
- did_set_spellfile(varp, &errmsg);
- } else if (varp == &win->w_s->b_p_spl) { // 'spell'
- did_set_spell(varp, &errmsg);
- } else if (varp == &win->w_s->b_p_spc) { // 'spellcapcheck'
- did_set_spellcapcheck(win, &errmsg);
- } else if (varp == &win->w_s->b_p_spo) { // 'spelloptions'
- did_set_spelloptions(win, &errmsg);
- } else if (varp == &p_sps) { // 'spellsuggest'
- did_set_spellsuggest(&errmsg);
- } else if (varp == &p_msm) { // 'mkspellmem'
- did_set_mkspellmem(&errmsg);
- } else if (gvarp == &p_bh) { // 'bufhidden'
- did_set_opt_strings(buf->b_p_bh, p_bufhidden_values, false, &errmsg);
- } else if (gvarp == &p_bt) { // 'buftype'
- did_set_buftype(buf, win, &errmsg);
- } else if (gvarp == &p_stl // 'statusline'
- || gvarp == &p_wbr // 'winbar'
- || varp == &p_tal // 'tabline'
- || varp == &p_ruf // 'rulerformat'
- || varp == &win->w_p_stc) { // 'statuscolumn'
- did_set_statusline(win, varp, gvarp, &errmsg);
- } else if (gvarp == &p_cpt) { // 'complete'
- did_set_complete(varp, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_cot) { // 'completeopt'
- did_set_completeopt(&errmsg);
-#ifdef BACKSLASH_IN_FILENAME
- } else if (gvarp == &p_csl) { // 'completeslash'
- did_set_completeslash(buf, &errmsg);
-#endif
- } else if (varp == &win->w_p_scl) { // 'signcolumn'
- did_set_signcolumn(win, varp, oldval, &errmsg);
- } else if (varp == &p_sloc) { // 'showcmdloc'
- did_set_opt_strings(*varp, p_sloc_values, false, &errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fdc) { // 'foldcolumn'
- did_set_foldcolumn(varp, &errmsg);
- } else if (varp == &p_bs) { // 'backspace'
- did_set_backspace(&errmsg);
- } else if (varp == &p_bo) {
- did_set_opt_flags(p_bo, p_bo_values, &bo_flags, true, &errmsg);
- } else if (gvarp == &p_tc) { // 'tagcase'
- did_set_tagcase(buf, opt_flags, &errmsg);
- } else if (varp == &p_cmp) { // 'casemap'
- did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, true, &errmsg);
- } else if (varp == &p_dip) { // 'diffopt'
- did_set_diffopt(&errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fdm) { // 'foldmethod'
- did_set_foldmethod(win, varp, &errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fmr) { // 'foldmarker'
- did_set_foldmarker(win, varp, &errmsg);
- } else if (gvarp == &p_cms) { // 'commentstring'
- did_set_commentstring(varp, &errmsg);
- } else if (varp == &p_fdo) { // 'foldopen'
- did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, true, &errmsg);
- } else if (varp == &p_fcl) { // 'foldclose'
- did_set_opt_strings(*varp, p_fcl_values, true, &errmsg);
- } else if (gvarp == &win->w_allbuf_opt.wo_fdi) { // 'foldignore'
- did_set_foldignore(win);
- } else if (gvarp == &p_ve) { // 'virtualedit'
- did_set_virtualedit(win, opt_flags, oldval, &errmsg);
- } else if (gvarp == &p_cino) { // 'cinoptions'
- // TODO(vim): recognize errors
- parse_cino(buf);
- } else if (gvarp == &p_lop) { // 'lispoptions'
- did_set_lispoptions(varp, &errmsg);
- } else if (varp == &p_icm) { // 'inccommand'
- did_set_opt_strings(*varp, p_icm_values, false, &errmsg);
- } else if (gvarp == &p_ft // 'filetype'
- || gvarp == &p_syn) { // 'syntax'
- did_set_filetype_or_syntax(varp, oldval, value_checked, &value_changed, &errmsg);
- } else if (varp == &win->w_p_winhl) { // 'winhighlight'
- did_set_winhl(win, &errmsg);
- } else if (varp == &p_tpf) {
- did_set_opt_flags(p_tpf, p_tpf_values, &tpf_flags, true, &errmsg);
- } else if (varp == &buf->b_p_vsts) { // 'varsofttabstop'
- did_set_varsoftabstop(buf, varp, &errmsg);
- } else if (varp == &buf->b_p_vts) { // 'vartabstop'
- did_set_vartabstop(buf, win, varp, &errmsg);
- } else if (varp == &p_dex // 'diffexpr'
- || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr'
- || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext'
- || gvarp == &p_fex // 'formatexpr'
- || gvarp == &p_inex // 'includeexpr'
- || gvarp == &p_inde // 'indentexpr'
- || varp == &p_pex // 'patchexpr'
- || varp == &p_ccv) { // 'charconvert'
- did_set_optexpr(varp);
- if (varp == &win->w_p_fde && foldmethodIsExpr(win)) {
- foldUpdateAll(win);
- }
- } else if (gvarp == &p_cfu) { // 'completefunc'
- set_completefunc_option(&errmsg);
- } else if (gvarp == &p_ofu) { // 'omnifunc'
- set_omnifunc_option(buf, &errmsg);
- } else if (gvarp == &p_tsrfu) { // 'thesaurusfunc'
- set_thesaurusfunc_option(&errmsg);
- } else if (varp == &p_opfunc) { // 'operatorfunc'
- set_operatorfunc_option(&errmsg);
- } else if (varp == &p_qftf) { // 'quickfixtextfunc'
- qf_process_qftf_option(&errmsg);
- } else if (gvarp == &p_tfu) { // 'tagfunc'
- set_tagfunc_option(&errmsg);
- } else if (varp == &p_ww) { // 'whichwrap'
- did_set_option_listflag(varp, WW_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_shm) { // 'shortmess'
- did_set_option_listflag(varp, SHM_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_cpo) { // 'cpoptions'
- did_set_option_listflag(varp, CPO_VI, errbuf, errbuflen, &errmsg);
- } else if (varp == &buf->b_p_fo) { // 'formatoptions'
- did_set_option_listflag(varp, FO_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &win->w_p_cocu) { // 'concealcursor'
- did_set_option_listflag(varp, COCU_ALL, errbuf, errbuflen, &errmsg);
- } else if (varp == &p_mouse) { // 'mouse'
- did_set_option_listflag(varp, MOUSE_ALL, errbuf, errbuflen, &errmsg);
- } else if (gvarp == &p_flp) { // 'formatlistpat'
- if (win->w_briopt_list) {
- // Changing Formatlistpattern when briopt includes the list setting:
- // redraw
- redraw_all_later(UPD_NOT_VALID);
- }
+ errmsg = did_set_shada(&opt, &opt_idx, &free_oldval, errbuf, errbuflen);
}
// If an error is detected, restore the previous value.
@@ -1830,7 +2108,7 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx
free_string_option(*varp);
*varp = oldval;
// When resetting some values, need to act on it.
- if (did_chartab) {
+ if (restore_chartab) {
(void)buf_init_chartab(buf, true);
}
} else {
@@ -1875,6 +2153,16 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx
setmouse(); // in case 'mouse' changed
}
+ if ((varp == &p_flp || varp == &(buf->b_p_flp))
+ && win->w_briopt_list) {
+ // Changing Formatlistpattern when briopt includes the list setting:
+ // redraw
+ redraw_all_later(UPD_NOT_VALID);
+ } else if (varp == &p_wbr || varp == &(win->w_p_wbr)) {
+ // add / remove window bars for 'winbar'
+ set_winbar(true);
+ }
+
if (win->w_curswant != MAXCOL
&& (opt->flags & (P_CURSWANT | P_RALL)) != 0) {
win->w_set_curswant = true;
@@ -1885,11 +2173,11 @@ static const char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx
return errmsg;
}
-const char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf,
+const char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *value, char *errbuf,
size_t errbuflen, int opt_flags, int *value_checked)
{
- return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, errbuf, errbuflen,
- opt_flags, value_checked);
+ return did_set_string_option_for(curbuf, curwin, opt_idx, varp, oldval, value, errbuf,
+ errbuflen, opt_flags, value_checked);
}
/// Check an option that can be a range of string values.
@@ -1910,7 +2198,7 @@ static int check_opt_strings(char *val, char **values, int list)
/// @param list when true: accept a list of values
///
/// @return OK for correct value, FAIL otherwise. Empty is always OK.
-static int opt_strings_flags(char *val, char **values, unsigned *flagp, bool list)
+static int opt_strings_flags(const char *val, char **values, unsigned *flagp, bool list)
{
unsigned new_flags = 0;
@@ -1946,9 +2234,8 @@ int check_ff_value(char *p)
static char shm_buf[SHM_LEN];
static int set_shm_recursive = 0;
-/// Save the acutal shortmess Flags and clear them
-/// temporarily to avoid that file messages
-/// overwrites any output from the following commands.
+/// Save the actual shortmess Flags and clear them temporarily to avoid that
+/// file messages overwrites any output from the following commands.
///
/// Caller must make sure to first call save_clear_shm_value() and then
/// restore_shm_value() exactly the same number of times.
@@ -2012,16 +2299,17 @@ static int get_encoded_char_adv(const char **p)
/// Handle setting 'listchars' or 'fillchars'.
/// Assume monocell characters
///
-/// @param varp either the global or the window-local value.
+/// @param value points to either the global or the window-local value.
+/// @param opt_lcs is tue for "listchars" and FALSE for "fillchars".
/// @param apply if false, do not store the flags, only check for errors.
/// @return error message, NULL if it's OK.
-const char *set_chars_option(win_T *wp, char **varp, bool apply)
+static const char *set_chars_option(win_T *wp, const char *value, bool opt_lcs, bool apply)
{
const char *last_multispace = NULL; // Last occurrence of "multispace:"
const char *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
int multispace_len = 0; // Length of lcs-multispace string
int lead_multispace_len = 0; // Length of lcs-leadmultispace string
- const bool is_listchars = (varp == &p_lcs || varp == &wp->w_p_lcs);
+ const bool is_listchars = opt_lcs;
struct chars_tab {
int *cp; ///< char value
@@ -2065,17 +2353,16 @@ const char *set_chars_option(win_T *wp, char **varp, bool apply)
struct chars_tab *tab;
int entries;
- const char *value = *varp;
if (is_listchars) {
tab = lcs_tab;
entries = ARRAY_SIZE(lcs_tab);
- if (varp == &wp->w_p_lcs && wp->w_p_lcs[0] == NUL) {
+ if (opt_lcs && wp->w_p_lcs[0] == NUL) {
value = p_lcs; // local value is empty, use the global value
}
} else {
tab = fcs_tab;
entries = ARRAY_SIZE(fcs_tab);
- if (varp == &wp->w_p_fcs && wp->w_p_fcs[0] == NUL) {
+ if (!opt_lcs && wp->w_p_fcs[0] == NUL) {
value = p_fcs; // local value is empty, use the global value
}
}
@@ -2241,17 +2528,17 @@ const char *set_chars_option(win_T *wp, char **varp, bool apply)
/// @return an untranslated error message if any of them is invalid, NULL otherwise.
const char *check_chars_options(void)
{
- if (set_chars_option(curwin, &p_lcs, false) != NULL) {
+ if (set_listchars_option(curwin, p_lcs, false) != NULL) {
return e_conflicts_with_value_of_listchars;
}
- if (set_chars_option(curwin, &p_fcs, false) != NULL) {
+ if (set_fillchars_option(curwin, p_fcs, false) != NULL) {
return e_conflicts_with_value_of_fillchars;
}
FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (set_chars_option(wp, &wp->w_p_lcs, true) != NULL) {
+ if (set_listchars_option(wp, wp->w_p_lcs, true) != NULL) {
return e_conflicts_with_value_of_listchars;
}
- if (set_chars_option(wp, &wp->w_p_fcs, true) != NULL) {
+ if (set_fillchars_option(wp, wp->w_p_fcs, true) != NULL) {
return e_conflicts_with_value_of_fillchars;
}
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 36714d816a..d6bbcbc80d 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3885,11 +3885,12 @@ static buf_T *qf_find_buf(qf_info_T *qi)
}
/// Process the 'quickfixtextfunc' option value.
-void qf_process_qftf_option(const char **errmsg)
+const char *did_set_quickfixtextfunc(optset_T *args FUNC_ATTR_UNUSED)
{
if (option_set_callback_func(p_qftf, &qftf_cb) == FAIL) {
- *errmsg = e_invarg;
+ return e_invarg;
}
+ return NULL;
}
/// Update the w:quickfix_title variable in the quickfix/location list window in
@@ -5214,7 +5215,10 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp
FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5, 6)
{
bool found_match = false;
- const size_t pat_len = strlen(spat);
+ size_t pat_len = strlen(spat);
+ if (pat_len > MAX_FUZZY_MATCHES) {
+ pat_len = MAX_FUZZY_MATCHES;
+ }
for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) {
colnr_T col = 0;
@@ -5262,6 +5266,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp
const size_t sz = sizeof(matches) / sizeof(matches[0]);
// Fuzzy string match
+ CLEAR_FIELD(matches);
while (fuzzy_match(str + col, spat, false, &score, matches, (int)sz) > 0) {
// Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 2d82ff1bba..b4a23d544e 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -780,9 +780,10 @@ RuntimeSearchPath runtime_search_path_build(void)
return search_path;
}
-void runtime_search_path_invalidate(void)
+const char *did_set_runtimepackpath(optset_T *args)
{
runtime_search_path_valid = false;
+ return NULL;
}
void runtime_search_path_free(RuntimeSearchPath path)
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 9d1e672128..094476a5ee 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -3045,6 +3045,10 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s
return 0;
}
+ int recursiveScore = 0;
+ uint32_t recursiveMatches[MAX_FUZZY_MATCHES];
+ CLEAR_FIELD(recursiveMatches);
+
// "Copy-on-Write" srcMatches into matches
if (first_match && srcMatches != NULL) {
memcpy(matches, srcMatches, (size_t)nextMatch * sizeof(srcMatches[0]));
@@ -3052,8 +3056,6 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s
}
// Recursive call that "skips" this match
- uint32_t recursiveMatches[MAX_FUZZY_MATCHES];
- int recursiveScore = 0;
const char *const next_char = str + utfc_ptr2len(str);
if (fuzzy_match_recursive(fuzpat, next_char, strIdx + 1, &recursiveScore, strBegin, strLen,
matches, recursiveMatches,
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index a571131ba1..0784c4c8ff 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1851,7 +1851,7 @@ static int count_syllables(slang_T *slang, const char *word)
/// Parse 'spelllang' and set w_s->b_langp accordingly.
/// @return NULL if it's OK, an untranslated error message otherwise.
-char *did_set_spelllang(win_T *wp)
+char *parse_spelllang(win_T *wp)
{
garray_T ga;
char *splp;
@@ -2309,7 +2309,7 @@ void spell_reload(void)
// window for this buffer in which 'spell' is set.
if (*wp->w_s->b_p_spl != NUL) {
if (wp->w_p_spell) {
- (void)did_set_spelllang(wp);
+ (void)parse_spelllang(wp);
break;
}
}
@@ -3637,7 +3637,7 @@ const char *did_set_spell_option(bool is_spellfile)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer == curbuf && wp->w_p_spell) {
- errmsg = did_set_spelllang(wp);
+ errmsg = parse_spelllang(wp);
break;
}
}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index d5d07df7b8..b93dd55042 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -1851,7 +1851,7 @@ static void spell_reload_one(char *fname, bool added_word)
// When "zg" was used and the file wasn't loaded yet, should redo
// 'spelllang' to load it now.
if (added_word && !didit) {
- did_set_spelllang(curwin);
+ parse_spelllang(curwin);
}
}
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index bde853fa20..84be88be7b 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -453,7 +453,7 @@ void spell_suggest(int count)
const int wo_spell_save = curwin->w_p_spell;
if (!curwin->w_p_spell) {
- did_set_spelllang(curwin);
+ parse_spelllang(curwin);
curwin->w_p_spell = true;
}
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 19c62e2b0e..2ee1a0335b 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -210,20 +210,23 @@ static Callback tfu_cb; // 'tagfunc' callback function
/// Reads the 'tagfunc' option value and convert that to a callback value.
/// Invoked when the 'tagfunc' option is set. The option value can be a name of
/// a function (string), or function(<name>) or funcref(<name>) or a lambda.
-void set_tagfunc_option(const char **errmsg)
+const char *did_set_tagfunc(optset_T *args)
{
+ buf_T *buf = (buf_T *)args->os_buf;
+
callback_free(&tfu_cb);
- callback_free(&curbuf->b_tfu_cb);
+ callback_free(&buf->b_tfu_cb);
- if (*curbuf->b_p_tfu == NUL) {
- return;
+ if (*buf->b_p_tfu == NUL) {
+ return NULL;
}
- if (option_set_callback_func(curbuf->b_p_tfu, &tfu_cb) == FAIL) {
- *errmsg = e_invarg;
+ if (option_set_callback_func(buf->b_p_tfu, &tfu_cb) == FAIL) {
+ return e_invarg;
}
- callback_copy(&curbuf->b_tfu_cb, &tfu_cb);
+ callback_copy(&buf->b_tfu_cb, &tfu_cb);
+ return NULL;
}
#if defined(EXITFREE)
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 88d9b95208..2e037aa699 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6089,7 +6089,7 @@ static void frame_setwidth(frame_T *curfrp, int width)
}
// Check 'winminheight' for a valid value and reduce it if needed.
-void did_set_winminheight(void)
+const char *did_set_winminheight(optset_T *args FUNC_ATTR_UNUSED)
{
bool first = true;
@@ -6106,10 +6106,11 @@ void did_set_winminheight(void)
first = false;
}
}
+ return NULL;
}
// Check 'winminwidth' for a valid value and reduce it if needed.
-void did_set_winminwidth(void)
+const char *did_set_winminwidth(optset_T *args FUNC_ATTR_UNUSED)
{
bool first = true;
@@ -6126,6 +6127,7 @@ void did_set_winminwidth(void)
first = false;
}
}
+ return NULL;
}
/// Status line of dragwin is dragged "offset" lines down (negative is up).
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index 5bb9e0281b..0dc6c19fa1 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -7,6 +7,7 @@ local NIL = helpers.NIL
local eval = helpers.eval
local feed = helpers.feed
local clear = helpers.clear
+local matches = helpers.matches
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local exec_capture = helpers.exec_capture
@@ -27,22 +28,27 @@ describe(':lua command', function()
eq('', exec_capture(
'lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})'))
eq({'', 'TEST'}, curbufmeths.get_lines(0, 100, false))
- source(dedent([[
+ source([[
lua << EOF
vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TSET"})
- EOF]]))
+ EOF]])
eq({'', 'TSET'}, curbufmeths.get_lines(0, 100, false))
- source(dedent([[
+ source([[
lua << EOF
- vim.api.nvim_buf_set_lines(1, 1, 2, false, {"SETT"})]]))
+ vim.api.nvim_buf_set_lines(1, 1, 2, false, {"SETT"})]])
eq({'', 'SETT'}, curbufmeths.get_lines(0, 100, false))
- source(dedent([[
+ source([[
lua << EOF
vim.api.nvim_buf_set_lines(1, 1, 2, false, {"ETTS"})
vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"})
vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"})
- EOF]]))
+ EOF]])
eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false))
+ matches('.*Vim%(lua%):E15: Invalid expression: .*', pcall_err(source, [[
+ lua << eval EOF
+ {}
+ EOF
+ ]]))
end)
it('throws catchable errors', function()
eq([[Vim(lua):E5107: Error loading lua [string ":lua"]:0: unexpected symbol near ')']],
diff --git a/test/old/testdir/test_matchfuzzy.vim b/test/old/testdir/test_matchfuzzy.vim
index be5c629cf5..90f3366b23 100644
--- a/test/old/testdir/test_matchfuzzy.vim
+++ b/test/old/testdir/test_matchfuzzy.vim
@@ -2,6 +2,7 @@
source shared.vim
source check.vim
+source term_util.vim
" Test for matchfuzzy()
func Test_matchfuzzy()
@@ -260,4 +261,30 @@ func Test_matchfuzzy_limit()
call assert_equal([{'id': 5, 'val': 'crayon'}], l->matchfuzzy('c', #{key: 'val', limit: 1}))
endfunc
+" This was using uninitialized memory
+func Test_matchfuzzy_initialized()
+ CheckRunVimInTerminal
+
+ " This can take a very long time (esp. when using valgrind). Run in a
+ " separate Vim instance and kill it after two seconds. We only check for
+ " memory errors.
+ let lines =<< trim END
+ lvimgrep [ss [fg*
+ END
+ call writefile(lines, 'XTest_matchfuzzy', 'D')
+
+ let buf = RunVimInTerminal('-u NONE -X -Z', {})
+ call term_sendkeys(buf, ":source XTest_matchfuzzy\n")
+ call TermWait(buf, 2000)
+
+ let job = term_getjob(buf)
+ if job_status(job) == "run"
+ call job_stop(job, "int")
+ call TermWait(buf, 50)
+ endif
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_options.vim b/test/old/testdir/test_options.vim
index d18802adc1..f101f550d1 100644
--- a/test/old/testdir/test_options.vim
+++ b/test/old/testdir/test_options.vim
@@ -45,6 +45,10 @@ func Test_isfname()
set isfname=
call assert_equal("~X", expand("~X"))
set isfname&
+ " Test for setting 'isfname' to an unsupported character
+ let save_isfname = &isfname
+ call assert_fails('exe $"set isfname+={"\u1234"}"', 'E474:')
+ call assert_equal(save_isfname, &isfname)
endfunc
" Test for getting the value of 'pastetoggle'
@@ -317,9 +321,54 @@ func Test_set_completion()
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
-
set tags&
+ " Expanding the option names
+ call feedkeys(":set \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"set all', @:)
+
+ " Expanding a second set of option names
+ call feedkeys(":set wrapscan \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"set wrapscan all', @:)
+
+ " Expanding a special keycode
+ " call feedkeys(":set <Home>\<Tab>\<C-B>\"\<CR>", 'xt')
+ " call assert_equal('"set <Home>', @:)
+
+ " Expanding an invalid special keycode
+ call feedkeys(":set <abcd>\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"set <abcd>\<Tab>", @:)
+
+ " Expanding a terminal keycode
+ " call feedkeys(":set t_AB\<Tab>\<C-B>\"\<CR>", 'xt')
+ " call assert_equal("\"set t_AB", @:)
+
+ " Expanding an invalid option name
+ call feedkeys(":set abcde=\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"set abcde=\<Tab>", @:)
+
+ " Expanding after a = for a boolean option
+ call feedkeys(":set wrapscan=\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"set wrapscan=\<Tab>", @:)
+
+ " Expanding a numeric option
+ call feedkeys(":set tabstop+=\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"set tabstop+=" .. &tabstop, @:)
+
+ " Expanding a non-boolean option
+ call feedkeys(":set invtabstop=\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"set invtabstop=", @:)
+
+ " Expand options for 'spellsuggest'
+ call feedkeys(":set spellsuggest=best,file:xyz\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"set spellsuggest=best,file:xyz", @:)
+
+ " Expand value for 'key'
+ " set key=abcd
+ " call feedkeys(":set key=\<Tab>\<C-B>\"\<CR>", 'xt')
+ " call assert_equal('"set key=*****', @:)
+ " set key=
+
" Expand values for 'filetype'
call feedkeys(":set filetype=sshdconfi\<Tab>\<C-B>\"\<CR>", 'xt')
call assert_equal('"set filetype=sshdconfig', @:)
@@ -396,9 +445,25 @@ func Test_set_errors()
if has('mouseshape')
call assert_fails('se mouseshape=i-r:x', 'E547:')
endif
- call assert_fails('set backupext=~ patchmode=~', 'E589:')
+
+ " Test for 'backupext' and 'patchmode' set to the same value
+ set backupext=.bak
+ set patchmode=.patch
+ call assert_fails('set patchmode=.bak', 'E589:')
+ call assert_equal('.patch', &patchmode)
+ call assert_fails('set backupext=.patch', 'E589:')
+ call assert_equal('.bak', &backupext)
+ set backupext& patchmode&
+
call assert_fails('set winminheight=10 winheight=9', 'E591:')
+ set winminheight& winheight&
+ set winheight=10 winminheight=10
+ call assert_fails('set winheight=9', 'E591:')
+ set winminheight& winheight&
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
+ set winminwidth& winwidth&
+ call assert_fails('set winwidth=9 winminwidth=10', 'E592:')
+ set winwidth& winminwidth&
call assert_fails("set showbreak=\x01", 'E595:')
call assert_fails('set t_foo=', 'E846:')
call assert_fails('set tabstop??', 'E488:')
@@ -931,7 +996,9 @@ endfunc
func Test_opt_sandbox()
for opt in ['backupdir', 'cdpath', 'exrc']
call assert_fails('sandbox set ' .. opt .. '?', 'E48:')
+ call assert_fails('sandbox let &' .. opt .. ' = 1', 'E48:')
endfor
+ call assert_fails('sandbox let &modelineexpr = 1', 'E48:')
endfunc
" Test for setting an option with local value to global value
@@ -1344,4 +1411,157 @@ func Test_set_min_lines_columns()
let &columns = save_columns
endfunc
+" Test for reverting a string option value if the new value is invalid.
+func Test_string_option_revert_on_failure()
+ new
+ let optlist = [
+ \ ['ambiwidth', 'double', 'a123'],
+ \ ['background', 'dark', 'a123'],
+ \ ['backspace', 'eol', 'a123'],
+ \ ['backupcopy', 'no', 'a123'],
+ \ ['belloff', 'showmatch', 'a123'],
+ \ ['breakindentopt', 'min:10', 'list'],
+ \ ['bufhidden', 'wipe', 'a123'],
+ \ ['buftype', 'nowrite', 'a123'],
+ \ ['casemap', 'keepascii', 'a123'],
+ \ ['cedit', "\<C-Y>", 'z'],
+ \ ['colorcolumn', '10', 'z'],
+ \ ['commentstring', '#%s', 'a123'],
+ \ ['complete', '.,t', 'a'],
+ \ ['completefunc', 'MyCmplFunc', '1a-'],
+ "\ ['completeopt', 'popup', 'a123'],
+ \ ['completeopt', 'preview', 'a123'],
+ "\ ['completepopup', 'width:20', 'border'],
+ \ ['concealcursor', 'v', 'xyz'],
+ "\ ['cpoptions', 'HJ', '~'],
+ \ ['cpoptions', 'J', '~'],
+ "\ ['cryptmethod', 'zip', 'a123'],
+ \ ['cursorlineopt', 'screenline', 'a123'],
+ \ ['debug', 'throw', 'a123'],
+ \ ['diffopt', 'iwhite', 'a123'],
+ \ ['display', 'uhex', 'a123'],
+ \ ['eadirection', 'hor', 'a123'],
+ \ ['encoding', 'utf-8', 'a123'],
+ \ ['eventignore', 'TextYankPost', 'a123'],
+ \ ['fileencoding', 'utf-8', 'a123,'],
+ \ ['fileformat', 'mac', 'a123'],
+ \ ['fileformats', 'mac', 'a123'],
+ \ ['filetype', 'abc', 'a^b'],
+ \ ['fillchars', 'diff:~', 'a123'],
+ \ ['foldclose', 'all', 'a123'],
+ \ ['foldmarker', '[[[,]]]', '[[['],
+ \ ['foldmethod', 'marker', 'a123'],
+ \ ['foldopen', 'percent', 'a123'],
+ \ ['formatoptions', 'an', '*'],
+ \ ['guicursor', 'n-v-c:block-Cursor/lCursor', 'n-v-c'],
+ \ ['helplang', 'en', 'a'],
+ "\ ['highlight', '!:CursorColumn', '8:'],
+ \ ['keymodel', 'stopsel', 'a123'],
+ "\ ['keyprotocol', 'kitty:kitty', 'kitty:'],
+ \ ['lispoptions', 'expr:1', 'a123'],
+ \ ['listchars', 'tab:->', 'tab:'],
+ \ ['matchpairs', '<:>', '<:'],
+ \ ['mkspellmem', '100000,1000,100', '100000'],
+ \ ['mouse', 'nvi', 'z'],
+ \ ['mousemodel', 'extend', 'a123'],
+ \ ['nrformats', 'alpha', 'a123'],
+ \ ['omnifunc', 'MyOmniFunc', '1a-'],
+ \ ['operatorfunc', 'MyOpFunc', '1a-'],
+ "\ ['previewpopup', 'width:20', 'a123'],
+ "\ ['printoptions', 'paper:A4', 'a123:'],
+ \ ['quickfixtextfunc', 'MyQfFunc', '1a-'],
+ \ ['rulerformat', '%l', '%['],
+ \ ['scrollopt', 'hor,jump', 'a123'],
+ \ ['selection', 'exclusive', 'a123'],
+ \ ['selectmode', 'cmd', 'a123'],
+ \ ['sessionoptions', 'options', 'a123'],
+ \ ['shortmess', 'w', '2'],
+ \ ['showbreak', '>>', "\x01"],
+ \ ['showcmdloc', 'statusline', 'a123'],
+ \ ['signcolumn', 'no', 'a123'],
+ \ ['spellcapcheck', '[.?!]\+', '%\{'],
+ \ ['spellfile', 'MySpell.en.add', "\x01"],
+ \ ['spelllang', 'en', "#"],
+ \ ['spelloptions', 'camel', 'a123'],
+ \ ['spellsuggest', 'double', 'a123'],
+ \ ['splitkeep', 'topline', 'a123'],
+ \ ['statusline', '%f', '%['],
+ "\ ['swapsync', 'sync', 'a123'],
+ \ ['switchbuf', 'usetab', 'a123'],
+ \ ['syntax', 'abc', 'a^b'],
+ \ ['tabline', '%f', '%['],
+ \ ['tagcase', 'ignore', 'a123'],
+ \ ['tagfunc', 'MyTagFunc', '1a-'],
+ \ ['thesaurusfunc', 'MyThesaurusFunc', '1a-'],
+ \ ['viewoptions', 'options', 'a123'],
+ \ ['virtualedit', 'onemore', 'a123'],
+ \ ['whichwrap', '<,>', '{,}'],
+ \ ['wildmode', 'list', 'a123'],
+ \ ['wildoptions', 'pum', 'a123']
+ \ ]
+ if has('gui')
+ call add(optlist, ['browsedir', 'buffer', 'a123'])
+ endif
+ if has('clipboard_working')
+ call add(optlist, ['clipboard', 'unnamed', 'a123'])
+ endif
+ if has('win32')
+ call add(optlist, ['completeslash', 'slash', 'a123'])
+ endif
+ if has('cscope')
+ call add(optlist, ['cscopequickfix', 't-', 'z-'])
+ endif
+ if !has('win32') && !has('nvim')
+ call add(optlist, ['imactivatefunc', 'MyActFunc', '1a-'])
+ call add(optlist, ['imstatusfunc', 'MyStatusFunc', '1a-'])
+ endif
+ if has('keymap')
+ call add(optlist, ['keymap', 'greek', '[]'])
+ endif
+ if has('mouseshape')
+ call add(optlist, ['mouseshape', 'm:no', 'a123:'])
+ endif
+ if has('win32') && has('gui')
+ call add(optlist, ['renderoptions', 'type:directx', 'type:directx,a123'])
+ endif
+ if has('rightleft')
+ call add(optlist, ['rightleftcmd', 'search', 'a123'])
+ endif
+ if has('terminal')
+ call add(optlist, ['termwinkey', '<C-L>', '<C'])
+ call add(optlist, ['termwinsize', '24x80', '100'])
+ endif
+ if has('win32') && has('terminal')
+ call add(optlist, ['termwintype', 'winpty', 'a123'])
+ endif
+ if exists('+toolbar')
+ call add(optlist, ['toolbar', 'text', 'a123'])
+ endif
+ if exists('+toolbariconsize')
+ call add(optlist, ['toolbariconsize', 'medium', 'a123'])
+ endif
+ if exists('+ttymouse') && !has('gui')
+ call add(optlist, ['ttymouse', 'xterm', 'a123'])
+ endif
+ if exists('+vartabs')
+ call add(optlist, ['varsofttabstop', '12', 'a123'])
+ call add(optlist, ['vartabstop', '4,20', '4,'])
+ endif
+ if exists('+winaltkeys')
+ call add(optlist, ['winaltkeys', 'no', 'a123'])
+ endif
+ for opt in optlist
+ exe $"let save_opt = &{opt[0]}"
+ try
+ exe $"let &{opt[0]} = '{opt[1]}'"
+ catch
+ call assert_report($"Caught {v:exception} with {opt->string()}")
+ endtry
+ call assert_fails($"let &{opt[0]} = '{opt[2]}'", '', opt[0])
+ call assert_equal(opt[1], eval($"&{opt[0]}"), opt[0])
+ exe $"let &{opt[0]} = save_opt"
+ endfor
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_perl.vim b/test/old/testdir/test_perl.vim
index 558d0a5d6b..ce2a566f62 100644
--- a/test/old/testdir/test_perl.vim
+++ b/test/old/testdir/test_perl.vim
@@ -224,11 +224,11 @@ endfunc
func Test_stdio()
throw 'skipped: TODO: '
redir =>l:out
- perl <<EOF
+ perl << trim EOF
VIM::Msg("&VIM::Msg");
print "STDOUT";
print STDERR "STDERR";
-EOF
+ EOF
redir END
call assert_equal(['&VIM::Msg', 'STDOUT', 'STDERR'], split(l:out, "\n"))
endfunc
@@ -305,7 +305,16 @@ END
perl <<
VIM::DoCommand('let s ..= "B"')
.
- call assert_equal('AB', s)
+ perl << trim END
+ VIM::DoCommand('let s ..= "C"')
+ END
+ perl << trim
+ VIM::DoCommand('let s ..= "D"')
+ .
+ perl << trim eof
+ VIM::DoCommand('let s ..= "E"')
+ eof
+ call assert_equal('ABCDE', s)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_python2.vim b/test/old/testdir/test_python2.vim
index 745b7da086..f21eb2c128 100644
--- a/test/old/testdir/test_python2.vim
+++ b/test/old/testdir/test_python2.vim
@@ -40,7 +40,7 @@ func Test_set_cursor()
endfunc
func Test_vim_function()
- throw 'skipped: Nvim does not support vim.bindeval()'
+ throw 'Skipped: Nvim does not support vim.bindeval()'
" Check creating vim.Function object
py import vim
@@ -171,3 +171,25 @@ func Test_Catch_Exception_Message()
call assert_match('^Vim(.*):.*RuntimeError: TEST$', v:exception )
endtry
endfunc
+
+" Test for various heredoc syntax
+func Test_python_heredoc()
+ python << END
+s='A'
+END
+ python <<
+s+='B'
+.
+ python << trim END
+ s+='C'
+ END
+ python << trim
+ s+='D'
+ .
+ python << trim eof
+ s+='E'
+ eof
+ call assert_equal('ABCDE', pyxeval('s'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_python3.vim b/test/old/testdir/test_python3.vim
index 69f5f6dcc0..23c63f22d8 100644
--- a/test/old/testdir/test_python3.vim
+++ b/test/old/testdir/test_python3.vim
@@ -40,7 +40,7 @@ func Test_set_cursor()
endfunc
func Test_vim_function()
- throw 'skipped: Nvim does not support vim.bindeval()'
+ throw 'Skipped: Nvim does not support vim.bindeval()'
" Check creating vim.Function object
py3 import vim
@@ -68,7 +68,7 @@ func Test_vim_function()
endfunc
func Test_skipped_python3_command_does_not_affect_pyxversion()
- throw 'skipped: Nvim hardcodes pyxversion=3'
+ throw 'Skipped: Nvim hardcodes pyxversion=3'
set pyxversion=0
if 0
python3 import vim
@@ -190,3 +190,101 @@ func Test_unicode()
set encoding=utf8
endfunc
+
+" Test for resetting options with local values to global values
+func Test_python3_opt_reset_local_to_global()
+ throw 'Skipped: Nvim does not support vim.bindeval()'
+ new
+
+ py3 curbuf = vim.current.buffer
+ py3 curwin = vim.current.window
+
+ " List of buffer-local options. Each list item has [option name, global
+ " value, buffer-local value, buffer-local value after reset] to use in the
+ " test.
+ let bopts = [
+ \ ['autoread', 1, 0, -1],
+ \ ['equalprg', 'geprg', 'leprg', ''],
+ \ ['keywordprg', 'gkprg', 'lkprg', ''],
+ \ ['path', 'gpath', 'lpath', ''],
+ \ ['backupcopy', 'yes', 'no', ''],
+ \ ['tags', 'gtags', 'ltags', ''],
+ \ ['tagcase', 'ignore', 'match', ''],
+ \ ['define', 'gdef', 'ldef', ''],
+ \ ['include', 'ginc', 'linc', ''],
+ \ ['dict', 'gdict', 'ldict', ''],
+ \ ['thesaurus', 'gtsr', 'ltsr', ''],
+ \ ['formatprg', 'gfprg', 'lfprg', ''],
+ \ ['errorformat', '%f:%l:%m', '%s-%l-%m', ''],
+ \ ['grepprg', 'ggprg', 'lgprg', ''],
+ \ ['makeprg', 'gmprg', 'lmprg', ''],
+ \ ['balloonexpr', 'gbexpr', 'lbexpr', ''],
+ \ ['cryptmethod', 'blowfish2', 'zip', ''],
+ \ ['lispwords', 'abc', 'xyz', ''],
+ \ ['makeencoding', 'utf-8', 'latin1', ''],
+ \ ['undolevels', 100, 200, -123456]]
+
+ " Set the global and buffer-local option values and then clear the
+ " buffer-local option value.
+ for opt in bopts
+ py3 << trim END
+ pyopt = vim.bindeval("opt")
+ vim.options[pyopt[0]] = pyopt[1]
+ curbuf.options[pyopt[0]] = pyopt[2]
+ END
+ exe "call assert_equal(opt[2], &" .. opt[0] .. ")"
+ exe "call assert_equal(opt[1], &g:" .. opt[0] .. ")"
+ exe "call assert_equal(opt[2], &l:" .. opt[0] .. ")"
+ py3 del curbuf.options[pyopt[0]]
+ exe "call assert_equal(opt[1], &" .. opt[0] .. ")"
+ exe "call assert_equal(opt[1], &g:" .. opt[0] .. ")"
+ exe "call assert_equal(opt[3], &l:" .. opt[0] .. ")"
+ exe "set " .. opt[0] .. "&"
+ endfor
+
+ " Set the global and window-local option values and then clear the
+ " window-local option value.
+ let wopts = [
+ \ ['scrolloff', 5, 10, -1],
+ \ ['sidescrolloff', 6, 12, -1],
+ \ ['statusline', '%<%f', '%<%F', '']]
+ for opt in wopts
+ py3 << trim
+ pyopt = vim.bindeval("opt")
+ vim.options[pyopt[0]] = pyopt[1]
+ curwin.options[pyopt[0]] = pyopt[2]
+ .
+ exe "call assert_equal(opt[2], &" .. opt[0] .. ")"
+ exe "call assert_equal(opt[1], &g:" .. opt[0] .. ")"
+ exe "call assert_equal(opt[2], &l:" .. opt[0] .. ")"
+ py3 del curwin.options[pyopt[0]]
+ exe "call assert_equal(opt[1], &" .. opt[0] .. ")"
+ exe "call assert_equal(opt[1], &g:" .. opt[0] .. ")"
+ exe "call assert_equal(opt[3], &l:" .. opt[0] .. ")"
+ exe "set " .. opt[0] .. "&"
+ endfor
+
+ close!
+endfunc
+
+" Test for various heredoc syntax
+func Test_python3_heredoc()
+ python3 << END
+s='A'
+END
+ python3 <<
+s+='B'
+.
+ python3 << trim END
+ s+='C'
+ END
+ python3 << trim
+ s+='D'
+ .
+ python3 << trim eof
+ s+='E'
+ eof
+ call assert_equal('ABCDE', pyxeval('s'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_pyx2.vim b/test/old/testdir/test_pyx2.vim
index eee825fa9b..74f4b187f0 100644
--- a/test/old/testdir/test_pyx2.vim
+++ b/test/old/testdir/test_pyx2.vim
@@ -15,10 +15,10 @@ endfunc
func Test_pyx()
redir => var
- pyx << EOF
-import sys
-print(sys.version)
-EOF
+ pyx << trim EOF
+ import sys
+ print(sys.version)
+ EOF
redir END
call assert_match(s:py2pattern, split(var)[0])
endfunc
@@ -79,3 +79,25 @@ func Test_Catch_Exception_Message()
call assert_match('^Vim(.*):.*RuntimeError: TEST$', v:exception )
endtry
endfunc
+
+" Test for various heredoc syntaxes
+func Test_pyx2_heredoc()
+ pyx << END
+result='A'
+END
+ pyx <<
+result+='B'
+.
+ pyx << trim END
+ result+='C'
+ END
+ pyx << trim
+ result+='D'
+ .
+ pyx << trim eof
+ result+='E'
+ eof
+ call assert_equal('ABCDE', pyxeval('result'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_pyx3.vim b/test/old/testdir/test_pyx3.vim
index db39f5134a..09ece6f812 100644
--- a/test/old/testdir/test_pyx3.vim
+++ b/test/old/testdir/test_pyx3.vim
@@ -15,10 +15,10 @@ endfunc
func Test_pyx()
redir => var
- pyx << EOF
-import sys
-print(sys.version)
-EOF
+ pyx << trim EOF
+ import sys
+ print(sys.version)
+ EOF
redir END
call assert_match(s:py3pattern, split(var)[0])
endfunc
@@ -79,3 +79,25 @@ func Test_Catch_Exception_Message()
call assert_match('^Vim(.*):.*RuntimeError: TEST$', v:exception )
endtry
endfunc
+
+" Test for various heredoc syntaxes
+func Test_pyx3_heredoc()
+ pyx << END
+result='A'
+END
+ pyx <<
+result+='B'
+.
+ pyx << trim END
+ result+='C'
+ END
+ pyx << trim
+ result+='D'
+ .
+ pyx << trim eof
+ result+='E'
+ eof
+ call assert_equal('ABCDE', pyxeval('result'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_ruby.vim b/test/old/testdir/test_ruby.vim
index 1fbf3392d9..4929496086 100644
--- a/test/old/testdir/test_ruby.vim
+++ b/test/old/testdir/test_ruby.vim
@@ -341,11 +341,11 @@ func Test_ruby_Vim_evaluate_list()
call setline(line('$'), ['2 line 2'])
ruby Vim.command("normal /^2\n")
let l = ["abc", "def"]
- ruby << EOF
- curline = $curbuf.line_number
- l = Vim.evaluate("l");
- $curbuf.append(curline, l.join("|"))
-EOF
+ ruby << trim EOF
+ curline = $curbuf.line_number
+ l = Vim.evaluate("l");
+ $curbuf.append(curline, l.join("|"))
+ EOF
normal j
.rubydo $_ = $_.gsub(/\|/, '/')
call assert_equal('abc/def', getline('$'))
@@ -414,4 +414,24 @@ func Test_rubyeval_error()
call assert_fails('call rubyeval("(")')
endfunc
+" Test for various heredoc syntax
+func Test_ruby_heredoc()
+ ruby << END
+Vim.command('let s = "A"')
+END
+ ruby <<
+Vim.command('let s ..= "B"')
+.
+ ruby << trim END
+ Vim.command('let s ..= "C"')
+ END
+ ruby << trim
+ Vim.command('let s ..= "D"')
+ .
+ ruby << trim eof
+ Vim.command('let s ..= "E"')
+ eof
+ call assert_equal('ABCDE', s)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/old/testdir/test_undo.vim b/test/old/testdir/test_undo.vim
index ee8b52caaf..4678a51d60 100644
--- a/test/old/testdir/test_undo.vim
+++ b/test/old/testdir/test_undo.vim
@@ -126,6 +126,11 @@ func Test_global_local_undolevels()
call assert_equal(50, &g:undolevels)
call assert_equal(-123456, &l:undolevels)
+ " Resetting the local 'undolevels' value to use the global value
+ setlocal undolevels=5
+ setlocal undolevels<
+ call assert_equal(-123456, &l:undolevels)
+
" Drop created windows
set ul&
new
diff --git a/test/old/testdir/test_vimscript.vim b/test/old/testdir/test_vimscript.vim
index 055a2bd2f2..68ce493927 100644
--- a/test/old/testdir/test_vimscript.vim
+++ b/test/old/testdir/test_vimscript.vim
@@ -6705,6 +6705,11 @@ func Test_echo_and_string()
let l = split(result, "\n")
call assert_equal(["{'a': [], 'b': []}",
\ "{'a': [], 'b': []}"], l)
+
+ call assert_fails('echo &:', 'E112:')
+ call assert_fails('echo &g:', 'E112:')
+ call assert_fails('echo &l:', 'E112:')
+
endfunc
"-------------------------------------------------------------------------------