aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/CODEOWNERS3
-rw-r--r--.github/ISSUE_TEMPLATE/lsp_bug_report.yml7
-rw-r--r--.github/workflows/ci.yml54
-rwxr-xr-x.github/workflows/env.sh2
-rw-r--r--.github/workflows/release.yml1
-rw-r--r--.luacheckrc4
-rw-r--r--CMakeLists.txt6
-rwxr-xr-xci/before_install.sh46
-rwxr-xr-xci/before_script.sh13
-rw-r--r--ci/common/suite.sh121
-rwxr-xr-xci/install.sh11
-rwxr-xr-xci/run_lint.sh7
-rwxr-xr-xci/run_tests.sh4
-rwxr-xr-xci/script.sh9
-rw-r--r--runtime/autoload/health/provider.vim2
-rw-r--r--runtime/doc/api.txt106
-rw-r--r--runtime/doc/autocmd.txt3
-rw-r--r--runtime/doc/change.txt3
-rw-r--r--runtime/doc/channel.txt2
-rw-r--r--runtime/doc/develop.txt2
-rw-r--r--runtime/doc/diagnostic.txt18
-rw-r--r--runtime/doc/eval.txt28
-rw-r--r--runtime/doc/filetype.txt69
-rw-r--r--runtime/doc/insert.txt5
-rw-r--r--runtime/doc/lsp-extension.txt2
-rw-r--r--runtime/doc/lsp.txt27
-rw-r--r--runtime/doc/lua.txt113
-rw-r--r--runtime/doc/map.txt4
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt4
-rw-r--r--runtime/doc/term.txt2
-rw-r--r--runtime/doc/treesitter.txt16
-rw-r--r--runtime/doc/usr_05.txt25
-rw-r--r--runtime/doc/usr_toc.txt13
-rw-r--r--runtime/filetype.lua26
-rw-r--r--runtime/filetype.vim20
-rw-r--r--runtime/lua/vim/diagnostic.lua70
-rw-r--r--runtime/lua/vim/filetype.lua1506
-rw-r--r--runtime/lua/vim/lsp.lua28
-rw-r--r--runtime/lua/vim/lsp/buf.lua2
-rw-r--r--runtime/lua/vim/lsp/handlers.lua14
-rw-r--r--runtime/lua/vim/lsp/log.lua4
-rw-r--r--runtime/lua/vim/lsp/rpc.lua5
-rw-r--r--runtime/lua/vim/lsp/sync.lua2
-rw-r--r--runtime/lua/vim/lsp/util.lua10
-rw-r--r--runtime/lua/vim/shared.lua54
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua2
-rw-r--r--runtime/nvim.appdata.xml2
-rw-r--r--scripts/gen_filetype.lua201
-rwxr-xr-xscripts/gen_vimdoc.py3
-rwxr-xr-xscripts/vim-patch.sh57
-rw-r--r--src/nvim/CMakeLists.txt3
-rw-r--r--src/nvim/api/buffer.c61
-rw-r--r--src/nvim/api/keysets.lua14
-rw-r--r--src/nvim/api/private/helpers.c232
-rw-r--r--src/nvim/api/vim.c71
-rw-r--r--src/nvim/api/window.c2
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/eval.c17
-rw-r--r--src/nvim/eval/funcs.c11
-rw-r--r--src/nvim/eval/typval.c2
-rw-r--r--src/nvim/event/loop.c2
-rw-r--r--src/nvim/ex_cmds.c7
-rw-r--r--src/nvim/ex_cmds_defs.h1
-rw-r--r--src/nvim/ex_docmd.c193
-rw-r--r--src/nvim/ex_docmd.h20
-rw-r--r--src/nvim/ex_getln.c38
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua4
-rw-r--r--src/nvim/generators/gen_keysets.lua15
-rw-r--r--src/nvim/getchar.c183
-rw-r--r--src/nvim/getchar.h4
-rw-r--r--src/nvim/globals.h2
-rw-r--r--src/nvim/keymap.h2
-rw-r--r--src/nvim/lua/converter.c7
-rw-r--r--src/nvim/lua/executor.c87
-rw-r--r--src/nvim/lua/executor.h1
-rw-r--r--src/nvim/lua/spell.c2
-rw-r--r--src/nvim/lua/vim.lua5
-rw-r--r--src/nvim/map.c2
-rw-r--r--src/nvim/normal.c16
-rw-r--r--src/nvim/ops.c23
-rw-r--r--src/nvim/options.lua12
-rw-r--r--src/nvim/terminal.c41
-rwxr-xr-xsrc/nvim/testdir/runnvim.sh4
-rw-r--r--src/nvim/testdir/test_excmd.vim44
-rw-r--r--src/nvim/testdir/test_filetype.vim6
-rw-r--r--src/nvim/testdir/test_put.vim22
-rw-r--r--src/nvim/tui/tui.c2
-rw-r--r--src/nvim/vim.h1
-rw-r--r--src/nvim/viml/parser/expressions.c2
-rw-r--r--src/nvim/viml/parser/expressions.h2
-rw-r--r--test/README.md4
-rw-r--r--test/functional/api/command_spec.lua121
-rw-r--r--test/functional/api/keymap_spec.lua213
-rw-r--r--test/functional/autocmd/recording_spec.lua28
-rw-r--r--test/functional/ex_cmds/append_spec.lua70
-rw-r--r--test/functional/legacy/memory_usage_spec.lua4
-rw-r--r--test/functional/lua/api_spec.lua13
-rw-r--r--test/functional/lua/commands_spec.lua9
-rw-r--r--test/functional/lua/diagnostic_spec.lua5
-rw-r--r--test/functional/lua/filetype_spec.lua669
-rw-r--r--test/functional/lua/vim_spec.lua3
-rw-r--r--test/functional/plugin/lsp_spec.lua5
-rw-r--r--test/functional/terminal/buffer_spec.lua2
-rw-r--r--test/functional/terminal/mouse_spec.lua86
-rw-r--r--test/functional/terminal/tui_spec.lua36
-rw-r--r--test/unit/charset/vim_str2nr_spec.lua2
-rw-r--r--test/unit/garray_spec.lua2
-rw-r--r--test/unit/os/env_spec.lua2
-rw-r--r--test/unit/os/fs_spec.lua4
-rw-r--r--third-party/CMakeLists.txt4
111 files changed, 4475 insertions, 714 deletions
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..7d41c17894
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,3 @@
+/.github/ @jamessan
+/ci/ @jamessan
+/scripts/ @jamessan
diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml
index b5b7687bf8..0ed163c9be 100644
--- a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml
@@ -29,13 +29,6 @@ body:
- type: textarea
attributes:
- label: ':checkhealth'
- description: |
- Paste the results from `nvim -c ":checkhealth nvim lspconfig"`
- render: markdown
-
- - type: textarea
- attributes:
label: 'Steps to reproduce using "nvim -u minimal_init.lua"'
description: |
- Download the minimal config with `curl -LO https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua` and modify it to include any specific commands or servers pertaining to your issues.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d2eef13098..b650c5dd85 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,6 +16,44 @@ concurrency:
cancel-in-progress: true
jobs:
+ lint:
+ if: (github.event_name == 'pull_request' && github.base_ref == 'master' && !github.event.pull_request.draft) || (github.event_name == 'push' && github.ref == 'refs/heads/master')
+ runs-on: ubuntu-20.04
+ env:
+ CC: gcc
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Setup common environment variables
+ run: ./.github/workflows/env.sh lint
+
+ - name: Install apt packages
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y autoconf automake build-essential ccache cmake cpanminus gettext gperf language-pack-tr libtool-bin locales ninja-build pkg-config python3 python3-pip python3-setuptools unzip flake8
+
+ - name: Setup interpreter packages
+ run: |
+ ./ci/install.sh
+
+ - name: Cache dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ ${{ env.CACHE_NVIM_DEPS_DIR }}
+ ~/.ccache
+ key: ${{ matrix.runner }}-lint-${{ matrix.cc }}-${{ hashFiles('cmake/*', 'third-party/**', '**/CMakeLists.txt') }}-${{ github.base_ref }}
+
+ - name: Build third-party
+ run: ./ci/before_script.sh
+
+ - name: Run lint
+ run: ./ci/script.sh
+
+ - name: Cache dependencies
+ if: ${{ success() }}
+ run: ./ci/before_cache.sh
+
unixish:
name: ${{ matrix.runner }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
strategy:
@@ -23,15 +61,11 @@ jobs:
matrix:
include:
- flavor: asan
- cc: clang-12
- runner: ubuntu-20.04
- os: linux
- - flavor: lint
- cc: gcc
+ cc: clang-13
runner: ubuntu-20.04
os: linux
- flavor: tsan
- cc: clang-12
+ cc: clang-13
runner: ubuntu-20.04
os: linux
- cc: clang
@@ -63,20 +97,17 @@ jobs:
run: |
wget https://apt.llvm.org/llvm.sh
chmod a+x llvm.sh
- sudo ./llvm.sh 12
+ sudo ./llvm.sh 13
rm llvm.sh
- name: Install brew packages
if: matrix.os == 'osx'
run: |
- # Workaround brew issues
- rm -f /usr/local/bin/2to3
brew update >/dev/null
brew install automake ccache perl cpanminus ninja
- name: Setup interpreter packages
run: |
- ./ci/before_install.sh
./ci/install.sh
- name: Cache dependencies
@@ -140,7 +171,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- - name: Setup commom environment variables
+ - name: Setup common environment variables
run: ./.github/workflows/env.sh ${{ matrix.flavor }}
- name: Install apt packages
@@ -167,7 +198,6 @@ jobs:
- name: Setup interpreter packages
run: |
- ./ci/before_install.sh
./ci/install.sh
- name: Cache dependencies
diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh
index a30e06ae26..d1bc412399 100755
--- a/.github/workflows/env.sh
+++ b/.github/workflows/env.sh
@@ -34,7 +34,7 @@ case "$FLAVOR" in
BUILD_FLAGS="$BUILD_FLAGS -DPREFER_LUA=ON"
cat <<EOF >> "$GITHUB_ENV"
CLANG_SANITIZER=ASAN_UBSAN
-SYMBOLIZER=asan_symbolize-12
+SYMBOLIZER=asan_symbolize-13
ASAN_OPTIONS=detect_leaks=1:check_initialization_order=1:log_path=$GITHUB_WORKSPACE/build/log/asan
UBSAN_OPTIONS=print_stacktrace=1 log_path=$GITHUB_WORKSPACE/build/log/ubsan
EOF
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5839be2944..5ad4c90eaf 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -80,7 +80,6 @@ jobs:
fetch-depth: 0
- name: Install brew packages
run: |
- rm -f /usr/local/bin/2to3
brew update >/dev/null
brew install automake ninja
- if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly')
diff --git a/.luacheckrc b/.luacheckrc
index 487f5ab552..9bbd323e84 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -26,6 +26,10 @@ read_globals = {
"vim",
}
+globals = {
+ "vim.g",
+}
+
exclude_files = {
'test/functional/fixtures/lua/syntax_error.lua',
}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9f1829cf55..0c43c5c494 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -543,7 +543,11 @@ endif()
message(STATUS "Using Lua interpreter: ${LUA_PRG}")
-option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
+if(DEBUG)
+ option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" OFF)
+else()
+ option(COMPILE_LUA "Pre-compile Lua sources into bytecode (for sources that are included in the binary)" ON)
+endif()
if(COMPILE_LUA AND NOT WIN32)
if(PREFER_LUA)
diff --git a/ci/before_install.sh b/ci/before_install.sh
deleted file mode 100755
index f12f972fe0..0000000000
--- a/ci/before_install.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o pipefail
-
-echo 'Python info:'
-(
- set -x
- python3 --version
- python2 --version
- python --version
- pip3 --version
- pip2 --version
- pip --version
-
- pyenv --version
- pyenv versions
-) 2>&1 | sed 's/^/ /' || true
-
-# Use pyenv, but not for OSX on Travis, where it only has the "system" version.
-if [[ "${TRAVIS_OS_NAME}" != osx ]] && command -v pyenv; then
- echo 'Setting Python versions via pyenv'
-
- # Prefer Python 2 over 3 (more conservative).
- pyenv global 2.7:3.8
-
- echo 'Updated Python info:'
- (
- set -x
- python3 --version
- python2 --version
- python --version
-
- python3 -m pip --version
- python2 -m pip --version
- ) 2>&1 | sed 's/^/ /'
-fi
-
-echo "Install node (LTS)"
-
-if [[ "${TRAVIS_OS_NAME}" == osx ]] || [ ! -f ~/.nvm/nvm.sh ]; then
- curl -o ~/.nvm/nvm.sh https://raw.githubusercontent.com/creationix/nvm/master/nvm.sh
-fi
-
-source ~/.nvm/nvm.sh
-nvm install 10
diff --git a/ci/before_script.sh b/ci/before_script.sh
index 701fe1d9eb..f7216338d4 100755
--- a/ci/before_script.sh
+++ b/ci/before_script.sh
@@ -6,12 +6,6 @@ set -o pipefail
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/build.sh"
-# Enable ipv6 on Travis. ref: a39c8b7ce30d
-if test -n "${TRAVIS_OS_NAME}" && ! test "${TRAVIS_OS_NAME}" = osx ; then
- echo "before_script.sh: enable ipv6"
- sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0
-fi
-
# Test some of the configuration variables.
if [[ -n "${GCOV}" ]] && [[ ! $(type -P "${GCOV}") ]]; then
echo "\$GCOV: '${GCOV}' is not executable."
@@ -27,13 +21,6 @@ ccache -s
# Reset ccache stats for real results in before_cache.
ccache --zero-stats
-if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
- # Adds user to a dummy group.
- # That allows to test changing the group of the file by `os_fchown`.
- sudo dscl . -create /Groups/chown_test
- sudo dscl . -append /Groups/chown_test GroupMembership "${USER}"
-fi
-
# Compile dependencies.
build_deps
diff --git a/ci/common/suite.sh b/ci/common/suite.sh
index 038b116c5a..561849ce2d 100644
--- a/ci/common/suite.sh
+++ b/ci/common/suite.sh
@@ -11,22 +11,10 @@ FAIL_SUMMARY=""
END_MARKER="$BUILD_DIR/.tests_finished"
FAIL_SUMMARY_FILE="$BUILD_DIR/.test_errors"
-ANSI_CLEAR="\033[0K"
-
-if test "$TRAVIS" = "true"; then
- ci_fold() {
- local action="$1"
- local name="$2"
- name="$(echo -n "$name" | tr '\n\0' '--' | sed 's/[^A-Za-z0-9]\{1,\}/-/g')"
- name="$(echo -n "$name" | sed 's/-$//')"
- echo -en "travis_fold:${action}:${name}\r${ANSI_CLEAR}"
- }
-elif test "$GITHUB_ACTIONS" = "true"; then
- ci_fold() {
+ci_fold() {
+ if test "$GITHUB_ACTIONS" = "true"; then
local action="$1"
local name="$2"
- name="$(echo -n "$name" | tr '\n\0' '--' | sed 's/[^A-Za-z0-9]\{1,\}/-/g')"
- name="$(echo -n "$name" | sed 's/-$//')"
case "$action" in
start)
echo "::group::${name}"
@@ -37,12 +25,8 @@ elif test "$GITHUB_ACTIONS" = "true"; then
*)
:;;
esac
- }
-else
- ci_fold() {
- return 0
- }
-fi
+ fi
+}
enter_suite() {
set +x
@@ -50,7 +34,7 @@ enter_suite() {
rm -f "${END_MARKER}"
local suite_name="$1"
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE}/$suite_name"
- ci_fold start "${NVIM_TEST_CURRENT_SUITE}"
+ ci_fold "start" "$suite_name"
set -x
}
@@ -60,7 +44,7 @@ exit_suite() {
echo "Suite ${NVIM_TEST_CURRENT_SUITE} failed, summary:"
echo "${FAIL_SUMMARY}"
else
- ci_fold end "${NVIM_TEST_CURRENT_SUITE}"
+ ci_fold "end" ""
fi
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE%/*}"
if test "$1" != "--continue" ; then
@@ -98,99 +82,6 @@ run_test() {
fi
}
-run_test_wd() {
- local hang_ok=
- if test "$1" = "--allow-hang" ; then
- hang_ok=1
- shift
- fi
-
- local timeout="$1"
- test $# -gt 0 && shift
-
- local cmd="$1"
- test $# -gt 0 && shift
-
- local restart_cmd="$1"
- : ${restart_cmd:=true}
- test $# -gt 0 && shift
-
- local test_name="$1"
- : ${test_name:=$cmd}
- test $# -gt 0 && shift
-
- local output_file="$(mktemp)"
- local status_file="$(mktemp)"
- local sid_file="$(mktemp)"
-
- local restarts=5
- local prev_tmpsize=-1
- while test $restarts -gt 0 ; do
- : > "$status_file"
- : > "$sid_file"
- setsid \
- env \
- output_file="$output_file" \
- status_file="$status_file" \
- sid_file="$sid_file" \
- cmd="$cmd" \
- CI_DIR="$CI_DIR" \
- sh -c '
- . "${CI_DIR}/common/test.sh"
- ps -o sid= > "$sid_file"
- (
- ret=0
- if ! eval "$cmd" 2>&1 ; then
- ret=1
- fi
- echo "$ret" > "$status_file"
- ) | tee -a "$output_file"
- '
- while test "$(stat -c "%s" "$status_file")" -eq 0 ; do
- prev_tmpsize=$tmpsize
- sleep $timeout
- tmpsize="$(stat -c "%s" "$output_file")"
- if test $tempsize -eq $prev_temsize ; then
- # no output, assuming either hang or exit
- break
- fi
- done
- restarts=$(( restarts - 1 ))
- if test "$(stat -c "%s" "$status_file")" -eq 0 ; then
- # Status file not updated, assuming hang
-
- # SID not known, this should not ever happen
- if test "$(stat -c "%s" "$sid_file")" -eq 0 ; then
- fail "$test_name" E "Shell did not run"
- break
- fi
-
- # Kill all processes which belong to one session: should get rid of test
- # processes as well as sh itself.
- pkill -KILL -s$(cat "$sid_file")
-
- if test $restarts -eq 0 ; then
- if test -z "$hang_ok" ; then
- fail "$test_name" E "Test hang up"
- fi
- else
- echo "Test ${test_name} hang up, restarting"
- eval "$restart_cmd"
- fi
- else
- local new_failed="$(cat "$status_file")"
- if test "$new_failed" != "0" ; then
- fail "$test_name" F "Test failed in run_test_wd"
- fi
- break
- fi
- done
-
- rm -f "$output_file"
- rm -f "$status_file"
- rm -f "$sid_file"
-}
-
ended_successfully() {
if test -f "${FAIL_SUMMARY_FILE}" ; then
echo 'Test failed, complete summary:'
diff --git a/ci/install.sh b/ci/install.sh
index 1edc1138ee..bd42274b49 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -3,15 +3,6 @@
set -e
set -o pipefail
-if [[ "${CI_TARGET}" == lint ]]; then
- python3 -m pip -q install --user --upgrade flake8
- exit
-fi
-
-if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
- export PATH="/usr/local/opt/ccache/libexec:$PATH"
-fi
-
# Use default CC to avoid compilation problems when installing Python modules.
echo "Install neovim module for Python 3."
CC=cc python3 -m pip -q install --user --upgrade pynvim
@@ -24,8 +15,6 @@ echo "Install neovim RubyGem."
gem install --no-document --bindir "$HOME/.local/bin" --user-install --pre neovim
echo "Install neovim npm package"
-source ~/.nvm/nvm.sh
-nvm use 10
npm install -g neovim
npm link neovim
diff --git a/ci/run_lint.sh b/ci/run_lint.sh
index 8373a3cb36..314976edc2 100755
--- a/ci/run_lint.sh
+++ b/ci/run_lint.sh
@@ -25,12 +25,7 @@ run_test 'make shlint' shlint
exit_suite --continue
enter_suite single-includes
-CLICOLOR_FORCE=1 run_test_wd \
- --allow-hang \
- 10s \
- 'make check-single-includes' \
- 'csi_clean' \
- single-includes
+run_test 'make check-single-includes' single-includes
exit_suite --continue
end_tests
diff --git a/ci/run_tests.sh b/ci/run_tests.sh
index d91ac5589e..c175910da5 100755
--- a/ci/run_tests.sh
+++ b/ci/run_tests.sh
@@ -17,10 +17,6 @@ build_nvim
exit_suite --continue
-source ~/.nvm/nvm.sh
-nvm use 10
-
-
enter_suite tests
if test "$CLANG_SANITIZER" != "TSAN" ; then
diff --git a/ci/script.sh b/ci/script.sh
index c8025ce34d..74fc4eda6c 100755
--- a/ci/script.sh
+++ b/ci/script.sh
@@ -3,14 +3,7 @@
set -e
set -o pipefail
-# This will pass the environment variables down to a bash process which runs
-# as $USER, while retaining the environment variables defined and belonging
-# to secondary groups given above in usermod.
-if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
- sudo -E su "${USER}" -c "ci/run_${CI_TARGET}.sh"
-else
- ci/run_${CI_TARGET}.sh
-fi
+ci/run_${CI_TARGET}.sh
if [[ -s "${GCOV_ERROR_FILE}" ]]; then
echo '=== Unexpected gcov errors: ==='
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 7b4dce3441..e6523aa215 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -523,7 +523,7 @@ function! s:check_virtualenv() abort
let hint = '$PATH ambiguities in subshells typically are '
\.'caused by your shell config overriding the $PATH previously set by the '
\.'virtualenv. Either prevent them from doing so, or use this workaround: '
- \.'https://vi.stackexchange.com/a/7654'
+ \.'https://vi.stackexchange.com/a/34996'
let hints[hint] = v:true
endif
endfor
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 8fb6290e50..0daca0de53 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -45,7 +45,7 @@ start with a TCP/IP socket instead, use |--listen| with a TCP-style address: >
More endpoints can be started with |serverstart()|.
Note that localhost TCP sockets are generally less secure than named pipes,
-and can lead to vunerabilities like remote code execution.
+and can lead to vulnerabilities like remote code execution.
Connecting to the socket is the easiest way a programmer can test the API,
which can be done through any msgpack-rpc client library or full-featured
@@ -198,7 +198,7 @@ any of these approaches:
2. Start Nvim with |--api-info|. Useful for statically-compiled clients.
Example (requires Python "pyyaml" and "msgpack-python" modules): >
- nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))'
+ nvim --api-info | python -c 'import msgpack, sys, yaml; yaml.dump(msgpack.unpackb(sys.stdin.buffer.read()), sys.stdout)'
<
3. Use the |api_info()| Vimscript function. >
:lua print(vim.inspect(vim.fn.api_info()))
@@ -361,7 +361,7 @@ UTF-32 and UTF-16 sizes of the deleted region is also passed as additional
arguments {old_utf32_size} and {old_utf16_size}.
"on_changedtick" is invoked when |b:changedtick| was incremented but no text
-was changed. The parameters recieved are ("changedtick", {buf}, {changedtick}).
+was changed. The parameters received are ("changedtick", {buf}, {changedtick}).
*api-lua-detach*
In-process Lua callbacks can detach by returning `true`. This will detach all
@@ -468,7 +468,7 @@ extmark position and enter some text, the extmark migrates forward. >
f o o z|b a r line (| = cursor)
4 extmark (after typing "z")
-If an extmark is on the last index of a line and you inputsa newline at that
+If an extmark is on the last index of a line and you inputs a newline at that
point, the extmark will accordingly migrate to the next line: >
f o o z b a r| line (| = cursor)
@@ -626,6 +626,59 @@ nvim__stats() *nvim__stats()*
Return: ~
Map of various internal stats.
+ *nvim_add_user_command()*
+nvim_add_user_command({name}, {command}, {*opts})
+ Create a new user command |user-commands|
+
+ {name} is the name of the new command. The name must begin
+ with an uppercase letter.
+
+ {command} is the replacement text or Lua function to execute.
+
+ Example: >
+ :call nvim_add_user_command('SayHello', 'echo "Hello world!"', {})
+ :SayHello
+ Hello world!
+<
+
+ Parameters: ~
+ {name} Name of the new user command. Must begin with
+ an uppercase letter.
+ {command} Replacement command to execute when this user
+ command is executed. When called from Lua, the
+ command can also be a Lua function. The
+ function is called with a single table argument
+ that contains the following keys:
+ • args: (string) The args passed to the
+ command, if any |<args>|
+ • bang: (boolean) "true" if the command was
+ executed with a ! modifier |<bang>|
+ • line1: (number) The starting line of the
+ command range |<line1>|
+ • line2: (number) The final line of the command
+ range |<line2>|
+ • range: (number) The number of items in the
+ command range: 0, 1, or 2 |<range>|
+ • count: (number) Any count supplied |<count>|
+ • reg: (string) The optional register, if
+ specified |<reg>|
+ • mods: (string) Command modifiers, if any
+ |<mods>|
+ {opts} Optional command attributes. See
+ |command-attributes| for more details. To use
+ boolean attributes (such as |:command-bang| or
+ |:command-bar|) set the value to "true". In
+ addition to the string options listed in
+ |:command-complete|, the "complete" key also
+ accepts a Lua function which works like the
+ "customlist" completion mode
+ |:command-completion-customlist|. Additional
+ parameters:
+ • desc: (string) Used for listing the command
+ when a Lua function is used for {command}.
+ • force: (boolean, default true) Override any
+ previous definition.
+
nvim_call_atomic({calls}) *nvim_call_atomic()*
Calls many API methods atomically.
@@ -634,7 +687,7 @@ nvim_call_atomic({calls}) *nvim_call_atomic()*
atomically, i.e. without interleaving redraws, RPC requests
from other clients, or user interactions (however API
methods may trigger autocommands or event processing which
- have such side-effects, e.g. |:sleep| may wake timers).
+ have such side effects, e.g. |:sleep| may wake timers).
2. To minimize RPC overhead (roundtrips) of a sequence of many
requests.
@@ -698,7 +751,7 @@ nvim_del_keymap({mode}, {lhs}) *nvim_del_keymap()*
|nvim_set_keymap()|
nvim_del_mark({name}) *nvim_del_mark()*
- Deletes a uppercase/file named mark. See |mark-motions|.
+ Deletes an uppercase/file named mark. See |mark-motions|.
Note:
fails with error if a lowercase or buffer local named mark
@@ -714,6 +767,12 @@ nvim_del_mark({name}) *nvim_del_mark()*
|nvim_buf_del_mark()|
|nvim_get_mark()|
+nvim_del_user_command({name}) *nvim_del_user_command()*
+ Delete a user-defined command.
+
+ Parameters: ~
+ {name} Name of the command to delete.
+
nvim_del_var({name}) *nvim_del_var()*
Removes a global (g:) variable.
@@ -1061,7 +1120,7 @@ nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()*
Parameters: ~
{name} Option name
{opts} Optional parameters
- • scope: One of 'global' or 'local'. Analagous to
+ • scope: One of 'global' or 'local'. Analogous to
|:setglobal| and |:setlocal|, respectively.
Return: ~
@@ -1524,8 +1583,11 @@ nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
{rhs} Right-hand-side |{rhs}| of the mapping.
{opts} Optional parameters map. Accepts all
|:map-arguments| as keys excluding |<buffer>| but
- including |noremap|. Values are Booleans. Unknown
- key is an error.
+ including |noremap| and "desc". |desc| can be used
+ to give a description to keymap. When called from
+ Lua, also accepts a "callback" key that takes a
+ Lua function to call when the mapping is executed.
+ Values are Booleans. Unknown key is an error.
nvim_set_option({name}, {value}) *nvim_set_option()*
Sets the global value of an option.
@@ -1545,7 +1607,7 @@ nvim_set_option_value({name}, {value}, {*opts})
{name} Option name
{value} New option value
{opts} Optional parameters
- • scope: One of 'global' or 'local'. Analagous to
+ • scope: One of 'global' or 'local'. Analogous to
|:setglobal| and |:setlocal|, respectively.
nvim_set_var({name}, {value}) *nvim_set_var()*
@@ -1790,6 +1852,16 @@ nvim__buf_redraw_range({buffer}, {first}, {last})
nvim__buf_stats({buffer}) *nvim__buf_stats()*
TODO: Documentation
+ *nvim_buf_add_user_command()*
+nvim_buf_add_user_command({buffer}, {name}, {command}, {*opts})
+ Create a new user command |user-commands| in the given buffer.
+
+ Parameters: ~
+ {buffer} Buffer handle, or 0 for current buffer.
+
+ See also: ~
+ nvim_add_user_command
+
nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
Activates buffer-update events on a channel, or as Lua
callbacks.
@@ -1925,6 +1997,18 @@ nvim_buf_del_mark({buffer}, {name}) *nvim_buf_del_mark()*
|nvim_buf_set_mark()|
|nvim_del_mark()|
+ *nvim_buf_del_user_command()*
+nvim_buf_del_user_command({buffer}, {name})
+ Delete a buffer-local user-defined command.
+
+ Only commands created with |:command-buffer| or
+ |nvim_buf_add_user_command()| can be deleted with this
+ function.
+
+ Parameters: ~
+ {buffer} Buffer handle, or 0 for current buffer.
+ {name} Name of the command to delete.
+
nvim_buf_del_var({buffer}, {name}) *nvim_buf_del_var()*
Removes a buffer-scoped (b:) variable
@@ -2687,7 +2771,7 @@ nvim_win_is_valid({window}) *nvim_win_is_valid()*
true if the window is valid, false otherwise
nvim_win_set_buf({window}, {buffer}) *nvim_win_set_buf()*
- Sets the current buffer in a window, without side-effects
+ Sets the current buffer in a window, without side effects
Attributes: ~
not allowed when |textlock| is active
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 3df8d5ced4..46d9a3b57a 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -840,6 +840,9 @@ RecordingLeave When a macro stops recording.
register.
|reg_recorded()| is only updated after this
event.
+ Sets these |v:event| keys:
+ regcontents
+ regname
*SessionLoadPost*
SessionLoadPost After loading the session file created using
the |:mksession| command.
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index ffdd8427f9..953f097a92 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -1595,7 +1595,8 @@ r Automatically insert the current comment leader after hitting
<Enter> in Insert mode.
*fo-o*
o Automatically insert the current comment leader after hitting 'o' or
- 'O' in Normal mode.
+ 'O' in Normal mode. In case comment is unwanted in a specific place
+ use CTRL-U to quickly delete it. |i_CTRL-U|
*fo-q*
q Allow formatting of comments with "gq".
Note that formatting will not change blank lines or lines containing
diff --git a/runtime/doc/channel.txt b/runtime/doc/channel.txt
index 5f376a600e..e14427494d 100644
--- a/runtime/doc/channel.txt
+++ b/runtime/doc/channel.txt
@@ -44,7 +44,7 @@ functions like |chansend()| consume channel ids.
2. Reading and writing raw bytes *channel-bytes*
Channels opened by Vimscript functions operate with raw bytes by default. For
-a job channel using RPC, bytes can still be read over its stderr. Similarily,
+a job channel using RPC, bytes can still be read over its stderr. Similarly,
only bytes can be written to Nvim's own stderr.
*channel-callback*
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 7127c74134..178b0dc62b 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -105,7 +105,7 @@ in eval.c:
- eval_call_provider(name, method, arguments, discard): calls
provider#{name}#Call with the method and arguments. If discard is true, any
- value returned by the provider will be discarded and and empty value be
+ value returned by the provider will be discarded and empty value will be
returned.
- eval_has_provider(name): Checks the `g:loaded_{name}_provider` variable
which must be set to 2 by the provider script to indicate that it is
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index a825435179..bb36fa46f6 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -132,7 +132,7 @@ with |vim.notify()|: >
In this example, there is nothing to do when diagnostics are hidden, so we
omit the "hide" function.
-Existing handlers can be overriden. For example, use the following to only
+Existing handlers can be overridden. For example, use the following to only
show a sign for the highest severity diagnostic on a given line: >
-- Create a custom namespace. This will aggregate signs from all other
@@ -177,8 +177,9 @@ All highlights defined for diagnostics begin with `Diagnostic` followed by
the type of highlight (e.g., `Sign`, `Underline`, etc.) and the severity (e.g.
`Error`, `Warn`, etc.)
-Sign, underline and virtual text highlights (by default) are linked to their
-corresponding default highlight.
+By default, highlights for signs, floating windows, and virtual text are linked to the
+corresponding default highlight. Underline highlights are not linked and use their
+own default highlight groups.
For example, the default highlighting for |hl-DiagnosticSignError| is linked
to |hl-DiagnosticError|. To change the default (and therefore the linked
@@ -298,7 +299,6 @@ Example: >
autocmd DiagnosticChanged * lua vim.diagnostic.setqflist({open = false })
<
==============================================================================
-==============================================================================
Lua module: vim.diagnostic *diagnostic-api*
config({opts}, {namespace}) *vim.diagnostic.config()*
@@ -343,7 +343,10 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
|diagnostic-severity|
• virtual_text: (default true) Use virtual
- text for diagnostics. Options:
+ text for diagnostics. If multiple
+ diagnostics are set for a namespace, one
+ prefix per diagnostic + the last diagnostic
+ message are shown. Options:
• severity: Only show virtual text for
diagnostics matching the given severity
|diagnostic-severity|
@@ -353,6 +356,11 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
is more than one diagnostic source in the
buffer. Otherwise, any truthy value means
to always show the diagnostic source.
+ • spacing: (number) Amount of empty spaces
+ inserted at the beginning of the virtual
+ text.
+ • prefix: (string) Prepend diagnostic
+ message with prefix.
• format: (function) A function that takes
a diagnostic as input and returns a
string. The return value is the text used
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 63f6c5628a..c2158f3a1e 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2278,7 +2278,7 @@ USAGE RESULT DESCRIPTION ~
abs({expr}) Float or Number absolute value of {expr}
acos({expr}) Float arc cosine of {expr}
add({object}, {item}) List/Blob append {item} to {object}
-and({expr}, {expr}) Number bitwise AND
+and({expr}, {expr}) Number bitwise AND
api_info() Dict api metadata
append({lnum}, {string}) Number append {string} below line {lnum}
append({lnum}, {list}) Number append lines {list} below line {lnum}
@@ -2310,7 +2310,7 @@ assert_notmatch({pat}, {text} [, {msg}])
assert_report({msg}) Number report a test failure
assert_true({actual} [, {msg}]) Number assert {actual} is true
atan({expr}) Float arc tangent of {expr}
-atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2}
+atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2}
browse({save}, {title}, {initdir}, {default})
String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester
@@ -2336,7 +2336,7 @@ char2nr({expr}[, {utf8}]) Number ASCII/UTF-8 value of first char in {expr}
charidx({string}, {idx} [, {countcc}])
Number char index of byte {idx} in {string}
chdir({dir}) String change current working directory
-cindent({lnum}) Number C indent for line {lnum}
+cindent({lnum}) Number C indent for line {lnum}
clearmatches([{win}]) none clear all matches
col({expr}) Number column nr of cursor or mark
complete({startcol}, {matches}) none set Insert mode completion
@@ -2349,7 +2349,7 @@ copy({expr}) any make a shallow copy of {expr}
cos({expr}) Float cosine of {expr}
cosh({expr}) Float hyperbolic cosine of {expr}
count({list}, {expr} [, {ic} [, {start}]])
- Number count how many {expr} are in {list}
+ Number count how many {expr} are in {list}
cscope_connection([{num}, {dbpath} [, {prepend}]])
Number checks existence of cscope connection
ctxget([{index}]) Dict return the |context| dict at {index}
@@ -2362,7 +2362,7 @@ ctxsize() Number return |context-stack| size
cursor({lnum}, {col} [, {off}])
Number move cursor to {lnum}, {col}, {off}
cursor({list}) Number move cursor to position in {list}
-debugbreak({pid}) Number interrupt process being debugged
+debugbreak({pid}) Number interrupt process being debugged
deepcopy({expr} [, {noref}]) any make a full copy of {expr}
delete({fname} [, {flags}]) Number delete the file or directory {fname}
deletebufline({buf}, {first}[, {last}])
@@ -2381,7 +2381,7 @@ eval({string}) any evaluate {string} into its value
eventhandler() Number |TRUE| if inside an event handler
executable({expr}) Number 1 if executable {expr} exists
execute({command}) String execute and capture output of {command}
-exepath({expr}) String full path of the command {expr}
+exepath({expr}) String full path of the command {expr}
exists({expr}) Number |TRUE| if {expr} exists
extend({expr1}, {expr2} [, {expr3}])
List/Dict insert items of {expr2} into {expr1}
@@ -2502,11 +2502,11 @@ inputlist({textlist}) Number let the user pick from a choice list
inputrestore() Number restore typeahead
inputsave() Number save and clear typeahead
inputsecret({prompt} [, {text}])
- String like input() but hiding the text
+ String like input() but hiding the text
insert({object}, {item} [, {idx}])
List insert {item} in {object} [before {idx}]
interrupt() none interrupt script execution
-invert({expr}) Number bitwise invert
+invert({expr}) Number bitwise invert
isdirectory({directory}) Number |TRUE| if {directory} is a directory
isinf({expr}) Number determine if {expr} is infinity value
(positive or negative)
@@ -2526,7 +2526,7 @@ json_encode({expr}) String Convert {expr} to JSON
keys({dict}) List keys in {dict}
len({expr}) Number the length of {expr}
libcall({lib}, {func}, {arg}) String call {func} in library {lib} with {arg}
-libcallnr({lib}, {func}, {arg}) Number idem, but return a Number
+libcallnr({lib}, {func}, {arg}) Number idem, but return a Number
line({expr} [, {winid}]) Number line nr of cursor, last line or mark
line2byte({lnum}) Number byte count of line {lnum}
lispindent({lnum}) Number Lisp indent for line {lnum}
@@ -2568,7 +2568,7 @@ msgpackparse({data}) List parse msgpack to a list of objects
nextnonblank({lnum}) Number line nr of non-blank line >= {lnum}
nr2char({expr}[, {utf8}]) String single char with ASCII/UTF-8 value {expr}
nvim_...({args}...) any call nvim |api| functions
-or({expr}, {expr}) Number bitwise OR
+or({expr}, {expr}) Number bitwise OR
pathshorten({expr}) String shorten directory names in a path
perleval({expr}) any evaluate |perl| expression
pow({x}, {y}) Float {x} to the power of {y}
@@ -2628,7 +2628,7 @@ screenrow() Number current cursor row
screenstring({row}, {col}) String characters at screen position
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
Number search for {pattern}
-searchcount([{options}]) Dict Get or update the last search count
+searchcount([{options}]) Dict Get or update the last search count
searchdecl({name} [, {global} [, {thisblock}]])
Number search for variable declaration
searchpair({start}, {middle}, {end} [, {flags} [, {skip} [...]]])
@@ -2700,7 +2700,7 @@ split({expr} [, {pat} [, {keepempty}]])
List make |List| from {pat} separated {expr}
sqrt({expr}) Float square root of {expr}
stdioopen({dict}) Number open stdio in a headless instance.
-stdpath({what}) String/List returns the standard path(s) for {what}
+stdpath({what}) String/List returns the standard path(s) for {what}
str2float({expr} [, {quoted}]) Float convert String to Float
str2list({expr} [, {utf8}]) List convert each character of {expr} to
ASCII/UTF-8 value
@@ -2736,7 +2736,7 @@ synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col}
synIDattr({synID}, {what} [, {mode}])
String attribute {what} of syntax ID {synID}
synIDtrans({synID}) Number translated syntax ID of {synID}
-synconcealed({lnum}, {col}) List info about concealing
+synconcealed({lnum}, {col}) List info about concealing
synstack({lnum}, {col}) List stack of syntax IDs at {lnum} and {col}
system({cmd} [, {input}]) String output of shell command/filter {cmd}
systemlist({cmd} [, {input}]) List output of shell command/filter {cmd}
@@ -2772,7 +2772,7 @@ values({dict}) List values in {dict}
virtcol({expr}) Number screen column of cursor or mark
visualmode([expr]) String last visual mode used
wait({timeout}, {condition}[, {interval}])
- Number Wait until {condition} is satisfied
+ Number Wait until {condition} is satisfied
wildmenumode() Number whether 'wildmenu' mode is active
win_execute({id}, {command} [, {silent}])
String execute {command} in window {id}
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index bbbe71ec3a..fdd9c8c12e 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -24,12 +24,21 @@ Each time a new or existing file is edited, Vim will try to recognize the type
of the file and set the 'filetype' option. This will trigger the FileType
event, which can be used to set the syntax highlighting, set options, etc.
-Detail: The ":filetype on" command will load this file:
+Detail: The ":filetype on" command will load these files:
+ $VIMRUNTIME/filetype.lua
$VIMRUNTIME/filetype.vim
- This file is a Vim script that defines autocommands for the
- BufNewFile and BufRead events. If the file type is not found by the
- name, the file $VIMRUNTIME/scripts.vim is used to detect it from the
- contents of the file.
+ filetype.lua creates an autocommand that fires for all BufNewFile and
+ BufRead events. It tries to detect the filetype based off of the
+ file's extension or name.
+
+ filetype.vim is a Vim script that defines autocommands for the
+ BufNewFile and BufRead events. In contrast to filetype.lua, this
+ file creates separate BufNewFile and BufRead events for each filetype
+ pattern.
+
+ If the file type is not found by the name, the file
+ $VIMRUNTIME/scripts.vim is used to detect it from the contents of the
+ file.
When the GUI is running or will start soon, the |menu.vim| script is
also sourced. See |'go-M'| about avoiding that.
@@ -149,9 +158,10 @@ is used. The default value is set like this: >
This means that the contents of compressed files are not inspected.
*new-filetype*
-If a file type that you want to use is not detected yet, there are four ways
-to add it. In any way, it's better not to modify the $VIMRUNTIME/filetype.vim
-file. It will be overwritten when installing a new version of Vim.
+If a file type that you want to use is not detected yet, there are a few ways
+to add it. In any way, it's better not to modify the $VIMRUNTIME/filetype.lua
+or $VIMRUNTIME/filetype.vim files. They will be overwritten when installing a
+new version of Nvim.
A. If you want to overrule all default file type checks.
This works by writing one file for each filetype. The disadvantage is that
@@ -191,7 +201,7 @@ B. If you want to detect your file after the default file type checks.
au BufRead,BufNewFile * if &ft == 'pascal' | set ft=mypascal
| endif
-C. If your file type can be detected by the file name.
+C. If your file type can be detected by the file name or extension.
1. Create your user runtime directory. You would normally use the first
item of the 'runtimepath' option. Example for Unix: >
:!mkdir -p ~/.config/nvim
@@ -206,9 +216,38 @@ C. If your file type can be detected by the file name.
au! BufRead,BufNewFile *.mine setfiletype mine
au! BufRead,BufNewFile *.xyz setfiletype drawing
augroup END
-< Write this file as "filetype.vim" in your user runtime directory. For
+<
+ Write this file as "filetype.vim" in your user runtime directory. For
example, for Unix: >
:w ~/.config/nvim/filetype.vim
+<
+ Alternatively, create a file called "filetype.lua" that adds new
+ filetypes.
+ Example: >
+ vim.filetype.add({
+ extension = {
+ foo = "fooscript",
+ },
+ filename = {
+ [".foorc"] = "foorc",
+ },
+ pattern = {
+ [".*/etc/foo/.*%.conf"] = "foorc",
+ },
+ })
+<
+ See |vim.filetype.add()|.
+ *g:do_filetype_lua*
+ For now, Lua filetype detection is opt-in. You can enable it by adding
+ the following to your |init.vim|: >
+ let g:do_filetype_lua = 1
+< *g:did_load_filetypes*
+ In either case, the builtin filetype detection provided by Nvim can be
+ disabled by setting the did_load_filetypes global variable. If this
+ variable exists, $VIMRUNTIME/filetype.vim will not run.
+ Example: >
+ " Disable filetype.vim
+ let g:did_load_filetypes = 1
< 3. To use the new filetype detection you must restart Vim.
@@ -245,9 +284,9 @@ D. If your filetype can only be detected by inspecting the contents of the
$VIMRUNTIME/scripts.vim.
*remove-filetype*
-If a file type is detected that is wrong for you, install a filetype.vim or
-scripts.vim to catch it (see above). You can set 'filetype' to a non-existing
-name to avoid that it will be set later anyway: >
+If a file type is detected that is wrong for you, install a filetype.lua,
+filetype.vim or scripts.vim to catch it (see above). You can set 'filetype' to
+a non-existing name to avoid that it will be set later anyway: >
:set filetype=ignored
If you are setting up a system with many users, and you don't want each user
@@ -314,12 +353,12 @@ define yourself. There are a few ways to avoid this:
You need to define your own mapping before the plugin is loaded (before
editing a file of that type). The plugin will then skip installing the
default mapping.
- *no_mail_maps*
+ *no_mail_maps* *g:no_mail_maps*
3. Disable defining mappings for a specific filetype by setting a variable,
which contains the name of the filetype. For the "mail" filetype this
would be: >
:let no_mail_maps = 1
-< *no_plugin_maps*
+< *no_plugin_maps* *g:no_plugin_maps*
4. Disable defining mappings for all filetypes by setting a variable: >
:let no_plugin_maps = 1
<
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index fd1d0f8ea6..d74d7cafa8 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -76,6 +76,8 @@ CTRL-U Delete all entered characters before the cursor in the current
line. If there are no newly entered characters and
'backspace' is not empty, delete all characters before the
cursor in the current line.
+ If C-indenting is enabled the indent will be adjusted if the
+ line becomes blank.
See |i_backspacing| about joining lines.
*i_CTRL-U-default*
By default, sets a new undo point before deleting.
@@ -1878,6 +1880,9 @@ When 'autoindent' is on, the indent for a new line is obtained from the
previous line. When 'smartindent' or 'cindent' is on, the indent for a line
is automatically adjusted for C programs.
+'formatoptions' can be set to copy the comment leader when opening a new
+line.
+
'textwidth' can be set to the maximum width for a line. When a line becomes
too long when appending characters a line break is automatically inserted.
diff --git a/runtime/doc/lsp-extension.txt b/runtime/doc/lsp-extension.txt
index d13303ada6..6e9ad940c7 100644
--- a/runtime/doc/lsp-extension.txt
+++ b/runtime/doc/lsp-extension.txt
@@ -60,7 +60,7 @@ The example will:
return nil
end
local dir = bufname
- -- Just in case our algo is buggy, don't infinite loop.
+ -- Just in case our algorithm is buggy, don't infinite loop.
for _ = 1, 100 do
local did_change
dir, did_change = dirname(dir)
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index a3929aeab9..bb42a87034 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -214,7 +214,7 @@ For |lsp-request|, each |lsp-handler| has this signature: >
request, a table with information about the error
is sent. Otherwise, it is `nil`. See |lsp-response|.
{result} (Result | Params | nil)
- When the language server is able to succesfully
+ When the language server is able to successfully
complete a request, this contains the `result` key
of the response. See |lsp-response|.
{ctx} (table)
@@ -236,7 +236,7 @@ For |lsp-request|, each |lsp-handler| has this signature: >
{config} (table)
Configuration for the handler.
- Each handler can define it's own configuration
+ Each handler can define its own configuration
table that allows users to customize the behavior
of a particular handler.
@@ -274,7 +274,7 @@ For |lsp-notification|, each |lsp-handler| has this signature: >
{config} (table)
Configuration for the handler.
- Each handler can define it's own configuration
+ Each handler can define its own configuration
table that allows users to customize the behavior
of a particular handler.
@@ -369,7 +369,7 @@ Handlers can be set by:
For example: >
vim.lsp.start_client {
- ..., -- Other configuration ommitted.
+ ..., -- Other configuration omitted.
handlers = {
["textDocument/definition"] = my_custom_server_definition
},
@@ -394,6 +394,9 @@ in the following order:
2. Handler defined in |vim.lsp.start_client()|, if any.
3. Handler defined in |vim.lsp.handlers|, if any.
+ *vim.lsp.log_levels*
+Log levels are defined in |vim.log.levels|
+
VIM.LSP.PROTOCOL *vim.lsp.protocol*
@@ -444,7 +447,7 @@ LspCodeLens
|nvim_buf_set_extmark()|.
LspCodeLensSeparator *hl-LspCodeLensSeparator*
- Used to color the seperator between two or more code lens.
+ Used to color the separator between two or more code lens.
*lsp-highlight-signature*
@@ -835,10 +838,10 @@ start_client({config}) *vim.lsp.start_client()*
throws an error. `code` is a number
describing the error. Other arguments
may be passed depending on the error
- kind. See |vim.lsp.client_errors| for
- possible errors. Use
- `vim.lsp.client_errors[code]` to get
- human-friendly name.
+ kind. See |vim.lsp.rpc.client_errors|
+ for possible errors. Use
+ `vim.lsp.rpc.client_errors[code]` to
+ get human-friendly name.
{before_init} Callback with parameters
(initialize_params, config) invoked
before the LSP "initialize" phase,
@@ -884,10 +887,10 @@ start_client({config}) *vim.lsp.start_client()*
default true): Allow using
incremental sync for buffer edits
• debounce_text_changes (number,
- default nil): Debounce didChange
+ default 150): Debounce didChange
notifications to the server by the
given number in milliseconds. No
- debounce occurs if nil
+ debounce occurs if set to 0.
• exit_timeout (number, default 500):
Milliseconds to wait for server to
exit cleanly after sending the
@@ -1301,7 +1304,7 @@ hover({_}, {result}, {ctx}, {config}) *vim.lsp.handlers.hover()*
{config} table Configuration table.
• border: (default=nil)
• Add borders to the floating window
- • See |vim.api.nvim_open_win()|
+ • See |nvim_open_win()|
*vim.lsp.handlers.signature_help()*
signature_help({_}, {result}, {ctx}, {config})
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 97062e5986..4f76c7c7a6 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -249,13 +249,15 @@ arguments separated by " " (space) instead of "\t" (tab).
*:lua*
:[range]lua {chunk}
Executes Lua chunk {chunk}.
-
+ if {chunk} starts with "=" the rest of the chunk is
+ evaluated as an expression and printed. `:lua =expr`
+ is equivalent to `:lua print(vim.inspect(expr))`
Examples: >
:lua vim.api.nvim_command('echo "Hello, Nvim!"')
< To see the Lua version: >
:lua print(_VERSION)
< To see the LuaJIT version: >
- :lua print(jit.version)
+ :lua =jit.version
<
*:lua-heredoc*
:[range]lua << [endmarker]
@@ -272,7 +274,7 @@ arguments separated by " " (space) instead of "\t" (tab).
lua << EOF
local linenr = vim.api.nvim_win_get_cursor(0)[1]
local curline = vim.api.nvim_buf_get_lines(
- 0, linenr, linenr + 1, false)[1]
+ 0, linenr - 1, linenr, false)[1]
print(string.format("Current line [%d] has %d bytes",
linenr, #curline))
EOF
@@ -791,9 +793,9 @@ vim.stricmp({a}, {b}) *vim.stricmp()*
respectively.
vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()*
- Convert byte index to UTF-32 and UTF-16 indicies. If {index} is not
- supplied, the length of the string is used. All indicies are zero-based.
- Returns two values: the UTF-32 and UTF-16 indicies respectively.
+ Convert byte index to UTF-32 and UTF-16 indices. If {index} is not
+ supplied, the length of the string is used. All indices are zero-based.
+ Returns two values: the UTF-32 and UTF-16 indices respectively.
Embedded NUL bytes are treated as terminating the string. Invalid
UTF-8 bytes, and embedded surrogates are counted as one code
@@ -913,6 +915,15 @@ vim.types *vim.types*
`vim.types.dictionary` will not change or that `vim.types` table will
only contain values for these three types.
+ *log_levels* *vim.log.levels*
+Log levels are one of the values defined in `vim.log.levels`:
+
+ vim.log.levels.DEBUG
+ vim.log.levels.ERROR
+ vim.log.levels.INFO
+ vim.log.levels.TRACE
+ vim.log.levels.WARN
+
------------------------------------------------------------------------------
LUA-VIMSCRIPT BRIDGE *lua-vimscript*
@@ -1647,16 +1658,25 @@ validate({opt}) *vim.validate()*
=> error('arg1: expected even number, got 3')
<
+ If multiple types are valid they can be given as a list. >
+
+ vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
+ => NOP (success)
+
+ vim.validate{arg1={1, {'string', table'}}}
+ => error('arg1: expected string|table, got number')
+<
+
Parameters: ~
- {opt} Map of parameter names to validations. Each key is
- a parameter name; each value is a tuple in one of
- these forms:
+ {opt} table of parameter names to validations. Each key
+ is a parameter name; each value is a tuple in one
+ of these forms:
1. (arg_value, type_name, optional)
• arg_value: argument value
- • type_name: string type name, one of: ("table",
- "t", "string", "s", "number", "n", "boolean",
- "b", "function", "f", "nil", "thread",
- "userdata")
+ • type_name: string|table type name, one of:
+ ("table", "t", "string", "s", "number", "n",
+ "boolean", "b", "function", "f", "nil",
+ "thread", "userdata") or list of them.
• optional: (optional) boolean, if true, `nil`
is valid
@@ -1760,4 +1780,71 @@ select({items}, {opts}, {on_choice}) *vim.ui.select()*
1-based index of `item` within `item` . `nil`
if the user aborted the dialog.
+
+==============================================================================
+Lua module: filetype *lua-filetype*
+
+add({filetypes}) *vim.filetype.add()*
+ Add new filetype mappings.
+
+ Filetype mappings can be added either by extension or by
+ filename (either the "tail" or the full file path). The full
+ file path is checked first, followed by the file name. If a
+ match is not found using the filename, then the filename is
+ matched against the list of patterns (sorted by priority)
+ until a match is found. Lastly, if pattern matching does not
+ find a filetype, then the file extension is used.
+
+ The filetype can be either a string (in which case it is used
+ as the filetype directly) or a function. If a function, it
+ takes the full path and buffer number of the file as arguments
+ (along with captures from the matched pattern, if any) and
+ should return a string that will be used as the buffer's
+ filetype.
+
+ Filename patterns can specify an optional priority to resolve
+ cases when a file path matches multiple patterns. Higher
+ priorities are matched first. When omitted, the priority
+ defaults to 0.
+
+ See $VIMRUNTIME/lua/vim/filetype.lua for more examples.
+
+ Note that Lua filetype detection is only enabled when
+ |g:do_filetype_lua| is set to 1.
+
+ Example: >
+
+ vim.filetype.add({
+ extension = {
+ foo = "fooscript",
+ bar = function(path, bufnr)
+ if some_condition() then
+ return "barscript"
+ end
+ return "bar"
+ end,
+ },
+ filename = {
+ [".foorc"] = "toml",
+ ["/etc/foo/config"] = "toml",
+ },
+ pattern = {
+ [".*&zwj;/etc/foo/.*"] = "fooscript",
+ -- Using an optional priority
+ [".*&zwj;/etc/foo/.*%.conf"] = { "dosini", { priority = 10 } },
+ ["README.(%a+)$"] = function(path, bufnr, ext)
+ if ext == "md" then
+ return "markdown"
+ elseif ext == "rst" then
+ return "rst"
+ end
+ end,
+ },
+ })
+<
+
+ Parameters: ~
+ {filetypes} table A table containing new filetype maps
+ (see example).
+
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 238ef39bd3..f6d9e45d64 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1247,8 +1247,8 @@ See |:verbose-cmd| for more information.
Command attributes ~
-
-User-defined commands are treated by Vim just like any other Ex commands. They
+ *command-attributes*
+User-defined commands are treated by Nvim just like any other Ex commands. They
can have arguments, or have a range specified. Arguments are subject to
completion as filenames, buffers, etc. Exactly how this works depends upon the
command's attributes, which are specified when the command is defined.
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index e1ae138d90..bfacbe19f5 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -90,7 +90,7 @@ Mouse input has the following behavior:
- If another window is clicked, terminal focus will be lost and nvim will jump
to the clicked window
- If the mouse wheel is used while the mouse is positioned in another window,
- the terminal wont lose focus and the hovered window will be scrolled.
+ the terminal won't lose focus and the hovered window will be scrolled.
==============================================================================
Configuration *terminal-config*
@@ -428,7 +428,7 @@ When 'background' is "dark":
hi debugBreakpoint term=reverse ctermbg=red guibg=red
-Shorcuts *termdebug_shortcuts*
+Shortcuts *termdebug_shortcuts*
You can define your own shortcuts (mappings) to control gdb, that can work in
any window, using the TermDebugSendCommand() function. Example: >
diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt
index 935d958729..62e13285f5 100644
--- a/runtime/doc/term.txt
+++ b/runtime/doc/term.txt
@@ -133,7 +133,7 @@ capabilities as if they had been in the terminfo definition.
If terminfo does not (yet) have this flag, Nvim will fall back to $TERM and
other environment variables. It will add constructed "setrgbf" and "setrgbb"
-capabilities in the case of the the "rxvt", "linux", "st", "tmux", and "iterm"
+capabilities in the case of the "rxvt", "linux", "st", "tmux", and "iterm"
terminal types, or when Konsole, genuine Xterm, a libvte terminal emulator
version 0.36 or later, or a terminal emulator that sets the COLORTERM
environment variable to "truecolor" is detected.
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 8f7241dd46..7de6a0f890 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -100,7 +100,7 @@ tsnode:prev_named_sibling() *tsnode:prev_named_sibling()*
tsnode:iter_children() *tsnode:iter_children()*
Iterates over all the direct children of {tsnode}, regardless of
- wether they are named or not.
+ whether they are named or not.
Returns the child node plus the eventual field name corresponding to
this child node.
@@ -155,9 +155,9 @@ tsnode:sexpr() *tsnode:sexpr()*
Get an S-expression representing the node as a string.
tsnode:id() *tsnode:id()*
- Get an unique identier for the node inside its own tree.
+ Get an unique identifier for the node inside its own tree.
- No guarantees are made about this identifer's internal representation,
+ No guarantees are made about this identifier's internal representation,
except for being a primitive lua type with value equality (so not a table).
Presently it is a (non-printable) string.
@@ -195,7 +195,7 @@ to a match.
Treesitter Query Predicates *lua-treesitter-predicates*
When writing queries for treesitter, one might use `predicates`, that is,
-special scheme nodes that are evaluted to verify things on a captured node for
+special scheme nodes that are evaluated to verify things on a captured node for
example, the |eq?| predicate : >
((identifier) @foo (#eq? @foo "foo"))
@@ -203,16 +203,16 @@ This will only match identifier corresponding to the `"foo"` text.
Here is a list of built-in predicates :
`eq?` *ts-predicate-eq?*
- This predicate will check text correspondance between nodes or
+ This predicate will check text correspondence between nodes or
strings : >
((identifier) @foo (#eq? @foo "foo"))
((node1) @left (node2) @right (#eq? @left @right))
<
`match?` *ts-predicate-match?*
`vim-match?` *ts-predicate-vim-match?*
- This will match if the provived vim regex matches the text
+ This will match if the provided vim regex matches the text
corresponding to a node : >
- ((idenfitier) @constant (#match? @constant "^[A-Z_]+$"))
+ ((identifier) @constant (#match? @constant "^[A-Z_]+$"))
< Note: the `^` and `$` anchors will respectively match the
start and end of the node's text.
@@ -267,7 +267,7 @@ Here is a list of built-in directives:
`offset!` *ts-predicate-offset!*
Takes the range of the captured node and applies the offsets
to it's range : >
- ((idenfitier) @constant (#offset! @constant 0 1 0 -1))
+ ((identifier) @constant (#offset! @constant 0 1 0 -1))
< This will generate a range object for the captured node with the
offsets applied. The arguments are
`({capture_id}, {start_row}, {start_col}, {end_row}, {end_col}, {key?})`
diff --git a/runtime/doc/usr_05.txt b/runtime/doc/usr_05.txt
index 2edef0ca23..f93a221e43 100644
--- a/runtime/doc/usr_05.txt
+++ b/runtime/doc/usr_05.txt
@@ -11,13 +11,12 @@ Vim's capabilities. Or define your own macros.
|05.1| The vimrc file
|05.2| The example vimrc file explained
-|05.3| The defaults.vim file explained
-|05.4| Simple mappings
-|05.5| Adding a package
-|05.6| Adding a plugin
-|05.7| Adding a help file
-|05.8| The option window
-|05.9| Often used options
+|05.3| Simple mappings
+|05.4| Adding a package
+|05.5| Adding a plugin
+|05.6| Adding a help file
+|05.7| The option window
+|05.8| Often used options
Next chapter: |usr_06.txt| Using syntax highlighting
Previous chapter: |usr_04.txt| Making small changes
@@ -200,7 +199,7 @@ mapping. If set (default), this may break plugins (but it's backward
compatible). See 'langremap'.
==============================================================================
-*05.4* Simple mappings
+*05.3* Simple mappings
A mapping enables you to bind a set of Vim commands to a single key. Suppose,
for example, that you need to surround certain words with curly braces. In
@@ -247,7 +246,7 @@ The ":map" command (with no arguments) lists your current mappings. At
least the ones for Normal mode. More about mappings in section |40.1|.
==============================================================================
-*05.5* Adding a package *add-package* *vimball-install*
+*05.4* Adding a package *add-package* *vimball-install*
A package is a set of files that you can add to Vim. There are two kinds of
packages: optional and automatically loaded on startup.
@@ -287,7 +286,7 @@ an archive or as a repository. For an archive you can follow these steps:
More information about packages can be found here: |packages|.
==============================================================================
-*05.6* Adding a plugin *add-plugin* *plugin*
+*05.5* Adding a plugin *add-plugin* *plugin*
Vim's functionality can be extended by adding plugins. A plugin is nothing
more than a Vim script file that is loaded automatically when Vim starts. You
@@ -423,7 +422,7 @@ Further reading:
|new-filetype| How to detect a new file type.
==============================================================================
-*05.7* Adding a help file *add-local-help*
+*05.6* Adding a help file *add-local-help*
If you are lucky, the plugin you installed also comes with a help file. We
will explain how to install the help file, so that you can easily find help
@@ -456,7 +455,7 @@ them through the tag.
For writing a local help file, see |write-local-help|.
==============================================================================
-*05.8* The option window
+*05.7* The option window
If you are looking for an option that does what you want, you can search in
the help files here: |options|. Another way is by using this command: >
@@ -495,7 +494,7 @@ border. This is what the 'scrolloff' option does, it specifies an offset
from the window border where scrolling starts.
==============================================================================
-*05.9* Often used options
+*05.8* Often used options
There are an awful lot of options. Most of them you will hardly ever use.
Some of the more useful ones will be mentioned here. Don't forget you can
diff --git a/runtime/doc/usr_toc.txt b/runtime/doc/usr_toc.txt
index f466a8ece9..bf9c02882c 100644
--- a/runtime/doc/usr_toc.txt
+++ b/runtime/doc/usr_toc.txt
@@ -99,13 +99,12 @@ Read this from start to end to learn the essential commands.
|usr_05.txt| Set your settings
|05.1| The vimrc file
|05.2| The example vimrc file explained
- |05.3| The defaults.vim file explained
- |05.4| Simple mappings
- |05.5| Adding a package
- |05.6| Adding a plugin
- |05.7| Adding a help file
- |05.8| The option window
- |05.9| Often used options
+ |05.3| Simple mappings
+ |05.4| Adding a package
+ |05.5| Adding a plugin
+ |05.6| Adding a help file
+ |05.7| The option window
+ |05.8| Often used options
|usr_06.txt| Using syntax highlighting
|06.1| Switching it on
diff --git a/runtime/filetype.lua b/runtime/filetype.lua
new file mode 100644
index 0000000000..fcfc5701f0
--- /dev/null
+++ b/runtime/filetype.lua
@@ -0,0 +1,26 @@
+if vim.g.did_load_filetypes and vim.g.did_load_filetypes ~= 0 then
+ return
+end
+
+-- For now, make this opt-in with a global variable
+if vim.g.do_filetype_lua ~= 1 then
+ return
+end
+
+vim.cmd [[
+augroup filetypedetect
+au BufRead,BufNewFile * call v:lua.vim.filetype.match(expand('<afile>'))
+
+" These *must* be sourced after the autocommand above is created
+runtime! ftdetect/*.vim
+runtime! ftdetect/*.lua
+
+" Set a marker so that the ftdetect scripts are not sourced a second time by filetype.vim
+let g:did_load_ftdetect = 1
+
+augroup END
+]]
+
+if not vim.g.ft_ignore_pat then
+ vim.g.ft_ignore_pat = "\\.\\(Z\\|gz\\|bz2\\|zip\\|tgz\\)$"
+end
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 104836862f..7fdbfe32d8 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -959,9 +959,9 @@ au BufNewFile,BufRead lilo.conf setf lilo
" Lisp (*.el = ELisp, *.cl = Common Lisp)
" *.jl was removed, it's also used for Julia, better skip than guess wrong.
if has("fname_case")
- au BufNewFile,BufRead *.lsp,*.lisp,*.el,*.cl,*.L,.emacs,.sawfishrc setf lisp
+ au BufNewFile,BufRead *.lsp,*.lisp,*.asd,*.el,*.cl,*.L,.emacs,.sawfishrc setf lisp
else
- au BufNewFile,BufRead *.lsp,*.lisp,*.el,*.cl,.emacs,.sawfishrc setf lisp
+ au BufNewFile,BufRead *.lsp,*.lisp,*.asd,*.el,*.cl,.emacs,.sawfishrc setf lisp
endif
" SBCL implementation of Common Lisp
@@ -1665,7 +1665,7 @@ au BufNewFile,BufRead .zshrc,.zshenv,.zlogin,.zlogout,.zcompdump setf zsh
au BufNewFile,BufRead *.zsh setf zsh
" Scheme
-au BufNewFile,BufRead *.scm,*.ss,*.rkt,*.rktd,*.rktl setf scheme
+au BufNewFile,BufRead *.scm,*.ss,*.sld,*.rkt,*.rktd,*.rktl setf scheme
" Screen RC
au BufNewFile,BufRead .screenrc,screenrc setf screen
@@ -1774,8 +1774,8 @@ au BufNewFile,BufRead *.sqr,*.sqi setf sqr
au BufNewFile,BufRead *.nut setf squirrel
" OpenSSH configuration
-au BufNewFile,BufRead ssh_config,*/.ssh/config setf sshconfig
-au BufNewFile,BufRead */etc/ssh/ssh_config.d/*.conf setf sshconfig
+au BufNewFile,BufRead ssh_config,*/.ssh/config,*/.ssh/*.conf setf sshconfig
+au BufNewFile,BufRead */etc/ssh/ssh_config.d/*.conf setf sshconfig
" OpenSSH server configuration
au BufNewFile,BufRead sshd_config setf sshdconfig
@@ -2407,10 +2407,12 @@ au BufNewFile,BufRead *.txt
\| setf text
\| endif
-" Use the filetype detect plugins. They may overrule any of the previously
-" detected filetypes.
-runtime! ftdetect/*.vim
-runtime! ftdetect/*.lua
+if !exists('g:did_load_ftdetect')
+ " Use the filetype detect plugins. They may overrule any of the previously
+ " detected filetypes.
+ runtime! ftdetect/*.vim
+ runtime! ftdetect/*.lua
+endif
" NOTE: The above command could have ended the filetypedetect autocmd group
" and started another one. Let's make sure it has ended to get to a consistent
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
index 742ebf69b2..417b661155 100644
--- a/runtime/lua/vim/diagnostic.lua
+++ b/runtime/lua/vim/diagnostic.lua
@@ -556,13 +556,19 @@ end
--- - underline: (default true) Use underline for diagnostics. Options:
--- * severity: Only underline diagnostics matching the given severity
--- |diagnostic-severity|
---- - virtual_text: (default true) Use virtual text for diagnostics. Options:
+--- - virtual_text: (default true) Use virtual text for diagnostics. If multiple diagnostics
+--- are set for a namespace, one prefix per diagnostic + the last diagnostic
+--- message are shown.
+--- Options:
--- * severity: Only show virtual text for diagnostics matching the given
--- severity |diagnostic-severity|
--- * source: (boolean or string) Include the diagnostic source in virtual
--- text. Use "if_many" to only show sources if there is more than
--- one diagnostic source in the buffer. Otherwise, any truthy value
--- means to always show the diagnostic source.
+--- * spacing: (number) Amount of empty spaces inserted at the beginning
+--- of the virtual text.
+--- * prefix: (string) Prepend diagnostic message with prefix.
--- * format: (function) A function that takes a diagnostic as input and
--- returns a string. The return value is the text used to display
--- the diagnostic. Example:
@@ -638,7 +644,11 @@ function M.set(namespace, bufnr, diagnostics, opts)
vim.validate {
namespace = {namespace, 'n'},
bufnr = {bufnr, 'n'},
- diagnostics = {diagnostics, 't'},
+ diagnostics = {
+ diagnostics,
+ vim.tbl_islist,
+ "a list of diagnostics",
+ },
opts = {opts, 't', true},
}
@@ -804,7 +814,11 @@ M.handlers.signs = {
vim.validate {
namespace = {namespace, 'n'},
bufnr = {bufnr, 'n'},
- diagnostics = {diagnostics, 't'},
+ diagnostics = {
+ diagnostics,
+ vim.tbl_islist,
+ "a list of diagnostics",
+ },
opts = {opts, 't', true},
}
@@ -867,7 +881,11 @@ M.handlers.underline = {
vim.validate {
namespace = {namespace, 'n'},
bufnr = {bufnr, 'n'},
- diagnostics = {diagnostics, 't'},
+ diagnostics = {
+ diagnostics,
+ vim.tbl_islist,
+ "a list of diagnostics",
+ },
opts = {opts, 't', true},
}
@@ -915,7 +933,11 @@ M.handlers.virtual_text = {
vim.validate {
namespace = {namespace, 'n'},
bufnr = {bufnr, 'n'},
- diagnostics = {diagnostics, 't'},
+ diagnostics = {
+ diagnostics,
+ vim.tbl_islist,
+ "a list of diagnostics",
+ },
opts = {opts, 't', true},
}
@@ -1075,7 +1097,11 @@ function M.show(namespace, bufnr, diagnostics, opts)
vim.validate {
namespace = { namespace, 'n', true },
bufnr = { bufnr, 'n', true },
- diagnostics = { diagnostics, 't', true },
+ diagnostics = {
+ diagnostics,
+ function(v) return v == nil or vim.tbl_islist(v) end,
+ "a list of diagnostics",
+ },
opts = { opts, 't', true },
}
@@ -1346,16 +1372,16 @@ function M.reset(namespace, bufnr)
diagnostic_cache[iter_bufnr][iter_namespace] = nil
M.hide(iter_namespace, iter_bufnr)
end
- end
- vim.api.nvim_buf_call(bufnr, function()
- vim.api.nvim_command(
- string.format(
- "doautocmd <nomodeline> DiagnosticChanged %s",
- vim.fn.fnameescape(vim.api.nvim_buf_get_name(bufnr))
+ vim.api.nvim_buf_call(iter_bufnr, function()
+ vim.api.nvim_command(
+ string.format(
+ "doautocmd <nomodeline> DiagnosticChanged %s",
+ vim.fn.fnameescape(vim.api.nvim_buf_get_name(iter_bufnr))
+ )
)
- )
- end)
+ end)
+ end
end
--- Add all diagnostics to the quickfix list.
@@ -1520,7 +1546,13 @@ local errlist_type_map = {
---@param diagnostics table List of diagnostics |diagnostic-structure|.
---@return array of quickfix list items |setqflist-what|
function M.toqflist(diagnostics)
- vim.validate { diagnostics = {diagnostics, 't'} }
+ vim.validate {
+ diagnostics = {
+ diagnostics,
+ vim.tbl_islist,
+ "a list of diagnostics",
+ },
+ }
local list = {}
for _, v in ipairs(diagnostics) do
@@ -1551,7 +1583,13 @@ end
--- |getloclist()|.
---@return array of diagnostics |diagnostic-structure|
function M.fromqflist(list)
- vim.validate { list = {list, 't'} }
+ vim.validate {
+ list = {
+ list,
+ vim.tbl_islist,
+ "a list of quickfix items",
+ },
+ }
local diagnostics = {}
for _, item in ipairs(list) do
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
new file mode 100644
index 0000000000..54b20f7391
--- /dev/null
+++ b/runtime/lua/vim/filetype.lua
@@ -0,0 +1,1506 @@
+local api = vim.api
+
+local M = {}
+
+---@private
+local function starsetf(ft)
+ return {function(path)
+ if not vim.g.fg_ignore_pat then
+ return ft
+ end
+
+ local re = vim.regex(vim.g.fg_ignore_pat)
+ if re:match_str(path) then
+ return ft
+ end
+ end, {
+ -- Starset matches should always have lowest priority
+ priority = -1,
+ }}
+end
+
+---@private
+local function getline(bufnr, lnum)
+ return api.nvim_buf_get_lines(bufnr, lnum-1, lnum, false)[1]
+end
+
+-- Filetypes based on file extension
+-- luacheck: push no unused args
+local extension = {
+ -- BEGIN EXTENSION
+ ["8th"] = "8th",
+ ["a65"] = "a65",
+ aap = "aap",
+ abap = "abap",
+ abc = "abc",
+ abl = "abel",
+ wrm = "acedb",
+ ads = "ada",
+ ada = "ada",
+ gpr = "ada",
+ adb = "ada",
+ tdf = "ahdl",
+ aidl = "aidl",
+ aml = "aml",
+ run = "ampl",
+ scpt = "applescript",
+ ino = "arduino",
+ pde = "arduino",
+ art = "art",
+ asciidoc = "asciidoc",
+ adoc = "asciidoc",
+ ["asn1"] = "asn",
+ asn = "asn",
+ atl = "atlas",
+ as = "atlas",
+ ahk = "autohotkey",
+ ["au3"] = "autoit",
+ ave = "ave",
+ gawk = "awk",
+ awk = "awk",
+ ref = "b",
+ imp = "b",
+ mch = "b",
+ bc = "bc",
+ bdf = "bdf",
+ beancount = "beancount",
+ bib = "bib",
+ bl = "blank",
+ bsdl = "bsdl",
+ bst = "bst",
+ bzl = "bzl",
+ bazel = "bzl",
+ BUILD = "bzl",
+ qc = "c",
+ cabal = "cabal",
+ cdl = "cdl",
+ toc = "cdrtoc",
+ cfc = "cf",
+ cfm = "cf",
+ cfi = "cf",
+ cfg = "cfg",
+ hgrc = "cfg",
+ chf = "ch",
+ chai = "chaiscript",
+ chs = "chaskell",
+ chopro = "chordpro",
+ crd = "chordpro",
+ crdpro = "chordpro",
+ cho = "chordpro",
+ chordpro = "chordpro",
+ eni = "cl",
+ dcl = "clean",
+ icl = "clean",
+ cljx = "clojure",
+ clj = "clojure",
+ cljc = "clojure",
+ cljs = "clojure",
+ cmake = "cmake",
+ cmod = "cmod",
+ lib = "cobol",
+ cob = "cobol",
+ cbl = "cobol",
+ atg = "coco",
+ recipe = "conaryrecipe",
+ mklx = "context",
+ mkiv = "context",
+ mkii = "context",
+ mkxl = "context",
+ mkvi = "context",
+ moc = "cpp",
+ hh = "cpp",
+ tlh = "cpp",
+ inl = "cpp",
+ ipp = "cpp",
+ ["c++"] = "cpp",
+ C = "cpp",
+ cxx = "cpp",
+ H = "cpp",
+ tcc = "cpp",
+ hxx = "cpp",
+ hpp = "cpp",
+ cpp = function()
+ if vim.g.cynlib_syntax_for_cc then
+ return "cynlib"
+ end
+ return "cpp"
+ end,
+ crm = "crm",
+ csx = "cs",
+ cs = "cs",
+ csc = "csc",
+ csdl = "csdl",
+ fdr = "csp",
+ csp = "csp",
+ css = "css",
+ con = "cterm",
+ feature = "cucumber",
+ cuh = "cuda",
+ cu = "cuda",
+ pld = "cupl",
+ si = "cuplsim",
+ cyn = "cynpp",
+ dart = "dart",
+ drt = "dart",
+ ds = "datascript",
+ dcd = "dcd",
+ def = "def",
+ desc = "desc",
+ directory = "desktop",
+ desktop = "desktop",
+ diff = "diff",
+ rej = "diff",
+ Dockerfile = "dockerfile",
+ sys = "dosbatch",
+ bat = "dosbatch",
+ wrap = "dosini",
+ ini = "dosini",
+ dot = "dot",
+ gv = "dot",
+ drac = "dracula",
+ drc = "dracula",
+ dtd = "dtd",
+ dts = "dts",
+ dtsi = "dts",
+ dylan = "dylan",
+ intr = "dylanintr",
+ lid = "dylanlid",
+ ecd = "ecd",
+ eex = "eelixir",
+ leex = "eelixir",
+ exs = "elixir",
+ elm = "elm",
+ epp = "epuppet",
+ erl = "erlang",
+ hrl = "erlang",
+ yaws = "erlang",
+ erb = "eruby",
+ rhtml = "eruby",
+ ec = "esqlc",
+ EC = "esqlc",
+ strl = "esterel",
+ exp = "expect",
+ factor = "factor",
+ fal = "falcon",
+ fan = "fan",
+ fwt = "fan",
+ fnl = "fennel",
+ ["m4gl"] = "fgl",
+ ["4gl"] = "fgl",
+ ["4gh"] = "fgl",
+ fish = "fish",
+ focexec = "focexec",
+ fex = "focexec",
+ fth = "forth",
+ ft = "forth",
+ FOR = "fortran",
+ ["f77"] = "fortran",
+ ["f03"] = "fortran",
+ fortran = "fortran",
+ ["F95"] = "fortran",
+ ["f90"] = "fortran",
+ ["F03"] = "fortran",
+ fpp = "fortran",
+ FTN = "fortran",
+ ftn = "fortran",
+ ["for"] = "fortran",
+ ["F90"] = "fortran",
+ ["F77"] = "fortran",
+ ["f95"] = "fortran",
+ FPP = "fortran",
+ f = "fortran",
+ F = "fortran",
+ ["F08"] = "fortran",
+ ["f08"] = "fortran",
+ fpc = "fpcmake",
+ fsl = "framescript",
+ bi = "freebasic",
+ fb = "freebasic",
+ fsi = "fsharp",
+ fsx = "fsharp",
+ gdmo = "gdmo",
+ mo = "gdmo",
+ ged = "gedcom",
+ gmi = "gemtext",
+ gemini = "gemtext",
+ gift = "gift",
+ gpi = "gnuplot",
+ go = "go",
+ gp = "gp",
+ gs = "grads",
+ gretl = "gretl",
+ gradle = "groovy",
+ groovy = "groovy",
+ gsp = "gsp",
+ haml = "haml",
+ hsm = "hamster",
+ ["hs-boot"] = "haskell",
+ hsig = "haskell",
+ hsc = "haskell",
+ hs = "haskell",
+ ht = "haste",
+ htpp = "hastepreproc",
+ hb = "hb",
+ sum = "hercules",
+ errsum = "hercules",
+ ev = "hercules",
+ vc = "hercules",
+ hex = "hex",
+ ["h32"] = "hex",
+ hog = "hog",
+ hws = "hollywood",
+ htt = "httest",
+ htb = "httest",
+ iba = "ibasic",
+ ibi = "ibasic",
+ icn = "icon",
+ inf = "inform",
+ INF = "inform",
+ ii = "initng",
+ iss = "iss",
+ mst = "ist",
+ ist = "ist",
+ ijs = "j",
+ JAL = "jal",
+ jal = "jal",
+ jpr = "jam",
+ jpl = "jam",
+ jav = "java",
+ java = "java",
+ jj = "javacc",
+ jjt = "javacc",
+ es = "javascript",
+ mjs = "javascript",
+ javascript = "javascript",
+ js = "javascript",
+ cjs = "javascript",
+ jsx = "javascriptreact",
+ clp = "jess",
+ jgr = "jgraph",
+ ["j73"] = "jovial",
+ jov = "jovial",
+ jovial = "jovial",
+ properties = "jproperties",
+ slnf = "json",
+ json = "json",
+ jsonp = "json",
+ webmanifest = "json",
+ ipynb = "json",
+ ["json-patch"] = "json",
+ jsonc = "jsonc",
+ jsp = "jsp",
+ jl = "julia",
+ kv = "kivy",
+ kix = "kix",
+ kts = "kotlin",
+ kt = "kotlin",
+ ktm = "kotlin",
+ ks = "kscript",
+ k = "kwt",
+ ACE = "lace",
+ ace = "lace",
+ latte = "latte",
+ lte = "latte",
+ ld = "ld",
+ ldif = "ldif",
+ less = "less",
+ lex = "lex",
+ lxx = "lex",
+ ["l++"] = "lex",
+ l = "lex",
+ lhs = "lhaskell",
+ ll = "lifelines",
+ liquid = "liquid",
+ cl = "lisp",
+ L = "lisp",
+ lisp = "lisp",
+ el = "lisp",
+ lsp = "lisp",
+ asd = "lisp",
+ lt = "lite",
+ lite = "lite",
+ lgt = "logtalk",
+ lotos = "lotos",
+ lot = "lotos",
+ lout = "lout",
+ lou = "lout",
+ ulpc = "lpc",
+ lpc = "lpc",
+ sig = "lprolog",
+ lsl = "lsl",
+ lss = "lss",
+ nse = "lua",
+ rockspec = "lua",
+ lua = "lua",
+ quake = "m3quake",
+ at = "m4",
+ eml = "mail",
+ mk = "make",
+ mak = "make",
+ dsp = "make",
+ page = "mallard",
+ map = "map",
+ mws = "maple",
+ mpl = "maple",
+ mv = "maple",
+ mkdn = "markdown",
+ md = "markdown",
+ mdwn = "markdown",
+ mkd = "markdown",
+ markdown = "markdown",
+ mdown = "markdown",
+ mhtml = "mason",
+ comp = "mason",
+ mason = "mason",
+ master = "master",
+ mas = "master",
+ mel = "mel",
+ mf = "mf",
+ mgl = "mgl",
+ mgp = "mgp",
+ my = "mib",
+ mib = "mib",
+ mix = "mix",
+ mixal = "mix",
+ nb = "mma",
+ mmp = "mmp",
+ DEF = "modula2",
+ ["m2"] = "modula2",
+ MOD = "modula2",
+ mi = "modula2",
+ ssc = "monk",
+ monk = "monk",
+ tsc = "monk",
+ isc = "monk",
+ moo = "moo",
+ mp = "mp",
+ mof = "msidl",
+ odl = "msidl",
+ msql = "msql",
+ mu = "mupad",
+ mush = "mush",
+ mysql = "mysql",
+ ["n1ql"] = "n1ql",
+ nql = "n1ql",
+ nanorc = "nanorc",
+ ncf = "ncf",
+ nginx = "nginx",
+ ninja = "ninja",
+ nqc = "nqc",
+ roff = "nroff",
+ tmac = "nroff",
+ man = "nroff",
+ mom = "nroff",
+ nr = "nroff",
+ tr = "nroff",
+ nsi = "nsis",
+ nsh = "nsis",
+ obj = "obj",
+ mlt = "ocaml",
+ mly = "ocaml",
+ mll = "ocaml",
+ mlp = "ocaml",
+ mlip = "ocaml",
+ mli = "ocaml",
+ ml = "ocaml",
+ occ = "occam",
+ xom = "omnimark",
+ xin = "omnimark",
+ opam = "opam",
+ ["or"] = "openroad",
+ ora = "ora",
+ pxsl = "papp",
+ papp = "papp",
+ pxml = "papp",
+ pas = "pascal",
+ lpr = "pascal",
+ dpr = "pascal",
+ pbtxt = "pbtxt",
+ g = "pccts",
+ pcmk = "pcmk",
+ pdf = "pdf",
+ plx = "perl",
+ psgi = "perl",
+ al = "perl",
+ ctp = "php",
+ php = "php",
+ phtml = "php",
+ pike = "pike",
+ pmod = "pike",
+ rcp = "pilrc",
+ pli = "pli",
+ ["pl1"] = "pli",
+ ["p36"] = "plm",
+ plm = "plm",
+ pac = "plm",
+ plp = "plp",
+ pls = "plsql",
+ plsql = "plsql",
+ po = "po",
+ pot = "po",
+ pod = "pod",
+ pk = "poke",
+ ps = "postscr",
+ epsi = "postscr",
+ afm = "postscr",
+ epsf = "postscr",
+ eps = "postscr",
+ pfa = "postscr",
+ ai = "postscr",
+ pov = "pov",
+ ppd = "ppd",
+ it = "ppwiz",
+ ih = "ppwiz",
+ action = "privoxy",
+ pc = "proc",
+ pdb = "prolog",
+ pml = "promela",
+ proto = "proto",
+ ["psd1"] = "ps1",
+ ["psm1"] = "ps1",
+ ["ps1"] = "ps1",
+ pssc = "ps1",
+ ["ps1xml"] = "ps1xml",
+ psf = "psf",
+ psl = "psl",
+ arr = "pyret",
+ pxd = "pyrex",
+ pyx = "pyrex",
+ pyw = "python",
+ py = "python",
+ pyi = "python",
+ ptl = "python",
+ rad = "radiance",
+ mat = "radiance",
+ ["pod6"] = "raku",
+ rakudoc = "raku",
+ rakutest = "raku",
+ rakumod = "raku",
+ ["pm6"] = "raku",
+ raku = "raku",
+ ["t6"] = "raku",
+ ["p6"] = "raku",
+ raml = "raml",
+ rbs = "rbs",
+ rego = "rego",
+ rem = "remind",
+ remind = "remind",
+ frt = "reva",
+ testUnit = "rexx",
+ rex = "rexx",
+ orx = "rexx",
+ rexx = "rexx",
+ jrexx = "rexx",
+ rxj = "rexx",
+ rexxj = "rexx",
+ testGroup = "rexx",
+ rxo = "rexx",
+ Rd = "rhelp",
+ rd = "rhelp",
+ rib = "rib",
+ Rmd = "rmd",
+ rmd = "rmd",
+ smd = "rmd",
+ Smd = "rmd",
+ rnc = "rnc",
+ rng = "rng",
+ rnw = "rnoweb",
+ snw = "rnoweb",
+ Rnw = "rnoweb",
+ Snw = "rnoweb",
+ rsc = "routeros",
+ x = "rpcgen",
+ rpl = "rpl",
+ Srst = "rrst",
+ srst = "rrst",
+ Rrst = "rrst",
+ rrst = "rrst",
+ rst = "rst",
+ rtf = "rtf",
+ rjs = "ruby",
+ rxml = "ruby",
+ rb = "ruby",
+ rant = "ruby",
+ ru = "ruby",
+ rbw = "ruby",
+ gemspec = "ruby",
+ builder = "ruby",
+ rake = "ruby",
+ rs = "rust",
+ sas = "sas",
+ sass = "sass",
+ sa = "sather",
+ sbt = "sbt",
+ scala = "scala",
+ sc = "scala",
+ scd = "scdoc",
+ ss = "scheme",
+ scm = "scheme",
+ sld = "scheme",
+ rkt = "scheme",
+ rktd = "scheme",
+ rktl = "scheme",
+ sce = "scilab",
+ sci = "scilab",
+ scss = "scss",
+ sd = "sd",
+ sdc = "sdc",
+ pr = "sdl",
+ sdl = "sdl",
+ sed = "sed",
+ sexp = "sexplib",
+ sieve = "sieve",
+ siv = "sieve",
+ sil = "sil",
+ sim = "simula",
+ ["s85"] = "sinda",
+ sin = "sinda",
+ ssm = "sisu",
+ sst = "sisu",
+ ssi = "sisu",
+ ["_sst"] = "sisu",
+ ["-sst"] = "sisu",
+ il = "skill",
+ ils = "skill",
+ cdf = "skill",
+ sl = "slang",
+ ice = "slice",
+ score = "slrnsc",
+ tpl = "smarty",
+ ihlp = "smcl",
+ smcl = "smcl",
+ hlp = "smcl",
+ smith = "smith",
+ smt = "smith",
+ sml = "sml",
+ spt = "snobol4",
+ sno = "snobol4",
+ sln = "solution",
+ sparql = "sparql",
+ rq = "sparql",
+ spec = "spec",
+ spice = "spice",
+ sp = "spice",
+ spd = "spup",
+ spdata = "spup",
+ speedup = "spup",
+ spi = "spyce",
+ spy = "spyce",
+ tyc = "sql",
+ typ = "sql",
+ pkb = "sql",
+ tyb = "sql",
+ pks = "sql",
+ sqlj = "sqlj",
+ sqi = "sqr",
+ sqr = "sqr",
+ nut = "squirrel",
+ ["s28"] = "srec",
+ ["s37"] = "srec",
+ srec = "srec",
+ mot = "srec",
+ ["s19"] = "srec",
+ st = "st",
+ imata = "stata",
+ ["do"] = "stata",
+ mata = "stata",
+ ado = "stata",
+ stp = "stp",
+ svelte = "svelte",
+ svg = "svg",
+ swift = "swift",
+ svh = "systemverilog",
+ sv = "systemverilog",
+ tak = "tak",
+ task = "taskedit",
+ tm = "tcl",
+ tcl = "tcl",
+ itk = "tcl",
+ itcl = "tcl",
+ tk = "tcl",
+ jacl = "tcl",
+ tmpl = "template",
+ ti = "terminfo",
+ dtx = "tex",
+ ltx = "tex",
+ bbl = "tex",
+ latex = "tex",
+ sty = "tex",
+ texi = "texinfo",
+ txi = "texinfo",
+ texinfo = "texinfo",
+ text = "text",
+ tf = "tf",
+ tli = "tli",
+ toml = "toml",
+ tpp = "tpp",
+ treetop = "treetop",
+ slt = "tsalt",
+ tsscl = "tsscl",
+ tssgm = "tssgm",
+ tssop = "tssop",
+ tutor = "tutor",
+ twig = "twig",
+ ts = function(path, bufnr)
+ if getline(bufnr, 1):find("<%?xml") then
+ return "xml"
+ else
+ return "typescript"
+ end
+ end,
+ tsx = "typescriptreact",
+ uc = "uc",
+ uit = "uil",
+ uil = "uil",
+ sba = "vb",
+ vb = "vb",
+ dsm = "vb",
+ ctl = "vb",
+ vbs = "vb",
+ vr = "vera",
+ vri = "vera",
+ vrh = "vera",
+ v = "verilog",
+ va = "verilogams",
+ vams = "verilogams",
+ vhdl = "vhdl",
+ vst = "vhdl",
+ vhd = "vhdl",
+ hdl = "vhdl",
+ vho = "vhdl",
+ vbe = "vhdl",
+ vim = "vim",
+ vba = "vim",
+ mar = "vmasm",
+ cm = "voscm",
+ wrl = "vrml",
+ vroom = "vroom",
+ vue = "vue",
+ wat = "wast",
+ wast = "wast",
+ wm = "webmacro",
+ wbt = "winbatch",
+ wml = "wml",
+ wsml = "wsml",
+ ad = "xdefaults",
+ xhtml = "xhtml",
+ xht = "xhtml",
+ msc = "xmath",
+ msf = "xmath",
+ ["psc1"] = "xml",
+ tpm = "xml",
+ xliff = "xml",
+ atom = "xml",
+ xul = "xml",
+ cdxml = "xml",
+ mpd = "xml",
+ rss = "xml",
+ fsproj = "xml",
+ ui = "xml",
+ vbproj = "xml",
+ xlf = "xml",
+ wsdl = "xml",
+ csproj = "xml",
+ wpl = "xml",
+ xmi = "xml",
+ ["xpm2"] = "xpm2",
+ xqy = "xquery",
+ xqm = "xquery",
+ xquery = "xquery",
+ xq = "xquery",
+ xql = "xquery",
+ xs = "xs",
+ xsd = "xsd",
+ xsl = "xslt",
+ xslt = "xslt",
+ yy = "yacc",
+ ["y++"] = "yacc",
+ yxx = "yacc",
+ yml = "yaml",
+ yaml = "yaml",
+ ["z8a"] = "z8a",
+ zig = "zig",
+ zu = "zimbu",
+ zut = "zimbutempl",
+ zsh = "zsh",
+ E = function() vim.fn["dist#ft#FTe"]() end,
+ EU = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ EW = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ EX = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ EXU = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ EXW = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ PL = function() vim.fn["dist#ft#FTpl"]() end,
+ R = function() vim.fn["dist#ft#FTr"]() end,
+ asm = function() vim.fn["dist#ft#FTasm"]() end,
+ bas = function() vim.fn["dist#ft#FTVB"]("basic") end,
+ bash = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ btm = function() vim.fn["dist#ft#FTbtm"]() end,
+ c = function() vim.fn["dist#ft#FTlpc"]() end,
+ ch = function() vim.fn["dist#ft#FTchange"]() end,
+ com = function() vim.fn["dist#ft#BindzoneCheck"]('dcl') end,
+ cpt = function() vim.fn["dist#ft#FThtml"]() end,
+ csh = function() vim.fn["dist#ft#CSH"]() end,
+ d = function() vim.fn["dist#ft#DtraceCheck"]() end,
+ db = function() vim.fn["dist#ft#BindzoneCheck"]('') end,
+ dtml = function() vim.fn["dist#ft#FThtml"]() end,
+ e = function() vim.fn["dist#ft#FTe"]() end,
+ ebuild = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ eclass = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ ent = function() vim.fn["dist#ft#FTent"]() end,
+ env = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,
+ eu = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ ew = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ ex = function() vim.fn["dist#ft#ExCheck"]() end,
+ exu = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ exw = function() vim.fn["dist#ft#EuphoriaCheck"]() end,
+ frm = function() vim.fn["dist#ft#FTVB"]("form") end,
+ fs = function() vim.fn["dist#ft#FTfs"]() end,
+ h = function() vim.fn["dist#ft#FTheader"]() end,
+ htm = function() vim.fn["dist#ft#FThtml"]() end,
+ html = function() vim.fn["dist#ft#FThtml"]() end,
+ i = function() vim.fn["dist#ft#FTprogress_asm"]() end,
+ idl = function() vim.fn["dist#ft#FTidl"]() end,
+ inc = function() vim.fn["dist#ft#FTinc"]() end,
+ inp = function() vim.fn["dist#ft#Check_inp"]() end,
+ ksh = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end,
+ lst = function() vim.fn["dist#ft#FTasm"]() end,
+ m = function() vim.fn["dist#ft#FTm"]() end,
+ mac = function() vim.fn["dist#ft#FTasm"]() end,
+ mc = function() vim.fn["dist#ft#McSetf"]() end,
+ mm = function() vim.fn["dist#ft#FTmm"]() end,
+ mms = function() vim.fn["dist#ft#FTmms"]() end,
+ p = function() vim.fn["dist#ft#FTprogress_pascal"]() end,
+ pl = function() vim.fn["dist#ft#FTpl"]() end,
+ pp = function() vim.fn["dist#ft#FTpp"]() end,
+ pro = function() vim.fn["dist#ft#ProtoCheck"]('idlang') end,
+ pt = function() vim.fn["dist#ft#FThtml"]() end,
+ r = function() vim.fn["dist#ft#FTr"]() end,
+ rdf = function() vim.fn["dist#ft#Redif"]() end,
+ rules = function() vim.fn["dist#ft#FTRules"]() end,
+ sh = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,
+ shtml = function() vim.fn["dist#ft#FThtml"]() end,
+ sql = function() vim.fn["dist#ft#SQL"]() end,
+ stm = function() vim.fn["dist#ft#FThtml"]() end,
+ tcsh = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end,
+ tex = function() vim.fn["dist#ft#FTtex"]() end,
+ w = function() vim.fn["dist#ft#FTprogress_cweb"]() end,
+ xml = function() vim.fn["dist#ft#FTxml"]() end,
+ y = function() vim.fn["dist#ft#FTy"]() end,
+ zsql = function() vim.fn["dist#ft#SQL"]() end,
+ txt = function(path, bufnr)
+ --helpfiles match *.txt, but should have a modeline as last line
+ if not getline(bufnr, -1):match("vim:.*ft=help") then
+ return "text"
+ end
+ end,
+ -- END EXTENSION
+}
+
+local filename = {
+ -- BEGIN FILENAME
+ ["a2psrc"] = "a2ps",
+ ["/etc/a2ps.cfg"] = "a2ps",
+ [".a2psrc"] = "a2ps",
+ [".asoundrc"] = "alsaconf",
+ ["/usr/share/alsa/alsa.conf"] = "alsaconf",
+ ["/etc/asound.conf"] = "alsaconf",
+ ["build.xml"] = "ant",
+ [".htaccess"] = "apache",
+ ["apt.conf"] = "aptconf",
+ ["/.aptitude/config"] = "aptconf",
+ ["=tagging-method"] = "arch",
+ [".arch-inventory"] = "arch",
+ ["GNUmakefile.am"] = "automake",
+ ["named.root"] = "bindzone",
+ WORKSPACE = "bzl",
+ BUILD = "bzl",
+ ["cabal.config"] = "cabalconfig",
+ ["cabal.project"] = "cabalproject",
+ calendar = "calendar",
+ catalog = "catalog",
+ ["/etc/cdrdao.conf"] = "cdrdaoconf",
+ [".cdrdao"] = "cdrdaoconf",
+ ["/etc/default/cdrdao"] = "cdrdaoconf",
+ ["/etc/defaults/cdrdao"] = "cdrdaoconf",
+ ["cfengine.conf"] = "cfengine",
+ ["CMakeLists.txt"] = "cmake",
+ ["auto.master"] = "conf",
+ ["configure.in"] = "config",
+ ["configure.ac"] = "config",
+ [".cvsrc"] = "cvsrc",
+ ["/debian/changelog"] = "debchangelog",
+ ["changelog.dch"] = "debchangelog",
+ ["changelog.Debian"] = "debchangelog",
+ ["NEWS.dch"] = "debchangelog",
+ ["NEWS.Debian"] = "debchangelog",
+ ["/debian/control"] = "debcontrol",
+ ["/debian/copyright"] = "debcopyright",
+ ["/etc/apt/sources.list"] = "debsources",
+ ["denyhosts.conf"] = "denyhosts",
+ ["dict.conf"] = "dictconf",
+ [".dictrc"] = "dictconf",
+ ["/etc/DIR_COLORS"] = "dircolors",
+ [".dir_colors"] = "dircolors",
+ [".dircolors"] = "dircolors",
+ ["/etc/dnsmasq.conf"] = "dnsmasq",
+ Containerfile = "dockerfile",
+ Dockerfile = "dockerfile",
+ npmrc = "dosini",
+ ["/etc/yum.conf"] = "dosini",
+ ["/etc/pacman.conf"] = "dosini",
+ [".npmrc"] = "dosini",
+ [".editorconfig"] = "dosini",
+ dune = "dune",
+ jbuild = "dune",
+ ["dune-workspace"] = "dune",
+ ["dune-project"] = "dune",
+ ["elinks.conf"] = "elinks",
+ ["mix.lock"] = "elixir",
+ ["filter-rules"] = "elmfilt",
+ ["exim.conf"] = "exim",
+ exports = "exports",
+ [".fetchmailrc"] = "fetchmail",
+ fstab = "fstab",
+ mtab = "fstab",
+ [".gdbinit"] = "gdb",
+ gdbinit = "gdb",
+ ["lltxxxxx.txt"] = "gedcom",
+ ["TAG_EDITMSG"] = "gitcommit",
+ ["MERGE_MSG"] = "gitcommit",
+ ["COMMIT_EDITMSG"] = "gitcommit",
+ [".gitconfig"] = "gitconfig",
+ [".gitmodules"] = "gitconfig",
+ ["/.config/git/config"] = "gitconfig",
+ ["/etc/gitconfig"] = "gitconfig",
+ ["gitolite.conf"] = "gitolite",
+ ["git-rebase-todo"] = "gitrebase",
+ gkrellmrc = "gkrellmrc",
+ [".gnashrc"] = "gnash",
+ [".gnashpluginrc"] = "gnash",
+ gnashpluginrc = "gnash",
+ gnashrc = "gnash",
+ [".gprc"] = "gp",
+ ["/.gnupg/gpg.conf"] = "gpg",
+ ["/.gnupg/options"] = "gpg",
+ ["/var/backups/gshadow.bak"] = "group",
+ ["/etc/gshadow"] = "group",
+ ["/etc/group-"] = "group",
+ ["/etc/gshadow.edit"] = "group",
+ ["/etc/gshadow-"] = "group",
+ ["/etc/group"] = "group",
+ ["/var/backups/group.bak"] = "group",
+ ["/etc/group.edit"] = "group",
+ ["/boot/grub/menu.lst"] = "grub",
+ ["/etc/grub.conf"] = "grub",
+ ["/boot/grub/grub.conf"] = "grub",
+ [".gtkrc"] = "gtkrc",
+ gtkrc = "gtkrc",
+ ["snort.conf"] = "hog",
+ ["vision.conf"] = "hog",
+ ["/etc/host.conf"] = "hostconf",
+ ["/etc/hosts.allow"] = "hostsaccess",
+ ["/etc/hosts.deny"] = "hostsaccess",
+ ["/i3/config"] = "i3config",
+ ["/sway/config"] = "i3config",
+ ["/.sway/config"] = "i3config",
+ ["/.i3/config"] = "i3config",
+ ["/.icewm/menu"] = "icemenu",
+ [".indent.pro"] = "indent",
+ indentrc = "indent",
+ inittab = "inittab",
+ ["ipf.conf"] = "ipfilter",
+ ["ipf6.conf"] = "ipfilter",
+ ["ipf.rules"] = "ipfilter",
+ [".eslintrc"] = "json",
+ [".babelrc"] = "json",
+ ["Pipfile.lock"] = "json",
+ [".firebaserc"] = "json",
+ [".prettierrc"] = "json",
+ Kconfig = "kconfig",
+ ["Kconfig.debug"] = "kconfig",
+ ["lftp.conf"] = "lftp",
+ [".lftprc"] = "lftp",
+ ["/.libao"] = "libao",
+ ["/etc/libao.conf"] = "libao",
+ ["lilo.conf"] = "lilo",
+ ["/etc/limits"] = "limits",
+ [".emacs"] = "lisp",
+ sbclrc = "lisp",
+ [".sbclrc"] = "lisp",
+ [".sawfishrc"] = "lisp",
+ ["/etc/login.access"] = "loginaccess",
+ ["/etc/login.defs"] = "logindefs",
+ ["lynx.cfg"] = "lynx",
+ ["m3overrides"] = "m3build",
+ ["m3makefile"] = "m3build",
+ ["cm3.cfg"] = "m3quake",
+ [".followup"] = "mail",
+ [".article"] = "mail",
+ [".letter"] = "mail",
+ ["/etc/aliases"] = "mailaliases",
+ ["/etc/mail/aliases"] = "mailaliases",
+ mailcap = "mailcap",
+ [".mailcap"] = "mailcap",
+ ["/etc/man.conf"] = "manconf",
+ ["man.config"] = "manconf",
+ ["meson.build"] = "meson",
+ ["meson_options.txt"] = "meson",
+ ["/etc/conf.modules"] = "modconf",
+ ["/etc/modules"] = "modconf",
+ ["/etc/modules.conf"] = "modconf",
+ ["/.mplayer/config"] = "mplayerconf",
+ ["mplayer.conf"] = "mplayerconf",
+ mrxvtrc = "mrxvtrc",
+ [".mrxvtrc"] = "mrxvtrc",
+ ["/etc/nanorc"] = "nanorc",
+ Neomuttrc = "neomuttrc",
+ [".netrc"] = "netrc",
+ [".ocamlinit"] = "ocaml",
+ [".octaverc"] = "octave",
+ octaverc = "octave",
+ ["octave.conf"] = "octave",
+ opam = "opam",
+ ["/etc/pam.conf"] = "pamconf",
+ ["pam_env.conf"] = "pamenv",
+ [".pam_environment"] = "pamenv",
+ ["/var/backups/passwd.bak"] = "passwd",
+ ["/var/backups/shadow.bak"] = "passwd",
+ ["/etc/passwd"] = "passwd",
+ ["/etc/passwd-"] = "passwd",
+ ["/etc/shadow.edit"] = "passwd",
+ ["/etc/shadow-"] = "passwd",
+ ["/etc/shadow"] = "passwd",
+ ["/etc/passwd.edit"] = "passwd",
+ ["pf.conf"] = "pf",
+ ["main.cf"] = "pfmain",
+ pinerc = "pine",
+ [".pinercex"] = "pine",
+ [".pinerc"] = "pine",
+ pinercex = "pine",
+ ["/etc/pinforc"] = "pinfo",
+ ["/.pinforc"] = "pinfo",
+ [".povrayrc"] = "povini",
+ [".procmailrc"] = "procmail",
+ [".procmail"] = "procmail",
+ ["/etc/protocols"] = "protocols",
+ [".pythonstartup"] = "python",
+ [".pythonrc"] = "python",
+ SConstruct = "python",
+ ratpoisonrc = "ratpoison",
+ [".ratpoisonrc"] = "ratpoison",
+ v = "rcs",
+ inputrc = "readline",
+ [".inputrc"] = "readline",
+ [".reminders"] = "remind",
+ ["resolv.conf"] = "resolv",
+ ["robots.txt"] = "robots",
+ Gemfile = "ruby",
+ Puppetfile = "ruby",
+ [".irbrc"] = "ruby",
+ irbrc = "ruby",
+ ["smb.conf"] = "samba",
+ screenrc = "screen",
+ [".screenrc"] = "screen",
+ ["/etc/sensors3.conf"] = "sensors",
+ ["/etc/sensors.conf"] = "sensors",
+ ["/etc/services"] = "services",
+ ["/etc/serial.conf"] = "setserial",
+ ["/etc/udev/cdsymlinks.conf"] = "sh",
+ ["/etc/slp.conf"] = "slpconf",
+ ["/etc/slp.reg"] = "slpreg",
+ ["/etc/slp.spi"] = "slpspi",
+ [".slrnrc"] = "slrnrc",
+ ["sendmail.cf"] = "sm",
+ ["squid.conf"] = "squid",
+ ["/.ssh/config"] = "sshconfig",
+ ["ssh_config"] = "sshconfig",
+ ["sshd_config"] = "sshdconfig",
+ ["/etc/sudoers"] = "sudoers",
+ ["sudoers.tmp"] = "sudoers",
+ ["/etc/sysctl.conf"] = "sysctl",
+ tags = "tags",
+ [".tclshrc"] = "tcl",
+ [".wishrc"] = "tcl",
+ ["tclsh.rc"] = "tcl",
+ ["texmf.cnf"] = "texmf",
+ COPYING = "text",
+ README = "text",
+ LICENSE = "text",
+ AUTHORS = "text",
+ tfrc = "tf",
+ [".tfrc"] = "tf",
+ ["tidy.conf"] = "tidy",
+ tidyrc = "tidy",
+ [".tidyrc"] = "tidy",
+ ["/.cargo/config"] = "toml",
+ Pipfile = "toml",
+ ["Gopkg.lock"] = "toml",
+ ["/.cargo/credentials"] = "toml",
+ ["Cargo.lock"] = "toml",
+ ["trustees.conf"] = "trustees",
+ ["/etc/udev/udev.conf"] = "udevconf",
+ ["/etc/updatedb.conf"] = "updatedb",
+ ["fdrupstream.log"] = "upstreamlog",
+ vgrindefs = "vgrindefs",
+ [".exrc"] = "vim",
+ ["_exrc"] = "vim",
+ ["_viminfo"] = "viminfo",
+ [".viminfo"] = "viminfo",
+ [".wgetrc"] = "wget",
+ wgetrc = "wget",
+ [".wvdialrc"] = "wvdial",
+ ["wvdial.conf"] = "wvdial",
+ [".Xresources"] = "xdefaults",
+ [".Xpdefaults"] = "xdefaults",
+ ["xdm-config"] = "xdefaults",
+ [".Xdefaults"] = "xdefaults",
+ ["/etc/xinetd.conf"] = "xinetd",
+ fglrxrc = "xml",
+ ["/etc/blkid.tab"] = "xml",
+ ["/etc/blkid.tab.old"] = "xml",
+ ["/etc/zprofile"] = "zsh",
+ [".zlogin"] = "zsh",
+ [".zlogout"] = "zsh",
+ [".zshrc"] = "zsh",
+ [".zprofile"] = "zsh",
+ [".zcompdump"] = "zsh",
+ [".zshenv"] = "zsh",
+ [".zfbfmarks"] = "zsh",
+ [".alias"] = function() vim.fn["dist#ft#CSH"]() end,
+ [".bashrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ [".cshrc"] = function() vim.fn["dist#ft#CSH"]() end,
+ [".kshrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end,
+ [".login"] = function() vim.fn["dist#ft#CSH"]() end,
+ [".profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,
+ [".tcshrc"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end,
+ ["/etc/profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,
+ APKBUILD = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ PKGBUILD = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ ["bash.bashrc"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ bashrc = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ crontab = starsetf('crontab'),
+ ["csh.cshrc"] = function() vim.fn["dist#ft#CSH"]() end,
+ ["csh.login"] = function() vim.fn["dist#ft#CSH"]() end,
+ ["csh.logout"] = function() vim.fn["dist#ft#CSH"]() end,
+ ["indent.pro"] = function() vim.fn["dist#ft#ProtoCheck"]('indent') end,
+ ["tcsh.login"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end,
+ ["tcsh.tcshrc"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end,
+ -- END FILENAME
+}
+
+local pattern = {
+ -- BEGIN PATTERN
+ [".*/etc/a2ps/.*%.cfg"] = "a2ps",
+ [".*/etc/a2ps%.cfg"] = "a2ps",
+ [".*/usr/share/alsa/alsa%.conf"] = "alsaconf",
+ [".*/etc/asound%.conf"] = "alsaconf",
+ [".*/etc/apache2/sites%-.*/.*%.com"] = "apache",
+ [".*/etc/httpd/.*%.conf"] = "apache",
+ [".*/%.aptitude/config"] = "aptconf",
+ ["[mM]akefile%.am"] = "automake",
+ [".*bsd"] = "bsdl",
+ ["bzr_log%..*"] = "bzr",
+ [".*enlightenment/.*%.cfg"] = "c",
+ [".*/etc/defaults/cdrdao"] = "cdrdaoconf",
+ [".*/etc/cdrdao%.conf"] = "cdrdaoconf",
+ [".*/etc/default/cdrdao"] = "cdrdaoconf",
+ [".*hgrc"] = "cfg",
+ [".*%.%.ch"] = "chill",
+ [".*%.cmake%.in"] = "cmake",
+ [".*/debian/changelog"] = "debchangelog",
+ [".*/debian/control"] = "debcontrol",
+ [".*/debian/copyright"] = "debcopyright",
+ [".*/etc/apt/sources%.list%.d/.*%.list"] = "debsources",
+ [".*/etc/apt/sources%.list"] = "debsources",
+ ["dictd.*%.conf"] = "dictdconf",
+ [".*/etc/DIR_COLORS"] = "dircolors",
+ [".*/etc/dnsmasq%.conf"] = "dnsmasq",
+ ["php%.ini%-.*"] = "dosini",
+ [".*/etc/pacman%.conf"] = "dosini",
+ [".*/etc/yum%.conf"] = "dosini",
+ [".*lvs"] = "dracula",
+ [".*lpe"] = "dracula",
+ [".*esmtprc"] = "esmtprc",
+ [".*Eterm/.*%.cfg"] = "eterm",
+ [".*%.git/modules/.*/config"] = "gitconfig",
+ [".*%.git/config"] = "gitconfig",
+ [".*/%.config/git/config"] = "gitconfig",
+ ["%.gitsendemail%.msg%......."] = "gitsendemail",
+ ["gkrellmrc_."] = "gkrellmrc",
+ [".*/usr/.*/gnupg/options%.skel"] = "gpg",
+ [".*/%.gnupg/options"] = "gpg",
+ [".*/%.gnupg/gpg%.conf"] = "gpg",
+ [".*/etc/group"] = "group",
+ [".*/etc/gshadow"] = "group",
+ [".*/etc/group%.edit"] = "group",
+ [".*/var/backups/gshadow%.bak"] = "group",
+ [".*/etc/group-"] = "group",
+ [".*/etc/gshadow-"] = "group",
+ [".*/var/backups/group%.bak"] = "group",
+ [".*/etc/gshadow%.edit"] = "group",
+ [".*/boot/grub/grub%.conf"] = "grub",
+ [".*/boot/grub/menu%.lst"] = "grub",
+ [".*/etc/grub%.conf"] = "grub",
+ ["hg%-editor%-.*%.txt"] = "hgcommit",
+ [".*/etc/host%.conf"] = "hostconf",
+ [".*/etc/hosts%.deny"] = "hostsaccess",
+ [".*/etc/hosts%.allow"] = "hostsaccess",
+ [".*%.html%.m4"] = "htmlm4",
+ [".*/%.i3/config"] = "i3config",
+ [".*/sway/config"] = "i3config",
+ [".*/i3/config"] = "i3config",
+ [".*/%.sway/config"] = "i3config",
+ [".*/%.icewm/menu"] = "icemenu",
+ [".*/etc/initng/.*/.*%.i"] = "initng",
+ [".*%.properties_.."] = "jproperties",
+ [".*%.properties_.._.."] = "jproperties",
+ [".*lftp/rc"] = "lftp",
+ [".*/%.libao"] = "libao",
+ [".*/etc/libao%.conf"] = "libao",
+ [".*/etc/.*limits%.conf"] = "limits",
+ [".*/etc/limits"] = "limits",
+ [".*/etc/.*limits%.d/.*%.conf"] = "limits",
+ [".*/LiteStep/.*/.*%.rc"] = "litestep",
+ [".*/etc/login%.access"] = "loginaccess",
+ [".*/etc/login%.defs"] = "logindefs",
+ [".*/etc/mail/aliases"] = "mailaliases",
+ [".*/etc/aliases"] = "mailaliases",
+ [".*[mM]akefile"] = "make",
+ [".*/etc/man%.conf"] = "manconf",
+ [".*/etc/modules%.conf"] = "modconf",
+ [".*/etc/conf%.modules"] = "modconf",
+ [".*/etc/modules"] = "modconf",
+ [".*%.[mi][3g]"] = "modula3",
+ [".*/%.mplayer/config"] = "mplayerconf",
+ ["rndc.*%.conf"] = "named",
+ ["rndc.*%.key"] = "named",
+ ["named.*%.conf"] = "named",
+ [".*/etc/nanorc"] = "nanorc",
+ [".*%.NS[ACGLMNPS]"] = "natural",
+ ["nginx.*%.conf"] = "nginx",
+ [".*/etc/nginx/.*"] = "nginx",
+ [".*nginx%.conf"] = "nginx",
+ [".*/nginx/.*%.conf"] = "nginx",
+ [".*/usr/local/nginx/conf/.*"] = "nginx",
+ [".*%.ml%.cppo"] = "ocaml",
+ [".*%.mli%.cppo"] = "ocaml",
+ [".*%.opam%.template"] = "opam",
+ [".*%.[Oo][Pp][Ll]"] = "opl",
+ [".*/etc/pam%.conf"] = "pamconf",
+ [".*/etc/passwd-"] = "passwd",
+ [".*/etc/shadow"] = "passwd",
+ [".*/etc/shadow%.edit"] = "passwd",
+ [".*/var/backups/shadow%.bak"] = "passwd",
+ [".*/var/backups/passwd%.bak"] = "passwd",
+ [".*/etc/passwd"] = "passwd",
+ [".*/etc/passwd%.edit"] = "passwd",
+ [".*/etc/shadow-"] = "passwd",
+ [".*/%.pinforc"] = "pinfo",
+ [".*/etc/pinforc"] = "pinfo",
+ [".*/etc/protocols"] = "protocols",
+ [".*baseq[2-3]/.*%.cfg"] = "quake",
+ [".*quake[1-3]/.*%.cfg"] = "quake",
+ [".*id1/.*%.cfg"] = "quake",
+ ["[rR]antfile"] = "ruby",
+ ["[rR]akefile"] = "ruby",
+ [".*/etc/sensors%.conf"] = "sensors",
+ [".*/etc/sensors3%.conf"] = "sensors",
+ [".*/etc/services"] = "services",
+ [".*/etc/serial%.conf"] = "setserial",
+ [".*/etc/udev/cdsymlinks%.conf"] = "sh",
+ [".*%._sst%.meta"] = "sisu",
+ [".*%.%-sst%.meta"] = "sisu",
+ [".*%.sst%.meta"] = "sisu",
+ [".*/etc/slp%.conf"] = "slpconf",
+ [".*/etc/slp%.reg"] = "slpreg",
+ [".*/etc/slp%.spi"] = "slpspi",
+ [".*/etc/ssh/ssh_config%.d/.*%.conf"] = "sshconfig",
+ [".*/%.ssh/config"] = "sshconfig",
+ [".*/etc/ssh/sshd_config%.d/.*%.conf"] = "sshdconfig",
+ [".*/etc/sudoers"] = "sudoers",
+ ["svn%-commit.*%.tmp"] = "svn",
+ [".*%.swift%.gyb"] = "swiftgyb",
+ [".*/etc/sysctl%.conf"] = "sysctl",
+ [".*/etc/sysctl%.d/.*%.conf"] = "sysctl",
+ [".*/etc/systemd/.*%.conf%.d/.*%.conf"] = "systemd",
+ [".*/%.config/systemd/user/.*%.d/.*%.conf"] = "systemd",
+ [".*/etc/systemd/system/.*%.d/.*%.conf"] = "systemd",
+ [".*%.t%.html"] = "tilde",
+ [".*/%.cargo/config"] = "toml",
+ [".*/%.cargo/credentials"] = "toml",
+ [".*/etc/udev/udev%.conf"] = "udevconf",
+ [".*/etc/udev/permissions%.d/.*%.permissions"] = "udevperm",
+ [".*/etc/updatedb%.conf"] = "updatedb",
+ [".*/%.init/.*%.override"] = "upstart",
+ [".*/usr/share/upstart/.*%.conf"] = "upstart",
+ [".*/%.config/upstart/.*%.override"] = "upstart",
+ [".*/etc/init/.*%.conf"] = "upstart",
+ [".*/etc/init/.*%.override"] = "upstart",
+ [".*/%.config/upstart/.*%.conf"] = "upstart",
+ [".*/%.init/.*%.conf"] = "upstart",
+ [".*/usr/share/upstart/.*%.override"] = "upstart",
+ [".*%.ws[fc]"] = "wsh",
+ [".*/etc/xinetd%.conf"] = "xinetd",
+ [".*/etc/blkid%.tab"] = "xml",
+ [".*/etc/blkid%.tab%.old"] = "xml",
+ [".*%.vbproj%.user"] = "xml",
+ [".*%.fsproj%.user"] = "xml",
+ [".*%.csproj%.user"] = "xml",
+ [".*/etc/xdg/menus/.*%.menu"] = "xml",
+ [".*Xmodmap"] = "xmodmap",
+ [".*/etc/zprofile"] = "zsh",
+ ["%.bash[_-]aliases"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ ["%.bash[_-]logout"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ ["%.bash[_-]profile"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ ["%.cshrc.*"] = function() vim.fn["dist#ft#CSH"]() end,
+ ["%.gtkrc.*"] = starsetf('gtkrc'),
+ ["%.kshrc.*"] = function() vim.fn["dist#ft#SetFileTypeSH"]("ksh") end,
+ ["%.login.*"] = function() vim.fn["dist#ft#CSH"]() end,
+ ["%.neomuttrc.*"] = starsetf('neomuttrc'),
+ ["%.profile.*"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,
+ ["%.reminders.*"] = starsetf('remind'),
+ ["%.tcshrc.*"] = function() vim.fn["dist#ft#SetFileTypeShell"]("tcsh") end,
+ ["%.zcompdump.*"] = starsetf('zsh'),
+ ["%.zlog.*"] = starsetf('zsh'),
+ ["%.zsh.*"] = starsetf('zsh'),
+ [".*%.[1-9]"] = function() vim.fn["dist#ft#FTnroff"]() end,
+ [".*%.[aA]"] = function() vim.fn["dist#ft#FTasm"]() end,
+ [".*%.[sS]"] = function() vim.fn["dist#ft#FTasm"]() end,
+ [".*%.properties_.._.._.*"] = starsetf('jproperties'),
+ [".*%.vhdl_[0-9].*"] = starsetf('vhdl'),
+ [".*/%.fvwm/.*"] = starsetf('fvwm'),
+ [".*/%.gitconfig%.d/.*"] = starsetf('gitconfig'),
+ [".*/%.neomutt/neomuttrc.*"] = starsetf('neomuttrc'),
+ [".*/Xresources/.*"] = starsetf('xdefaults'),
+ [".*/app%-defaults/.*"] = starsetf('xdefaults'),
+ [".*/bind/db%..*"] = starsetf('bindzone'),
+ [".*/debian/patches/.*"] = function() vim.fn["dist#ft#Dep3patch"]() end,
+ [".*/etc/Muttrc%.d/.*"] = starsetf('muttrc'),
+ [".*/etc/apache2/.*%.conf.*"] = starsetf('apache'),
+ [".*/etc/apache2/conf%..*/.*"] = starsetf('apache'),
+ [".*/etc/apache2/mods%-.*/.*"] = starsetf('apache'),
+ [".*/etc/apache2/sites%-.*/.*"] = starsetf('apache'),
+ [".*/etc/cron%.d/.*"] = starsetf('crontab'),
+ [".*/etc/dnsmasq%.d/.*"] = starsetf('dnsmasq'),
+ [".*/etc/httpd/conf%..*/.*"] = starsetf('apache'),
+ [".*/etc/httpd/conf%.d/.*%.conf.*"] = starsetf('apache'),
+ [".*/etc/httpd/mods%-.*/.*"] = starsetf('apache'),
+ [".*/etc/httpd/sites%-.*/.*"] = starsetf('apache'),
+ [".*/etc/logcheck/.*%.d.*/.*"] = starsetf('logcheck'),
+ [".*/etc/modprobe%..*"] = starsetf('modconf'),
+ [".*/etc/pam%.d/.*"] = starsetf('pamconf'),
+ [".*/etc/profile"] = function() vim.fn["dist#ft#SetFileTypeSH"](vim.fn.getline(1)) end,
+ [".*/etc/proftpd/.*%.conf.*"] = starsetf('apachestyle'),
+ [".*/etc/proftpd/conf%..*/.*"] = starsetf('apachestyle'),
+ [".*/etc/sudoers%.d/.*"] = starsetf('sudoers'),
+ [".*/etc/xinetd%.d/.*"] = starsetf('xinetd'),
+ [".*/etc/yum%.repos%.d/.*"] = starsetf('dosini'),
+ [".*/gitolite%-admin/conf/.*"] = starsetf('gitolite'),
+ [".*/named/db%..*"] = starsetf('bindzone'),
+ [".*/tmp/lltmp.*"] = starsetf('gedcom'),
+ [".*asterisk.*/.*voicemail%.conf.*"] = starsetf('asteriskvm'),
+ [".*asterisk/.*%.conf.*"] = starsetf('asterisk'),
+ [".*vimrc.*"] = starsetf('vim'),
+ [".*xmodmap.*"] = starsetf('xmodmap'),
+ ["/etc/gitconfig%.d/.*"] = starsetf('gitconfig'),
+ ["/etc/hostname%..*"] = starsetf('config'),
+ ["Containerfile%..*"] = starsetf('dockerfile'),
+ ["Dockerfile%..*"] = starsetf('dockerfile'),
+ ["JAM.*%..*"] = starsetf('jam'),
+ ["Kconfig%..*"] = starsetf('kconfig'),
+ ["Neomuttrc.*"] = starsetf('neomuttrc'),
+ ["Prl.*%..*"] = starsetf('jam'),
+ ["Xresources.*"] = starsetf('xdefaults'),
+ ["[mM]akefile.*"] = starsetf('make'),
+ ["[rR]akefile.*"] = starsetf('ruby'),
+ ["access%.conf.*"] = starsetf('apache'),
+ ["apache%.conf.*"] = starsetf('apache'),
+ ["apache2%.conf.*"] = starsetf('apache'),
+ ["bash%-fc[-%.]"] = function() vim.fn["dist#ft#SetFileTypeSH"]("bash") end,
+ ["cabal%.project%..*"] = starsetf('cabalproject'),
+ ["crontab%..*"] = starsetf('crontab'),
+ ["drac%..*"] = starsetf('dracula'),
+ ["gtkrc.*"] = starsetf('gtkrc'),
+ ["httpd%.conf.*"] = starsetf('apache'),
+ ["lilo%.conf.*"] = starsetf('lilo'),
+ ["neomuttrc.*"] = starsetf('neomuttrc'),
+ ["proftpd%.conf.*"] = starsetf('apachestyle'),
+ ["reportbug%-.*"] = starsetf('mail'),
+ ["sgml%.catalog.*"] = starsetf('catalog'),
+ ["srm%.conf.*"] = starsetf('apache'),
+ ["tmac%..*"] = starsetf('nroff'),
+ ["zlog.*"] = starsetf('zsh'),
+ ["zsh.*"] = starsetf('zsh'),
+ ["ae%d+%.txt"] = 'mail',
+ -- END PATTERN
+}
+-- luacheck: pop
+
+---@private
+local function sort_by_priority(t)
+ local sorted = {}
+ for k, v in pairs(t) do
+ local ft = type(v) == "table" and v[1] or v
+ assert(type(ft) == "string" or type(ft) == "function", "Expected string or function for filetype")
+
+ local opts = (type(v) == "table" and type(v[2]) == "table") and v[2] or {}
+ if not opts.priority then
+ opts.priority = 0
+ end
+ table.insert(sorted, { [k] = { ft, opts } })
+ end
+ table.sort(sorted, function(a, b)
+ return a[next(a)][2].priority > b[next(b)][2].priority
+ end)
+ return sorted
+end
+
+local pattern_sorted = sort_by_priority(pattern)
+
+---@private
+local function normalize_path(path)
+ return (path:gsub("\\", "/"))
+end
+
+--- Add new filetype mappings.
+---
+--- Filetype mappings can be added either by extension or by filename (either
+--- the "tail" or the full file path). The full file path is checked first,
+--- followed by the file name. If a match is not found using the filename, then
+--- the filename is matched against the list of patterns (sorted by priority)
+--- until a match is found. Lastly, if pattern matching does not find a
+--- filetype, then the file extension is used.
+---
+--- The filetype can be either a string (in which case it is used as the
+--- filetype directly) or a function. If a function, it takes the full path and
+--- buffer number of the file as arguments (along with captures from the matched
+--- pattern, if any) and should return a string that will be used as the
+--- buffer's filetype.
+---
+--- Filename patterns can specify an optional priority to resolve cases when a
+--- file path matches multiple patterns. Higher priorities are matched first.
+--- When omitted, the priority defaults to 0.
+---
+--- See $VIMRUNTIME/lua/vim/filetype.lua for more examples.
+---
+--- Note that Lua filetype detection is only enabled when |g:do_filetype_lua| is
+--- set to 1.
+---
+--- Example:
+--- <pre>
+--- vim.filetype.add({
+--- extension = {
+--- foo = "fooscript",
+--- bar = function(path, bufnr)
+--- if some_condition() then
+--- return "barscript"
+--- end
+--- return "bar"
+--- end,
+--- },
+--- filename = {
+--- [".foorc"] = "toml",
+--- ["/etc/foo/config"] = "toml",
+--- },
+--- pattern = {
+--- [".*/etc/foo/.*"] = "fooscript",
+--- -- Using an optional priority
+--- [".*/etc/foo/.*%.conf"] = { "dosini", { priority = 10 } },
+--- ["README.(%a+)$"] = function(path, bufnr, ext)
+--- if ext == "md" then
+--- return "markdown"
+--- elseif ext == "rst" then
+--- return "rst"
+--- end
+--- end,
+--- },
+--- })
+--- </pre>
+---
+---@param filetypes table A table containing new filetype maps (see example).
+function M.add(filetypes)
+ for k, v in pairs(filetypes.extension or {}) do
+ extension[k] = v
+ end
+
+ for k, v in pairs(filetypes.filename or {}) do
+ filename[normalize_path(k)] = v
+ end
+
+ for k, v in pairs(filetypes.pattern or {}) do
+ pattern[normalize_path(k)] = v
+ end
+
+ if filetypes.pattern then
+ pattern_sorted = sort_by_priority(pattern)
+ end
+end
+
+---@private
+local function dispatch(ft, path, bufnr, ...)
+ if type(ft) == "function" then
+ ft = ft(path, bufnr, ...)
+ end
+
+ if type(ft) == "string" then
+ api.nvim_buf_set_option(bufnr, "filetype", ft)
+ return true
+ end
+
+ -- Any non-falsey value (that is, anything other than 'nil' or 'false') will
+ -- end filetype matching. This is useful for e.g. the dist#ft functions that
+ -- return 0, but set the buffer's filetype themselves
+ return ft
+end
+
+---@private
+function M.match(name, bufnr)
+ -- When fired from the main filetypedetect autocommand the {bufnr} argument is omitted, so we use
+ -- the current buffer. The {bufnr} argument is provided to allow extensibility in case callers
+ -- wish to perform filetype detection on buffers other than the current one.
+ bufnr = bufnr or api.nvim_get_current_buf()
+
+ name = normalize_path(name)
+
+ -- First check for the simple case where the full path exists as a key
+ local path = vim.fn.resolve(vim.fn.fnamemodify(name, ":p"))
+ if dispatch(filename[path], path, bufnr) then
+ return
+ end
+
+ -- Next check against just the file name
+ local tail = vim.fn.fnamemodify(name, ":t")
+ if dispatch(filename[tail], path, bufnr) then
+ return
+ end
+
+ -- Next, check the file path against available patterns
+ for _, v in ipairs(pattern_sorted) do
+ local k = next(v)
+ local ft = v[k][1]
+ -- If the pattern contains a / match against the full path, otherwise just the tail
+ local pat = "^" .. k .. "$"
+ local matches
+ if k:find("/") then
+ -- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against
+ -- both the short file name (as typed) and the full file name (after expanding to full path
+ -- and resolving symlinks)
+ matches = name:match(pat) or path:match(pat)
+ else
+ matches = tail:match(pat)
+ end
+ if matches then
+ if dispatch(ft, path, bufnr, matches) then
+ return
+ end
+ end
+ end
+
+ -- Finally, check file extension
+ local ext = vim.fn.fnamemodify(name, ":e")
+ if dispatch(extension[ext], path, bufnr) then
+ return
+ end
+end
+
+return M
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 00839ec181..7df0064b6b 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -256,7 +256,7 @@ local function validate_client_config(config)
(not config.flags
or not config.flags.debounce_text_changes
or type(config.flags.debounce_text_changes) == 'number'),
- "flags.debounce_text_changes must be nil or a number with the debounce time in milliseconds"
+ "flags.debounce_text_changes must be a number with the debounce time in milliseconds"
)
local cmd, cmd_args = lsp._cmd_parts(config.cmd)
@@ -290,7 +290,7 @@ end
--- Memoizes a function. On first run, the function return value is saved and
--- immediately returned on subsequent runs. If the function returns a multival,
--- only the first returned value will be memoized and returned. The function will only be run once,
---- even if it has side-effects.
+--- even if it has side effects.
---
---@param fn (function) Function to run
---@returns (function) Memoized function
@@ -383,8 +383,8 @@ do
return
end
local state = state_by_client[client.id]
- local debounce = client.config.flags.debounce_text_changes
- if not debounce then
+ local debounce = client.config.flags.debounce_text_changes or 150
+ if debounce == 0 then
local changes = state.use_incremental_sync and incremental_changes(client) or full_changes()
client.notify("textDocument/didChange", {
textDocument = {
@@ -645,8 +645,8 @@ end
---@param on_error Callback with parameters (code, ...), invoked
--- when the client operation throws an error. `code` is a number describing
--- the error. Other arguments may be passed depending on the error kind. See
---- |vim.lsp.client_errors| for possible errors.
---- Use `vim.lsp.client_errors[code]` to get human-friendly name.
+--- |vim.lsp.rpc.client_errors| for possible errors.
+--- Use `vim.lsp.rpc.client_errors[code]` to get human-friendly name.
---
---@param before_init Callback with parameters (initialize_params, config)
--- invoked before the LSP "initialize" phase, where `params` contains the
@@ -757,8 +757,8 @@ function lsp.start_client(config)
---
---@param code (number) Error code
---@param err (...) Other arguments may be passed depending on the error kind
- ---@see |vim.lsp.client_errors| for possible errors. Use
- ---`vim.lsp.client_errors[code]` to get a human-friendly name.
+ ---@see |vim.lsp.rpc.client_errors| for possible errors. Use
+ ---`vim.lsp.rpc.client_errors[code]` to get a human-friendly name.
function dispatch.on_error(code, err)
local _ = log.error() and log.error(log_prefix, "on_error", { code = lsp.client_errors[code], err = err })
err_message(log_prefix, ': Error ', lsp.client_errors[code], ': ', vim.inspect(err))
@@ -897,7 +897,7 @@ function lsp.start_client(config)
client.initialized = true
uninitialized_clients[client_id] = nil
client.workspace_folders = workspace_folders
- -- TODO(mjlbach): Backwards compatbility, to be removed in 0.7
+ -- TODO(mjlbach): Backwards compatibility, to be removed in 0.7
client.workspaceFolders = client.workspace_folders
client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities")
-- These are the cleaned up capabilities we use for dynamically deciding
@@ -1131,7 +1131,7 @@ function lsp._text_document_did_save_handler(bufnr)
if client.resolved_capabilities.text_document_save then
local included_text
if client.resolved_capabilities.text_document_save_include_text then
- included_text = text()
+ included_text = text(bufnr)
end
client.notify('textDocument/didSave', {
textDocument = {
@@ -1708,14 +1708,14 @@ end
--
-- Can be used to lookup the number from the name or the
-- name from the number.
--- Levels by name: "trace", "debug", "info", "warn", "error"
--- Level numbers begin with "trace" at 0
+-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR"
+-- Level numbers begin with "TRACE" at 0
lsp.log_levels = log.levels
--- Sets the global log level for LSP logging.
---
---- Levels by name: "trace", "debug", "info", "warn", "error"
---- Level numbers begin with "trace" at 0
+--- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR"
+--- Level numbers begin with "TRACE" at 0
---
--- Use `lsp.log_levels` for reverse lookup.
---
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index 8e3ed9b002..543fdb0237 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -453,7 +453,7 @@ end
--- Send request to the server to resolve document highlights for the current
--- text document position. This request can be triggered by a key mapping or
---- by events such as `CursorHold`, eg:
+--- by events such as `CursorHold`, e.g.:
---
--- <pre>
--- autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index c974d1a6b4..a48302cc4b 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -246,7 +246,7 @@ end
---@param config table Configuration table.
--- - border: (default=nil)
--- - Add borders to the floating window
---- - See |vim.api.nvim_open_win()|
+--- - See |nvim_open_win()|
function M.hover(_, result, ctx, config)
config = config or {}
config.focus_id = ctx.method
@@ -439,14 +439,20 @@ for k, fn in pairs(M) do
})
if err then
- local client = vim.lsp.get_client_by_id(ctx.client_id)
- local client_name = client and client.name or string.format("client_id=%d", ctx.client_id)
-- LSP spec:
-- interface ResponseError:
-- code: integer;
-- message: string;
-- data?: string | number | boolean | array | object | null;
- return err_message(client_name .. ': ' .. tostring(err.code) .. ': ' .. err.message)
+
+ -- Per LSP, don't show ContentModified error to the user.
+ if err.code ~= protocol.ErrorCodes.ContentModified then
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
+ local client_name = client and client.name or string.format("client_id=%d", ctx.client_id)
+
+ err_message(client_name .. ': ' .. tostring(err.code) .. ': ' .. err.message)
+ end
+ return
end
return fn(err, result, ctx, config)
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index dbc473b52c..e0b5653587 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -8,8 +8,8 @@ local log = {}
-- Log level dictionary with reverse lookup as well.
--
-- Can be used to lookup the number from the name or the name from the number.
--- Levels by name: 'trace', 'debug', 'info', 'warn', 'error'
--- Level numbers begin with 'trace' at 0
+-- Levels by name: "TRACE", "DEBUG", "INFO", "WARN", "ERROR"
+-- Level numbers begin with "TRACE" at 0
log.levels = vim.deepcopy(vim.log.levels)
-- Default log level is warn.
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 1fb75ddeb7..1ecac50df4 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -133,7 +133,8 @@ local function request_parser_loop()
end
end
-local client_errors = vim.tbl_add_reverse_lookup {
+--- Mapping of error codes used by the client
+local client_errors = {
INVALID_SERVER_MESSAGE = 1;
INVALID_SERVER_JSON = 2;
NO_RESULT_CALLBACK_FOUND = 3;
@@ -143,6 +144,8 @@ local client_errors = vim.tbl_add_reverse_lookup {
SERVER_RESULT_CALLBACK_ERROR = 7;
}
+client_errors = vim.tbl_add_reverse_lookup(client_errors)
+
--- Constructs an error message from an LSP error object.
---
---@param err (table) The error object
diff --git a/runtime/lua/vim/lsp/sync.lua b/runtime/lua/vim/lsp/sync.lua
index d01f45ad8f..0f4e5b572b 100644
--- a/runtime/lua/vim/lsp/sync.lua
+++ b/runtime/lua/vim/lsp/sync.lua
@@ -298,7 +298,7 @@ end
---@private
-- rangelength depends on the offset encoding
--- bytes for utf-8 (clangd with extenion)
+-- bytes for utf-8 (clangd with extension)
-- codepoints for utf-16
-- codeunits for utf-32
-- Line endings count here as 2 chars for \r\n (dos), 1 char for \n (unix), and 1 char for \r (mac)
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 5921eb5bf0..dcd68a3433 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1000,10 +1000,10 @@ function M.jump_to_location(location)
--- Jump to new location (adjusting for UTF-16 encoding of characters)
api.nvim_set_current_buf(bufnr)
- api.nvim_buf_set_option(0, 'buflisted', true)
+ api.nvim_buf_set_option(bufnr, 'buflisted', true)
local range = location.range or location.targetSelectionRange
local row = range.start.line
- local col = get_line_byte_from_position(0, range.start)
+ local col = get_line_byte_from_position(bufnr, range.start)
api.nvim_win_set_cursor(0, {row + 1, col})
-- Open folds under the cursor
vim.cmd("normal! zv")
@@ -1505,7 +1505,7 @@ do --[[ References ]]
---@param bufnr number Buffer id
function M.buf_clear_references(bufnr)
validate { bufnr = {bufnr, 'n', true} }
- api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
+ api.nvim_buf_clear_namespace(bufnr or 0, reference_ns, 0, -1)
end
--- Shows a list of document highlights for a certain buffer.
@@ -1677,7 +1677,7 @@ function M.symbols_to_items(symbols, bufnr)
end
return _items
end
- return _symbols_to_items(symbols, {}, bufnr)
+ return _symbols_to_items(symbols, {}, bufnr or 0)
end
--- Removes empty lines from the beginning and end.
@@ -1796,7 +1796,7 @@ end
---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
---`current_position`, end = `current_position` } }
function M.make_range_params(window, offset_encoding)
- local buf = vim.api.nvim_win_get_buf(window)
+ local buf = vim.api.nvim_win_get_buf(window or 0)
offset_encoding = offset_encoding or M._get_offset_encoding(buf)
local position = make_position_param(window, offset_encoding)
return {
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 1cf618725d..e170befa4c 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -526,13 +526,23 @@ end
--- => error('arg1: expected even number, got 3')
--- </pre>
---
----@param opt Map of parameter names to validations. Each key is a parameter
+--- If multiple types are valid they can be given as a list.
+--- <pre>
+--- vim.validate{arg1={{'foo'}, {'table', 'string'}}, arg2={'foo', {'table', 'string'}}}
+--- => NOP (success)
+---
+--- vim.validate{arg1={1, {'string', table'}}}
+--- => error('arg1: expected string|table, got number')
+---
+--- </pre>
+---
+---@param opt table of parameter names to validations. Each key is a parameter
--- name; each value is a tuple in one of these forms:
--- 1. (arg_value, type_name, optional)
--- - arg_value: argument value
---- - type_name: string type name, one of: ("table", "t", "string",
+--- - type_name: string|table type name, one of: ("table", "t", "string",
--- "s", "number", "n", "boolean", "b", "function", "f", "nil",
---- "thread", "userdata")
+--- "thread", "userdata") or list of them.
--- - optional: (optional) boolean, if true, `nil` is valid
--- 2. (arg_value, fn, msg)
--- - arg_value: argument value
@@ -571,31 +581,43 @@ do
end
local val = spec[1] -- Argument value.
- local t = spec[2] -- Type name, or callable.
+ local types = spec[2] -- Type name, or callable.
local optional = (true == spec[3])
- if type(t) == 'string' then
- local t_name = type_names[t]
- if not t_name then
- return false, string.format('invalid type name: %s', t)
- end
+ if type(types) == 'string' then
+ types = {types}
+ end
- if (not optional or val ~= nil) and not _is_type(val, t_name) then
- return false, string.format("%s: expected %s, got %s", param_name, t_name, type(val))
- end
- elseif vim.is_callable(t) then
+ if vim.is_callable(types) then
-- Check user-provided validation function.
- local valid, optional_message = t(val)
+ local valid, optional_message = types(val)
if not valid then
- local error_message = string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), val)
+ local error_message = string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), tostring(val))
if optional_message ~= nil then
error_message = error_message .. string.format(". Info: %s", optional_message)
end
return false, error_message
end
+ elseif type(types) == 'table' then
+ local success = false
+ for i, t in ipairs(types) do
+ local t_name = type_names[t]
+ if not t_name then
+ return false, string.format('invalid type name: %s', t)
+ end
+ types[i] = t_name
+
+ if (optional and val == nil) or _is_type(val, t_name) then
+ success = true
+ break
+ end
+ end
+ if not success then
+ return false, string.format("%s: expected %s, got %s", param_name, table.concat(types, '|'), type(val))
+ end
else
- return false, string.format("invalid type name: %s", tostring(t))
+ return false, string.format("invalid type name: %s", tostring(types))
end
end
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 594765761d..85fd5cd8e0 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -77,7 +77,7 @@ end
--- Determines whether this tree is valid.
--- If the tree is invalid, `parse()` must be called
---- to get the an updated tree.
+--- to get the updated tree.
function LanguageTree:is_valid()
return self._valid
end
diff --git a/runtime/nvim.appdata.xml b/runtime/nvim.appdata.xml
index 225dd79878..4ad656f1a3 100644
--- a/runtime/nvim.appdata.xml
+++ b/runtime/nvim.appdata.xml
@@ -26,7 +26,9 @@
</screenshots>
<releases>
+ <release date="2021-12-31" version="0.6.1"/>
<release date="2021-11-30" version="0.6.0"/>
+ <release date="2021-09-26" version="0.5.1"/>
<release date="2021-07-02" version="0.5.0"/>
<release date="2020-08-04" version="0.4.4"/>
<release date="2019-11-06" version="0.4.3"/>
diff --git a/scripts/gen_filetype.lua b/scripts/gen_filetype.lua
new file mode 100644
index 0000000000..42478a1082
--- /dev/null
+++ b/scripts/gen_filetype.lua
@@ -0,0 +1,201 @@
+local do_not_run = true
+if do_not_run then
+ print([[
+ This script was used to bootstrap the filetype patterns in runtime/lua/vim/filetype.lua. It
+ should no longer be used except for testing purposes. New filetypes, or changes to existing
+ filetypes, should be ported manually as part of the vim-patch process.
+ ]])
+ return
+end
+
+local filetype_vim = "runtime/filetype.vim"
+local filetype_lua = "runtime/lua/vim/filetype.lua"
+
+local keywords = {
+ ["for"] = true,
+ ["or"] = true,
+ ["and"] = true,
+ ["end"] = true,
+ ["do"] = true,
+ ["if"] = true,
+ ["while"] = true,
+ ["repeat"] = true,
+}
+
+local sections = {
+ extension = { str = {}, func = {} },
+ filename = { str = {}, func = {} },
+ pattern = { str = {}, func = {} },
+}
+
+local specialchars = "%*%?\\%$%[%]%{%}"
+
+local function add_pattern(pat, ft)
+ local ok = true
+
+ -- Patterns that start or end with { or } confuse splitting on commas and make parsing harder, so just skip those
+ if not string.find(pat, "^%{") and not string.find(pat, "%}$") then
+ for part in string.gmatch(pat, "[^,]+") do
+ if not string.find(part, "[" .. specialchars .. "]") then
+ if type(ft) == "string" then
+ sections.filename.str[part] = ft
+ else
+ sections.filename.func[part] = ft
+ end
+ elseif string.match(part, "^%*%.[^%./" .. specialchars .. "]+$") then
+ if type(ft) == "string" then
+ sections.extension.str[part:sub(3)] = ft
+ else
+ sections.extension.func[part:sub(3)] = ft
+ end
+ else
+ if string.match(part, "^%*/[^" .. specialchars .. "]+$") then
+ -- For patterns matching */some/pattern we want to easily match files
+ -- with path /some/pattern, so include those in filename detection
+ if type(ft) == "string" then
+ sections.filename.str[part:sub(2)] = ft
+ else
+ sections.filename.func[part:sub(2)] = ft
+ end
+ end
+
+ if string.find(part, "^[%w-_.*?%[%]/]+$") then
+ local p = part:gsub("%.", "%%."):gsub("%*", ".*"):gsub("%?", ".")
+ -- Insert into array to maintain order rather than setting
+ -- key-value directly
+ if type(ft) == "string" then
+ sections.pattern.str[p] = ft
+ else
+ sections.pattern.func[p] = ft
+ end
+ else
+ ok = false
+ end
+ end
+ end
+ end
+
+ return ok
+end
+
+local function parse_line(line)
+ local pat, ft
+ pat, ft = line:match("^%s*au%a* Buf[%a,]+%s+(%S+)%s+setf%s+(%S+)")
+ if pat then
+ return add_pattern(pat, ft)
+ else
+ local func
+ pat, func = line:match("^%s*au%a* Buf[%a,]+%s+(%S+)%s+call%s+(%S+)")
+ if pat then
+ return add_pattern(pat, function() return func end)
+ end
+ end
+end
+
+local unparsed = {}
+local full_line
+for line in io.lines(filetype_vim) do
+ local cont = string.match(line, "^%s*\\%s*(.*)$")
+ if cont then
+ full_line = full_line .. " " .. cont
+ else
+ if full_line then
+ if not parse_line(full_line) and string.find(full_line, "^%s*au%a* Buf") then
+ table.insert(unparsed, full_line)
+ end
+ end
+ full_line = line
+ end
+end
+
+if #unparsed > 0 then
+ print("Failed to parse the following patterns:")
+ for _, v in ipairs(unparsed) do
+ print(v)
+ end
+end
+
+local function add_item(indent, key, ft)
+ if type(ft) == "string" then
+ if string.find(key, "%A") or keywords[key] then
+ key = string.format("[\"%s\"]", key)
+ end
+ return string.format([[%s%s = "%s",]], indent, key, ft)
+ elseif type(ft) == "function" then
+ local func = ft()
+ if string.find(key, "%A") or keywords[key] then
+ key = string.format("[\"%s\"]", key)
+ end
+ -- Right now only a single argument is supported, which covers
+ -- everything in filetype.vim as of this writing
+ local arg = string.match(func, "%((.*)%)$")
+ func = string.gsub(func, "%(.*$", "")
+ if arg == "" then
+ -- Function with no arguments, call the function directly
+ return string.format([[%s%s = function() vim.fn["%s"]() end,]], indent, key, func)
+ elseif string.match(arg, [[^(["']).*%1$]]) then
+ -- String argument
+ if func == "s:StarSetf" then
+ return string.format([[%s%s = starsetf(%s),]], indent, key, arg)
+ else
+ return string.format([[%s%s = function() vim.fn["%s"](%s) end,]], indent, key, func, arg)
+ end
+ elseif string.find(arg, "%(") then
+ -- Function argument
+ return string.format([[%s%s = function() vim.fn["%s"](vim.fn.%s) end,]], indent, key, func, arg)
+ else
+ assert(false, arg)
+ end
+ end
+end
+
+do
+ local lines = {}
+ local start = false
+ for line in io.lines(filetype_lua) do
+ if line:match("^%s+-- END [A-Z]+$") then
+ start = false
+ end
+
+ if not start then
+ table.insert(lines, line)
+ end
+
+ local indent, section = line:match("^(%s+)-- BEGIN ([A-Z]+)$")
+ if section then
+ start = true
+ local t = sections[string.lower(section)]
+
+ local sorted = {}
+ for k, v in pairs(t.str) do
+ table.insert(sorted, {[k] = v})
+ end
+
+ table.sort(sorted, function(a, b)
+ return a[next(a)] < b[next(b)]
+ end)
+
+ for _, v in ipairs(sorted) do
+ local k = next(v)
+ table.insert(lines, add_item(indent, k, v[k]))
+ end
+
+ sorted = {}
+ for k, v in pairs(t.func) do
+ table.insert(sorted, {[k] = v})
+ end
+
+ table.sort(sorted, function(a, b)
+ return next(a) < next(b)
+ end)
+
+ for _, v in ipairs(sorted) do
+ local k = next(v)
+ table.insert(lines, add_item(indent, k, v[k]))
+ end
+ end
+ end
+ local f = io.open(filetype_lua, "w")
+ f:write(table.concat(lines, "\n") .. "\n")
+ f:close()
+end
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index 89fc14121e..3810ebd9d0 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -128,12 +128,14 @@ CONFIG = {
'shared.lua',
'uri.lua',
'ui.lua',
+ 'filetype.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
os.path.join(base_dir, 'runtime/lua/vim/uri.lua'),
os.path.join(base_dir, 'runtime/lua/vim/ui.lua'),
+ os.path.join(base_dir, 'runtime/lua/vim/filetype.lua'),
]),
'file_patterns': '*.lua',
'fn_name_prefix': '',
@@ -148,6 +150,7 @@ CONFIG = {
'shared': 'vim',
'uri': 'vim',
'ui': 'vim.ui',
+ 'filetype': 'vim.filetype',
},
'append_only': [
'shared.lua',
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index ac47f6aafd..1c265f0f40 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -266,8 +266,6 @@ get_vimpatch() {
msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'."
}
-# shellcheck disable=SC2015
-# ^ "Note that A && B || C is not if-then-else."
stage_patch() {
get_vimpatch "$1"
local try_apply="${2:-}"
@@ -282,23 +280,32 @@ stage_patch() {
echo " branch; not creating a new branch."
else
printf '\nFetching "%s/master".\n' "${nvim_remote}"
- output="$(git fetch "${nvim_remote}" master 2>&1)" &&
- msg_ok "${output}" ||
- (msg_err "${output}"; false)
+ if output="$(git fetch "$nvim_remote" master 2>&1)"; then
+ msg_ok "$output"
+ else
+ msg_err "$output"
+ exit 1
+ fi
local nvim_branch="${BRANCH_PREFIX}${vim_version}"
echo
echo "Creating new branch '${nvim_branch}' based on '${nvim_remote}/master'."
cd "${NVIM_SOURCE_DIR}"
- output="$(git checkout -b "${nvim_branch}" "${nvim_remote}/master" 2>&1)" &&
- msg_ok "${output}" ||
- (msg_err "${output}"; false)
+ if output="$(git checkout -b "$nvim_branch" "$nvim_remote/master" 2>&1)"; then
+ msg_ok "$output"
+ else
+ msg_err "$output"
+ exit 1
+ fi
fi
printf "\nCreating empty commit with correct commit message.\n"
- output="$(commit_message | git commit --allow-empty --file 2>&1 -)" &&
- msg_ok "${output}" ||
- (msg_err "${output}"; false)
+ if output="$(commit_message | git commit --allow-empty --file 2>&1 -)"; then
+ msg_ok "$output"
+ else
+ msg_err "$output"
+ exit 1
+ fi
local ret=0
if test -n "$try_apply" ; then
@@ -340,8 +347,6 @@ git_hub_pr() {
git hub pull new -m "${pr_message}"
}
-# shellcheck disable=SC2015
-# ^ "Note that A && B || C is not if-then-else."
submit_pr() {
require_executable git
local push_first
@@ -392,17 +397,23 @@ submit_pr() {
fi
fi
echo "Pushing to '${push_remote}/${checked_out_branch}'."
- output="$(git push "${push_remote}" "${checked_out_branch}" 2>&1)" &&
- msg_ok "${output}" ||
- (msg_err "${output}"; false)
+ if output="$(git push "$push_remote" "$checked_out_branch" 2>&1)"; then
+ msg_ok "$output"
+ else
+ msg_err "$output"
+ exit 1
+ fi
echo
fi
echo "Creating pull request."
- output="$(${submit_fn} "${pr_title}" "${pr_body}" 2>&1)" &&
- msg_ok "${output}" ||
- (msg_err "${output}"; false)
+ if output="$($submit_fn "$pr_title" "$pr_body" 2>&1)"; then
+ msg_ok "$output"
+ else
+ msg_err "$output"
+ exit 1
+ fi
echo
echo "Cleaning up files."
@@ -565,13 +576,13 @@ show_vimpatches() {
runtime_commits[$commit]=1
done
- list_missing_vimpatches 1 "$@" | while read -r vim_commit; do
+ while read -r vim_commit; do
if [[ "${runtime_commits[$vim_commit]-}" ]]; then
printf ' • %s (+runtime)\n' "${vim_commit}"
else
printf ' • %s\n' "${vim_commit}"
fi
- done
+ done <<< "$(list_missing_vimpatches 1 "$@")"
cat << EOF
@@ -692,14 +703,14 @@ review_commit() {
message_length="$(wc -l <<< "${expected_commit_message}")"
local commit_message
commit_message="$(tail -n +4 "${NVIM_SOURCE_DIR}/n${patch_file}" | head -n "${message_length}")"
- if [[ "${commit_message#${git_patch_prefix}}" == "${expected_commit_message}" ]]; then
+ if [[ "${commit_message#"$git_patch_prefix"}" == "${expected_commit_message}" ]]; then
msg_ok "Found expected commit message."
else
msg_err "Wrong commit message."
echo " Expected:"
echo "${expected_commit_message}"
echo " Actual:"
- echo "${commit_message#${git_patch_prefix}}"
+ echo "${commit_message#"$git_patch_prefix"}"
fi
get_vimpatch "${vim_version}"
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 9c4b778169..94572b57cd 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -62,6 +62,7 @@ set(LUA_SHARED_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/shared.lua)
set(LUA_INSPECT_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/inspect.lua)
set(LUA_F_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/F.lua)
set(LUA_META_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_meta.lua)
+set(LUA_FILETYPE_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/filetype.lua)
set(CHAR_BLOB_GENERATOR ${GENERATOR_DIR}/gen_char_blob.lua)
set(LINT_SUPPRESS_FILE ${PROJECT_BINARY_DIR}/errors.json)
set(LINT_SUPPRESS_URL_BASE "https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint")
@@ -334,6 +335,7 @@ add_custom_command(
${LUA_INSPECT_MODULE_SOURCE} inspect_module
${LUA_F_MODULE_SOURCE} lua_F_module
${LUA_META_MODULE_SOURCE} lua_meta_module
+ ${LUA_FILETYPE_MODULE_SOURCE} lua_filetype_module
DEPENDS
${CHAR_BLOB_GENERATOR}
${LUA_VIM_MODULE_SOURCE}
@@ -341,6 +343,7 @@ add_custom_command(
${LUA_INSPECT_MODULE_SOURCE}
${LUA_F_MODULE_SOURCE}
${LUA_META_MODULE_SOURCE}
+ ${LUA_FILETYPE_MODULE_SOURCE}
VERBATIM
)
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index ce9c4e27ad..2d5403d4b8 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -835,7 +835,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
/// @param[out] err Error details, if any
/// @returns Array of maparg()-like dictionaries describing mappings.
/// The "buffer" key holds the associated buffer handle.
-ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
+ArrayOf(Dictionary) nvim_buf_get_keymap(uint64_t channel_id, Buffer buffer, String mode, Error *err)
FUNC_API_SINCE(3)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -844,7 +844,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
return (Array)ARRAY_DICT_INIT;
}
- return keymap_array(mode, buf);
+ return keymap_array(mode, buf, channel_id == LUA_INTERNAL_CALL);
}
/// Sets a buffer-local |mapping| for the given mode.
@@ -1273,6 +1273,63 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
return res;
}
+/// Create a new user command |user-commands| in the given buffer.
+///
+/// @param buffer Buffer handle, or 0 for current buffer.
+/// @param[out] err Error details, if any.
+/// @see nvim_add_user_command
+void nvim_buf_add_user_command(Buffer buffer, String name, Object command,
+ Dict(user_command) *opts, Error *err)
+ FUNC_API_SINCE(9)
+{
+ buf_T *target_buf = find_buffer_by_handle(buffer, err);
+ if (ERROR_SET(err)) {
+ return;
+ }
+
+ buf_T *save_curbuf = curbuf;
+ curbuf = target_buf;
+ add_user_command(name, command, opts, UC_BUFFER, err);
+ curbuf = save_curbuf;
+}
+
+/// Delete a buffer-local user-defined command.
+///
+/// Only commands created with |:command-buffer| or
+/// |nvim_buf_add_user_command()| can be deleted with this function.
+///
+/// @param buffer Buffer handle, or 0 for current buffer.
+/// @param name Name of the command to delete.
+/// @param[out] err Error details, if any.
+void nvim_buf_del_user_command(Buffer buffer, String name, Error *err)
+ FUNC_API_SINCE(9)
+{
+ garray_T *gap;
+ if (buffer == -1) {
+ gap = &ucmds;
+ } else {
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ gap = &buf->b_ucmds;
+ }
+
+ for (int i = 0; i < gap->ga_len; i++) {
+ ucmd_T *cmd = USER_CMD_GA(gap, i);
+ if (!STRCMP(name.data, cmd->uc_name)) {
+ free_ucmd(cmd);
+
+ gap->ga_len -= 1;
+
+ if (i < gap->ga_len) {
+ memmove(cmd, cmd + 1, (size_t)(gap->ga_len - i) * sizeof(ucmd_T));
+ }
+
+ return;
+ }
+ }
+
+ api_set_error(err, kErrorTypeException, "No such user-defined command: %s", name.data);
+}
+
Dictionary nvim__buf_stats(Buffer buffer, Error *err)
{
Dictionary rv = ARRAY_DICT_INIT;
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index f3e7f2f1dc..97ee885ff6 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -29,10 +29,24 @@ return {
"script";
"expr";
"unique";
+ "callback";
+ "desc";
};
get_commands = {
"builtin";
};
+ user_command = {
+ "addr";
+ "bang";
+ "bar";
+ "complete";
+ "count";
+ "desc";
+ "force";
+ "nargs";
+ "range";
+ "register";
+ };
float_config = {
"row";
"col";
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 9b407eab8b..38a82343c3 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -594,6 +594,7 @@ Array string_to_array(const String input, bool crlf)
void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String rhs,
Dict(keymap) *opts, Error *err)
{
+ LuaRef lua_funcref = LUA_NOREF;
bool global = (buffer == -1);
if (global) {
buffer = 0;
@@ -604,6 +605,10 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
return;
}
+ if (opts != NULL && opts->callback.type == kObjectTypeLuaRef) {
+ lua_funcref = opts->callback.data.luaref;
+ opts->callback.data.luaref = LUA_NOREF;
+ }
MapArguments parsed_args = MAP_ARGUMENTS_INIT;
if (opts) {
#define KEY_TO_BOOL(name) \
@@ -623,9 +628,13 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
parsed_args.buffer = !global;
set_maparg_lhs_rhs((char_u *)lhs.data, lhs.size,
- (char_u *)rhs.data, rhs.size,
+ (char_u *)rhs.data, rhs.size, lua_funcref,
CPO_TO_CPO_FLAGS, &parsed_args);
-
+ if (opts != NULL && opts->desc.type == kObjectTypeString) {
+ parsed_args.desc = xstrdup(opts->desc.data.string.data);
+ } else {
+ parsed_args.desc = NULL;
+ }
if (parsed_args.lhs_len > MAXMAPLEN) {
api_set_error(err, kErrorTypeValidation, "LHS exceeds maximum map length: %s", lhs.data);
goto fail_and_free;
@@ -658,7 +667,8 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
bool is_noremap = parsed_args.noremap;
assert(!(is_unmap && is_noremap));
- if (!is_unmap && (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) {
+ if (!is_unmap && lua_funcref == LUA_NOREF
+ && (parsed_args.rhs_len == 0 && !parsed_args.rhs_is_noop)) {
if (rhs.size == 0) { // assume that the user wants RHS to be a <Nop>
parsed_args.rhs_is_noop = true;
} else {
@@ -668,9 +678,13 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
api_set_error(err, kErrorTypeValidation, "Parsing of nonempty RHS failed: %s", rhs.data);
goto fail_and_free;
}
- } else if (is_unmap && parsed_args.rhs_len) {
- api_set_error(err, kErrorTypeValidation,
- "Gave nonempty RHS in unmap command: %s", parsed_args.rhs);
+ } else if (is_unmap && (parsed_args.rhs_len || parsed_args.rhs_lua != LUA_NOREF)) {
+ if (parsed_args.rhs_len) {
+ api_set_error(err, kErrorTypeValidation,
+ "Gave nonempty RHS in unmap command: %s", parsed_args.rhs);
+ } else {
+ api_set_error(err, kErrorTypeValidation, "Gave nonempty RHS for unmap");
+ }
goto fail_and_free;
}
@@ -700,9 +714,12 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String
goto fail_and_free;
} // switch
+ parsed_args.rhs_lua = LUA_NOREF; // don't clear ref on success
fail_and_free:
+ NLUA_CLEAR_REF(parsed_args.rhs_lua);
xfree(parsed_args.rhs);
xfree(parsed_args.orig_rhs);
+ XFREE_CLEAR(parsed_args.desc);
return;
}
@@ -961,6 +978,10 @@ Object copy_object(Object obj)
case kObjectTypeDictionary:
return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary));
+
+ case kObjectTypeLuaRef:
+ return LUAREF_OBJ(api_new_luaref(obj.data.luaref));
+
default:
abort();
}
@@ -1048,8 +1069,9 @@ void api_set_error(Error *err, ErrorType errType, const char *format, ...)
///
/// @param mode The abbreviation for the mode
/// @param buf The buffer to get the mapping array. NULL for global
+/// @param from_lua Whether it is called from internal lua api.
/// @returns Array of maparg()-like dictionaries describing mappings
-ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
+ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, bool from_lua)
{
Array mappings = ARRAY_DICT_INIT;
dict_T *const dict = tv_dict_alloc();
@@ -1069,8 +1091,19 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
// Check for correct mode
if (int_mode & current_maphash->m_mode) {
mapblock_fill_dict(dict, current_maphash, buffer_value, false);
- ADD(mappings, vim_to_object((typval_T[]) { { .v_type = VAR_DICT, .vval.v_dict = dict } }));
-
+ Object api_dict = vim_to_object((typval_T[]) { { .v_type = VAR_DICT,
+ .vval.v_dict = dict } });
+ if (from_lua) {
+ Dictionary d = api_dict.data.dictionary;
+ for (size_t j = 0; j < d.size; j++) {
+ if (strequal("callback", d.items[j].key.data)) {
+ d.items[j].value.type = kObjectTypeLuaRef;
+ d.items[j].value.data.luaref = api_new_luaref((LuaRef)d.items[j].value.data.integer);
+ break;
+ }
+ }
+ }
+ ADD(mappings, api_dict);
tv_dict_clear(dict);
}
}
@@ -1342,3 +1375,184 @@ const char *get_default_stl_hl(win_T *wp)
return "StatusLineNC";
}
}
+
+void add_user_command(String name, Object command, Dict(user_command) *opts, int flags, Error *err)
+{
+ uint32_t argt = 0;
+ long def = -1;
+ cmd_addr_T addr_type_arg = ADDR_NONE;
+ int compl = EXPAND_NOTHING;
+ char *compl_arg = NULL;
+ char *rep = NULL;
+ LuaRef luaref = LUA_NOREF;
+ LuaRef compl_luaref = LUA_NOREF;
+
+ if (HAS_KEY(opts->range) && HAS_KEY(opts->count)) {
+ api_set_error(err, kErrorTypeValidation, "'range' and 'count' are mutually exclusive");
+ goto err;
+ }
+
+ if (opts->nargs.type == kObjectTypeInteger) {
+ switch (opts->nargs.data.integer) {
+ case 0:
+ // Default value, nothing to do
+ break;
+ case 1:
+ argt |= EX_EXTRA | EX_NOSPC | EX_NEEDARG;
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
+ goto err;
+ }
+ } else if (opts->nargs.type == kObjectTypeString) {
+ if (opts->nargs.data.string.size > 1) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
+ goto err;
+ }
+
+ switch (opts->nargs.data.string.data[0]) {
+ case '*':
+ argt |= EX_EXTRA;
+ break;
+ case '?':
+ argt |= EX_EXTRA | EX_NOSPC;
+ break;
+ case '+':
+ argt |= EX_EXTRA | EX_NEEDARG;
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
+ goto err;
+ }
+ } else if (HAS_KEY(opts->nargs)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'nargs'");
+ goto err;
+ }
+
+ if (HAS_KEY(opts->complete) && !argt) {
+ api_set_error(err, kErrorTypeValidation, "'complete' used without 'nargs'");
+ goto err;
+ }
+
+ if (opts->range.type == kObjectTypeBoolean) {
+ if (opts->range.data.boolean) {
+ argt |= EX_RANGE;
+ addr_type_arg = ADDR_LINES;
+ }
+ } else if (opts->range.type == kObjectTypeString) {
+ if (opts->range.data.string.data[0] == '%' && opts->range.data.string.size == 1) {
+ argt |= EX_RANGE | EX_DFLALL;
+ addr_type_arg = ADDR_LINES;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'");
+ goto err;
+ }
+ } else if (opts->range.type == kObjectTypeInteger) {
+ argt |= EX_RANGE | EX_ZEROR;
+ def = opts->range.data.integer;
+ addr_type_arg = ADDR_LINES;
+ } else if (HAS_KEY(opts->range)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'range'");
+ goto err;
+ }
+
+ if (opts->count.type == kObjectTypeBoolean) {
+ if (opts->count.data.boolean) {
+ argt |= EX_COUNT | EX_ZEROR | EX_RANGE;
+ addr_type_arg = ADDR_OTHER;
+ def = 0;
+ }
+ } else if (opts->count.type == kObjectTypeInteger) {
+ argt |= EX_COUNT | EX_ZEROR | EX_RANGE;
+ addr_type_arg = ADDR_OTHER;
+ def = opts->count.data.integer;
+ } else if (HAS_KEY(opts->count)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'count'");
+ goto err;
+ }
+
+ if (opts->addr.type == kObjectTypeString) {
+ if (parse_addr_type_arg((char_u *)opts->addr.data.string.data, (int)opts->addr.data.string.size,
+ &addr_type_arg) != OK) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'");
+ goto err;
+ }
+
+ if (addr_type_arg != ADDR_LINES) {
+ argt |= EX_ZEROR;
+ }
+ } else if (HAS_KEY(opts->addr)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'addr'");
+ goto err;
+ }
+
+ if (api_object_to_bool(opts->bang, "bang", false, err)) {
+ argt |= EX_BANG;
+ } else if (ERROR_SET(err)) {
+ goto err;
+ }
+
+ if (api_object_to_bool(opts->bar, "bar", false, err)) {
+ argt |= EX_TRLBAR;
+ } else if (ERROR_SET(err)) {
+ goto err;
+ }
+
+
+ if (api_object_to_bool(opts->register_, "register", false, err)) {
+ argt |= EX_REGSTR;
+ } else if (ERROR_SET(err)) {
+ goto err;
+ }
+
+ bool force = api_object_to_bool(opts->force, "force", true, err);
+ if (ERROR_SET(err)) {
+ goto err;
+ }
+
+ if (opts->complete.type == kObjectTypeLuaRef) {
+ compl = EXPAND_USER_LUA;
+ compl_luaref = api_new_luaref(opts->complete.data.luaref);
+ } else if (opts->complete.type == kObjectTypeString) {
+ if (parse_compl_arg((char_u *)opts->complete.data.string.data,
+ (int)opts->complete.data.string.size, &compl, &argt,
+ (char_u **)&compl_arg) != OK) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'");
+ goto err;
+ }
+ } else if (HAS_KEY(opts->complete)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid value for 'complete'");
+ goto err;
+ }
+
+ switch (command.type) {
+ case kObjectTypeLuaRef:
+ luaref = api_new_luaref(command.data.luaref);
+ if (opts->desc.type == kObjectTypeString) {
+ rep = opts->desc.data.string.data;
+ } else {
+ snprintf((char *)IObuff, IOSIZE, "<Lua function %d>", luaref);
+ rep = (char *)IObuff;
+ }
+ break;
+ case kObjectTypeString:
+ rep = command.data.string.data;
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation, "'command' must be a string or Lua function");
+ goto err;
+ }
+
+ if (uc_add_command((char_u *)name.data, name.size, (char_u *)rep, argt, def, flags,
+ compl, (char_u *)compl_arg, compl_luaref, addr_type_arg, luaref,
+ force) != OK) {
+ api_set_error(err, kErrorTypeException, "Failed to create user command");
+ goto err;
+ }
+
+ return;
+
+err:
+ NLUA_CLEAR_REF(luaref);
+ NLUA_CLEAR_REF(compl_luaref);
+}
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 4a0222234d..59db12f2c0 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -383,7 +383,7 @@ error:
/// @param str String to be converted.
/// @param from_part Legacy Vim parameter. Usually true.
/// @param do_lt Also translate <lt>. Ignored if `special` is false.
-/// @param special Replace |keycodes|, e.g. <CR> becomes a "\n" char.
+/// @param special Replace |keycodes|, e.g. <CR> becomes a "\r" char.
/// @see replace_termcodes
/// @see cpoptions
String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, Boolean special)
@@ -662,7 +662,7 @@ Object nvim_get_option(String name, Error *err)
///
/// @param name Option name
/// @param opts Optional parameters
-/// - scope: One of 'global' or 'local'. Analagous to
+/// - scope: One of 'global' or 'local'. Analogous to
/// |:setglobal| and |:setlocal|, respectively.
/// @param[out] err Error details, if any
/// @return Option value
@@ -724,7 +724,7 @@ end:
/// @param name Option name
/// @param value New option value
/// @param opts Optional parameters
-/// - scope: One of 'global' or 'local'. Analagous to
+/// - scope: One of 'global' or 'local'. Analogous to
/// |:setglobal| and |:setlocal|, respectively.
/// @param[out] err Error details, if any
void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error *err)
@@ -1163,7 +1163,7 @@ static void term_close(void *data)
/// Send data to channel `id`. For a job, it writes it to the
/// stdin of the process. For the stdio channel |channel-stdio|,
/// it writes to Nvim's stdout. For an internal terminal instance
-/// (|nvim_open_term()|) it writes directly to terimal output.
+/// (|nvim_open_term()|) it writes directly to terminal output.
/// See |channel-bytes| for more information.
///
/// This function writes raw data, not RPC messages. If the channel
@@ -1538,10 +1538,10 @@ Dictionary nvim_get_mode(void)
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @returns Array of maparg()-like dictionaries describing mappings.
/// The "buffer" key is always zero.
-ArrayOf(Dictionary) nvim_get_keymap(String mode)
+ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
FUNC_API_SINCE(3)
{
- return keymap_array(mode, NULL);
+ return keymap_array(mode, NULL, channel_id == LUA_INTERNAL_CALL);
}
/// Sets a global |mapping| for the given mode.
@@ -1566,7 +1566,10 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode)
/// @param lhs Left-hand-side |{lhs}| of the mapping.
/// @param rhs Right-hand-side |{rhs}| of the mapping.
/// @param opts Optional parameters map. Accepts all |:map-arguments|
-/// as keys excluding |<buffer>| but including |noremap|.
+/// as keys excluding |<buffer>| but including |noremap| and "desc".
+/// |desc| can be used to give a description to keymap.
+/// When called from Lua, also accepts a "callback" key that takes
+/// a Lua function to call when the mapping is executed.
/// Values are Booleans. Unknown key is an error.
/// @param[out] err Error details, if any.
void nvim_set_keymap(String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err)
@@ -1741,7 +1744,7 @@ Array nvim_list_chans(void)
/// 1. To perform several requests from an async context atomically, i.e.
/// without interleaving redraws, RPC requests from other clients, or user
/// interactions (however API methods may trigger autocommands or event
-/// processing which have such side-effects, e.g. |:sleep| may wake timers).
+/// processing which have such side effects, e.g. |:sleep| may wake timers).
/// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests.
///
/// @param channel_id
@@ -2101,7 +2104,7 @@ void nvim__screenshot(String path)
}
-/// Deletes a uppercase/file named mark. See |mark-motions|.
+/// Deletes an uppercase/file named mark. See |mark-motions|.
///
/// @note fails with error if a lowercase or buffer local named mark is used.
/// @param name Mark name
@@ -2363,3 +2366,53 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
return result;
}
+
+/// Create a new user command |user-commands|
+///
+/// {name} is the name of the new command. The name must begin with an uppercase letter.
+///
+/// {command} is the replacement text or Lua function to execute.
+///
+/// Example:
+/// <pre>
+/// :call nvim_add_user_command('SayHello', 'echo "Hello world!"', {})
+/// :SayHello
+/// Hello world!
+/// </pre>
+///
+/// @param name Name of the new user command. Must begin with an uppercase letter.
+/// @param command Replacement command to execute when this user command is executed. When called
+/// from Lua, the command can also be a Lua function. The function is called with a
+/// single table argument that contains the following keys:
+/// - args: (string) The args passed to the command, if any |<args>|
+/// - bang: (boolean) "true" if the command was executed with a ! modifier |<bang>|
+/// - line1: (number) The starting line of the command range |<line1>|
+/// - line2: (number) The final line of the command range |<line2>|
+/// - range: (number) The number of items in the command range: 0, 1, or 2 |<range>|
+/// - count: (number) Any count supplied |<count>|
+/// - reg: (string) The optional register, if specified |<reg>|
+/// - mods: (string) Command modifiers, if any |<mods>|
+/// @param opts Optional command attributes. See |command-attributes| for more details. To use
+/// boolean attributes (such as |:command-bang| or |:command-bar|) set the value to
+/// "true". In addition to the string options listed in |:command-complete|, the
+/// "complete" key also accepts a Lua function which works like the "customlist"
+/// completion mode |:command-completion-customlist|. Additional parameters:
+/// - desc: (string) Used for listing the command when a Lua function is used for
+/// {command}.
+/// - force: (boolean, default true) Override any previous definition.
+/// @param[out] err Error details, if any.
+void nvim_add_user_command(String name, Object command, Dict(user_command) *opts, Error *err)
+ FUNC_API_SINCE(9)
+{
+ add_user_command(name, command, opts, 0, err);
+}
+
+/// Delete a user-defined command.
+///
+/// @param name Name of the command to delete.
+/// @param[out] err Error details, if any.
+void nvim_del_user_command(String name, Error *err)
+ FUNC_API_SINCE(9)
+{
+ nvim_buf_del_user_command(-1, name, err);
+}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 6e68c057dc..907306da7b 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -39,7 +39,7 @@ Buffer nvim_win_get_buf(Window window, Error *err)
return win->w_buffer->handle;
}
-/// Sets the current buffer in a window, without side-effects
+/// Sets the current buffer in a window, without side effects
///
/// @param window Window handle, or 0 for current window
/// @param buffer Buffer handle
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 49e527e98b..63a550c017 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -352,6 +352,7 @@ struct mapblock {
char_u *m_keys; // mapped from, lhs
char_u *m_str; // mapped to, rhs
char_u *m_orig_str; // rhs as entered by the user
+ LuaRef m_luaref; // lua function reference as rhs
int m_keylen; // strlen(m_keys)
int m_mode; // valid mode
int m_noremap; // if non-zero no re-mapping for m_str
@@ -359,6 +360,7 @@ struct mapblock {
char m_nowait; // <nowait> used
char m_expr; // <expr> used, m_str is an expression
sctx_T m_script_ctx; // SCTX where map was defined
+ char *m_desc; // description of keymap
};
/// Used for highlighting in the status line.
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 3517b3244e..5eef4350b7 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -1076,6 +1076,10 @@ static int insert_handle_key(InsertState *s)
case K_COMMAND: // some command
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ goto check_pum;
+
+ case K_LUA:
+ map_execute_lua();
check_pum:
// TODO(bfredl): Not entirely sure this indirection is necessary
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 86384bc5b2..6dbdc09c3b 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -7299,12 +7299,19 @@ void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, long buf
noremap_value = mp->m_noremap == REMAP_SCRIPT ? 2 : !!mp->m_noremap;
}
- if (compatible) {
- tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
+ if (mp->m_luaref != LUA_NOREF) {
+ tv_dict_add_nr(dict, S_LEN("callback"), mp->m_luaref);
} else {
- tv_dict_add_allocated_str(dict, S_LEN("rhs"),
- str2special_save((const char *)mp->m_str, false,
- true));
+ if (compatible) {
+ tv_dict_add_str(dict, S_LEN("rhs"), (const char *)mp->m_orig_str);
+ } else {
+ tv_dict_add_allocated_str(dict, S_LEN("rhs"),
+ str2special_save((const char *)mp->m_str, false,
+ true));
+ }
+ }
+ if (mp->m_desc != NULL) {
+ tv_dict_add_allocated_str(dict, S_LEN("desc"), xstrdup(mp->m_desc));
}
tv_dict_add_allocated_str(dict, S_LEN("lhs"), lhs);
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 32026282cf..7701688b49 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -3991,7 +3991,6 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
MotionType reg_type = get_reg_type(regname, &reglen);
format_reg_type(reg_type, reglen, buf, ARRAY_SIZE(buf));
- rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)xstrdup(buf);
}
@@ -5980,6 +5979,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
{
char_u *keys_buf = NULL;
char_u *rhs;
+ LuaRef rhs_lua;
int mode;
int abbr = FALSE;
int get_dict = FALSE;
@@ -6016,7 +6016,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, true,
CPO_TO_CPO_FLAGS);
- rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local);
+ rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local, &rhs_lua);
xfree(keys_buf);
if (!get_dict) {
@@ -6027,10 +6027,15 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
} else {
rettv->vval.v_string = (char_u *)str2special_save((char *)rhs, false, false);
}
+ } else if (rhs_lua != LUA_NOREF) {
+ size_t msglen = 100;
+ char *msg = (char *)xmalloc(msglen);
+ snprintf(msg, msglen, "<Lua function %d>", mp->m_luaref);
+ rettv->vval.v_string = (char_u *)msg;
}
} else {
tv_dict_alloc_ret(rettv);
- if (rhs != NULL) {
+ if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
// Return a dictionary.
mapblock_fill_dict(rettv->vval.v_dict, mp, buffer_local, true);
}
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 11bbaaed9c..42ac1839e6 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -2455,13 +2455,11 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic
#define TYPVAL_ENCODE_NAME nothing
#define TYPVAL_ENCODE_FIRST_ARG_TYPE const void *const
#define TYPVAL_ENCODE_FIRST_ARG_NAME ignored
-#define TYPVAL_ENCODE_TRANSLATE_OBJECT_NAME
#include "nvim/eval/typval_encode.c.h"
#undef TYPVAL_ENCODE_SCOPE
#undef TYPVAL_ENCODE_NAME
#undef TYPVAL_ENCODE_FIRST_ARG_TYPE
#undef TYPVAL_ENCODE_FIRST_ARG_NAME
-#undef TYPVAL_ENCODE_TRANSLATE_OBJECT_NAME
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
#undef TYPVAL_ENCODE_CONV_NIL
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index 892c46dd04..89fced59c5 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -75,7 +75,7 @@ bool loop_poll_events(Loop *loop, int ms)
/// @note Event is queued into `fast_events`, which is processed outside of the
/// primary `events` queue by loop_poll_events(). For `main_loop`, that
/// means `fast_events` is NOT processed in an "editor mode"
-/// (VimState.execute), so redraw and other side-effects are likely to be
+/// (VimState.execute), so redraw and other side effects are likely to be
/// skipped.
/// @see loop_schedule_deferred
void loop_schedule_fast(Loop *loop, Event event)
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index cc5ab1b554..95390b1a70 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3006,7 +3006,12 @@ void ex_append(exarg_T *eap)
did_undo = true;
ml_append(lnum, theline, (colnr_T)0, false);
- appended_lines_mark(lnum + (empty ? 1 : 0), 1L);
+ if (empty) {
+ // there are no marks below the inserted lines
+ appended_lines(lnum, 1L);
+ } else {
+ appended_lines_mark(lnum, 1L);
+ }
xfree(theline);
++lnum;
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index ea899b660b..e5eab61f9e 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -192,6 +192,7 @@ struct expand {
int xp_context; // type of expansion
size_t xp_pattern_len; // bytes in xp_pattern before cursor
char_u *xp_arg; // completion function
+ LuaRef xp_luaref; // Ref to Lua completion function
sctx_T xp_script_ctx; // SCTX for completion function
int xp_backslash; // one of the XP_BS_ values
#ifndef BACKSLASH_IN_FILENAME
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 25eaacd687..71c34f98ff 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -81,23 +81,7 @@
static int quitmore = 0;
static bool ex_pressedreturn = false;
-typedef struct ucmd {
- char_u *uc_name; // The command name
- uint32_t uc_argt; // The argument type
- char_u *uc_rep; // The command's replacement string
- long uc_def; // The default value for a range/count
- int uc_compl; // completion type
- cmd_addr_T uc_addr_type; // The command's address type
- sctx_T uc_script_ctx; // SCTX where the command was defined
- char_u *uc_compl_arg; // completion argument if any
-} ucmd_T;
-
-#define UC_BUFFER 1 // -buffer: local to current buffer
-
-static garray_T ucmds = { 0, 0, sizeof(ucmd_T), 4, NULL };
-
-#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i])
-#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i])
+garray_T ucmds = { 0, 0, sizeof(ucmd_T), 4, NULL };
// Whether a command index indicates a user command.
#define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
@@ -2761,6 +2745,7 @@ static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *
*complp = uc->uc_compl;
}
if (xp != NULL) {
+ xp->xp_luaref = uc->uc_compl_luaref;
xp->xp_arg = uc->uc_compl_arg;
xp->xp_script_ctx = uc->uc_script_ctx;
xp->xp_script_ctx.sc_lnum += sourcing_lnum;
@@ -5171,8 +5156,9 @@ char_u *get_command_name(expand_T *xp, int idx)
return cmdnames[idx].cmd_name;
}
-static int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def,
- int flags, int compl, char_u *compl_arg, cmd_addr_T addr_type, bool force)
+int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def, int flags,
+ int compl, char_u *compl_arg, LuaRef compl_luaref, cmd_addr_T addr_type,
+ LuaRef luaref, bool force)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
ucmd_T *cmd = NULL;
@@ -5226,6 +5212,8 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t a
XFREE_CLEAR(cmd->uc_rep);
XFREE_CLEAR(cmd->uc_compl_arg);
+ NLUA_CLEAR_REF(cmd->uc_luaref);
+ NLUA_CLEAR_REF(cmd->uc_compl_luaref);
break;
}
@@ -5256,13 +5244,17 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t a
cmd->uc_script_ctx = current_sctx;
cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
cmd->uc_compl_arg = compl_arg;
+ cmd->uc_compl_luaref = compl_luaref;
cmd->uc_addr_type = addr_type;
+ cmd->uc_luaref = luaref;
return OK;
fail:
xfree(rep_buf);
xfree(compl_arg);
+ NLUA_CLEAR_REF(luaref);
+ NLUA_CLEAR_REF(compl_luaref);
return FAIL;
}
@@ -5301,6 +5293,7 @@ static const char *command_complete[] =
[EXPAND_CSCOPE] = "cscope",
[EXPAND_USER_DEFINED] = "custom",
[EXPAND_USER_LIST] = "customlist",
+ [EXPAND_USER_LUA] = "<Lua function>",
[EXPAND_DIFF_BUFFERS] = "diff_buffer",
[EXPAND_DIRECTORIES] = "dir",
[EXPAND_ENV_VARS] = "environment",
@@ -5702,8 +5695,8 @@ static void ex_command(exarg_T *eap)
} else if (compl > 0 && (argt & EX_EXTRA) == 0) {
emsg(_(e_complete_used_without_nargs));
} else {
- uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
- addr_type_arg, eap->forceit);
+ uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, LUA_NOREF,
+ addr_type_arg, LUA_NOREF, eap->forceit);
}
}
@@ -5717,11 +5710,13 @@ void ex_comclear(exarg_T *eap)
uc_clear(&curbuf->b_ucmds);
}
-static void free_ucmd(ucmd_T *cmd)
+void free_ucmd(ucmd_T *cmd)
{
xfree(cmd->uc_name);
xfree(cmd->uc_rep);
xfree(cmd->uc_compl_arg);
+ NLUA_CLEAR_REF(cmd->uc_compl_luaref);
+ NLUA_CLEAR_REF(cmd->uc_luaref);
}
/*
@@ -5759,9 +5754,7 @@ static void ex_delcommand(exarg_T *eap)
return;
}
- xfree(cmd->uc_name);
- xfree(cmd->uc_rep);
- xfree(cmd->uc_compl_arg);
+ free_ucmd(cmd);
--gap->ga_len;
@@ -5843,7 +5836,7 @@ static char_u *uc_split_args(char_u *arg, size_t *lenp)
return buf;
}
-static size_t add_cmd_modifier(char_u *buf, char *mod_str, bool *multi_mods)
+static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods)
{
size_t result = STRLEN(mod_str);
if (*multi_mods) {
@@ -6044,70 +6037,8 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
*buf = '\0';
}
- bool multi_mods = false;
-
- // :aboveleft and :leftabove
- if (cmdmod.split & WSP_ABOVE) {
- result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
- }
- // :belowright and :rightbelow
- if (cmdmod.split & WSP_BELOW) {
- result += add_cmd_modifier(buf, "belowright", &multi_mods);
- }
- // :botright
- if (cmdmod.split & WSP_BOT) {
- result += add_cmd_modifier(buf, "botright", &multi_mods);
- }
-
- typedef struct {
- bool *set;
- char *name;
- } mod_entry_T;
- static mod_entry_T mod_entries[] = {
- { &cmdmod.browse, "browse" },
- { &cmdmod.confirm, "confirm" },
- { &cmdmod.hide, "hide" },
- { &cmdmod.keepalt, "keepalt" },
- { &cmdmod.keepjumps, "keepjumps" },
- { &cmdmod.keepmarks, "keepmarks" },
- { &cmdmod.keeppatterns, "keeppatterns" },
- { &cmdmod.lockmarks, "lockmarks" },
- { &cmdmod.noswapfile, "noswapfile" }
- };
- // the modifiers that are simple flags
- for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) {
- if (*mod_entries[i].set) {
- result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods);
- }
- }
-
- // TODO(vim): How to support :noautocmd?
- // TODO(vim): How to support :sandbox?
+ result += uc_mods((char *)buf);
- // :silent
- if (msg_silent > 0) {
- result += add_cmd_modifier(buf, emsg_silent > 0 ? "silent!" : "silent",
- &multi_mods);
- }
- // :tab
- if (cmdmod.tab > 0) {
- result += add_cmd_modifier(buf, "tab", &multi_mods);
- }
- // :topleft
- if (cmdmod.split & WSP_TOP) {
- result += add_cmd_modifier(buf, "topleft", &multi_mods);
- }
-
- // TODO(vim): How to support :unsilent?
-
- // :verbose
- if (p_verbose > 0) {
- result += add_cmd_modifier(buf, "verbose", &multi_mods);
- }
- // :vertical
- if (cmdmod.split & WSP_VERT) {
- result += add_cmd_modifier(buf, "vertical", &multi_mods);
- }
if (quote && buf != NULL) {
buf += result - 2;
*buf = '"';
@@ -6152,6 +6083,76 @@ static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd,
return result;
}
+size_t uc_mods(char *buf)
+{
+ size_t result = 0;
+ bool multi_mods = false;
+
+ // :aboveleft and :leftabove
+ if (cmdmod.split & WSP_ABOVE) {
+ result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
+ }
+ // :belowright and :rightbelow
+ if (cmdmod.split & WSP_BELOW) {
+ result += add_cmd_modifier(buf, "belowright", &multi_mods);
+ }
+ // :botright
+ if (cmdmod.split & WSP_BOT) {
+ result += add_cmd_modifier(buf, "botright", &multi_mods);
+ }
+
+ typedef struct {
+ bool *set;
+ char *name;
+ } mod_entry_T;
+ static mod_entry_T mod_entries[] = {
+ { &cmdmod.browse, "browse" },
+ { &cmdmod.confirm, "confirm" },
+ { &cmdmod.hide, "hide" },
+ { &cmdmod.keepalt, "keepalt" },
+ { &cmdmod.keepjumps, "keepjumps" },
+ { &cmdmod.keepmarks, "keepmarks" },
+ { &cmdmod.keeppatterns, "keeppatterns" },
+ { &cmdmod.lockmarks, "lockmarks" },
+ { &cmdmod.noswapfile, "noswapfile" }
+ };
+ // the modifiers that are simple flags
+ for (size_t i = 0; i < ARRAY_SIZE(mod_entries); i++) {
+ if (*mod_entries[i].set) {
+ result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods);
+ }
+ }
+
+ // TODO(vim): How to support :noautocmd?
+ // TODO(vim): How to support :sandbox?
+
+ // :silent
+ if (msg_silent > 0) {
+ result += add_cmd_modifier(buf, emsg_silent > 0 ? "silent!" : "silent", &multi_mods);
+ }
+ // :tab
+ if (cmdmod.tab > 0) {
+ result += add_cmd_modifier(buf, "tab", &multi_mods);
+ }
+ // :topleft
+ if (cmdmod.split & WSP_TOP) {
+ result += add_cmd_modifier(buf, "topleft", &multi_mods);
+ }
+
+ // TODO(vim): How to support :unsilent?
+
+ // :verbose
+ if (p_verbose > 0) {
+ result += add_cmd_modifier(buf, "verbose", &multi_mods);
+ }
+ // :vertical
+ if (cmdmod.split & WSP_VERT) {
+ result += add_cmd_modifier(buf, "vertical", &multi_mods);
+ }
+
+ return result;
+}
+
static void do_ucmd(exarg_T *eap)
{
char_u *buf;
@@ -6174,6 +6175,11 @@ static void do_ucmd(exarg_T *eap)
cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx);
}
+ if (cmd->uc_luaref > 0) {
+ nlua_do_ucmd(cmd, eap);
+ return;
+ }
+
/*
* Replace <> in the command by the arguments.
* First round: "buf" is NULL, compute length, allocate "buf".
@@ -9545,15 +9551,18 @@ static void ex_filetype(exarg_T *eap)
void filetype_maybe_enable(void)
{
if (filetype_detect == kNone) {
- source_runtime(FILETYPE_FILE, true);
+ // Normally .vim files are sourced before .lua files when both are
+ // supported, but we reverse the order here because we want the Lua
+ // autocommand to be defined first so that it runs first
+ source_runtime(FILETYPE_FILE, DIP_ALL);
filetype_detect = kTrue;
}
if (filetype_plugin == kNone) {
- source_runtime(FTPLUGIN_FILE, true);
+ source_runtime(FTPLUGIN_FILE, DIP_ALL);
filetype_plugin = kTrue;
}
if (filetype_indent == kNone) {
- source_runtime(INDENT_FILE, true);
+ source_runtime(INDENT_FILE, DIP_ALL);
filetype_indent = kTrue;
}
}
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index a302d4a3c5..abf6ec347b 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -32,6 +32,26 @@ typedef struct {
tasave_T tabuf;
} save_state_T;
+typedef struct ucmd {
+ char_u *uc_name; // The command name
+ uint32_t uc_argt; // The argument type
+ char_u *uc_rep; // The command's replacement string
+ long uc_def; // The default value for a range/count
+ int uc_compl; // completion type
+ cmd_addr_T uc_addr_type; // The command's address type
+ sctx_T uc_script_ctx; // SCTX where the command was defined
+ char_u *uc_compl_arg; // completion argument if any
+ LuaRef uc_compl_luaref; // Reference to Lua completion function
+ LuaRef uc_luaref; // Reference to Lua function
+} ucmd_T;
+
+#define UC_BUFFER 1 // -buffer: local to current buffer
+
+extern garray_T ucmds;
+
+#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i])
+#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i])
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_docmd.h.generated.h"
#endif
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index ba2238ace2..78b8e43e65 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1024,11 +1024,13 @@ static int command_line_execute(VimState *state, int key)
CommandLineState *s = (CommandLineState *)state;
s->c = key;
- if (s->c == K_EVENT || s->c == K_COMMAND) {
+ if (s->c == K_EVENT || s->c == K_COMMAND || s->c == K_LUA) {
if (s->c == K_EVENT) {
state_handle_k_event();
- } else {
+ } else if (s->c == K_COMMAND) {
do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
+ } else {
+ map_execute_lua();
}
if (!cmdline_was_last_drawn) {
@@ -4983,6 +4985,9 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u **
if (xp->xp_context == EXPAND_USER_LIST) {
return ExpandUserList(xp, num_file, file);
}
+ if (xp->xp_context == EXPAND_USER_LUA) {
+ return ExpandUserLua(xp, num_file, file);
+ }
if (xp->xp_context == EXPAND_PACKADD) {
return ExpandPackAddDir(pat, num_file, file);
}
@@ -5411,6 +5416,35 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
return OK;
}
+static int ExpandUserLua(expand_T *xp, int *num_file, char_u ***file)
+{
+ typval_T rettv;
+ nlua_call_user_expand_func(xp, &rettv);
+ if (rettv.v_type != VAR_LIST) {
+ tv_clear(&rettv);
+ return FAIL;
+ }
+
+ list_T *const retlist = rettv.vval.v_list;
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char *), 3);
+ // Loop over the items in the list.
+ TV_LIST_ITER_CONST(retlist, li, {
+ if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING
+ || TV_LIST_ITEM_TV(li)->vval.v_string == NULL) {
+ continue; // Skip non-string items and empty strings.
+ }
+
+ GA_APPEND(char *, &ga, xstrdup((const char *)TV_LIST_ITEM_TV(li)->vval.v_string));
+ });
+ tv_list_unref(retlist);
+
+ *file = ga.ga_data;
+ *num_file = ga.ga_len;
+ return OK;
+}
+
/// Expand color scheme, compiler or filetype names.
/// Search from 'runtimepath':
/// 'runtimepath'/{dirnames}/{pat}.vim
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 21f8c3855e..c6dd25154b 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -441,8 +441,8 @@ local function process_function(fn)
local cparam = string.format('arg%u', j)
local param_type = real_type(param[1])
local lc_param_type = real_type(param[1]):lower()
- local extra = ((param_type == "Object" or param_type == "Dictionary") and "false, ") or ""
- if param[1] == "DictionaryOf(LuaRef)" then
+ local extra = param_type == "Dictionary" and "false, " or ""
+ if param[1] == "Object" or param[1] == "DictionaryOf(LuaRef)" then
extra = "true, "
end
local errshift = 0
diff --git a/src/nvim/generators/gen_keysets.lua b/src/nvim/generators/gen_keysets.lua
index 63ef202fe1..01d8c1d357 100644
--- a/src/nvim/generators/gen_keysets.lua
+++ b/src/nvim/generators/gen_keysets.lua
@@ -26,6 +26,17 @@ local defspipe = io.open(defs_file, 'wb')
local keysets = require'api.keysets'
+local keywords = {
+ register = true,
+}
+
+local function sanitize(key)
+ if keywords[key] then
+ return key .. "_"
+ end
+ return key
+end
+
for name, keys in pairs(keysets) do
local neworder, hashfun = hashy.hashy_hash(name, keys, function (idx)
return name.."_table["..idx.."].str"
@@ -33,7 +44,7 @@ for name, keys in pairs(keysets) do
defspipe:write("typedef struct {\n")
for _, key in ipairs(neworder) do
- defspipe:write(" Object "..key..";\n")
+ defspipe:write(" Object "..sanitize(key)..";\n")
end
defspipe:write("} KeyDict_"..name..";\n\n")
@@ -41,7 +52,7 @@ for name, keys in pairs(keysets) do
funcspipe:write("KeySetLink "..name.."_table[] = {\n")
for _, key in ipairs(neworder) do
- funcspipe:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..key..")},\n")
+ funcspipe:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..sanitize(key)..")},\n")
end
funcspipe:write(' {NULL, 0},\n')
funcspipe:write("};\n\n")
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 424bf758e2..5565e17597 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -15,6 +15,7 @@
#include <stdbool.h>
#include <string.h>
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
#include "nvim/buffer_defs.h"
@@ -1902,7 +1903,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
// complete match
if (keylen >= 0 && keylen <= typebuf.tb_len) {
- char_u *map_str;
+ char_u *map_str = NULL;
int save_m_expr;
int save_m_noremap;
int save_m_silent;
@@ -1947,6 +1948,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
save_m_silent = mp->m_silent;
char_u *save_m_keys = NULL; // only saved when needed
char_u *save_m_str = NULL; // only saved when needed
+ LuaRef save_m_luaref = mp->m_luaref;
// Handle ":map <expr>": evaluate the {rhs} as an
// expression. Also save and restore the command line
@@ -1959,8 +1961,10 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
may_garbage_collect = false;
save_m_keys = vim_strsave(mp->m_keys);
- save_m_str = vim_strsave(mp->m_str);
- map_str = eval_map_expr(save_m_str, NUL);
+ if (save_m_luaref == LUA_NOREF) {
+ save_m_str = vim_strsave(mp->m_str);
+ }
+ map_str = eval_map_expr(mp, NUL);
vgetc_busy = save_vgetc_busy;
may_garbage_collect = save_may_garbage_collect;
} else {
@@ -2618,11 +2622,13 @@ int fix_input_buffer(char_u *buf, int len)
/// @param[in] orig_lhs Original mapping LHS, with characters to replace.
/// @param[in] orig_lhs_len `strlen` of orig_lhs.
/// @param[in] orig_rhs Original mapping RHS, with characters to replace.
+/// @param[in] rhs_lua Lua reference for Lua maps.
/// @param[in] orig_rhs_len `strlen` of orig_rhs.
/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
/// @param[out] mapargs MapArguments struct holding the replaced strings.
-void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const char_u *orig_rhs,
- const size_t orig_rhs_len, int cpo_flags, MapArguments *mapargs)
+void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len,
+ const char_u *orig_rhs, const size_t orig_rhs_len,
+ LuaRef rhs_lua, int cpo_flags, MapArguments *mapargs)
{
char_u *lhs_buf = NULL;
char_u *rhs_buf = NULL;
@@ -2638,22 +2644,34 @@ void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const
true, true, true, cpo_flags);
mapargs->lhs_len = STRLEN(replaced);
STRLCPY(mapargs->lhs, replaced, sizeof(mapargs->lhs));
+ mapargs->rhs_lua = rhs_lua;
- mapargs->orig_rhs_len = orig_rhs_len;
- mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char_u));
- STRLCPY(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
+ if (rhs_lua == LUA_NOREF) {
+ mapargs->orig_rhs_len = orig_rhs_len;
+ mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char_u));
+ STRLCPY(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1);
- if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
- mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
- mapargs->rhs_len = 0;
- mapargs->rhs_is_noop = true;
+ if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing
+ mapargs->rhs = xcalloc(1, sizeof(char_u)); // single null-char
+ mapargs->rhs_len = 0;
+ mapargs->rhs_is_noop = true;
+ } else {
+ replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf,
+ false, true, true, cpo_flags);
+ mapargs->rhs_len = STRLEN(replaced);
+ mapargs->rhs_is_noop = false;
+ mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u));
+ STRLCPY(mapargs->rhs, replaced, mapargs->rhs_len + 1);
+ }
} else {
- replaced = replace_termcodes(orig_rhs, orig_rhs_len, &rhs_buf,
- false, true, true, cpo_flags);
- mapargs->rhs_len = STRLEN(replaced);
- mapargs->rhs_is_noop = false;
- mapargs->rhs = xcalloc(mapargs->rhs_len + 1, sizeof(char_u));
- STRLCPY(mapargs->rhs, replaced, mapargs->rhs_len + 1);
+ char tmp_buf[64];
+ // stores <lua>ref_no<cr> in map_str
+ mapargs->orig_rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "<LUA>%d<CR>", rhs_lua);
+ mapargs->orig_rhs = vim_strsave((char_u *)tmp_buf);
+ mapargs->rhs_len = (size_t)vim_snprintf(S_LEN(tmp_buf), "%c%c%c%d\r", K_SPECIAL,
+ (char_u)KEY2TERMCAP0(K_LUA), KEY2TERMCAP1(K_LUA),
+ rhs_lua);
+ mapargs->rhs = vim_strsave((char_u *)tmp_buf);
}
xfree(lhs_buf);
@@ -2765,7 +2783,7 @@ int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *mapargs)
size_t orig_rhs_len = STRLEN(rhs_start);
set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len,
- rhs_start, orig_rhs_len,
+ rhs_start, orig_rhs_len, LUA_NOREF,
CPO_TO_CPO_FLAGS, &parsed_args);
xfree(lhs_to_replace);
@@ -2827,7 +2845,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
validate_maphash();
bool has_lhs = (args->lhs[0] != NUL);
- bool has_rhs = (args->rhs[0] != NUL) || args->rhs_is_noop;
+ bool has_rhs = args->rhs_lua != LUA_NOREF || (args->rhs[0] != NUL) || args->rhs_is_noop;
// check for :unmap without argument
if (maptype == 1 && !has_lhs) {
@@ -3017,10 +3035,14 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
} else { // new rhs for existing entry
mp->m_mode &= ~mode; // remove mode bits
if (mp->m_mode == 0 && !did_it) { // reuse entry
- xfree(mp->m_str);
+ XFREE_CLEAR(mp->m_str);
+ XFREE_CLEAR(mp->m_orig_str);
+ XFREE_CLEAR(mp->m_desc);
+ NLUA_CLEAR_REF(mp->m_luaref);
+
mp->m_str = vim_strsave(rhs);
- xfree(mp->m_orig_str);
mp->m_orig_str = vim_strsave(orig_rhs);
+ mp->m_luaref = args->rhs_lua;
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
mp->m_silent = args->silent;
@@ -3028,6 +3050,9 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
mp->m_expr = args->expr;
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ if (args->desc != NULL) {
+ mp->m_desc = xstrdup(args->desc);
+ }
did_it = true;
}
}
@@ -3096,6 +3121,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
mp->m_keys = vim_strsave(lhs);
mp->m_str = vim_strsave(rhs);
mp->m_orig_str = vim_strsave(orig_rhs);
+ mp->m_luaref = args->rhs_lua;
mp->m_keylen = (int)STRLEN(mp->m_keys);
mp->m_noremap = noremap;
mp->m_nowait = args->nowait;
@@ -3104,6 +3130,10 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T
mp->m_expr = args->expr;
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
+ mp->m_desc = NULL;
+ if (args->desc != NULL) {
+ mp->m_desc = xstrdup(args->desc);
+ }
// add the new entry in front of the abbrlist or maphash[] list
if (is_abbrev) {
@@ -3200,8 +3230,10 @@ static void mapblock_free(mapblock_T **mpp)
mp = *mpp;
xfree(mp->m_keys);
- xfree(mp->m_str);
- xfree(mp->m_orig_str);
+ NLUA_CLEAR_REF(mp->m_luaref);
+ XFREE_CLEAR(mp->m_str);
+ XFREE_CLEAR(mp->m_orig_str);
+ XFREE_CLEAR(mp->m_desc);
*mpp = mp->m_next;
xfree(mp);
}
@@ -3392,7 +3424,8 @@ static void showmap(mapblock_T *mp, bool local)
{
size_t len = 1;
- if (message_filtered(mp->m_keys) && message_filtered(mp->m_str)) {
+ if (message_filtered(mp->m_keys)
+ && mp->m_str != NULL && message_filtered(mp->m_str)) {
return;
}
@@ -3437,7 +3470,11 @@ static void showmap(mapblock_T *mp, bool local)
/* Use FALSE below if we only want things like <Up> to show up as such on
* the rhs, and not M-x etc, TRUE gets both -- webb */
- if (*mp->m_str == NUL) {
+ if (mp->m_luaref != LUA_NOREF) {
+ char msg[100];
+ snprintf(msg, sizeof(msg), "<Lua function %d>", mp->m_luaref);
+ msg_puts_attr(msg, HL_ATTR(HLF_8));
+ } else if (mp->m_str == NULL) {
msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
} else {
// Remove escaping of CSI, because "m_str" is in a format to be used
@@ -3447,6 +3484,11 @@ static void showmap(mapblock_T *mp, bool local)
msg_outtrans_special(s, false, 0);
xfree(s);
}
+
+ if (mp->m_desc != NULL) {
+ msg_puts("\n "); // Shift line to same level as rhs.
+ msg_puts(mp->m_desc);
+ }
if (p_verbose > 0) {
last_set_msg(mp->m_script_ctx);
}
@@ -3533,7 +3575,7 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
}
for (; mp; mp = mp->m_next) {
if ((mp->m_mode & mode)
- && strstr((char *)mp->m_str, rhs) != NULL) {
+ && mp->m_str != NULL && strstr((char *)mp->m_str, rhs) != NULL) {
return true;
}
}
@@ -3879,7 +3921,7 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
(void)ins_typebuf(tb, 1, 0, true, mp->m_silent);
}
if (mp->m_expr) {
- s = eval_map_expr(mp->m_str, c);
+ s = eval_map_expr(mp, c);
} else {
s = mp->m_str;
}
@@ -3909,11 +3951,11 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
/// special characters.
///
/// @param c NUL or typed character for abbreviation
-static char_u *eval_map_expr(char_u *str, int c)
+static char_u *eval_map_expr(mapblock_T *mp, int c)
{
char_u *res;
- char_u *p;
- char_u *expr;
+ char_u *p = NULL;
+ char_u *expr = NULL;
char_u *save_cmd;
pos_T save_cursor;
int save_msg_col;
@@ -3921,8 +3963,10 @@ static char_u *eval_map_expr(char_u *str, int c)
/* Remove escaping of CSI, because "str" is in a format to be used as
* typeahead. */
- expr = vim_strsave(str);
- vim_unescape_csi(expr);
+ if (mp->m_luaref == LUA_NOREF) {
+ expr = vim_strsave(mp->m_str);
+ vim_unescape_csi(expr);
+ }
save_cmd = save_cmdline_alloc();
@@ -3934,7 +3978,22 @@ static char_u *eval_map_expr(char_u *str, int c)
save_cursor = curwin->w_cursor;
save_msg_col = msg_col;
save_msg_row = msg_row;
- p = eval_to_string(expr, NULL, false);
+ if (mp->m_luaref != LUA_NOREF) {
+ Error err = ERROR_INIT;
+ Array args = ARRAY_DICT_INIT;
+ Object ret = nlua_call_ref(mp->m_luaref, NULL, args, true, &err);
+ if (ret.type == kObjectTypeString) {
+ p = (char_u *)xstrndup(ret.data.string.data, ret.data.string.size);
+ }
+ api_free_object(ret);
+ if (err.type != kErrorTypeNone) {
+ semsg_multiline("E5108: %s", err.msg);
+ api_clear_error(&err);
+ }
+ } else {
+ p = eval_to_string(expr, NULL, false);
+ xfree(expr);
+ }
textlock--;
ex_normal_lock--;
curwin->w_cursor = save_cursor;
@@ -3942,7 +4001,6 @@ static char_u *eval_map_expr(char_u *str, int c)
msg_row = save_msg_row;
restore_cmdline_alloc(save_cmd);
- xfree(expr);
if (p == NULL) {
return NULL;
@@ -4049,8 +4107,11 @@ int makemap(FILE *fd, buf_T *buf)
continue;
}
- // skip mappings that contain a <SNR> (script-local thing),
+ // skip lua mappings and mappings that contain a <SNR> (script-local thing),
// they probably don't work when loaded again
+ if (mp->m_luaref != LUA_NOREF) {
+ continue;
+ }
for (p = mp->m_str; *p != NUL; p++) {
if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
&& p[2] == (int)KE_SNR) {
@@ -4331,10 +4392,11 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
/// @param mp_ptr return: pointer to mapblock or NULL
/// @param local_ptr return: buffer-local mapping or NULL
char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr,
- int *local_ptr)
+ int *local_ptr, int *rhs_lua)
{
int len, minlen;
mapblock_T *mp;
+ *rhs_lua = LUA_NOREF;
validate_maphash();
@@ -4375,7 +4437,8 @@ char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapb
if (local_ptr != NULL) {
*local_ptr = local;
}
- return mp->m_str;
+ *rhs_lua = mp->m_luaref;
+ return mp->m_luaref == LUA_NOREF ? mp->m_str : NULL;
}
}
}
@@ -4560,3 +4623,47 @@ char_u *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
return (char_u *)line_ga.ga_data;
}
+
+bool map_execute_lua(void)
+{
+ garray_T line_ga;
+ int c1 = -1;
+ bool aborted = false;
+
+ ga_init(&line_ga, 1, 32);
+
+ no_mapping++;
+
+ got_int = false;
+ while (c1 != NUL && !aborted) {
+ ga_grow(&line_ga, 32);
+ // Get one character at a time.
+ c1 = vgetorpeek(true);
+ if (got_int) {
+ aborted = true;
+ } else if (c1 == '\r' || c1 == '\n') {
+ c1 = NUL; // end the line
+ } else {
+ ga_append(&line_ga, (char)c1);
+ }
+ }
+
+ no_mapping--;
+
+ if (aborted) {
+ ga_clear(&line_ga);
+ return false;
+ }
+
+ LuaRef ref = (LuaRef)atoi(line_ga.ga_data);
+ Error err = ERROR_INIT;
+ Array args = ARRAY_DICT_INIT;
+ nlua_call_ref(ref, NULL, args, false, &err);
+ if (err.type != kErrorTypeNone) {
+ semsg_multiline("E5108: %s", err.msg);
+ api_clear_error(&err);
+ }
+
+ ga_clear(&line_ga);
+ return true;
+}
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index 5950611d3f..be10e150e5 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -50,14 +50,16 @@ struct map_arguments {
char_u *rhs; /// The {rhs} of the mapping.
size_t rhs_len;
+ LuaRef rhs_lua; /// lua function as rhs
bool rhs_is_noop; /// True when the {orig_rhs} is <nop>.
char_u *orig_rhs; /// The original text of the {rhs}.
size_t orig_rhs_len;
+ char *desc; /// map escription
};
typedef struct map_arguments MapArguments;
#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \
- { 0 }, 0, NULL, 0, false, NULL, 0 }
+ { 0 }, 0, NULL, 0, LUA_NOREF, false, NULL, 0, NULL }
#define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code
#define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 697d4b11a7..40c61d01b5 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -28,7 +28,7 @@
#endif
#ifndef FILETYPE_FILE
-# define FILETYPE_FILE "filetype.vim"
+# define FILETYPE_FILE "filetype.lua filetype.vim"
#endif
#ifndef FTPLUGIN_FILE
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 5ff5a38614..5a74d1dc00 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -245,6 +245,7 @@ enum key_extra {
KE_MOUSEMOVE = 100, // mouse moved with no button down
// , KE_CANCEL = 101 // return from vgetc
KE_EVENT = 102, // event
+ KE_LUA = 103, // lua special key
KE_COMMAND = 104, // <Cmd> special key
};
@@ -443,6 +444,7 @@ enum key_extra {
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
+#define K_LUA TERMCAP2KEY(KS_EXTRA, KE_LUA)
// Bits for modifier mask
// 0x01 cannot be used, because the modifier must be 0x02 or higher
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index b6792a5a97..8a702ddd60 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -1242,7 +1242,12 @@ LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
{ \
type ret; \
- ret = (type)lua_tonumber(lstate, -1); \
+ if (lua_type(lstate, -1) != LUA_TNUMBER) { \
+ api_set_error(err, kErrorTypeValidation, "Expected Lua number"); \
+ ret = (type)-1; \
+ } else { \
+ ret = (type)lua_tonumber(lstate, -1); \
+ } \
lua_pop(lstate, 1); \
return ret; \
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 107ff22913..c814974fe7 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -18,6 +18,7 @@
#include "nvim/event/loop.h"
#include "nvim/event/time.h"
#include "nvim/ex_cmds2.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/extmark.h"
#include "nvim/func_attr.h"
@@ -433,6 +434,15 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// [package, loaded, module]
lua_setfield(lstate, -2, "vim.F"); // [package, loaded]
+ code = (char *)&lua_filetype_module[0];
+ if (luaL_loadbuffer(lstate, code, sizeof(lua_filetype_module) - 1, "@vim/filetype.lua")
+ || nlua_pcall(lstate, 0, 1)) {
+ nlua_error(lstate, _("E5106: Error while creating vim.filetype module: %.*s"));
+ return 1;
+ }
+ // [package, loaded, module]
+ lua_setfield(lstate, -2, "vim.filetype"); // [package, loaded]
+
lua_pop(lstate, 2); // []
}
@@ -914,6 +924,24 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, int arg
}
}
+void nlua_call_user_expand_func(expand_T *xp, typval_T *ret_tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ lua_State *const lstate = global_lstate;
+
+ nlua_pushref(lstate, xp->xp_luaref);
+ lua_pushstring(lstate, (char *)xp->xp_pattern);
+ lua_pushstring(lstate, (char *)xp->xp_line);
+ lua_pushinteger(lstate, xp->xp_col);
+
+ if (nlua_pcall(lstate, 3, 1)) {
+ nlua_error(lstate, _("E5108: Error executing Lua function: %.*s"));
+ return;
+ }
+
+ nlua_pop_typval(lstate, ret_tv);
+}
+
static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name,
typval_T *const args, int argcount, bool special, typval_T *ret_tv)
{
@@ -1096,11 +1124,23 @@ void ex_lua(exarg_T *const eap)
FUNC_ATTR_NONNULL_ALL
{
size_t len;
- char *const code = script_get(eap, &len);
+ char *code = script_get(eap, &len);
if (eap->skip) {
xfree(code);
return;
}
+ // When =expr is used transform it to print(vim.inspect(expr))
+ if (code[0] == '=') {
+ len += sizeof("print(vim.inspect())") - sizeof("=");
+ // code_buf needs to be 1 char larger then len for null byte in the end.
+ // lua nlua_typval_exec doesn't expect null terminated string so len
+ // needs to end before null byte.
+ char *code_buf = xmallocz(len);
+ vim_snprintf(code_buf, len+1, "print(vim.inspect(%s))", code+1);
+ xfree(code);
+ code = code_buf;
+ }
+
nlua_typval_exec(code, len, ":lua", NULL, 0, false, NULL);
xfree(code);
@@ -1432,3 +1472,48 @@ void nlua_execute_on_key(int c)
#endif
}
+void nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap)
+{
+ lua_State *const lstate = global_lstate;
+
+ nlua_pushref(lstate, cmd->uc_luaref);
+
+ lua_newtable(lstate);
+ lua_pushboolean(lstate, eap->forceit == 1);
+ lua_setfield(lstate, -2, "bang");
+
+ lua_pushinteger(lstate, eap->line1);
+ lua_setfield(lstate, -2, "line1");
+
+ lua_pushinteger(lstate, eap->line2);
+ lua_setfield(lstate, -2, "line2");
+
+ lua_pushstring(lstate, (const char *)eap->arg);
+ lua_setfield(lstate, -2, "args");
+
+ lua_pushstring(lstate, (const char *)&eap->regname);
+ lua_setfield(lstate, -2, "reg");
+
+ lua_pushinteger(lstate, eap->addr_count);
+ lua_setfield(lstate, -2, "range");
+
+ if (eap->addr_count > 0) {
+ lua_pushinteger(lstate, eap->line2);
+ } else {
+ lua_pushinteger(lstate, cmd->uc_def);
+ }
+ lua_setfield(lstate, -2, "count");
+
+ // The size of this buffer is chosen empirically to be large enough to hold
+ // every possible modifier (with room to spare). If the list of possible
+ // modifiers grows this may need to be updated.
+ char buf[200] = { 0 };
+ (void)uc_mods(buf);
+ lua_pushstring(lstate, buf);
+ lua_setfield(lstate, -2, "mods");
+
+ if (nlua_pcall(lstate, 1, 0)) {
+ nlua_error(lstate, _("Error executing Lua callback: %.*s"));
+ }
+}
+
diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h
index a1f66bd02b..bf78f7ec5e 100644
--- a/src/nvim/lua/executor.h
+++ b/src/nvim/lua/executor.h
@@ -7,6 +7,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds_defs.h"
+#include "nvim/ex_docmd.h"
#include "nvim/func_attr.h"
#include "nvim/lua/converter.h"
diff --git a/src/nvim/lua/spell.c b/src/nvim/lua/spell.c
index b84124bc19..3a63f61200 100644
--- a/src/nvim/lua/spell.c
+++ b/src/nvim/lua/spell.c
@@ -1,3 +1,5 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <lua.h>
#include <lauxlib.h>
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index c1a1e7f162..6ef46ee844 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -40,6 +40,9 @@ assert(vim)
vim.inspect = package.loaded['vim.inspect']
assert(vim.inspect)
+vim.filetype = package.loaded['vim.filetype']
+assert(vim.filetype)
+
local pathtrails = {}
vim._so_trails = {}
for s in (package.cpath..';'):gmatch('[^;]*;') do
@@ -424,7 +427,7 @@ end
--- Without a runtime, writes to :Messages
---@see :help nvim_notify
---@param msg string Content of the notification to show to the user
----@param log_level number|nil enum from vim.log.levels
+---@param log_level number|nil enum from |vim.log.levels|
---@param opts table|nil additional options (timeout, etc)
function vim.notify(msg, log_level, opts) -- luacheck: no unused
if log_level == vim.log.levels.ERROR then
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 1d9abe3ef2..c77433df71 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -29,8 +29,6 @@
#define uint32_t_eq kh_int_hash_equal
#define int_hash kh_int_hash_func
#define int_eq kh_int_hash_equal
-#define linenr_T_hash kh_int_hash_func
-#define linenr_T_eq kh_int_hash_equal
#define handle_T_hash kh_int_hash_func
#define handle_T_eq kh_int_hash_equal
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 3246596f16..60bf393085 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -334,6 +334,7 @@ static const struct nv_cmd {
{ K_SELECT, nv_select, 0, 0 },
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
{ K_COMMAND, nv_colon, 0, 0 },
+ { K_LUA, nv_colon, 0, 0 },
};
// Number of commands in nv_cmds[].
@@ -4043,21 +4044,22 @@ static void nv_regreplay(cmdarg_T *cap)
}
}
-/// Handle a ":" command and <Cmd>.
+/// Handle a ":" command and <Cmd> or Lua keymaps.
static void nv_colon(cmdarg_T *cap)
{
int old_p_im;
bool cmd_result;
bool is_cmdkey = cap->cmdchar == K_COMMAND;
+ bool is_lua = cap->cmdchar == K_LUA;
- if (VIsual_active && !is_cmdkey) {
+ if (VIsual_active && !is_cmdkey && !is_lua) {
nv_operator(cap);
} else {
if (cap->oap->op_type != OP_NOP) {
// Using ":" as a movement is charwise exclusive.
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
- } else if (cap->count0 && !is_cmdkey) {
+ } else if (cap->count0 && !is_cmdkey && !is_lua) {
// translate "count:" into ":.,.+(count - 1)"
stuffcharReadbuff('.');
if (cap->count0 > 1) {
@@ -4073,9 +4075,13 @@ static void nv_colon(cmdarg_T *cap)
old_p_im = p_im;
+ if (is_lua) {
+ cmd_result = map_execute_lua();
+ } else {
// get a command line and execute it
- cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
- cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
+ cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
+ cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
+ }
// If 'insertmode' changed, enter or exit Insert mode
if (p_im != old_p_im) {
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 6c2db1e9ac..013a78bdac 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -915,10 +915,29 @@ int do_record(int c)
apply_autocmds(EVENT_RECORDINGENTER, NULL, NULL, false, curbuf);
}
} else { // stop recording
+ save_v_event_T save_v_event;
+ // Set the v:event dictionary with information about the recording.
+ dict_T *dict = get_v_event(&save_v_event);
+
+ // The recorded text contents.
+ p = get_recorded();
+ if (p != NULL) {
+ // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
+ vim_unescape_csi(p);
+ (void)tv_dict_add_str(dict, S_LEN("regcontents"), (const char *)p);
+ }
+
+ // Name of requested register, or empty string for unnamed operation.
+ char buf[NUMBUFLEN+2];
+ buf[0] = (char)regname;
+ buf[1] = NUL;
+ (void)tv_dict_add_str(dict, S_LEN("regname"), buf);
+
// Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
// needs to be removed again to put it in a register. exec_reg then
// adds the escaping back later.
apply_autocmds(EVENT_RECORDINGLEAVE, NULL, NULL, false, curbuf);
+ restore_v_event(dict, &save_v_event);
reg_recorded = reg_recording;
reg_recording = 0;
if (ui_has(kUIMessages)) {
@@ -926,13 +945,9 @@ int do_record(int c)
} else {
msg("");
}
- p = get_recorded();
if (p == NULL) {
retval = FAIL;
} else {
- // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
- vim_unescape_csi(p);
-
// We don't want to change the default register here, so save and
// restore the current register name.
old_y_previous = y_previous;
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 28b4eb9fe2..5133fe7ac8 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -411,7 +411,7 @@ return {
},
{
full_name='compatible', abbreviation='cp',
- short_desc=N_("No description"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
redraw={'all_windows'},
varname='p_force_off',
@@ -665,14 +665,14 @@ return {
},
{
full_name='edcompatible', abbreviation='ed',
- short_desc=N_("No description"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
varname='p_force_off',
defaults={if_true=false}
},
{
full_name='emoji', abbreviation='emo',
- short_desc=N_("No description"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
redraw={'all_windows', 'ui_option'},
varname='p_emoji',
@@ -1184,7 +1184,7 @@ return {
},
{
full_name='inccommand', abbreviation='icm',
- short_desc=N_("Live preview of substitution"),
+ short_desc=N_("Live preview of substitution"),
type='string', scope={'global'},
redraw={'all_windows'},
varname='p_icm',
@@ -2499,7 +2499,7 @@ return {
},
{
full_name='termencoding', abbreviation='tenc',
- short_desc=N_("Terminal encodig"),
+ short_desc=N_("Terminal encoding"),
type='string', scope={'global'},
defaults={if_true=""}
},
@@ -2622,7 +2622,7 @@ return {
},
{
full_name='ttyfast', abbreviation='tf',
- short_desc=N_("No description"),
+ short_desc=N_("No description"),
type='bool', scope={'global'},
no_mkrc=true,
varname='p_force_on',
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 6add541ad4..70a5c7aa08 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -135,7 +135,6 @@ struct terminal {
int row, col;
bool visible;
} cursor;
- int pressed_button; // which mouse button is pressed
bool pending_resize; // pending width/height
bool color_set[16];
@@ -529,6 +528,10 @@ static int terminal_execute(VimState *state, int key)
do_cmdline(NULL, getcmdkeycmd, NULL, 0);
break;
+ case K_LUA:
+ map_execute_lua();
+ break;
+
case Ctrl_N:
if (s->got_bsl) {
return 0;
@@ -1209,21 +1212,12 @@ static VTermKey convert_key(int key, VTermModifier *statep)
}
}
-static void mouse_action(Terminal *term, int button, int row, int col, bool drag, VTermModifier mod)
+static void mouse_action(Terminal *term, int button, int row, int col, bool pressed,
+ VTermModifier mod)
{
- if (term->pressed_button && (term->pressed_button != button || !drag)) {
- // release the previous button
- vterm_mouse_button(term->vt, term->pressed_button, 0, mod);
- term->pressed_button = 0;
- }
-
- // move the mouse
vterm_mouse_move(term->vt, row, col, mod);
-
- if (!term->pressed_button) {
- // press the button if not already pressed
- vterm_mouse_button(term->vt, button, 1, mod);
- term->pressed_button = button;
+ if (button) {
+ vterm_mouse_button(term->vt, button, pressed, mod);
}
}
@@ -1242,32 +1236,35 @@ static bool send_mouse_event(Terminal *term, int c)
// event in the terminal window and mouse events was enabled by the
// program. translate and forward the event
int button;
- bool drag = false;
+ bool pressed = false;
switch (c) {
case K_LEFTDRAG:
- drag = true; FALLTHROUGH;
case K_LEFTMOUSE:
+ pressed = true; FALLTHROUGH;
+ case K_LEFTRELEASE:
button = 1; break;
case K_MOUSEMOVE:
- drag = true; button = 0; break;
+ button = 0; break;
case K_MIDDLEDRAG:
- drag = true; FALLTHROUGH;
case K_MIDDLEMOUSE:
+ pressed = true; FALLTHROUGH;
+ case K_MIDDLERELEASE:
button = 2; break;
case K_RIGHTDRAG:
- drag = true; FALLTHROUGH;
case K_RIGHTMOUSE:
+ pressed = true; FALLTHROUGH;
+ case K_RIGHTRELEASE:
button = 3; break;
case K_MOUSEDOWN:
- button = 4; break;
+ pressed = true; button = 4; break;
case K_MOUSEUP:
- button = 5; break;
+ pressed = true; button = 5; break;
default:
return false;
}
- mouse_action(term, button, row, col - offset, drag, 0);
+ mouse_action(term, button, row, col - offset, pressed, 0);
size_t len = vterm_output_read(term->vt, term->textbuf,
sizeof(term->textbuf));
terminal_send(term, term->textbuf, len);
diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh
index 25cb8437b4..fdd3f3144b 100755
--- a/src/nvim/testdir/runnvim.sh
+++ b/src/nvim/testdir/runnvim.sh
@@ -66,7 +66,7 @@ main() {(
fi
fi
if test "$FAILED" = 1 ; then
- ci_fold start "$NVIM_TEST_CURRENT_SUITE/$test_name"
+ ci_fold start "$test_name"
fi
valgrind_check .
if test -n "$LOG_DIR" ; then
@@ -78,7 +78,7 @@ main() {(
fi
rm -f "$tlog"
if test "$FAILED" = 1 ; then
- ci_fold end "$NVIM_TEST_CURRENT_SUITE/$test_name"
+ ci_fold end ""
fi
if test "$FAILED" = 1 ; then
echo "Test $test_name failed, see output above and summary for more details" >> test.log
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index 2d01cbba83..1c053c824f 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -1,6 +1,8 @@
" Tests for various Ex commands.
source check.vim
+source shared.vim
+source term_util.vim
func Test_ex_delete()
new
@@ -122,6 +124,27 @@ func Test_append_cmd()
close!
endfunc
+func Test_append_cmd_empty_buf()
+ CheckRunVimInTerminal
+ let lines =<< trim END
+ func Timer(timer)
+ append
+ aaaaa
+ bbbbb
+ .
+ endfunc
+ call timer_start(10, 'Timer')
+ END
+ call writefile(lines, 'Xtest_append_cmd_empty_buf')
+ let buf = RunVimInTerminal('-S Xtest_append_cmd_empty_buf', {'rows': 6})
+ call WaitForAssert({-> assert_equal('bbbbb', term_getline(buf, 2))})
+ call WaitForAssert({-> assert_equal('aaaaa', term_getline(buf, 1))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_append_cmd_empty_buf')
+endfunc
+
" Test for the :insert command
func Test_insert_cmd()
set noautoindent " test assumes noautoindent, but it's on by default in Nvim
@@ -151,6 +174,27 @@ func Test_insert_cmd()
close!
endfunc
+func Test_insert_cmd_empty_buf()
+ CheckRunVimInTerminal
+ let lines =<< trim END
+ func Timer(timer)
+ insert
+ aaaaa
+ bbbbb
+ .
+ endfunc
+ call timer_start(10, 'Timer')
+ END
+ call writefile(lines, 'Xtest_insert_cmd_empty_buf')
+ let buf = RunVimInTerminal('-S Xtest_insert_cmd_empty_buf', {'rows': 6})
+ call WaitForAssert({-> assert_equal('bbbbb', term_getline(buf, 2))})
+ call WaitForAssert({-> assert_equal('aaaaa', term_getline(buf, 1))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_insert_cmd_empty_buf')
+endfunc
+
" Test for the :change command
func Test_change_cmd()
set noautoindent " test assumes noautoindent, but it's on by default in Nvim
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 1ffa1f86dc..4da68539fb 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -286,7 +286,7 @@ let s:filename_checks = {
\ 'lilo': ['lilo.conf', 'lilo.conf-file'],
\ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf', '/etc/limits.conf', '/etc/limits.d/file.conf', '/etc/some-limits.conf', '/etc/some-limits.d/file.conf', 'any/etc/limits', 'any/etc/limits.conf', 'any/etc/limits.d/file.conf', 'any/etc/some-limits.conf', 'any/etc/some-limits.d/file.conf'],
\ 'liquid': ['file.liquid'],
- \ 'lisp': ['file.lsp', 'file.lisp', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
+ \ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'],
\ 'loginaccess': ['/etc/login.access', 'any/etc/login.access'],
@@ -436,7 +436,7 @@ let s:filename_checks = {
\ 'sather': ['file.sa'],
\ 'sbt': ['file.sbt'],
\ 'scala': ['file.scala', 'file.sc'],
- \ 'scheme': ['file.scm', 'file.ss', 'file.rkt', 'file.rktd', 'file.rktl'],
+ \ 'scheme': ['file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
\ 'sexplib': ['file.sexp'],
@@ -481,7 +481,7 @@ let s:filename_checks = {
\ 'squid': ['squid.conf'],
\ 'squirrel': ['file.nut'],
\ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'],
- \ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config'],
+ \ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config', 'any/.ssh/file.conf'],
\ 'sshdconfig': ['sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'],
\ 'st': ['file.st'],
\ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'],
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index f42b177c50..440717eaa8 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -113,14 +113,14 @@ func Test_put_p_indent_visual()
endfunc
func Test_multibyte_op_end_mark()
- new
- call setline(1, 'тест')
- normal viwdp
- call assert_equal([0, 1, 7, 0], getpos("'>"))
- call assert_equal([0, 1, 7, 0], getpos("']"))
-
- normal Vyp
- call assert_equal([0, 1, 2147483647, 0], getpos("'>"))
- call assert_equal([0, 2, 7, 0], getpos("']"))
- bwipe!
- endfunc
+ new
+ call setline(1, 'тест')
+ normal viwdp
+ call assert_equal([0, 1, 7, 0], getpos("'>"))
+ call assert_equal([0, 1, 7, 0], getpos("']"))
+
+ normal Vyp
+ call assert_equal([0, 1, 2147483647, 0], getpos("'>"))
+ call assert_equal([0, 2, 7, 0], getpos("']"))
+ bwipe!
+endfunc
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index e7a60aca49..58061f020d 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1877,7 +1877,7 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, const char *col
"\x1b[?c");
} else if (konsolev > 0 && konsolev < 180770) {
// Konsole before version 18.07.70: set up a nonce profile. This has
- // side-effects on temporary font resizing. #6798
+ // side effects on temporary font resizing. #6798
data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
TMUX_WRAP(tmux,
"\x1b]50;CursorShape=%?"
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 2f8ddd1e88..6e0e9922a6 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -143,6 +143,7 @@ enum {
EXPAND_COMPILER,
EXPAND_USER_DEFINED,
EXPAND_USER_LIST,
+ EXPAND_USER_LUA,
EXPAND_SHELLCMD,
EXPAND_CSCOPE,
EXPAND_SIGN,
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index ba6cfab98b..8a14710351 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -1536,7 +1536,7 @@ static inline void east_set_error(const ParserState *const pstate, ExprASTError
/* TODO(ZyX-I): Extend syntax to allow ${expr}. This is needed to */ \
/* handle environment variables like those bash uses for */ \
/* `export -f`: their names consist not only of alphanumeric */ \
- /* characetrs. */ \
+ /* characters. */ \
case kExprNodeComplexIdentifier: \
case kExprNodePlainIdentifier: \
case kExprNodeCurlyBracesIdentifier: { \
diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h
index fe9327b27d..9d0bc9d468 100644
--- a/src/nvim/viml/parser/expressions.h
+++ b/src/nvim/viml/parser/expressions.h
@@ -57,7 +57,7 @@ typedef enum {
} LexExprTokenType;
typedef enum {
- kExprCmpEqual, ///< Equality, unequality.
+ kExprCmpEqual, ///< Equality, inequality.
kExprCmpMatches, ///< Matches regex, not matches regex.
kExprCmpGreater, ///< `>` or `<=`
kExprCmpGreaterOrEqual, ///< `>=` or `<`.
diff --git a/test/README.md b/test/README.md
index c6e173ead2..cc630cb8bf 100644
--- a/test/README.md
+++ b/test/README.md
@@ -38,7 +38,7 @@ Layout
- `/test/functional` : functional tests
- `/test/unit` : unit tests
- `/test/config` : contains `*.in` files which are transformed into `*.lua`
- files using `configure_file` CMake command: this is for acessing CMake
+ files using `configure_file` CMake command: this is for accessing CMake
variables in lua tests.
- `/test/includes` : include-files for use by luajit `ffi.cdef` C definitions
parser: normally used to make macros not accessible via this mechanism
@@ -197,7 +197,7 @@ Guidelines
(success + fail + error + pending) is the same in all environments.
- *Note:* `pending()` is ignored if it is missing an argument, unless it is
[contained in an `it()` block](https://github.com/neovim/neovim/blob/d21690a66e7eb5ebef18046c7a79ef898966d786/test/functional/ex_cmds/grep_spec.lua#L11).
- Provide empty function argument if the `pending()` call is outside of `it()`
+ Provide empty function argument if the `pending()` call is outside `it()`
([example](https://github.com/neovim/neovim/commit/5c1dc0fbe7388528875aff9d7b5055ad718014de#diff-bf80b24c724b0004e8418102f68b0679R18)).
- Really long `source([=[...]=])` blocks may break Vim's Lua syntax
highlighting. Try `:syntax sync fromstart` to fix it.
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index 6f929ad1ca..6c2c136edc 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -6,8 +6,14 @@ local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq = helpers.eq
local meths = helpers.meths
+local bufmeths = helpers.bufmeths
+local matches = helpers.matches
local source = helpers.source
local pcall_err = helpers.pcall_err
+local exec_lua = helpers.exec_lua
+local assert_alive = helpers.assert_alive
+local feed = helpers.feed
+local funcs = helpers.funcs
describe('nvim_get_commands', function()
local cmd_dict = { addr=NIL, bang=false, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='echo "Hello World"', name='Hello', nargs='1', range=NIL, register=false, script_id=0, }
@@ -78,3 +84,118 @@ describe('nvim_get_commands', function()
eq({Cmd2=cmd2, Cmd3=cmd3, Cmd4=cmd4, Finger=cmd1, TestCmd=cmd0}, meths.get_commands({builtin=false}))
end)
end)
+
+describe('nvim_add_user_command', function()
+ before_each(clear)
+
+ it('works with strings', function()
+ meths.add_user_command('SomeCommand', 'let g:command_fired = <args>', {nargs = 1})
+ meths.command('SomeCommand 42')
+ eq(42, meths.eval('g:command_fired'))
+ end)
+
+ it('works with Lua functions', function()
+ exec_lua [[
+ result = {}
+ vim.api.nvim_add_user_command('CommandWithLuaCallback', function(opts)
+ result = opts
+ end, {
+ nargs = "*",
+ bang = true,
+ count = 2,
+ })
+ ]]
+
+ eq({
+ args = "hello",
+ bang = false,
+ line1 = 1,
+ line2 = 1,
+ mods = "",
+ range = 0,
+ count = 2,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithLuaCallback hello')
+ return result
+ ]])
+
+ eq({
+ args = "",
+ bang = true,
+ line1 = 10,
+ line2 = 10,
+ mods = "botright",
+ range = 1,
+ count = 10,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('botright 10CommandWithLuaCallback!')
+ return result
+ ]])
+
+ eq({
+ args = "",
+ bang = false,
+ line1 = 1,
+ line2 = 42,
+ mods = "",
+ range = 1,
+ count = 42,
+ reg = "",
+ }, exec_lua [[
+ vim.api.nvim_command('CommandWithLuaCallback 42')
+ return result
+ ]])
+ end)
+
+ it('can define buffer-local commands', function()
+ local bufnr = meths.create_buf(false, false)
+ bufmeths.add_user_command(bufnr, "Hello", "", {})
+ matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
+ meths.set_current_buf(bufnr)
+ meths.command("Hello")
+ assert_alive()
+ end)
+
+ it('can use a Lua complete function', function()
+ exec_lua [[
+ vim.api.nvim_add_user_command('Test', '', {
+ nargs = "*",
+ complete = function(arg, cmdline, pos)
+ local options = {"aaa", "bbb", "ccc"}
+ local t = {}
+ for _, v in ipairs(options) do
+ if string.find(v, "^" .. arg) then
+ table.insert(t, v)
+ end
+ end
+ return t
+ end,
+ })
+ ]]
+
+ feed(':Test a<Tab>')
+ eq('Test aaa', funcs.getcmdline())
+ feed('<C-U>Test b<Tab>')
+ eq('Test bbb', funcs.getcmdline())
+ end)
+end)
+
+describe('nvim_del_user_command', function()
+ before_each(clear)
+
+ it('can delete global commands', function()
+ meths.add_user_command('Hello', 'echo "Hi"', {})
+ meths.command('Hello')
+ meths.del_user_command('Hello')
+ matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
+ end)
+
+ it('can delete buffer-local commands', function()
+ bufmeths.add_user_command(0, 'Hello', 'echo "Hi"', {})
+ meths.command('Hello')
+ bufmeths.del_user_command(0, 'Hello')
+ matches("Not an editor command: Hello", pcall_err(meths.command, "Hello"))
+ end)
+end)
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index dd8eef7ca0..bc2759ade7 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -5,6 +5,7 @@ local clear = helpers.clear
local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq, neq = helpers.eq, helpers.neq
+local exec_lua = helpers.exec_lua
local feed = helpers.feed
local funcs = helpers.funcs
local meths = helpers.meths
@@ -316,6 +317,55 @@ describe('nvim_get_keymap', function()
command('nnoremap \\|<Char-0x20><Char-32><Space><Bar> \\|<Char-0x20><Char-32><Space> <Bar>')
eq({space_table}, meths.get_keymap('n'))
end)
+
+ it('can handle lua keymaps', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+ eq(1, exec_lua[[return GlobalCount]])
+
+ eq(2, exec_lua[[
+ vim.api.nvim_get_keymap('n')[1].callback()
+ return GlobalCount
+ ]])
+ local mapargs = meths.get_keymap('n')
+ assert.Truthy(type(mapargs[1].callback) == 'number', 'callback is not luaref number')
+ mapargs[1].callback = nil
+ eq({
+ lhs='asdf',
+ script=0,
+ silent=0,
+ expr=0,
+ sid=0,
+ buffer=0,
+ nowait=0,
+ mode='n',
+ noremap=0,
+ lnum=0,
+ }, mapargs[1])
+ end)
+
+ it ('can handle map descriptions', function()
+ meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
+ eq({
+ lhs='lhs',
+ rhs='rhs',
+ script=0,
+ silent=0,
+ expr=0,
+ sid=0,
+ buffer=0,
+ nowait=0,
+ mode='n',
+ noremap=0,
+ lnum=0,
+ desc='map description'
+ }, meths.get_keymap('n')[1])
+ end)
end)
describe('nvim_set_keymap, nvim_del_keymap', function()
@@ -353,6 +403,7 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.sid = not opts.sid and 0 or opts.sid
to_return.buffer = not opts.buffer and 0 or opts.buffer
to_return.lnum = not opts.lnum and 0 or opts.lnum
+ to_return.desc = opts.desc
return to_return
end
@@ -717,6 +768,105 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
end)
end
end
+
+ it('can make lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ end)
+
+ it (':map command shows lua keymap correctly', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+ ]]
+ assert.truthy(string.match(exec_lua[[return vim.api.nvim_exec(':nmap asdf', true)]],
+ "^\nn asdf <Lua function %d+>"))
+ end)
+
+ it ('mapcheck() returns lua keymap correctly', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+ ]]
+ assert.truthy(string.match(funcs.mapcheck('asdf', 'n'),
+ "^<Lua function %d+>"))
+ end)
+
+ it ('maparg() returns lua keymap correctly', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() print('jkl;') end })
+ ]]
+ assert.truthy(string.match(funcs.maparg('asdf', 'n'),
+ "^<Lua function %d+>"))
+ local mapargs = funcs.maparg('asdf', 'n', false, true)
+ assert.Truthy(type(mapargs.callback) == 'number', 'callback is not luaref number')
+ mapargs.callback = nil
+ eq(generate_mapargs('n', 'asdf', nil, {}), mapargs)
+ end)
+
+ it('can make lua expr mappings', function()
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'aa', '', {callback = function() return vim.api.nvim_replace_termcodes(':lua SomeValue = 99<cr>', true, false, true) end, expr = true })
+ ]]
+
+ feed('aa')
+
+ eq(99, exec_lua[[return SomeValue]])
+ end)
+
+ it('can overwrite lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
+ ]]
+
+ feed('asdf\n')
+
+ eq(0, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can unmap lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_set_keymap ('n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_del_keymap('n', 'asdf' )
+ ]]
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
+ end)
+
+ it('can set descriptions on keymaps', function()
+ meths.set_keymap('n', 'lhs', 'rhs', {desc="map description"})
+ eq(generate_mapargs('n', 'lhs', 'rhs', {desc="map description"}), get_mapargs('n', 'lhs'))
+ eq("\nn lhs rhs\n map description",
+ helpers.exec_capture("nmap lhs"))
+ end)
end)
describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
@@ -814,4 +964,67 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
helpers.assert_alive()
end)
+
+ it('can make lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can make lua expr mappings', function()
+ exec_lua [[
+ vim.api.nvim_buf_set_keymap (0, 'n', 'aa', '', {callback = function() return vim.api.nvim_replace_termcodes(':lua SomeValue = 99<cr>', true, false, true) end, expr = true })
+ ]]
+
+ feed('aa')
+
+ eq(99, exec_lua[[return SomeValue ]])
+ end)
+
+ it('can overwrite lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount - 1 end })
+ ]]
+
+ feed('asdf\n')
+
+ eq(0, exec_lua[[return GlobalCount]])
+ end)
+
+ it('can unmap lua mappings', function()
+ eq(0, exec_lua [[
+ GlobalCount = 0
+ vim.api.nvim_buf_set_keymap (0, 'n', 'asdf', '', {callback = function() GlobalCount = GlobalCount + 1 end })
+ return GlobalCount
+ ]])
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+
+ exec_lua [[
+ vim.api.nvim_buf_del_keymap(0, 'n', 'asdf' )
+ ]]
+
+ feed('asdf\n')
+
+ eq(1, exec_lua[[return GlobalCount]])
+ eq('\nNo mapping found', helpers.exec_capture('nmap asdf'))
+ end)
end)
diff --git a/test/functional/autocmd/recording_spec.lua b/test/functional/autocmd/recording_spec.lua
index 81152758de..b9aec774f1 100644
--- a/test/functional/autocmd/recording_spec.lua
+++ b/test/functional/autocmd/recording_spec.lua
@@ -11,7 +11,7 @@ describe('RecordingEnter', function()
source_vim [[
let g:recorded = 0
autocmd RecordingEnter * let g:recorded += 1
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq(1, eval('g:recorded'))
end)
@@ -20,7 +20,7 @@ describe('RecordingEnter', function()
source_vim [[
let g:recording = ''
autocmd RecordingEnter * let g:recording = reg_recording()
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq('q', eval('g:recording'))
end)
@@ -32,7 +32,7 @@ describe('RecordingLeave', function()
source_vim [[
let g:recorded = 0
autocmd RecordingLeave * let g:recorded += 1
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq(1, eval('g:recorded'))
end)
@@ -43,10 +43,30 @@ describe('RecordingLeave', function()
let g:recording = ''
autocmd RecordingLeave * let g:recording = reg_recording()
autocmd RecordingLeave * let g:recorded = reg_recorded()
- execute "normal! qqyyq"
+ call feedkeys("qqyyq", 'xt')
]]
eq('q', eval 'g:recording')
eq('', eval 'g:recorded')
eq('q', eval 'reg_recorded()')
end)
+
+ it('populates v:event', function()
+ source_vim [[
+ let g:regname = ''
+ let g:regcontents = ''
+ autocmd RecordingLeave * let g:regname = v:event.regname
+ autocmd RecordingLeave * let g:regcontents = v:event.regcontents
+ call feedkeys("qqyyq", 'xt')
+ ]]
+ eq('q', eval 'g:regname')
+ eq('yy', eval 'g:regcontents')
+ end)
+
+ it('resets v:event', function()
+ source_vim [[
+ autocmd RecordingLeave * let g:event = v:event
+ call feedkeys("qqyyq", 'xt')
+ ]]
+ eq(0, eval 'len(v:event)')
+ end)
end)
diff --git a/test/functional/ex_cmds/append_spec.lua b/test/functional/ex_cmds/append_spec.lua
index 0a4d701794..fadb5c9b42 100644
--- a/test/functional/ex_cmds/append_spec.lua
+++ b/test/functional/ex_cmds/append_spec.lua
@@ -1,23 +1,26 @@
local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
+local dedent = helpers.dedent
+local exec = helpers.exec
local feed = helpers.feed
local clear = helpers.clear
local funcs = helpers.funcs
local command = helpers.command
local curbufmeths = helpers.curbufmeths
-
-before_each(function()
- clear()
- curbufmeths.set_lines(0, 1, true, { 'foo', 'bar', 'baz' })
-end)
-
-local buffer_contents = function()
- return curbufmeths.get_lines(0, -1, false)
-end
+local Screen = require('test.functional.ui.screen')
local cmdtest = function(cmd, prep, ret1)
describe(':' .. cmd, function()
+ before_each(function()
+ clear()
+ curbufmeths.set_lines(0, 1, true, { 'foo', 'bar', 'baz' })
+ end)
+
+ local buffer_contents = function()
+ return curbufmeths.get_lines(0, -1, false)
+ end
+
it(cmd .. 's' .. prep .. ' the current line by default', function()
command(cmd .. '\nabc\ndef\n')
eq(ret1, buffer_contents())
@@ -52,3 +55,52 @@ end
cmdtest('insert', ' before', { 'abc', 'def', 'foo', 'bar', 'baz' })
cmdtest('append', ' after', { 'foo', 'abc', 'def', 'bar', 'baz' })
cmdtest('change', '', { 'abc', 'def', 'bar', 'baz' })
+
+describe('the first line is redrawn correctly after inserting text in an empty buffer', function()
+ local screen
+ before_each(function()
+ clear()
+ screen = Screen.new(20, 8)
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true, reverse = true},
+ })
+ screen:attach()
+ end)
+
+ it('using :append', function()
+ exec(dedent([[
+ append
+ aaaaa
+ bbbbb
+ .]]))
+ screen:expect([[
+ aaaaa |
+ ^bbbbb |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
+ it('using :insert', function()
+ exec(dedent([[
+ insert
+ aaaaa
+ bbbbb
+ .]]))
+ screen:expect([[
+ aaaaa |
+ ^bbbbb |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index d86caca0e9..8d25b9d927 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -195,10 +195,10 @@ describe('memory usage', function()
local after = monitor_memory_usage(pid)
source('bwipe!')
poke_eventloop()
- -- Allow for an increase of 5% in memory usage, which accommodates minor fluctuation,
+ -- Allow for an increase of 10% in memory usage, which accommodates minor fluctuation,
-- but is small enough that if memory were not released (prior to PR #14884), the test
-- would fail.
- local upper = before.last * 1.05
+ local upper = before.last * 1.10
check_result({before=before, after=after}, pcall(ok, after.last <= upper))
end)
end)
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index 81e00bba6d..cb37fb9a1c 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -8,6 +8,7 @@ local clear = helpers.clear
local eval = helpers.eval
local NIL = helpers.NIL
local eq = helpers.eq
+local exec_lua = helpers.exec_lua
before_each(clear)
@@ -111,6 +112,12 @@ describe('luaeval(vim.api.…)', function()
eq(7, eval([[type(luaeval('vim.api.nvim__id(nil)'))]]))
eq({foo=1, bar={42, {{baz=true}, 5}}}, funcs.luaeval('vim.api.nvim__id({foo=1, bar={42, {{baz=true}, 5}}})'))
+
+ eq(true, funcs.luaeval('vim.api.nvim__id(vim.api.nvim__id)(true)'))
+ eq(42, exec_lua [[
+ local f = vim.api.nvim__id({42, vim.api.nvim__id})
+ return f[2](f[1])
+ ]])
end)
it('correctly converts container objects with type_idx to API objects', function()
@@ -159,12 +166,8 @@ describe('luaeval(vim.api.…)', function()
it('errors out correctly when working with API', function()
-- Conversion errors
- eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
- remove_trace(exc_exec([[call luaeval("vim.api.nvim__id(vim.api.nvim__id)")]])))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua table',
remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({1, foo=42})")]])))
- eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Cannot convert given lua type',
- remove_trace(exc_exec([[call luaeval("vim.api.nvim__id({42, vim.api.nvim__id})")]])))
-- Errors in number of arguments
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected 1 argument',
remove_trace(exc_exec([[call luaeval("vim.api.nvim__id()")]])))
@@ -180,6 +183,8 @@ describe('luaeval(vim.api.…)', function()
remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 'test', 1, false)")]])))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Number is not integral',
remove_trace(exc_exec([[call luaeval("vim.api.nvim_buf_get_lines(0, 1.5, 1, false)")]])))
+ eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected Lua number',
+ remove_trace(exc_exec([[call luaeval("vim.api.nvim_win_is_valid(nil)")]])))
eq('Vim(call):E5108: Error executing lua [string "luaeval()"]:1: Expected lua table',
remove_trace(exc_exec([[call luaeval("vim.api.nvim__id_float('test')")]])))
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index 9b9ba531b0..b3c3f937ac 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -141,6 +141,15 @@ describe(':lua command', function()
{4:Press ENTER or type command to continue}^ |
]]}
end)
+
+ it('Can print results of =expr', function()
+ helpers.exec_lua("x = 5")
+ eq("5", helpers.exec_capture(':lua =x'))
+ helpers.exec_lua("function x() return 'hello' end")
+ eq([["hello"]], helpers.exec_capture(':lua = x()'))
+ helpers.exec_lua("x = {a = 1, b = 2}")
+ eq("{\n a = 1,\n b = 2\n}", helpers.exec_capture(':lua =x'))
+ end)
end)
describe(':luado command', function()
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
index a88da63e90..7d260f2e29 100644
--- a/test/functional/lua/diagnostic_spec.lua
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -1119,6 +1119,11 @@ describe('vim.diagnostic', function()
end)
describe('set()', function()
+ it('validates its arguments', function()
+ matches("expected a list of diagnostics",
+ pcall_err(exec_lua, [[vim.diagnostic.set(1, 0, {lnum = 1, col = 2})]]))
+ end)
+
it('can perform updates after insert_leave', function()
exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
nvim("input", "o")
diff --git a/test/functional/lua/filetype_spec.lua b/test/functional/lua/filetype_spec.lua
new file mode 100644
index 0000000000..756591571e
--- /dev/null
+++ b/test/functional/lua/filetype_spec.lua
@@ -0,0 +1,669 @@
+local helpers = require('test.functional.helpers')(after_each)
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local clear = helpers.clear
+local pathroot = helpers.pathroot
+local meths = helpers.meths
+local curbufmeths = helpers.curbufmeths
+local funcs = helpers.funcs
+
+local root = pathroot()
+
+describe('vim.filetype', function()
+ before_each(function()
+ clear()
+
+ exec_lua [[
+ local bufnr = vim.api.nvim_create_buf(true, false)
+ vim.api.nvim_set_current_buf(bufnr)
+ ]]
+ end)
+
+ it('works with extensions', function()
+ eq('radicalscript', exec_lua [[
+ vim.filetype.add({
+ extension = {
+ rs = 'radicalscript',
+ },
+ })
+ vim.filetype.match('main.rs')
+ return vim.bo.filetype
+ ]])
+ end)
+
+ it('prioritizes filenames over extensions', function()
+ eq('somethingelse', exec_lua [[
+ vim.filetype.add({
+ extension = {
+ rs = 'radicalscript',
+ },
+ filename = {
+ ['main.rs'] = 'somethingelse',
+ },
+ })
+ vim.filetype.match('main.rs')
+ return vim.bo.filetype
+ ]])
+ end)
+
+ it('works with filenames', function()
+ eq('nim', exec_lua [[
+ vim.filetype.add({
+ filename = {
+ ['s_O_m_e_F_i_l_e'] = 'nim',
+ },
+ })
+ vim.filetype.match('s_O_m_e_F_i_l_e')
+ return vim.bo.filetype
+ ]])
+
+ eq('dosini', exec_lua([[
+ local root = ...
+ vim.filetype.add({
+ filename = {
+ ['config'] = 'toml',
+ [root .. '/.config/fun/config'] = 'dosini',
+ },
+ })
+ vim.filetype.match(root .. '/.config/fun/config')
+ return vim.bo.filetype
+ ]], root))
+ end)
+
+ it('works with patterns', function()
+ eq('markdown', exec_lua([[
+ local root = ...
+ vim.filetype.add({
+ pattern = {
+ [root .. '/blog/.*%.txt'] = 'markdown',
+ }
+ })
+ vim.filetype.match(root .. '/blog/why_neovim_is_awesome.txt')
+ return vim.bo.filetype
+ ]], root))
+ end)
+
+ it('works with functions', function()
+ eq('foss', exec_lua [[
+ vim.filetype.add({
+ pattern = {
+ ["relevant_to_(%a+)"] = function(path, bufnr, capture)
+ if capture == "me" then
+ return "foss"
+ end
+ end,
+ }
+ })
+ vim.filetype.match('relevant_to_me')
+ return vim.bo.filetype
+ ]])
+ end)
+
+ it('correctly detects filetypes from test_filetype', function()
+ -- Checks copied from test_filetype.vim
+ local filename_checks = {
+ ['8th'] = {'file.8th'},
+ ['a2ps'] = {'/etc/a2ps.cfg', '/etc/a2ps/file.cfg', 'a2psrc', '.a2psrc', 'any/etc/a2ps.cfg', 'any/etc/a2ps/file.cfg'},
+ ['a65'] = {'file.a65'},
+ ['aap'] = {'file.aap'},
+ ['abap'] = {'file.abap'},
+ ['abc'] = {'file.abc'},
+ ['abel'] = {'file.abl'},
+ ['acedb'] = {'file.wrm'},
+ ['ada'] = {'file.adb', 'file.ads', 'file.ada', 'file.gpr'},
+ ['ahdl'] = {'file.tdf'},
+ ['aidl'] = {'file.aidl'},
+ ['alsaconf'] = {'.asoundrc', '/usr/share/alsa/alsa.conf', '/etc/asound.conf', 'any/etc/asound.conf', 'any/usr/share/alsa/alsa.conf'},
+ ['aml'] = {'file.aml'},
+ ['ampl'] = {'file.run'},
+ ['ant'] = {'build.xml'},
+ ['apache'] = {'.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'},
+ ['apachestyle'] = {'/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'},
+ ['applescript'] = {'file.scpt'},
+ ['aptconf'] = {'apt.conf', '/.aptitude/config', 'any/.aptitude/config'},
+ ['arch'] = {'.arch-inventory', '=tagging-method'},
+ ['arduino'] = {'file.ino', 'file.pde'},
+ ['art'] = {'file.art'},
+ ['asciidoc'] = {'file.asciidoc', 'file.adoc'},
+ ['asn'] = {'file.asn', 'file.asn1'},
+ ['asterisk'] = {'asterisk/file.conf', 'asterisk/file.conf-file', 'some-asterisk/file.conf', 'some-asterisk/file.conf-file'},
+ ['atlas'] = {'file.atl', 'file.as'},
+ ['autohotkey'] = {'file.ahk'},
+ ['autoit'] = {'file.au3'},
+ ['automake'] = {'GNUmakefile.am', 'makefile.am', 'Makefile.am'},
+ ['ave'] = {'file.ave'},
+ ['awk'] = {'file.awk', 'file.gawk'},
+ ['b'] = {'file.mch', 'file.ref', 'file.imp'},
+ ['bzl'] = {'file.bazel', 'file.bzl', 'WORKSPACE'},
+ ['bc'] = {'file.bc'},
+ ['bdf'] = {'file.bdf'},
+ ['bib'] = {'file.bib'},
+ ['beancount'] = {'file.beancount'},
+ ['bindzone'] = {'named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'},
+ ['blank'] = {'file.bl'},
+ ['bsdl'] = {'file.bsd', 'file.bsdl', 'bsd', 'some-bsd'},
+ ['bst'] = {'file.bst'},
+ ['bzr'] = {'bzr_log.any', 'bzr_log.file'},
+ ['c'] = {'enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg'},
+ ['cabal'] = {'file.cabal'},
+ ['cabalconfig'] = {'cabal.config'},
+ ['cabalproject'] = {'cabal.project', 'cabal.project.local'},
+ ['calendar'] = {'calendar', '/.calendar/file', '/share/calendar/any/calendar.file', '/share/calendar/calendar.file', 'any/share/calendar/any/calendar.file', 'any/share/calendar/calendar.file'},
+ ['catalog'] = {'catalog', 'sgml.catalogfile', 'sgml.catalog', 'sgml.catalog-file'},
+ ['cdl'] = {'file.cdl'},
+ ['cdrdaoconf'] = {'/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao', 'any/etc/cdrdao.conf', 'any/etc/default/cdrdao', 'any/etc/defaults/cdrdao'},
+ ['cdrtoc'] = {'file.toc'},
+ ['cf'] = {'file.cfm', 'file.cfi', 'file.cfc'},
+ ['cfengine'] = {'cfengine.conf'},
+ ['cfg'] = {'file.cfg', 'file.hgrc', 'filehgrc', 'hgrc', 'some-hgrc'},
+ ['ch'] = {'file.chf'},
+ ['chaiscript'] = {'file.chai'},
+ ['chaskell'] = {'file.chs'},
+ ['chill'] = {'file..ch'},
+ ['chordpro'] = {'file.chopro', 'file.crd', 'file.cho', 'file.crdpro', 'file.chordpro'},
+ ['cl'] = {'file.eni'},
+ ['clean'] = {'file.dcl', 'file.icl'},
+ ['clojure'] = {'file.clj', 'file.cljs', 'file.cljx', 'file.cljc'},
+ ['cmake'] = {'CMakeLists.txt', 'file.cmake', 'file.cmake.in'},
+ ['cmusrc'] = {'any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'},
+ ['cobol'] = {'file.cbl', 'file.cob', 'file.lib'},
+ ['coco'] = {'file.atg'},
+ ['conaryrecipe'] = {'file.recipe'},
+ ['conf'] = {'auto.master'},
+ ['config'] = {'configure.in', 'configure.ac', '/etc/hostname.file'},
+ ['context'] = {'tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'},
+ ['cpp'] = {'file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'},
+ ['crm'] = {'file.crm'},
+ ['crontab'] = {'crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'},
+ ['cs'] = {'file.cs', 'file.csx'},
+ ['csc'] = {'file.csc'},
+ ['csdl'] = {'file.csdl'},
+ ['csp'] = {'file.csp', 'file.fdr'},
+ ['css'] = {'file.css'},
+ ['cterm'] = {'file.con'},
+ ['cucumber'] = {'file.feature'},
+ ['cuda'] = {'file.cu', 'file.cuh'},
+ ['cupl'] = {'file.pld'},
+ ['cuplsim'] = {'file.si'},
+ ['cvs'] = {'cvs123'},
+ ['cvsrc'] = {'.cvsrc'},
+ ['cynpp'] = {'file.cyn'},
+ ['dart'] = {'file.dart', 'file.drt'},
+ ['datascript'] = {'file.ds'},
+ ['dcd'] = {'file.dcd'},
+ ['debchangelog'] = {'changelog.Debian', 'changelog.dch', 'NEWS.Debian', 'NEWS.dch', '/debian/changelog'},
+ ['debcontrol'] = {'/debian/control', 'any/debian/control'},
+ ['debcopyright'] = {'/debian/copyright', 'any/debian/copyright'},
+ ['debsources'] = {'/etc/apt/sources.list', '/etc/apt/sources.list.d/file.list', 'any/etc/apt/sources.list', 'any/etc/apt/sources.list.d/file.list'},
+ ['def'] = {'file.def'},
+ ['denyhosts'] = {'denyhosts.conf'},
+ ['desc'] = {'file.desc'},
+ ['desktop'] = {'file.desktop', '.directory', 'file.directory'},
+ ['dictconf'] = {'dict.conf', '.dictrc'},
+ ['dictdconf'] = {'dictd.conf', 'dictdfile.conf', 'dictd-file.conf'},
+ ['diff'] = {'file.diff', 'file.rej'},
+ ['dircolors'] = {'.dir_colors', '.dircolors', '/etc/DIR_COLORS', 'any/etc/DIR_COLORS'},
+ ['dnsmasq'] = {'/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'},
+ ['dockerfile'] = {'Containerfile', 'Dockerfile', 'file.Dockerfile', 'Dockerfile.debian', 'Containerfile.something'},
+ ['dosbatch'] = {'file.bat', 'file.sys'},
+ ['dosini'] = {'.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/pacman.conf', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'},
+ ['dot'] = {'file.dot', 'file.gv'},
+ ['dracula'] = {'file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'},
+ ['dtd'] = {'file.dtd'},
+ ['dts'] = {'file.dts', 'file.dtsi'},
+ ['dune'] = {'jbuild', 'dune', 'dune-project', 'dune-workspace'},
+ ['dylan'] = {'file.dylan'},
+ ['dylanintr'] = {'file.intr'},
+ ['dylanlid'] = {'file.lid'},
+ ['ecd'] = {'file.ecd'},
+ ['edif'] = {'file.edf', 'file.edif', 'file.edo'},
+ ['elinks'] = {'elinks.conf'},
+ ['elixir'] = {'file.ex', 'file.exs', 'mix.lock'},
+ ['eelixir'] = {'file.eex', 'file.leex'},
+ ['elm'] = {'file.elm'},
+ ['elmfilt'] = {'filter-rules'},
+ ['epuppet'] = {'file.epp'},
+ ['erlang'] = {'file.erl', 'file.hrl', 'file.yaws'},
+ ['eruby'] = {'file.erb', 'file.rhtml'},
+ ['esmtprc'] = {'anyesmtprc', 'esmtprc', 'some-esmtprc'},
+ ['esqlc'] = {'file.ec', 'file.EC'},
+ ['esterel'] = {'file.strl'},
+ ['eterm'] = {'anyEterm/file.cfg', 'Eterm/file.cfg', 'some-Eterm/file.cfg'},
+ ['exim'] = {'exim.conf'},
+ ['expect'] = {'file.exp'},
+ ['exports'] = {'exports'},
+ ['factor'] = {'file.factor'},
+ ['falcon'] = {'file.fal'},
+ ['fan'] = {'file.fan', 'file.fwt'},
+ ['fennel'] = {'file.fnl'},
+ ['fetchmail'] = {'.fetchmailrc'},
+ ['fgl'] = {'file.4gl', 'file.4gh', 'file.m4gl'},
+ ['fish'] = {'file.fish'},
+ ['focexec'] = {'file.fex', 'file.focexec'},
+ ['forth'] = {'file.ft', 'file.fth'},
+ ['fortran'] = {'file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'},
+ ['fpcmake'] = {'file.fpc'},
+ ['framescript'] = {'file.fsl'},
+ ['freebasic'] = {'file.fb', 'file.bi'},
+ ['fsharp'] = {'file.fs', 'file.fsi', 'file.fsx'},
+ ['fstab'] = {'fstab', 'mtab'},
+ ['fvwm'] = {'/.fvwm/file', 'any/.fvwm/file'},
+ ['gdb'] = {'.gdbinit', 'gdbinit'},
+ ['gdmo'] = {'file.mo', 'file.gdmo'},
+ ['gedcom'] = {'file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'},
+ ['gemtext'] = {'file.gmi', 'file.gemini'},
+ ['gift'] = {'file.gift'},
+ ['gitcommit'] = {'COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'},
+ ['gitconfig'] = {'file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'},
+ ['gitolite'] = {'gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'},
+ ['gitrebase'] = {'git-rebase-todo'},
+ ['gitsendemail'] = {'.gitsendemail.msg.xxxxxx'},
+ ['gkrellmrc'] = {'gkrellmrc', 'gkrellmrc_x'},
+ ['gnash'] = {'gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'},
+ ['gnuplot'] = {'file.gpi'},
+ ['go'] = {'file.go'},
+ ['gomod'] = {'go.mod'},
+ ['gp'] = {'file.gp', '.gprc'},
+ ['gpg'] = {'/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'},
+ ['grads'] = {'file.gs'},
+ ['gretl'] = {'file.gretl'},
+ ['groovy'] = {'file.gradle', 'file.groovy'},
+ ['group'] = {'any/etc/group', 'any/etc/group-', 'any/etc/group.edit', 'any/etc/gshadow', 'any/etc/gshadow-', 'any/etc/gshadow.edit', 'any/var/backups/group.bak', 'any/var/backups/gshadow.bak', '/etc/group', '/etc/group-', '/etc/group.edit', '/etc/gshadow', '/etc/gshadow-', '/etc/gshadow.edit', '/var/backups/group.bak', '/var/backups/gshadow.bak'},
+ ['grub'] = {'/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf', 'any/boot/grub/grub.conf', 'any/boot/grub/menu.lst', 'any/etc/grub.conf'},
+ ['gsp'] = {'file.gsp'},
+ ['gtkrc'] = {'.gtkrc', 'gtkrc', '.gtkrc-file', 'gtkrc-file'},
+ ['haml'] = {'file.haml'},
+ ['hamster'] = {'file.hsm'},
+ ['haskell'] = {'file.hs', 'file.hsc', 'file.hs-boot', 'file.hsig'},
+ ['haste'] = {'file.ht'},
+ ['hastepreproc'] = {'file.htpp'},
+ ['hb'] = {'file.hb'},
+ ['hercules'] = {'file.vc', 'file.ev', 'file.sum', 'file.errsum'},
+ ['hex'] = {'file.hex', 'file.h32'},
+ ['hgcommit'] = {'hg-editor-file.txt'},
+ ['hog'] = {'file.hog', 'snort.conf', 'vision.conf'},
+ ['hollywood'] = {'file.hws'},
+ ['hostconf'] = {'/etc/host.conf', 'any/etc/host.conf'},
+ ['hostsaccess'] = {'/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'},
+ ['i3config'] = {'/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'},
+ ['logcheck'] = {'/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'},
+ ['modula3'] = {'file.m3', 'file.mg', 'file.i3', 'file.ig'},
+ ['natural'] = {'file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'},
+ ['neomuttrc'] = {'Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'},
+ ['opl'] = {'file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'},
+ ['pcmk'] = {'file.pcmk'},
+ ['r'] = {'file.r'},
+ ['rhelp'] = {'file.rd'},
+ ['rmd'] = {'file.rmd', 'file.smd'},
+ ['rnoweb'] = {'file.rnw', 'file.snw'},
+ ['rrst'] = {'file.rrst', 'file.srst'},
+ ['template'] = {'file.tmpl'},
+ ['htmlm4'] = {'file.html.m4'},
+ ['httest'] = {'file.htt', 'file.htb'},
+ ['ibasic'] = {'file.iba', 'file.ibi'},
+ ['icemenu'] = {'/.icewm/menu', 'any/.icewm/menu'},
+ ['icon'] = {'file.icn'},
+ ['indent'] = {'.indent.pro', 'indentrc'},
+ ['inform'] = {'file.inf', 'file.INF'},
+ ['initng'] = {'/etc/initng/any/file.i', 'file.ii', 'any/etc/initng/any/file.i'},
+ ['inittab'] = {'inittab'},
+ ['ipfilter'] = {'ipf.conf', 'ipf6.conf', 'ipf.rules'},
+ ['iss'] = {'file.iss'},
+ ['ist'] = {'file.ist', 'file.mst'},
+ ['j'] = {'file.ijs'},
+ ['jal'] = {'file.jal', 'file.JAL'},
+ ['jam'] = {'file.jpl', 'file.jpr', 'JAM-file.file', 'JAM.file', 'Prl-file.file', 'Prl.file'},
+ ['java'] = {'file.java', 'file.jav'},
+ ['javacc'] = {'file.jj', 'file.jjt'},
+ ['javascript'] = {'file.js', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'},
+ ['javascriptreact'] = {'file.jsx'},
+ ['jess'] = {'file.clp'},
+ ['jgraph'] = {'file.jgr'},
+ ['jovial'] = {'file.jov', 'file.j73', 'file.jovial'},
+ ['jproperties'] = {'file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'},
+ ['json'] = {'file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'},
+ ['jsonc'] = {'file.jsonc'},
+ ['jsp'] = {'file.jsp'},
+ ['julia'] = {'file.jl'},
+ ['kconfig'] = {'Kconfig', 'Kconfig.debug', 'Kconfig.file'},
+ ['kivy'] = {'file.kv'},
+ ['kix'] = {'file.kix'},
+ ['kotlin'] = {'file.kt', 'file.ktm', 'file.kts'},
+ ['kscript'] = {'file.ks'},
+ ['kwt'] = {'file.k'},
+ ['lace'] = {'file.ace', 'file.ACE'},
+ ['latte'] = {'file.latte', 'file.lte'},
+ ['ld'] = {'file.ld'},
+ ['ldif'] = {'file.ldif'},
+ ['less'] = {'file.less'},
+ ['lex'] = {'file.lex', 'file.l', 'file.lxx', 'file.l++'},
+ ['lftp'] = {'lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'},
+ ['lhaskell'] = {'file.lhs'},
+ ['libao'] = {'/etc/libao.conf', '/.libao', 'any/.libao', 'any/etc/libao.conf'},
+ ['lifelines'] = {'file.ll'},
+ ['lilo'] = {'lilo.conf', 'lilo.conf-file'},
+ ['limits'] = {'/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf', '/etc/limits.conf', '/etc/limits.d/file.conf', '/etc/some-limits.conf', '/etc/some-limits.d/file.conf', 'any/etc/limits', 'any/etc/limits.conf', 'any/etc/limits.d/file.conf', 'any/etc/some-limits.conf', 'any/etc/some-limits.d/file.conf'},
+ ['liquid'] = {'file.liquid'},
+ ['lisp'] = {'file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'},
+ ['lite'] = {'file.lite', 'file.lt'},
+ ['litestep'] = {'/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'},
+ ['loginaccess'] = {'/etc/login.access', 'any/etc/login.access'},
+ ['logindefs'] = {'/etc/login.defs', 'any/etc/login.defs'},
+ ['logtalk'] = {'file.lgt'},
+ ['lotos'] = {'file.lot', 'file.lotos'},
+ ['lout'] = {'file.lou', 'file.lout'},
+ ['lprolog'] = {'file.sig'},
+ ['lsl'] = {'file.lsl'},
+ ['lss'] = {'file.lss'},
+ ['lua'] = {'file.lua', 'file.rockspec', 'file.nse'},
+ ['lynx'] = {'lynx.cfg'},
+ ['matlab'] = {'file.m'},
+ ['m3build'] = {'m3makefile', 'm3overrides'},
+ ['m3quake'] = {'file.quake', 'cm3.cfg'},
+ ['m4'] = {'file.at'},
+ ['mail'] = {'snd.123', '.letter', '.letter.123', '.followup', '.article', '.article.123', 'pico.123', 'mutt-xx-xxx', 'muttng-xx-xxx', 'ae123.txt', 'file.eml', 'reportbug-file'},
+ ['mailaliases'] = {'/etc/mail/aliases', '/etc/aliases', 'any/etc/aliases', 'any/etc/mail/aliases'},
+ ['mailcap'] = {'.mailcap', 'mailcap'},
+ ['make'] = {'file.mk', 'file.mak', 'file.dsp', 'makefile', 'Makefile', 'makefile-file', 'Makefile-file', 'some-makefile', 'some-Makefile'},
+ ['mallard'] = {'file.page'},
+ ['manconf'] = {'/etc/man.conf', 'man.config', 'any/etc/man.conf'},
+ ['map'] = {'file.map'},
+ ['maple'] = {'file.mv', 'file.mpl', 'file.mws'},
+ ['markdown'] = {'file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'},
+ ['mason'] = {'file.mason', 'file.mhtml', 'file.comp'},
+ ['master'] = {'file.mas', 'file.master'},
+ ['mel'] = {'file.mel'},
+ ['meson'] = {'meson.build', 'meson_options.txt'},
+ ['messages'] = {'/log/auth', '/log/cron', '/log/daemon', '/log/debug', '/log/kern', '/log/lpr', '/log/mail', '/log/messages', '/log/news/news', '/log/syslog', '/log/user',
+ '/log/auth.log', '/log/cron.log', '/log/daemon.log', '/log/debug.log', '/log/kern.log', '/log/lpr.log', '/log/mail.log', '/log/messages.log', '/log/news/news.log', '/log/syslog.log', '/log/user.log',
+ '/log/auth.err', '/log/cron.err', '/log/daemon.err', '/log/debug.err', '/log/kern.err', '/log/lpr.err', '/log/mail.err', '/log/messages.err', '/log/news/news.err', '/log/syslog.err', '/log/user.err',
+ '/log/auth.info', '/log/cron.info', '/log/daemon.info', '/log/debug.info', '/log/kern.info', '/log/lpr.info', '/log/mail.info', '/log/messages.info', '/log/news/news.info', '/log/syslog.info', '/log/user.info',
+ '/log/auth.warn', '/log/cron.warn', '/log/daemon.warn', '/log/debug.warn', '/log/kern.warn', '/log/lpr.warn', '/log/mail.warn', '/log/messages.warn', '/log/news/news.warn', '/log/syslog.warn', '/log/user.warn',
+ '/log/auth.crit', '/log/cron.crit', '/log/daemon.crit', '/log/debug.crit', '/log/kern.crit', '/log/lpr.crit', '/log/mail.crit', '/log/messages.crit', '/log/news/news.crit', '/log/syslog.crit', '/log/user.crit',
+ '/log/auth.notice', '/log/cron.notice', '/log/daemon.notice', '/log/debug.notice', '/log/kern.notice', '/log/lpr.notice', '/log/mail.notice', '/log/messages.notice', '/log/news/news.notice', '/log/syslog.notice', '/log/user.notice'},
+ ['mf'] = {'file.mf'},
+ ['mgl'] = {'file.mgl'},
+ ['mgp'] = {'file.mgp'},
+ ['mib'] = {'file.mib', 'file.my'},
+ ['mix'] = {'file.mix', 'file.mixal'},
+ ['mma'] = {'file.nb'},
+ ['mmp'] = {'file.mmp'},
+ ['modconf'] = {'/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'},
+ ['modula2'] = {'file.m2', 'file.mi'},
+ ['monk'] = {'file.isc', 'file.monk', 'file.ssc', 'file.tsc'},
+ ['moo'] = {'file.moo'},
+ ['mp'] = {'file.mp'},
+ ['mplayerconf'] = {'mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'},
+ ['mrxvtrc'] = {'mrxvtrc', '.mrxvtrc'},
+ ['msidl'] = {'file.odl', 'file.mof'},
+ ['msql'] = {'file.msql'},
+ ['mupad'] = {'file.mu'},
+ ['mush'] = {'file.mush'},
+ ['muttrc'] = {'Muttngrc', 'Muttrc', '.muttngrc', '.muttngrc-file', '.muttrc', '.muttrc-file', '/.mutt/muttngrc', '/.mutt/muttngrc-file', '/.mutt/muttrc', '/.mutt/muttrc-file', '/.muttng/muttngrc', '/.muttng/muttngrc-file', '/.muttng/muttrc', '/.muttng/muttrc-file', '/etc/Muttrc.d/file', '/etc/Muttrc.d/file.rc', 'Muttngrc-file', 'Muttrc-file', 'any/.mutt/muttngrc', 'any/.mutt/muttngrc-file', 'any/.mutt/muttrc', 'any/.mutt/muttrc-file', 'any/.muttng/muttngrc', 'any/.muttng/muttngrc-file', 'any/.muttng/muttrc', 'any/.muttng/muttrc-file', 'any/etc/Muttrc.d/file', 'muttngrc', 'muttngrc-file', 'muttrc', 'muttrc-file'},
+ ['mysql'] = {'file.mysql'},
+ ['n1ql'] = {'file.n1ql', 'file.nql'},
+ ['named'] = {'namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'},
+ ['nanorc'] = {'/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'},
+ ['ncf'] = {'file.ncf'},
+ ['netrc'] = {'.netrc'},
+ ['nginx'] = {'file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'},
+ ['ninja'] = {'file.ninja'},
+ ['nqc'] = {'file.nqc'},
+ ['nroff'] = {'file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'},
+ ['nsis'] = {'file.nsi', 'file.nsh'},
+ ['obj'] = {'file.obj'},
+ ['ocaml'] = {'file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit', 'file.mlt', 'file.mlp', 'file.mlip', 'file.mli.cppo', 'file.ml.cppo'},
+ ['occam'] = {'file.occ'},
+ ['octave'] = {'octaverc', '.octaverc', 'octave.conf'},
+ ['omnimark'] = {'file.xom', 'file.xin'},
+ ['opam'] = {'opam', 'file.opam', 'file.opam.template'},
+ ['openroad'] = {'file.or'},
+ ['ora'] = {'file.ora'},
+ ['pamconf'] = {'/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'},
+ ['pamenv'] = {'/etc/security/pam_env.conf', '/home/user/.pam_environment', '.pam_environment', 'pam_env.conf'},
+ ['papp'] = {'file.papp', 'file.pxml', 'file.pxsl'},
+ ['pascal'] = {'file.pas', 'file.dpr', 'file.lpr'},
+ ['passwd'] = {'any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak', '/etc/passwd', '/etc/passwd-', '/etc/passwd.edit', '/etc/shadow', '/etc/shadow-', '/etc/shadow.edit', '/var/backups/passwd.bak', '/var/backups/shadow.bak'},
+ ['pbtxt'] = {'file.pbtxt'},
+ ['pccts'] = {'file.g'},
+ ['pdf'] = {'file.pdf'},
+ ['perl'] = {'file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'},
+ ['pf'] = {'pf.conf'},
+ ['pfmain'] = {'main.cf'},
+ ['php'] = {'file.php', 'file.php9', 'file.phtml', 'file.ctp'},
+ ['lpc'] = {'file.lpc', 'file.ulpc'},
+ ['pike'] = {'file.pike', 'file.pmod'},
+ ['cmod'] = {'file.cmod'},
+ ['pilrc'] = {'file.rcp'},
+ ['pine'] = {'.pinerc', 'pinerc', '.pinercex', 'pinercex'},
+ ['pinfo'] = {'/etc/pinforc', '/.pinforc', 'any/.pinforc', 'any/etc/pinforc'},
+ ['pli'] = {'file.pli', 'file.pl1'},
+ ['plm'] = {'file.plm', 'file.p36', 'file.pac'},
+ ['plp'] = {'file.plp'},
+ ['plsql'] = {'file.pls', 'file.plsql'},
+ ['po'] = {'file.po', 'file.pot'},
+ ['pod'] = {'file.pod'},
+ ['poke'] = {'file.pk'},
+ ['postscr'] = {'file.ps', 'file.pfa', 'file.afm', 'file.eps', 'file.epsf', 'file.epsi', 'file.ai'},
+ ['pov'] = {'file.pov'},
+ ['povini'] = {'.povrayrc'},
+ ['ppd'] = {'file.ppd'},
+ ['ppwiz'] = {'file.it', 'file.ih'},
+ ['privoxy'] = {'file.action'},
+ ['proc'] = {'file.pc'},
+ ['procmail'] = {'.procmail', '.procmailrc'},
+ ['prolog'] = {'file.pdb'},
+ ['promela'] = {'file.pml'},
+ ['proto'] = {'file.proto'},
+ ['protocols'] = {'/etc/protocols', 'any/etc/protocols'},
+ ['ps1'] = {'file.ps1', 'file.psd1', 'file.psm1', 'file.pssc'},
+ ['ps1xml'] = {'file.ps1xml'},
+ ['psf'] = {'file.psf'},
+ ['psl'] = {'file.psl'},
+ ['puppet'] = {'file.pp'},
+ ['pyret'] = {'file.arr'},
+ ['pyrex'] = {'file.pyx', 'file.pxd'},
+ ['python'] = {'file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'},
+ ['quake'] = {'anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'},
+ ['radiance'] = {'file.rad', 'file.mat'},
+ ['raku'] = {'file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'},
+ ['ratpoison'] = {'.ratpoisonrc', 'ratpoisonrc'},
+ ['rbs'] = {'file.rbs'},
+ ['rc'] = {'file.rc', 'file.rch'},
+ ['rcs'] = {'file,v'},
+ ['readline'] = {'.inputrc', 'inputrc'},
+ ['remind'] = {'.reminders', 'file.remind', 'file.rem', '.reminders-file'},
+ ['rego'] = {'file.rego'},
+ ['resolv'] = {'resolv.conf'},
+ ['reva'] = {'file.frt'},
+ ['rexx'] = {'file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'},
+ ['rib'] = {'file.rib'},
+ ['rnc'] = {'file.rnc'},
+ ['rng'] = {'file.rng'},
+ ['robots'] = {'robots.txt'},
+ ['routeros'] = {'file.rsc'},
+ ['rpcgen'] = {'file.x'},
+ ['rpl'] = {'file.rpl'},
+ ['rst'] = {'file.rst'},
+ ['rtf'] = {'file.rtf'},
+ ['ruby'] = {'.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile'},
+ ['rust'] = {'file.rs'},
+ ['samba'] = {'smb.conf'},
+ ['sas'] = {'file.sas'},
+ ['sass'] = {'file.sass'},
+ ['sather'] = {'file.sa'},
+ ['sbt'] = {'file.sbt'},
+ ['scala'] = {'file.scala', 'file.sc'},
+ ['scheme'] = {'file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'},
+ ['scilab'] = {'file.sci', 'file.sce'},
+ ['screen'] = {'.screenrc', 'screenrc'},
+ ['sexplib'] = {'file.sexp'},
+ ['scdoc'] = {'file.scd'},
+ ['scss'] = {'file.scss'},
+ ['sd'] = {'file.sd'},
+ ['sdc'] = {'file.sdc'},
+ ['sdl'] = {'file.sdl', 'file.pr'},
+ ['sed'] = {'file.sed'},
+ ['sensors'] = {'/etc/sensors.conf', '/etc/sensors3.conf', 'any/etc/sensors.conf', 'any/etc/sensors3.conf'},
+ ['services'] = {'/etc/services', 'any/etc/services'},
+ ['setserial'] = {'/etc/serial.conf', 'any/etc/serial.conf'},
+ ['sh'] = {'.bashrc', 'file.bash', '/usr/share/doc/bash-completion/filter.sh','/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'},
+ ['sieve'] = {'file.siv', 'file.sieve'},
+ ['simula'] = {'file.sim'},
+ ['sinda'] = {'file.sin', 'file.s85'},
+ ['sisu'] = {'file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'},
+ ['skill'] = {'file.il', 'file.ils', 'file.cdf'},
+ ['slang'] = {'file.sl'},
+ ['slice'] = {'file.ice'},
+ ['solution'] = {'file.sln'},
+ ['slpconf'] = {'/etc/slp.conf', 'any/etc/slp.conf'},
+ ['slpreg'] = {'/etc/slp.reg', 'any/etc/slp.reg'},
+ ['slpspi'] = {'/etc/slp.spi', 'any/etc/slp.spi'},
+ ['slrnrc'] = {'.slrnrc'},
+ ['slrnsc'] = {'file.score'},
+ ['sm'] = {'sendmail.cf'},
+ ['svelte'] = {'file.svelte'},
+ ['smarty'] = {'file.tpl'},
+ ['smcl'] = {'file.hlp', 'file.ihlp', 'file.smcl'},
+ ['smith'] = {'file.smt', 'file.smith'},
+ ['sml'] = {'file.sml'},
+ ['snobol4'] = {'file.sno', 'file.spt'},
+ ['sparql'] = {'file.rq', 'file.sparql'},
+ ['spec'] = {'file.spec'},
+ ['spice'] = {'file.sp', 'file.spice'},
+ ['spup'] = {'file.speedup', 'file.spdata', 'file.spd'},
+ ['spyce'] = {'file.spy', 'file.spi'},
+ ['sql'] = {'file.tyb', 'file.typ', 'file.tyc', 'file.pkb', 'file.pks'},
+ ['sqlj'] = {'file.sqlj'},
+ ['sqr'] = {'file.sqr', 'file.sqi'},
+ ['squid'] = {'squid.conf'},
+ ['squirrel'] = {'file.nut'},
+ ['srec'] = {'file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'},
+ ['sshconfig'] = {'ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config', 'any/.ssh/file.conf'},
+ ['sshdconfig'] = {'sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'},
+ ['st'] = {'file.st'},
+ ['stata'] = {'file.ado', 'file.do', 'file.imata', 'file.mata'},
+ ['stp'] = {'file.stp'},
+ ['sudoers'] = {'any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'},
+ ['svg'] = {'file.svg'},
+ ['svn'] = {'svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'},
+ ['swift'] = {'file.swift'},
+ ['swiftgyb'] = {'file.swift.gyb'},
+ ['sil'] = {'file.sil'},
+ ['sysctl'] = {'/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'},
+ ['systemd'] = {'any/systemd/file.automount', 'any/systemd/file.dnssd', 'any/systemd/file.link', 'any/systemd/file.mount', 'any/systemd/file.netdev', 'any/systemd/file.network', 'any/systemd/file.nspawn', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.slice', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/some.conf.d/file.conf', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile', '/.config/systemd/user/.#', '/.config/systemd/user/.#-file', '/.config/systemd/user/file.d/.#', '/.config/systemd/user/file.d/.#-file', '/.config/systemd/user/file.d/file.conf', '/etc/systemd/file.conf.d/file.conf', '/etc/systemd/system/.#', '/etc/systemd/system/.#-file', '/etc/systemd/system/file.d/.#', '/etc/systemd/system/file.d/.#-file', '/etc/systemd/system/file.d/file.conf', '/systemd/file.automount', '/systemd/file.dnssd', '/systemd/file.link', '/systemd/file.mount', '/systemd/file.netdev', '/systemd/file.network', '/systemd/file.nspawn', '/systemd/file.path', '/systemd/file.service', '/systemd/file.slice', '/systemd/file.socket', '/systemd/file.swap', '/systemd/file.target', '/systemd/file.timer', 'any/.config/systemd/user/.#', 'any/.config/systemd/user/.#-file', 'any/.config/systemd/user/file.d/.#', 'any/.config/systemd/user/file.d/.#-file', 'any/.config/systemd/user/file.d/file.conf', 'any/etc/systemd/file.conf.d/file.conf', 'any/etc/systemd/system/.#', 'any/etc/systemd/system/.#-file', 'any/etc/systemd/system/file.d/.#', 'any/etc/systemd/system/file.d/.#-file', 'any/etc/systemd/system/file.d/file.conf'},
+ ['systemverilog'] = {'file.sv', 'file.svh'},
+ ['tags'] = {'tags'},
+ ['tak'] = {'file.tak'},
+ ['taskdata'] = {'pending.data', 'completed.data', 'undo.data'},
+ ['taskedit'] = {'file.task'},
+ ['tcl'] = {'file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'},
+ ['teraterm'] = {'file.ttl'},
+ ['terminfo'] = {'file.ti'},
+ ['tex'] = {'file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'},
+ ['texinfo'] = {'file.texinfo', 'file.texi', 'file.txi'},
+ ['texmf'] = {'texmf.cnf'},
+ ['text'] = {'file.text', 'file.txt', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'},
+ ['tf'] = {'file.tf', '.tfrc', 'tfrc'},
+ ['tidy'] = {'.tidyrc', 'tidyrc', 'tidy.conf'},
+ ['tilde'] = {'file.t.html'},
+ ['tli'] = {'file.tli'},
+ ['tmux'] = {'tmuxfile.conf', '.tmuxfile.conf', '.tmux-file.conf', '.tmux.conf', 'tmux-file.conf', 'tmux.conf', 'tmux.conf.local'},
+ ['toml'] = {'file.toml', 'Gopkg.lock', 'Pipfile', '/home/user/.cargo/config'},
+ ['tpp'] = {'file.tpp'},
+ ['treetop'] = {'file.treetop'},
+ ['trustees'] = {'trustees.conf'},
+ ['tsalt'] = {'file.slt'},
+ ['tsscl'] = {'file.tsscl'},
+ ['tssgm'] = {'file.tssgm'},
+ ['tssop'] = {'file.tssop'},
+ ['twig'] = {'file.twig'},
+ ['typescriptreact'] = {'file.tsx'},
+ ['uc'] = {'file.uc'},
+ ['udevconf'] = {'/etc/udev/udev.conf', 'any/etc/udev/udev.conf'},
+ ['udevperm'] = {'/etc/udev/permissions.d/file.permissions', 'any/etc/udev/permissions.d/file.permissions'},
+ ['udevrules'] = {'/etc/udev/rules.d/file.rules', '/usr/lib/udev/rules.d/file.rules', '/lib/udev/rules.d/file.rules'},
+ ['uil'] = {'file.uit', 'file.uil'},
+ ['updatedb'] = {'/etc/updatedb.conf', 'any/etc/updatedb.conf'},
+ ['upstart'] = {'/usr/share/upstart/file.conf', '/usr/share/upstart/file.override', '/etc/init/file.conf', '/etc/init/file.override', '/.init/file.conf', '/.init/file.override', '/.config/upstart/file.conf', '/.config/upstart/file.override', 'any/.config/upstart/file.conf', 'any/.config/upstart/file.override', 'any/.init/file.conf', 'any/.init/file.override', 'any/etc/init/file.conf', 'any/etc/init/file.override', 'any/usr/share/upstart/file.conf', 'any/usr/share/upstart/file.override'},
+ ['upstreamdat'] = {'upstream.dat', 'UPSTREAM.DAT', 'upstream.file.dat', 'UPSTREAM.FILE.DAT', 'file.upstream.dat', 'FILE.UPSTREAM.DAT'},
+ ['upstreaminstalllog'] = {'upstreaminstall.log', 'UPSTREAMINSTALL.LOG', 'upstreaminstall.file.log', 'UPSTREAMINSTALL.FILE.LOG', 'file.upstreaminstall.log', 'FILE.UPSTREAMINSTALL.LOG'},
+ ['upstreamlog'] = {'fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'},
+ ['usserverlog'] = {'usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'},
+ ['usw2kagtlog'] = {'usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'},
+ ['vb'] = {'file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'},
+ ['vera'] = {'file.vr', 'file.vri', 'file.vrh'},
+ ['verilog'] = {'file.v'},
+ ['verilogams'] = {'file.va', 'file.vams'},
+ ['vgrindefs'] = {'vgrindefs'},
+ ['vhdl'] = {'file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123', 'file.vho', 'some.vhdl_1', 'some.vhdl_1-file'},
+ ['vim'] = {'file.vim', 'file.vba', '.exrc', '_exrc', 'some-vimrc', 'some-vimrc-file', 'vimrc', 'vimrc-file'},
+ ['viminfo'] = {'.viminfo', '_viminfo'},
+ ['vmasm'] = {'file.mar'},
+ ['voscm'] = {'file.cm'},
+ ['vrml'] = {'file.wrl'},
+ ['vroom'] = {'file.vroom'},
+ ['vue'] = {'file.vue'},
+ ['wast'] = {'file.wast', 'file.wat'},
+ ['webmacro'] = {'file.wm'},
+ ['wget'] = {'.wgetrc', 'wgetrc'},
+ ['winbatch'] = {'file.wbt'},
+ ['wml'] = {'file.wml'},
+ ['wsh'] = {'file.wsf', 'file.wsc'},
+ ['wsml'] = {'file.wsml'},
+ ['wvdial'] = {'wvdial.conf', '.wvdialrc'},
+ ['xdefaults'] = {'.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad', '/Xresources/file', '/app-defaults/file', 'Xresources', 'Xresources-file', 'any/Xresources/file', 'any/app-defaults/file'},
+ ['xhtml'] = {'file.xhtml', 'file.xht'},
+ ['xinetd'] = {'/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'},
+ ['xmath'] = {'file.msc', 'file.msf'},
+ ['xml'] = {'/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd'},
+ ['xmodmap'] = {'anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'},
+ ['xf86conf'] = {'xorg.conf', 'xorg.conf-4'},
+ ['xpm'] = {'file.xpm'},
+ ['xpm2'] = {'file.xpm2'},
+ ['xquery'] = {'file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'},
+ ['xs'] = {'file.xs'},
+ ['xsd'] = {'file.xsd'},
+ ['xslt'] = {'file.xsl', 'file.xslt'},
+ ['yacc'] = {'file.yy', 'file.yxx', 'file.y++'},
+ ['yaml'] = {'file.yaml', 'file.yml'},
+ ['raml'] = {'file.raml'},
+ ['z8a'] = {'file.z8a'},
+ ['zig'] = {'file.zig'},
+ ['zimbu'] = {'file.zu'},
+ ['zimbutempl'] = {'file.zut'},
+ ['zsh'] = {'.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh', '.zcompdump', '.zlogin', '.zlogout', '.zshenv', '.zshrc', '.zcompdump-file', '.zlog', '.zlog-file', '.zsh', '.zsh-file', 'any/etc/zprofile', 'zlog', 'zlog-file', 'zsh', 'zsh-file'},
+ ['help'] = {funcs.getenv('VIMRUNTIME') .. '/doc/help.txt'},
+ }
+
+ local filename_case_checks = {
+ ['modula2'] = {'file.DEF', 'file.MOD'},
+ ['bzl'] = {'file.BUILD', 'BUILD'},
+ }
+
+ local function check_items(checks)
+ meths.set_option('swapfile', false)
+ for ft, names in pairs(checks) do
+ for _, name in ipairs(names) do
+ meths.command('new')
+ meths.command('edit ' .. funcs.fnameescape(name))
+ if curbufmeths.get_option('filetype') == '' and curbufmeths.get_option('readonly') then -- luacheck: ignore 542
+ -- File exists but not able to edit it (permission denied)
+ else
+ eq(ft, curbufmeths.get_option('filetype'))
+ end
+ meths.command('bwipe!')
+ end
+ end
+ meths.command('set swapfile&')
+ end
+
+ meths.set_var('do_filetype_lua', 1)
+ meths.command('filetype on')
+ check_items(filename_checks)
+ if funcs.has('fname_case') == 1 then
+ check_items(filename_case_checks)
+ end
+ meths.command('filetype off')
+ end)
+end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index 317f92fcdc..9bf376b6fe 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -906,6 +906,7 @@ describe('lua stdlib', function()
exec_lua("vim.validate{arg1={nil, 'thread', true }}")
exec_lua("vim.validate{arg1={{}, 't' }, arg2={ 'foo', 's' }}")
exec_lua("vim.validate{arg1={2, function(a) return (a % 2) == 0 end, 'even number' }}")
+ exec_lua("vim.validate{arg1={5, {'n', 's'} }, arg2={ 'foo', {'n', 's'} }}")
matches('expected table, got number',
pcall_err(exec_lua, "vim.validate{ 1, 'x' }"))
@@ -935,6 +936,8 @@ describe('lua stdlib', function()
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end, 'even number'}}"))
matches('arg1: expected %?, got 3',
pcall_err(exec_lua, "vim.validate{arg1={3, function(a) return a == 1 end}}"))
+ matches('arg1: expected number|string, got nil',
+ pcall_err(exec_lua, "vim.validate{ arg1={ nil, {'n', 's'} }}"))
-- Pass an additional message back.
matches('arg1: expected %?, got 3. Info: TEST_MSG',
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 1af31c38f8..2fe7eca260 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -73,8 +73,11 @@ local function fake_lsp_server_setup(test_name, timeout_ms, options)
on_init = function(client, result)
TEST_RPC_CLIENT = client
vim.rpcrequest(1, "init", result)
- client.config.flags.allow_incremental_sync = options.allow_incremental_sync or false
end;
+ flags = {
+ allow_incremental_sync = options.allow_incremental_sync or false;
+ debounce_text_changes = 0;
+ };
on_exit = function(...)
vim.rpcnotify(1, "exit", ...)
end;
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index f25cfa2039..1ff451434d 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -350,7 +350,7 @@ describe('on_lines does not emit out-of-bounds line indexes when', function()
end)
it('creating a terminal buffer #16394', function()
- feed_command([[autocmd TermOpen * ++once call v:lua.register_callback(expand("<abuf>"))]])
+ feed_command('autocmd TermOpen * ++once call v:lua.register_callback(str2nr(expand("<abuf>")))')
feed_command('terminal')
sleep(500)
eq('', exec_lua([[return _G.cb_error]]))
diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua
index 833ded9479..780a0b9b5a 100644
--- a/test/functional/terminal/mouse_spec.lua
+++ b/test/functional/terminal/mouse_spec.lua
@@ -66,7 +66,7 @@ describe(':terminal mouse', function()
]])
end)
- it('will forward mouse clicks to the program', function()
+ it('will forward mouse press, drag and release to the program', function()
if helpers.pending_win32(pending) then return end
feed('<LeftMouse><1,2>')
screen:expect([[
@@ -78,6 +78,36 @@ describe(':terminal mouse', function()
"#{1: } |
{3:-- TERMINAL --} |
]])
+ feed('<LeftDrag><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ @##{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftDrag><3,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ @$#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftRelease><3,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ #$#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
end)
it('will forward mouse scroll to the program', function()
@@ -94,6 +124,60 @@ describe(':terminal mouse', function()
]])
end)
+ it('dragging and scrolling do not interfere with each other', function()
+ if helpers.pending_win32(pending) then return end
+ feed('<LeftMouse><1,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ "#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<ScrollWheelUp><1,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ `"#{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftDrag><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ @##{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<ScrollWheelUp><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ `##{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ feed('<LeftRelease><2,2>')
+ screen:expect([[
+ line27 |
+ line28 |
+ line29 |
+ line30 |
+ mouse enabled |
+ ###{1: } |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('will forward mouse clicks to the program with the correct even if set nu', function()
if helpers.pending_win32(pending) then return end
nvim('command', 'set number')
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index bf57b135cb..faf44fa01d 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -20,7 +20,6 @@ local nvim_prog = helpers.nvim_prog
local nvim_set = helpers.nvim_set
local ok = helpers.ok
local read_file = helpers.read_file
-local exec_lua = helpers.exec_lua
if helpers.pending_win32(pending) then return end
@@ -581,34 +580,21 @@ describe('TUI', function()
end)
it("paste: 'nomodifiable' buffer", function()
- local has_luajit = exec_lua('return jit ~= nil')
child_session:request('nvim_command', 'set nomodifiable')
child_session:request('nvim_exec_lua', [[
- -- Stack traces for this test are non-deterministic, so disable them
- _G.debug.traceback = function(msg) return msg end
+ -- Truncate the error message to hide the line number
+ _G.debug.traceback = function(msg) return msg:sub(-49) end
]], {})
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
- if has_luajit then
- screen:expect{grid=[[
- |
- {4:~ }|
- {5: }|
- {8:paste: Error executing lua: vim.lua:0: Vim:E21: Ca}|
- {8:nnot make changes, 'modifiable' is off} |
- {10:Press ENTER or type command to continue}{1: } |
- {3:-- TERMINAL --} |
- ]]}
- else
- screen:expect{grid=[[
- |
- {4:~ }|
- {5: }|
- {8:paste: Error executing lua: Vim:E21: Cannot make c}|
- {8:hanges, 'modifiable' is off} |
- {10:Press ENTER or type command to continue}{1: } |
- {3:-- TERMINAL --} |
- ]]}
- end
+ screen:expect{grid=[[
+ |
+ {4:~ }|
+ {5: }|
+ {8:paste: Error executing lua: Vim:E21: Cannot make c}|
+ {8:hanges, 'modifiable' is off} |
+ {10:Press ENTER or type command to continue}{1: } |
+ {3:-- TERMINAL --} |
+ ]]}
feed_data('\n') -- <Enter>
child_session:request('nvim_command', 'set modifiable')
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
diff --git a/test/unit/charset/vim_str2nr_spec.lua b/test/unit/charset/vim_str2nr_spec.lua
index 5fc3b83a13..caf330c378 100644
--- a/test/unit/charset/vim_str2nr_spec.lua
+++ b/test/unit/charset/vim_str2nr_spec.lua
@@ -463,7 +463,7 @@ describe('vim_str2nr()', function()
test_vim_str2nr("1'2'3'4", flags, {len = 7, num = 1234, unum = 1234, pre = 0}, 0)
-- counter-intuitive, but like Vim, strict=true should partially accept
- -- these: (' and - are not alpha-numeric)
+ -- these: (' and - are not alphanumeric)
test_vim_str2nr("7''331", flags, {len = 1, num = 7, unum = 7, pre = 0}, 0)
test_vim_str2nr("123'x4", flags, {len = 3, num = 123, unum = 123, pre = 0}, 0)
test_vim_str2nr("1337'", flags, {len = 4, num = 1337, unum = 1337, pre = 0}, 0)
diff --git a/test/unit/garray_spec.lua b/test/unit/garray_spec.lua
index 28df8a6e3f..5d41dd39ec 100644
--- a/test/unit/garray_spec.lua
+++ b/test/unit/garray_spec.lua
@@ -18,7 +18,7 @@ local growsize = 95
-- constructing a class wrapper around garray. It could for example associate
-- ga_clear_strings to the underlying garray cdata if the garray is a string
-- array. But for now I estimate that that kind of magic might make testing
--- less "transparant" (i.e.: the interface would become quite different as to
+-- less "transparent" (i.e.: the interface would become quite different as to
-- how one would use it from C.
-- accessors
diff --git a/test/unit/os/env_spec.lua b/test/unit/os/env_spec.lua
index e7cb5e5d5e..a0e02b6624 100644
--- a/test/unit/os/env_spec.lua
+++ b/test/unit/os/env_spec.lua
@@ -191,7 +191,7 @@ describe('env.c', function()
if ffi.abi('64bit') then
-- couldn't use a bigger number because it gets converted to
- -- double somewere, should be big enough anyway
+ -- double somewhere, should be big enough anyway
-- maxuint64 = ffi.new 'size_t', 18446744073709551615
local maxuint64 = ffi.new('size_t', 18446744073709000000)
eq(NULL, cimp.os_getenvname_at_index(maxuint64))
diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua
index 7fd71cb1ae..0bb33772cd 100644
--- a/test/unit/os/fs_spec.lua
+++ b/test/unit/os/fs_spec.lua
@@ -1029,7 +1029,7 @@ describe('fs.c', function()
itp('returns the correct blocksize of a file', function()
local path = 'unit-test-directory/test.file'
-- there is a bug in luafilesystem where
- -- `lfs.attributes path, 'blksize'` returns the worng value:
+ -- `lfs.attributes path, 'blksize'` returns the wrong value:
-- https://github.com/keplerproject/luafilesystem/pull/44
-- using this workaround for now:
local blksize = lfs.attributes(path).blksize
@@ -1038,7 +1038,7 @@ describe('fs.c', function()
if blksize then
eq(blksize, fs.os_fileinfo_blocksize(info))
else
- -- luafs dosn't support blksize on windows
+ -- luafs doesn't support blksize on windows
-- libuv on windows returns a constant value as blocksize
-- checking for this constant value should be enough
eq(2048, fs.os_fileinfo_blocksize(info))
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index b0b91df791..613b39c833 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -203,8 +203,8 @@ set(LIBICONV_SHA256 ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc891
set(TREESITTER_C_URL https://github.com/tree-sitter/tree-sitter-c/archive/v0.20.1.tar.gz)
set(TREESITTER_C_SHA256 ffcc2ef0eded59ad1acec9aec4f9b0c7dd209fc1a85d85f8b0e81298e3dddcc2)
-set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/25f64e1eb66bb1ab3eccd4f0b7da543005f3ba79.tar.gz)
-set(TREESITTER_SHA256 4f43bad474df494d00a779157f1c437638987d0e7896f9c73492cfeef35366b5)
+set(TREESITTER_URL https://github.com/tree-sitter/tree-sitter/archive/v0.20.2.tar.gz)
+set(TREESITTER_SHA256 2a0445f8172bbf83db005aedb4e893d394e2b7b33251badd3c94c2c5cc37c403)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)