mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge remote-tracking branch 'upstream/master' into libcall
This commit is contained in:
commit
6566251d14
44
.builds/freebsd.yml
Normal file
44
.builds/freebsd.yml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
image: freebsd/12.x
|
||||||
|
|
||||||
|
packages:
|
||||||
|
- cmake
|
||||||
|
- gmake
|
||||||
|
- ninja
|
||||||
|
- libtool
|
||||||
|
- sha
|
||||||
|
- automake
|
||||||
|
- pkgconf
|
||||||
|
- unzip
|
||||||
|
- wget
|
||||||
|
- gettext
|
||||||
|
- python
|
||||||
|
- libffi
|
||||||
|
|
||||||
|
sources:
|
||||||
|
- https://github.com/neovim/neovim
|
||||||
|
|
||||||
|
environment:
|
||||||
|
SOURCEHUT: 1
|
||||||
|
LANG: en_US.UTF-8
|
||||||
|
CMAKE_EXTRA_FLAGS: -DTRAVIS_CI_BUILD=ON -DMIN_LOG_LEVEL=3
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- build-deps: |
|
||||||
|
cd neovim
|
||||||
|
gmake deps
|
||||||
|
- build: |
|
||||||
|
cd neovim
|
||||||
|
gmake CMAKE_BUILD_TYPE=Release CMAKE_EXTRA_FLAGS="${CMAKE_EXTRA_FLAGS}" nvim
|
||||||
|
- functionaltest: |
|
||||||
|
cd neovim
|
||||||
|
gmake functionaltest
|
||||||
|
- unittest: |
|
||||||
|
cd neovim
|
||||||
|
gmake unittest
|
||||||
|
|
||||||
|
# Unfortunately, oldtest is tanking hard on sourcehut's FreeBSD instance
|
||||||
|
# and not producing any logs as a result. So don't do this task for now.
|
||||||
|
# Ref: https://github.com/neovim/neovim/pull/11477#discussion_r352095005.
|
||||||
|
# - test-oldtest: |
|
||||||
|
# cd neovim
|
||||||
|
# gmake oldtest
|
@ -16,26 +16,28 @@ packages:
|
|||||||
sources:
|
sources:
|
||||||
- https://github.com/neovim/neovim
|
- https://github.com/neovim/neovim
|
||||||
|
|
||||||
|
environment:
|
||||||
|
SOURCEHUT: 1
|
||||||
|
LC_CTYPE: en_US.UTF-8
|
||||||
|
CMAKE_EXTRA_FLAGS: -DTRAVIS_CI_BUILD=ON -DMIN_LOG_LEVEL=3
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- build: |
|
- build-deps: |
|
||||||
export AUTOCONF_VERSION=2.69
|
export AUTOCONF_VERSION=2.69
|
||||||
export AUTOMAKE_VERSION=1.15
|
export AUTOMAKE_VERSION=1.15
|
||||||
cd neovim
|
mkdir neovim/.deps
|
||||||
mkdir .deps
|
cd neovim/.deps
|
||||||
cd .deps
|
|
||||||
cmake -G Ninja ../third-party/
|
cmake -G Ninja ../third-party/
|
||||||
cmake --build . --config Debug
|
cmake --build . --config Debug
|
||||||
cd ..
|
- build: |
|
||||||
mkdir build
|
mkdir neovim/build
|
||||||
cd build
|
cd neovim/build
|
||||||
cmake -G Ninja -DMIN_LOG_LEVEL=3 ..
|
cmake -G Ninja $CMAKE_EXTRA_FLAGS ..
|
||||||
cmake --build . --config Debug
|
cmake --build . --config Debug
|
||||||
./bin/nvim --version
|
./bin/nvim --version
|
||||||
- test: |
|
- functionaltest: |
|
||||||
export LC_CTYPE=en_US.UTF-8
|
|
||||||
# functional tests
|
|
||||||
cd neovim/build
|
cd neovim/build
|
||||||
# cmake --build . --config Debug --target functionaltest
|
cmake --build . --config Debug --target functionaltest
|
||||||
# oldtests
|
- oldtest: |
|
||||||
cd ..
|
cd neovim
|
||||||
gmake oldtest
|
gmake oldtest
|
||||||
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +1,2 @@
|
|||||||
*.h linguist-language=C
|
*.h linguist-language=C
|
||||||
|
src/nvim/testdir/test42.in diff
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,7 +10,9 @@ compile_commands.json
|
|||||||
/dist/
|
/dist/
|
||||||
/.deps/
|
/.deps/
|
||||||
/tmp/
|
/tmp/
|
||||||
|
/.clangd/
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
*.mo
|
*.mo
|
||||||
.*.sw?
|
.*.sw?
|
||||||
*~
|
*~
|
||||||
@ -42,6 +44,7 @@ tags
|
|||||||
/src/nvim/testdir/valgrind.*
|
/src/nvim/testdir/valgrind.*
|
||||||
/src/nvim/testdir/.gdbinit
|
/src/nvim/testdir/.gdbinit
|
||||||
/runtime/indent/testdir/*.out
|
/runtime/indent/testdir/*.out
|
||||||
|
+runtime/indent/testdir/*.fail
|
||||||
# Generated by src/nvim/testdir/runnvim.sh.
|
# Generated by src/nvim/testdir/runnvim.sh.
|
||||||
/src/nvim/testdir/*.tlog
|
/src/nvim/testdir/*.tlog
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
-- Ignore W211 (unused variable) with preload files.
|
-- Ignore W211 (unused variable) with preload files.
|
||||||
files["**/preload.lua"] = {ignore = { "211" }}
|
files["**/preload.lua"] = {ignore = { "211" }}
|
||||||
|
-- Allow vim module to modify itself, but only here.
|
||||||
|
files["src/nvim/lua/vim.lua"] = {ignore = { "122/vim" }}
|
||||||
|
|
||||||
-- Don't report unused self arguments of methods.
|
-- Don't report unused self arguments of methods.
|
||||||
self = false
|
self = false
|
||||||
|
22
.luacov
Normal file
22
.luacov
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
-- Configuration file for LuaCov
|
||||||
|
|
||||||
|
local source = require("lfs").currentdir()
|
||||||
|
|
||||||
|
local function pesc(s)
|
||||||
|
assert(type(s) == 'string', s)
|
||||||
|
return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
include = {
|
||||||
|
-- Absolute paths (starting with source dir, not hidden (i.e. .deps)).
|
||||||
|
pesc(source) .. "[/\\][^.].+",
|
||||||
|
-- Relative (non-hidden) paths.
|
||||||
|
'^[^/\\.]',
|
||||||
|
},
|
||||||
|
modules = {
|
||||||
|
['vim'] = 'runtime/lua/vim/shared.lua'
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- vim: ft=lua tw=80 sw=2 et
|
57
.travis.yml
57
.travis.yml
@ -4,6 +4,19 @@ language: c
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
|
# Encrypted environment variables, see
|
||||||
|
# http://docs.travis-ci.com/user/encryption-keys/
|
||||||
|
#
|
||||||
|
# SNAP_SECRET_KEY: generated by:
|
||||||
|
# travis encrypt SNAP_SECRET_KEY=xx --add
|
||||||
|
# https://github.com/neovim/neovim/pull/11428
|
||||||
|
# snapcraft key expires after 1 year. Steps to refresh it:
|
||||||
|
# 1. snapcraft enable-ci travis --refresh
|
||||||
|
# 2. mv .snapcraft/travis_snapcraft.cfg ci/snap/travis_snapcraft.cfg
|
||||||
|
# 3. Copy after_success command to ci/snap/deploy.sh from .travis.yml
|
||||||
|
# 4. Undo changes to .travis.yml
|
||||||
|
- secure: hd0qn2u8ABbJg5Bx4pBRcUQbKYFmcSHoecyHIPTCnGJT+NI41Bvm/IkN/N5DhBF+LbD3Q2nmR/dzI5H/dqS7RxMFvEx1DuFLendFHHX3MYf0AuKpXYY3gwgMTmqx8p/v6srlU7RBGWNGzHCWqksAem+EIWCe3I7WvfdKo1/DV/Y=
|
||||||
|
|
||||||
# Set "false" to force rebuild of third-party dependencies.
|
# Set "false" to force rebuild of third-party dependencies.
|
||||||
- CACHE_ENABLE=true
|
- CACHE_ENABLE=true
|
||||||
# Build directory for Neovim.
|
# Build directory for Neovim.
|
||||||
@ -24,10 +37,6 @@ env:
|
|||||||
-DDEPS_PREFIX=$DEPS_BUILD_DIR/usr
|
-DDEPS_PREFIX=$DEPS_BUILD_DIR/usr
|
||||||
-DMIN_LOG_LEVEL=3"
|
-DMIN_LOG_LEVEL=3"
|
||||||
- DEPS_CMAKE_FLAGS="-DUSE_BUNDLED_GPERF=OFF"
|
- DEPS_CMAKE_FLAGS="-DUSE_BUNDLED_GPERF=OFF"
|
||||||
# Additional CMake flags for 32-bit builds.
|
|
||||||
- CMAKE_FLAGS_32BIT="-DCMAKE_SYSTEM_LIBRARY_PATH=/lib32:/usr/lib32:/usr/local/lib32
|
|
||||||
-DCMAKE_IGNORE_PATH=/lib:/usr/lib:/usr/local/lib
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/cmake/i386-linux-gnu.toolchain.cmake"
|
|
||||||
# Environment variables for Clang sanitizers.
|
# Environment variables for Clang sanitizers.
|
||||||
- ASAN_OPTIONS="detect_leaks=1:check_initialization_order=1:log_path=$LOG_DIR/asan"
|
- ASAN_OPTIONS="detect_leaks=1:check_initialization_order=1:log_path=$LOG_DIR/asan"
|
||||||
- TSAN_OPTIONS="log_path=$LOG_DIR/tsan"
|
- TSAN_OPTIONS="log_path=$LOG_DIR/tsan"
|
||||||
@ -99,6 +108,8 @@ jobs:
|
|||||||
- GCOV=gcov-9
|
- GCOV=gcov-9
|
||||||
- CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
|
- CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
|
||||||
- GCOV_ERROR_FILE="/tmp/libgcov-errors.log"
|
- GCOV_ERROR_FILE="/tmp/libgcov-errors.log"
|
||||||
|
- USE_LUACOV=1
|
||||||
|
- BUSTED_ARGS="--coverage"
|
||||||
- *common-job-env
|
- *common-job-env
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
@ -136,6 +147,8 @@ jobs:
|
|||||||
compiler: gcc
|
compiler: gcc
|
||||||
env:
|
env:
|
||||||
- BUILD_32BIT=ON
|
- BUILD_32BIT=ON
|
||||||
|
- CMAKE_FLAGS="$CMAKE_FLAGS -m32 -DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/cmake/i386-linux-gnu.toolchain.cmake"
|
||||||
|
- DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -m32 -DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/cmake/i386-linux-gnu.toolchain.cmake"
|
||||||
# Minimum required CMake.
|
# Minimum required CMake.
|
||||||
- CMAKE_URL=https://cmake.org/files/v2.8/cmake-2.8.12-Linux-i386.sh
|
- CMAKE_URL=https://cmake.org/files/v2.8/cmake-2.8.12-Linux-i386.sh
|
||||||
- *common-job-env
|
- *common-job-env
|
||||||
@ -145,6 +158,42 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
- CLANG_SANITIZER=TSAN
|
- CLANG_SANITIZER=TSAN
|
||||||
- *common-job-env
|
- *common-job-env
|
||||||
|
- if: type != pull_request
|
||||||
|
name: snap
|
||||||
|
os: linux
|
||||||
|
env:
|
||||||
|
- LC_ALL: C.UTF-8
|
||||||
|
- LANG: C.UTF-8
|
||||||
|
- SNAPCRAFT_ENABLE_SILENT_REPORT: y
|
||||||
|
- SNAPCRAFT_ENABLE_DEVELOPER_DEBUG: y
|
||||||
|
addons:
|
||||||
|
snaps:
|
||||||
|
- name: snapcraft
|
||||||
|
channel: stable
|
||||||
|
classic: true
|
||||||
|
- name: http
|
||||||
|
- name: transfer
|
||||||
|
- name: lxd
|
||||||
|
channel: stable
|
||||||
|
# Override default before_install, before_cache.
|
||||||
|
before_install: /bin/true
|
||||||
|
before_cache: /bin/true
|
||||||
|
install: ci/snap/install.sh
|
||||||
|
before_script: echo "Building snap..."
|
||||||
|
script: ci/snap/script.sh
|
||||||
|
after_success: ci/snap/after_success.sh
|
||||||
|
deploy:
|
||||||
|
skip_cleanup: true
|
||||||
|
provider: script
|
||||||
|
script: ci/snap/deploy.sh
|
||||||
|
on:
|
||||||
|
branch: master
|
||||||
|
allow_failures:
|
||||||
|
- env:
|
||||||
|
- LC_ALL: C.UTF-8
|
||||||
|
- LANG: C.UTF-8
|
||||||
|
- SNAPCRAFT_ENABLE_SILENT_REPORT: y
|
||||||
|
- SNAPCRAFT_ENABLE_DEVELOPER_DEBUG: y
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
before_install: ci/before_install.sh
|
before_install: ci/before_install.sh
|
||||||
|
@ -6,6 +6,13 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
project(nvim C)
|
project(nvim C)
|
||||||
|
|
||||||
|
if(POLICY CMP0065)
|
||||||
|
cmake_policy(SET CMP0065 NEW)
|
||||||
|
endif()
|
||||||
|
if(POLICY CMP0060)
|
||||||
|
cmake_policy(SET CMP0060 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Point CMake at any custom modules we may ship
|
# Point CMake at any custom modules we may ship
|
||||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
@ -113,47 +120,32 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
|
|||||||
# If not in a git repo (e.g., a tarball) these tokens define the complete
|
# If not in a git repo (e.g., a tarball) these tokens define the complete
|
||||||
# version string, else they are combined with the result of `git describe`.
|
# version string, else they are combined with the result of `git describe`.
|
||||||
set(NVIM_VERSION_MAJOR 0)
|
set(NVIM_VERSION_MAJOR 0)
|
||||||
set(NVIM_VERSION_MINOR 4)
|
set(NVIM_VERSION_MINOR 5)
|
||||||
set(NVIM_VERSION_PATCH 0)
|
set(NVIM_VERSION_PATCH 0)
|
||||||
set(NVIM_VERSION_PRERELEASE "") # for package maintainers
|
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
|
||||||
|
|
||||||
# API level
|
# API level
|
||||||
set(NVIM_API_LEVEL 6) # Bump this after any API change.
|
set(NVIM_API_LEVEL 7) # Bump this after any API change.
|
||||||
set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
|
set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
|
||||||
set(NVIM_API_PRERELEASE false)
|
set(NVIM_API_PRERELEASE true)
|
||||||
|
|
||||||
file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR)
|
|
||||||
include(GetGitRevisionDescription)
|
|
||||||
get_git_head_revision(GIT_REFSPEC NVIM_VERSION_COMMIT)
|
|
||||||
if(NVIM_VERSION_COMMIT) # is a git repo
|
|
||||||
git_describe(NVIM_VERSION_MEDIUM)
|
|
||||||
# `git describe` annotates the most recent tagged release; for pre-release
|
|
||||||
# builds we must replace that with the unreleased version.
|
|
||||||
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+"
|
|
||||||
"v${NVIM_VERSION_MAJOR}.${NVIM_VERSION_MINOR}.${NVIM_VERSION_PATCH}"
|
|
||||||
NVIM_VERSION_MEDIUM
|
|
||||||
${NVIM_VERSION_MEDIUM})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(NVIM_VERSION_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
|
set(NVIM_VERSION_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
|
||||||
# NVIM_VERSION_CFLAGS set further below.
|
# NVIM_VERSION_CFLAGS set further below.
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
# Minimize logging for release-type builds.
|
|
||||||
if(NOT CMAKE_C_FLAGS_RELEASE MATCHES DMIN_LOG_LEVEL)
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DMIN_LOG_LEVEL=3")
|
|
||||||
endif()
|
|
||||||
if(NOT CMAKE_C_FLAGS_MINSIZEREL MATCHES DMIN_LOG_LEVEL)
|
|
||||||
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DMIN_LOG_LEVEL=3")
|
|
||||||
endif()
|
|
||||||
if(NOT CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES DMIN_LOG_LEVEL)
|
|
||||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -DMIN_LOG_LEVEL=3")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Log level (MIN_LOG_LEVEL in log.h)
|
# Log level (MIN_LOG_LEVEL in log.h)
|
||||||
if("${MIN_LOG_LEVEL}" MATCHES "^$")
|
if("${MIN_LOG_LEVEL}" MATCHES "^$")
|
||||||
message(STATUS "MIN_LOG_LEVEL not specified, default is 1 (INFO)")
|
# Minimize logging for release-type builds.
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Release"
|
||||||
|
OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"
|
||||||
|
OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||||
|
message(STATUS "MIN_LOG_LEVEL not specified, default is 3 (ERROR) for release builds")
|
||||||
|
set(MIN_LOG_LEVEL 3)
|
||||||
|
else()
|
||||||
|
message(STATUS "MIN_LOG_LEVEL not specified, default is 1 (INFO)")
|
||||||
|
set(MIN_LOG_LEVEL 1)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
if(NOT MIN_LOG_LEVEL MATCHES "^[0-3]$")
|
if(NOT MIN_LOG_LEVEL MATCHES "^[0-3]$")
|
||||||
message(FATAL_ERROR "invalid MIN_LOG_LEVEL: " ${MIN_LOG_LEVEL})
|
message(FATAL_ERROR "invalid MIN_LOG_LEVEL: " ${MIN_LOG_LEVEL})
|
||||||
@ -309,8 +301,10 @@ if(UNIX)
|
|||||||
|
|
||||||
if(HAS_FSTACK_PROTECTOR_STRONG_FLAG)
|
if(HAS_FSTACK_PROTECTOR_STRONG_FLAG)
|
||||||
add_compile_options(-fstack-protector-strong)
|
add_compile_options(-fstack-protector-strong)
|
||||||
|
link_libraries(-fstack-protector-strong)
|
||||||
elseif(HAS_FSTACK_PROTECTOR_FLAG)
|
elseif(HAS_FSTACK_PROTECTOR_FLAG)
|
||||||
add_compile_options(-fstack-protector --param ssp-buffer-size=4)
|
add_compile_options(-fstack-protector --param ssp-buffer-size=4)
|
||||||
|
link_libraries(-fstack-protector --param ssp-buffer-size=4)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -323,10 +317,10 @@ if(HAS_DIAG_COLOR_FLAG)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(TRAVIS_CI_BUILD "Travis/QuickBuild CI, extra flags will be set" OFF)
|
option(TRAVIS_CI_BUILD "Travis/sourcehut CI, extra flags will be set" OFF)
|
||||||
|
|
||||||
if(TRAVIS_CI_BUILD)
|
if(TRAVIS_CI_BUILD)
|
||||||
message(STATUS "Travis/QuickBuild CI build enabled")
|
message(STATUS "Travis/sourcehut CI build enabled")
|
||||||
add_compile_options(-Werror)
|
add_compile_options(-Werror)
|
||||||
if(DEFINED ENV{BUILD_32BIT})
|
if(DEFINED ENV{BUILD_32BIT})
|
||||||
# Get some test coverage for unsigned char
|
# Get some test coverage for unsigned char
|
||||||
@ -375,6 +369,13 @@ include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS})
|
|||||||
find_package(LibLUV 1.30.0 REQUIRED)
|
find_package(LibLUV 1.30.0 REQUIRED)
|
||||||
include_directories(SYSTEM ${LIBLUV_INCLUDE_DIRS})
|
include_directories(SYSTEM ${LIBLUV_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
find_package(UTF8PROC REQUIRED)
|
||||||
|
include_directories(SYSTEM ${UTF8PROC_INCLUDE_DIRS})
|
||||||
|
if(WIN32)
|
||||||
|
add_definitions(-DUTF8PROC_STATIC)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# Note: The test lib requires LuaJIT; it will be skipped if LuaJIT is missing.
|
# Note: The test lib requires LuaJIT; it will be skipped if LuaJIT is missing.
|
||||||
option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF)
|
option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF)
|
||||||
|
|
||||||
@ -486,18 +487,19 @@ include(LuaHelpers)
|
|||||||
set(LUA_DEPENDENCIES lpeg mpack bit)
|
set(LUA_DEPENDENCIES lpeg mpack bit)
|
||||||
if(NOT LUA_PRG)
|
if(NOT LUA_PRG)
|
||||||
foreach(CURRENT_LUA_PRG luajit lua5.1 lua5.2 lua)
|
foreach(CURRENT_LUA_PRG luajit lua5.1 lua5.2 lua)
|
||||||
# If LUA_PRG is set find_program() will not search
|
unset(_CHECK_LUA_PRG CACHE)
|
||||||
unset(LUA_PRG CACHE)
|
|
||||||
unset(LUA_PRG_WORKS)
|
unset(LUA_PRG_WORKS)
|
||||||
find_program(LUA_PRG ${CURRENT_LUA_PRG})
|
find_program(_CHECK_LUA_PRG ${CURRENT_LUA_PRG})
|
||||||
|
|
||||||
if(LUA_PRG)
|
if(_CHECK_LUA_PRG)
|
||||||
check_lua_deps(${LUA_PRG} "${LUA_DEPENDENCIES}" LUA_PRG_WORKS)
|
check_lua_deps(${_CHECK_LUA_PRG} "${LUA_DEPENDENCIES}" LUA_PRG_WORKS)
|
||||||
if(LUA_PRG_WORKS)
|
if(LUA_PRG_WORKS)
|
||||||
|
set(LUA_PRG "${_CHECK_LUA_PRG}" CACHE FILEPATH "Path to a program.")
|
||||||
break()
|
break()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
unset(_CHECK_LUA_PRG CACHE)
|
||||||
else()
|
else()
|
||||||
check_lua_deps(${LUA_PRG} "${LUA_DEPENDENCIES}" LUA_PRG_WORKS)
|
check_lua_deps(${LUA_PRG} "${LUA_DEPENDENCIES}" LUA_PRG_WORKS)
|
||||||
endif()
|
endif()
|
||||||
@ -560,10 +562,7 @@ if(BUSTED_PRG)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(UNITTEST_PREREQS nvim-test unittest-headers)
|
set(UNITTEST_PREREQS nvim-test unittest-headers)
|
||||||
set(FUNCTIONALTEST_PREREQS nvim printargs-test shell-test streams-test ${GENERATED_HELP_TAGS})
|
set(FUNCTIONALTEST_PREREQS nvim printenv-test printargs-test shell-test streams-test tty-test ${GENERATED_HELP_TAGS})
|
||||||
if(NOT WIN32)
|
|
||||||
list(APPEND FUNCTIONALTEST_PREREQS tty-test)
|
|
||||||
endif()
|
|
||||||
set(BENCHMARK_PREREQS nvim tty-test)
|
set(BENCHMARK_PREREQS nvim tty-test)
|
||||||
|
|
||||||
# Useful for automated build systems, if they want to manually run the tests.
|
# Useful for automated build systems, if they want to manually run the tests.
|
||||||
|
@ -85,7 +85,7 @@ the VCS/git logs more valuable.
|
|||||||
|
|
||||||
### Automated builds (CI)
|
### Automated builds (CI)
|
||||||
|
|
||||||
Each pull request must pass the automated builds on [Travis CI], [QuickBuild]
|
Each pull request must pass the automated builds on [Travis CI], [sourcehut]
|
||||||
and [AppVeyor].
|
and [AppVeyor].
|
||||||
|
|
||||||
- CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings
|
- CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings
|
||||||
@ -100,14 +100,19 @@ and [AppVeyor].
|
|||||||
- The [lint](#lint) build checks modified lines _and their immediate
|
- The [lint](#lint) build checks modified lines _and their immediate
|
||||||
neighbors_, to encourage incrementally updating the legacy style to meet our
|
neighbors_, to encourage incrementally updating the legacy style to meet our
|
||||||
[style](#style). (See [#3174][3174] for background.)
|
[style](#style). (See [#3174][3174] for background.)
|
||||||
- [How to investigate QuickBuild failures](https://github.com/neovim/neovim/pull/4718#issuecomment-217631350)
|
- CI for freebsd and openbsd runs on [sourcehut].
|
||||||
- QuickBuild uses this invocation:
|
- To get a backtrace on freebsd (after connecting via ssh):
|
||||||
```
|
```sh
|
||||||
mkdir -p build/${params.get("buildType")} \
|
sudo pkg install tmux # If you want tmux.
|
||||||
&& cd build/${params.get("buildType")} \
|
lldb build/bin/nvim -c nvim.core
|
||||||
&& cmake -G "Unix Makefiles" -DBUSTED_OUTPUT_TYPE=TAP -DCMAKE_BUILD_TYPE=${params.get("buildType")}
|
|
||||||
-DTRAVIS_CI_BUILD=ON ../.. && ${node.getAttribute("make", "make")}
|
# To get a full backtrace:
|
||||||
VERBOSE=1 nvim unittest-prereqs functionaltest-prereqs
|
# 1. Rebuild with debug info.
|
||||||
|
rm -rf nvim.core build
|
||||||
|
gmake CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_EXTRA_FLAGS="-DTRAVIS_CI_BUILD=ON -DMIN_LOG_LEVEL=3" nvim
|
||||||
|
# 2. Run the failing test to generate a new core file.
|
||||||
|
TEST_FILE=test/functional/foo.lua gmake functionaltest
|
||||||
|
lldb build/bin/nvim -c nvim.core
|
||||||
```
|
```
|
||||||
|
|
||||||
### Clang scan-build
|
### Clang scan-build
|
||||||
@ -223,7 +228,7 @@ as context, use the `-W` argument as well.
|
|||||||
[review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist
|
[review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist
|
||||||
[3174]: https://github.com/neovim/neovim/issues/3174
|
[3174]: https://github.com/neovim/neovim/issues/3174
|
||||||
[Travis CI]: https://travis-ci.org/neovim/neovim
|
[Travis CI]: https://travis-ci.org/neovim/neovim
|
||||||
[QuickBuild]: http://neovim-qb.szakmeister.net/dashboard
|
[sourcehut]: https://builds.sr.ht/~jmk
|
||||||
[AppVeyor]: https://ci.appveyor.com/project/neovim/neovim
|
[AppVeyor]: https://ci.appveyor.com/project/neovim/neovim
|
||||||
[Merge a Vim patch]: https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim
|
[Merge a Vim patch]: https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim
|
||||||
[Clang report]: https://neovim.io/doc/reports/clang/
|
[Clang report]: https://neovim.io/doc/reports/clang/
|
||||||
|
24
Makefile
24
Makefile
@ -119,8 +119,13 @@ oldtest: | nvim build/runtime/doc/tags
|
|||||||
ifeq ($(strip $(TEST_FILE)),)
|
ifeq ($(strip $(TEST_FILE)),)
|
||||||
+$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" $(MAKEOVERRIDES)
|
+$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" $(MAKEOVERRIDES)
|
||||||
else
|
else
|
||||||
+$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" NEW_TESTS=$(TEST_FILE) SCRIPTS= $(MAKEOVERRIDES)
|
@# Handle TEST_FILE=test_foo{,.res,.vim}.
|
||||||
|
+$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" SCRIPTS= $(MAKEOVERRIDES) $(patsubst %.vim,%,$(patsubst %.res,%,$(TEST_FILE)))
|
||||||
endif
|
endif
|
||||||
|
# Build oldtest by specifying the relative .vim filename.
|
||||||
|
.PHONY: phony_force
|
||||||
|
src/nvim/testdir/%.vim: phony_force
|
||||||
|
+$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" SCRIPTS= $(MAKEOVERRIDES) $(patsubst src/nvim/testdir/%.vim,%,$@)
|
||||||
|
|
||||||
build/runtime/doc/tags helptags: | nvim
|
build/runtime/doc/tags helptags: | nvim
|
||||||
+$(BUILD_CMD) -C build runtime/doc/tags
|
+$(BUILD_CMD) -C build runtime/doc/tags
|
||||||
@ -138,6 +143,14 @@ functionaltest-lua: | nvim
|
|||||||
lualint: | build/.ran-cmake deps
|
lualint: | build/.ran-cmake deps
|
||||||
$(BUILD_CMD) -C build lualint
|
$(BUILD_CMD) -C build lualint
|
||||||
|
|
||||||
|
shlint:
|
||||||
|
@shellcheck --version | head -n 2
|
||||||
|
shellcheck scripts/vim-patch.sh
|
||||||
|
|
||||||
|
_opt_shlint:
|
||||||
|
@command -v shellcheck && { $(MAKE) shlint; exit $$?; } \
|
||||||
|
|| echo "SKIP: shlint (shellcheck not found)"
|
||||||
|
|
||||||
pylint:
|
pylint:
|
||||||
flake8 contrib/ scripts/ src/ test/
|
flake8 contrib/ scripts/ src/ test/
|
||||||
|
|
||||||
@ -158,6 +171,7 @@ clean:
|
|||||||
+test -d build && $(BUILD_CMD) -C build clean || true
|
+test -d build && $(BUILD_CMD) -C build clean || true
|
||||||
$(MAKE) -C src/nvim/testdir clean
|
$(MAKE) -C src/nvim/testdir clean
|
||||||
$(MAKE) -C runtime/doc clean
|
$(MAKE) -C runtime/doc clean
|
||||||
|
$(MAKE) -C runtime/indent clean
|
||||||
|
|
||||||
distclean:
|
distclean:
|
||||||
rm -rf $(DEPS_BUILD_DIR) build
|
rm -rf $(DEPS_BUILD_DIR) build
|
||||||
@ -187,16 +201,16 @@ appimage:
|
|||||||
appimage-%:
|
appimage-%:
|
||||||
bash scripts/genappimage.sh $*
|
bash scripts/genappimage.sh $*
|
||||||
|
|
||||||
lint: check-single-includes clint lualint _opt_pylint
|
lint: check-single-includes clint lualint _opt_pylint _opt_shlint
|
||||||
|
|
||||||
# Generic pattern rules, allowing for `make build/bin/nvim` etc.
|
# Generic pattern rules, allowing for `make build/bin/nvim` etc.
|
||||||
# Does not work with "Unix Makefiles".
|
# Does not work with "Unix Makefiles".
|
||||||
ifeq ($(BUILD_TYPE),Ninja)
|
ifeq ($(BUILD_TYPE),Ninja)
|
||||||
build/%:
|
build/%: phony_force
|
||||||
$(BUILD_CMD) -C build $(patsubst build/%,%,$@)
|
$(BUILD_CMD) -C build $(patsubst build/%,%,$@)
|
||||||
|
|
||||||
$(DEPS_BUILD_DIR)/%:
|
$(DEPS_BUILD_DIR)/%: phony_force
|
||||||
$(BUILD_CMD) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@)
|
$(BUILD_CMD) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: test lualint pylint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix
|
.PHONY: test lualint pylint shlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix
|
||||||
|
@ -67,7 +67,7 @@ To skip bundled (`third-party/*`) dependencies:
|
|||||||
|
|
||||||
1. Install the dependencies using a package manager.
|
1. Install the dependencies using a package manager.
|
||||||
```
|
```
|
||||||
sudo apt install gperf luajit luarocks libuv1-dev libluajit-5.1-dev libunibilium-dev libmsgpack-dev libtermkey-dev libvterm-dev
|
sudo apt install gperf luajit luarocks libuv1-dev libluajit-5.1-dev libunibilium-dev libmsgpack-dev libtermkey-dev libvterm-dev libutf8proc-dev
|
||||||
sudo luarocks build mpack
|
sudo luarocks build mpack
|
||||||
sudo luarocks build lpeg
|
sudo luarocks build lpeg
|
||||||
sudo luarocks build inspect
|
sudo luarocks build inspect
|
||||||
|
@ -24,7 +24,7 @@ matrix:
|
|||||||
fast_finish: true
|
fast_finish: true
|
||||||
install: []
|
install: []
|
||||||
before_build:
|
before_build:
|
||||||
- ps: Install-Product node 8
|
- ps: Install-Product node 10
|
||||||
build_script:
|
build_script:
|
||||||
- powershell ci\build.ps1
|
- powershell ci\build.ps1
|
||||||
after_build:
|
after_build:
|
||||||
@ -40,6 +40,3 @@ cache:
|
|||||||
artifacts:
|
artifacts:
|
||||||
- path: build/Neovim.zip
|
- path: build/Neovim.zip
|
||||||
- path: build/bin/nvim.exe
|
- path: build/bin/nvim.exe
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
|
@ -3,10 +3,6 @@
|
|||||||
set -e
|
set -e
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
if [[ "${CI_TARGET}" == lint ]]; then
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo 'Python info:'
|
echo 'Python info:'
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
@ -47,12 +43,12 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]] || [ ! -f ~/.nvm/nvm.sh ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
source ~/.nvm/nvm.sh
|
source ~/.nvm/nvm.sh
|
||||||
nvm install --lts
|
nvm install 10
|
||||||
nvm use --lts
|
nvm use 10
|
||||||
|
|
||||||
if [[ -n "$CMAKE_URL" ]]; then
|
if [[ -n "$CMAKE_URL" ]]; then
|
||||||
echo "Installing custom CMake: $CMAKE_URL"
|
echo "Installing custom CMake: $CMAKE_URL"
|
||||||
curl --retry 5 --silent --fail -o /tmp/cmake-installer.sh "$CMAKE_URL"
|
curl --retry 5 --silent --show-error --fail -o /tmp/cmake-installer.sh "$CMAKE_URL"
|
||||||
mkdir -p "$HOME/.local/bin" /opt/cmake-custom
|
mkdir -p "$HOME/.local/bin" /opt/cmake-custom
|
||||||
bash /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license
|
bash /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license
|
||||||
ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake"
|
ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake"
|
||||||
|
@ -35,5 +35,10 @@ fi
|
|||||||
# Compile dependencies.
|
# Compile dependencies.
|
||||||
build_deps
|
build_deps
|
||||||
|
|
||||||
|
# Install cluacov for Lua coverage.
|
||||||
|
if [[ "$USE_LUACOV" == 1 ]]; then
|
||||||
|
"${DEPS_BUILD_DIR}/usr/bin/luarocks" install cluacov
|
||||||
|
fi
|
||||||
|
|
||||||
rm -rf "${LOG_DIR}"
|
rm -rf "${LOG_DIR}"
|
||||||
mkdir -p "${LOG_DIR}"
|
mkdir -p "${LOG_DIR}"
|
||||||
|
53
ci/build.ps1
53
ci/build.ps1
@ -1,10 +1,11 @@
|
|||||||
$ErrorActionPreference = 'stop'
|
Set-StrictMode -Version Latest
|
||||||
Set-PSDebug -Strict -Trace 1
|
$ErrorActionPreference = 'Stop'
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
$isPullRequest = ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -ne $null)
|
$isPullRequest = ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -ne $null)
|
||||||
$env:CONFIGURATION -match '^(?<compiler>\w+)_(?<bits>32|64)(?:-(?<option>\w+))?$'
|
$env:CONFIGURATION -match '^(?<compiler>\w+)_(?<bits>32|64)(?:-(?<option>\w+))?$'
|
||||||
$compiler = $Matches.compiler
|
$compiler = $Matches.compiler
|
||||||
$compileOption = $Matches.option
|
$compileOption = if ($Matches -contains 'option') {$Matches.option} else {''}
|
||||||
$bits = $Matches.bits
|
$bits = $Matches.bits
|
||||||
$cmakeBuildType = $(if ($env:CMAKE_BUILD_TYPE -ne $null) {$env:CMAKE_BUILD_TYPE} else {'RelWithDebInfo'});
|
$cmakeBuildType = $(if ($env:CMAKE_BUILD_TYPE -ne $null) {$env:CMAKE_BUILD_TYPE} else {'RelWithDebInfo'});
|
||||||
$buildDir = [System.IO.Path]::GetFullPath("$(pwd)")
|
$buildDir = [System.IO.Path]::GetFullPath("$(pwd)")
|
||||||
@ -23,7 +24,6 @@ $uploadToCodeCov = $false
|
|||||||
|
|
||||||
function exitIfFailed() {
|
function exitIfFailed() {
|
||||||
if ($LastExitCode -ne 0) {
|
if ($LastExitCode -ne 0) {
|
||||||
Set-PSDebug -Off
|
|
||||||
exit $LastExitCode
|
exit $LastExitCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,6 +46,10 @@ if ($compiler -eq 'MINGW') {
|
|||||||
$nvimCmakeVars['USE_GCOV'] = 'ON'
|
$nvimCmakeVars['USE_GCOV'] = 'ON'
|
||||||
$uploadToCodecov = $true
|
$uploadToCodecov = $true
|
||||||
$env:GCOV = "C:\msys64\mingw$bits\bin\gcov"
|
$env:GCOV = "C:\msys64\mingw$bits\bin\gcov"
|
||||||
|
|
||||||
|
# Setup/build Lua coverage.
|
||||||
|
$env:USE_LUACOV = 1
|
||||||
|
$env:BUSTED_ARGS = "--coverage"
|
||||||
}
|
}
|
||||||
# These are native MinGW builds, but they use the toolchain inside
|
# These are native MinGW builds, but they use the toolchain inside
|
||||||
# MSYS2, this allows using all the dependencies and tools available
|
# MSYS2, this allows using all the dependencies and tools available
|
||||||
@ -94,6 +98,27 @@ npm.cmd install -g neovim
|
|||||||
Get-Command -CommandType Application neovim-node-host.cmd
|
Get-Command -CommandType Application neovim-node-host.cmd
|
||||||
npm.cmd link neovim
|
npm.cmd link neovim
|
||||||
|
|
||||||
|
|
||||||
|
$env:TREE_SITTER_DIR = $env:USERPROFILE + "\tree-sitter-build"
|
||||||
|
mkdir "$env:TREE_SITTER_DIR\bin"
|
||||||
|
|
||||||
|
$xbits = if ($bits -eq '32') {'x86'} else {'x64'}
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/tree-sitter/tree-sitter/releases/download/0.15.9/tree-sitter-windows-$xbits.gz" -OutFile tree-sitter.exe.gz
|
||||||
|
C:\msys64\usr\bin\gzip -d tree-sitter.exe.gz
|
||||||
|
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Uri "https://codeload.github.com/tree-sitter/tree-sitter-c/zip/v0.15.2" -OutFile tree_sitter_c.zip
|
||||||
|
Expand-Archive .\tree_sitter_c.zip -DestinationPath .
|
||||||
|
cd tree-sitter-c-0.15.2
|
||||||
|
..\tree-sitter.exe test
|
||||||
|
if (-Not (Test-Path -PathType Leaf "$env:TREE_SITTER_DIR\bin\c.dll")) {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($compiler -eq 'MSVC') {
|
||||||
|
# Required for LuaRocks (https://github.com/luarocks/luarocks/issues/1039#issuecomment-507296940).
|
||||||
|
$env:VCINSTALLDIR = "C:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.16.27023/"
|
||||||
|
}
|
||||||
|
|
||||||
function convertToCmakeArgs($vars) {
|
function convertToCmakeArgs($vars) {
|
||||||
return $vars.GetEnumerator() | foreach { "-D$($_.Key)=$($_.Value)" }
|
return $vars.GetEnumerator() | foreach { "-D$($_.Key)=$($_.Value)" }
|
||||||
}
|
}
|
||||||
@ -113,26 +138,26 @@ cmake --build . --config $cmakeBuildType -- $cmakeGeneratorArgs ; exitIfFailed
|
|||||||
# Ensure that the "win32" feature is set.
|
# Ensure that the "win32" feature is set.
|
||||||
.\bin\nvim -u NONE --headless -c 'exe !has(\"win32\").\"cq\"' ; exitIfFailed
|
.\bin\nvim -u NONE --headless -c 'exe !has(\"win32\").\"cq\"' ; exitIfFailed
|
||||||
|
|
||||||
|
if ($env:USE_LUACOV -eq 1) {
|
||||||
|
& $env:DEPS_PREFIX\luarocks\luarocks.bat install cluacov
|
||||||
|
}
|
||||||
|
|
||||||
# Functional tests
|
# Functional tests
|
||||||
# The $LastExitCode from MSBuild can't be trusted
|
# The $LastExitCode from MSBuild can't be trusted
|
||||||
$failed = $false
|
$failed = $false
|
||||||
# Temporarily turn off tracing to reduce log file output
|
|
||||||
Set-PSDebug -Off
|
|
||||||
cmake --build . --config $cmakeBuildType --target functionaltest -- $cmakeGeneratorArgs 2>&1 |
|
cmake --build . --config $cmakeBuildType --target functionaltest -- $cmakeGeneratorArgs 2>&1 |
|
||||||
foreach { $failed = $failed -or
|
foreach { $failed = $failed -or
|
||||||
$_ -match 'functional tests failed with error'; $_ }
|
$_ -match 'functional tests failed with error'; $_ }
|
||||||
if ($failed) {
|
|
||||||
if ($uploadToCodecov) {
|
|
||||||
bash -l /c/projects/neovim/ci/common/submit_coverage.sh functionaltest
|
|
||||||
}
|
|
||||||
exit $LastExitCode
|
|
||||||
}
|
|
||||||
Set-PSDebug -Strict -Trace 1
|
|
||||||
|
|
||||||
|
|
||||||
if ($uploadToCodecov) {
|
if ($uploadToCodecov) {
|
||||||
|
if ($env:USE_LUACOV -eq 1) {
|
||||||
|
& $env:DEPS_PREFIX\bin\luacov.bat
|
||||||
|
}
|
||||||
bash -l /c/projects/neovim/ci/common/submit_coverage.sh functionaltest
|
bash -l /c/projects/neovim/ci/common/submit_coverage.sh functionaltest
|
||||||
}
|
}
|
||||||
|
if ($failed) {
|
||||||
|
exit $LastExitCode
|
||||||
|
}
|
||||||
|
|
||||||
# Old tests
|
# Old tests
|
||||||
# Add MSYS to path, required for e.g. `find` used in test scripts.
|
# Add MSYS to path, required for e.g. `find` used in test scripts.
|
||||||
|
@ -18,9 +18,6 @@ build_make() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
build_deps() {
|
build_deps() {
|
||||||
if test "${BUILD_32BIT}" = ON ; then
|
|
||||||
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
|
|
||||||
fi
|
|
||||||
if test "${FUNCTIONALTEST}" = "functionaltest-lua" \
|
if test "${FUNCTIONALTEST}" = "functionaltest-lua" \
|
||||||
|| test "${CLANG_SANITIZER}" = "ASAN_UBSAN" ; then
|
|| test "${CLANG_SANITIZER}" = "ASAN_UBSAN" ; then
|
||||||
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} -DUSE_BUNDLED_LUA=ON"
|
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} -DUSE_BUNDLED_LUA=ON"
|
||||||
@ -53,9 +50,6 @@ prepare_build() {
|
|||||||
if test -n "${CLANG_SANITIZER}" ; then
|
if test -n "${CLANG_SANITIZER}" ; then
|
||||||
CMAKE_FLAGS="${CMAKE_FLAGS} -DCLANG_${CLANG_SANITIZER}=ON"
|
CMAKE_FLAGS="${CMAKE_FLAGS} -DCLANG_${CLANG_SANITIZER}=ON"
|
||||||
fi
|
fi
|
||||||
if test "${BUILD_32BIT}" = ON ; then
|
|
||||||
CMAKE_FLAGS="${CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "${BUILD_DIR}"
|
mkdir -p "${BUILD_DIR}"
|
||||||
cd "${BUILD_DIR}"
|
cd "${BUILD_DIR}"
|
||||||
|
@ -43,3 +43,14 @@ fi
|
|||||||
# Cleanup always, especially collected data.
|
# Cleanup always, especially collected data.
|
||||||
find . \( -name '*.gcov' -o -name '*.gcda' \) -ls -delete | wc -l
|
find . \( -name '*.gcov' -o -name '*.gcda' \) -ls -delete | wc -l
|
||||||
rm -f coverage.xml
|
rm -f coverage.xml
|
||||||
|
|
||||||
|
# Upload Lua coverage (generated manually on AppVeyor/Windows).
|
||||||
|
if [ "$USE_LUACOV" = 1 ] && [ "$1" != "oldtest" ]; then
|
||||||
|
if [ -x "${DEPS_BUILD_DIR}/usr/bin/luacov" ]; then
|
||||||
|
"${DEPS_BUILD_DIR}/usr/bin/luacov"
|
||||||
|
fi
|
||||||
|
if ! "$codecov_sh" -f luacov.report.out -X gcov -X fix -Z -F "lua,${codecov_flags}"; then
|
||||||
|
echo "codecov upload failed."
|
||||||
|
fi
|
||||||
|
rm luacov.stats.out
|
||||||
|
fi
|
||||||
|
@ -4,7 +4,7 @@ set -e
|
|||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
if [[ "${CI_TARGET}" == lint ]]; then
|
if [[ "${CI_TARGET}" == lint ]]; then
|
||||||
python -m pip -q install --user --upgrade flake8
|
python3 -m pip -q install --user --upgrade flake8
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -24,3 +24,27 @@ gem install --no-document --version ">= 0.8.0" neovim
|
|||||||
echo "Install neovim npm package"
|
echo "Install neovim npm package"
|
||||||
npm install -g neovim
|
npm install -g neovim
|
||||||
npm link neovim
|
npm link neovim
|
||||||
|
|
||||||
|
echo "Install tree-sitter npm package"
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
# https://github.com/tree-sitter/tree-sitter/commit/e14e285a1087264a8c74a7c62fcaecc49db9d904
|
||||||
|
# If queries added to tree-sitter-c, we can use latest tree-sitter-cli
|
||||||
|
npm install -g tree-sitter-cli@v0.15.9
|
||||||
|
|
||||||
|
echo "Install tree-sitter c parser"
|
||||||
|
curl "https://codeload.github.com/tree-sitter/tree-sitter-c/tar.gz/v0.15.2" -o tree_sitter_c.tar.gz
|
||||||
|
tar xf tree_sitter_c.tar.gz
|
||||||
|
cd tree-sitter-c-0.15.2
|
||||||
|
export TREE_SITTER_DIR=$HOME/tree-sitter-build/
|
||||||
|
mkdir -p "$TREE_SITTER_DIR/bin"
|
||||||
|
|
||||||
|
if [[ "$BUILD_32BIT" != "ON" ]]; then
|
||||||
|
# builds c parser in $HOME/tree-sitter-build/bin/c.(so|dylib)
|
||||||
|
tree-sitter test
|
||||||
|
else
|
||||||
|
# no tree-sitter binary for 32bit linux, so fake it (no tree-sitter unit tests)
|
||||||
|
cd src/
|
||||||
|
gcc -m32 -o "$TREE_SITTER_DIR/bin/c.so" -shared parser.c -I.
|
||||||
|
fi
|
||||||
|
test -f "$TREE_SITTER_DIR/bin/c.so"
|
||||||
|
@ -20,6 +20,10 @@ enter_suite 'pylint'
|
|||||||
run_test 'make pylint' pylint
|
run_test 'make pylint' pylint
|
||||||
exit_suite --continue
|
exit_suite --continue
|
||||||
|
|
||||||
|
enter_suite 'shlint'
|
||||||
|
run_test 'make shlint' shlint
|
||||||
|
exit_suite --continue
|
||||||
|
|
||||||
enter_suite single-includes
|
enter_suite single-includes
|
||||||
CLICOLOR_FORCE=1 run_test_wd \
|
CLICOLOR_FORCE=1 run_test_wd \
|
||||||
--allow-hang \
|
--allow-hang \
|
||||||
|
@ -19,6 +19,8 @@ exit_suite --continue
|
|||||||
|
|
||||||
enter_suite tests
|
enter_suite tests
|
||||||
|
|
||||||
|
export TREE_SITTER_DIR=$HOME/tree-sitter-build/
|
||||||
|
|
||||||
if test "$CLANG_SANITIZER" != "TSAN" ; then
|
if test "$CLANG_SANITIZER" != "TSAN" ; then
|
||||||
# Additional threads are only created when the builtin UI starts, which
|
# Additional threads are only created when the builtin UI starts, which
|
||||||
# doesn't happen in the unit/functional tests
|
# doesn't happen in the unit/functional tests
|
||||||
|
14
ci/snap/after_success.sh
Executable file
14
ci/snap/after_success.sh
Executable file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
|
||||||
|
RESULT_SNAP=$(find ./ -name "*.snap")
|
||||||
|
|
||||||
|
sudo snap install "$RESULT_SNAP" --dangerous --classic
|
||||||
|
|
||||||
|
/snap/bin/nvim --version
|
||||||
|
|
||||||
|
SHA256=$(sha256sum "$RESULT_SNAP")
|
||||||
|
echo "SHA256: ${SHA256} ."
|
21
ci/snap/deploy.sh
Executable file
21
ci/snap/deploy.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# not a tagged release, abort
|
||||||
|
# [[ "$TRAVIS_TAG" != "$TRAVIS_BRANCH" ]] && exit 0
|
||||||
|
|
||||||
|
mkdir -p .snapcraft
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
openssl aes-256-cbc -K "$encrypted_ece1c4844832_key" -iv "$encrypted_ece1c4844832_iv" \
|
||||||
|
-in ci/snap/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d
|
||||||
|
|
||||||
|
SNAP=$(find ./ -name "*.snap")
|
||||||
|
|
||||||
|
# TODO(justinmk): This always does `edge` until we enable tagged builds.
|
||||||
|
if [[ "$SNAP" =~ "dirty" || "$SNAP" =~ "nightly" ]]; then
|
||||||
|
snapcraft push "$SNAP" --release edge
|
||||||
|
else
|
||||||
|
snapcraft push "$SNAP" --release candidate
|
||||||
|
fi
|
10
ci/snap/install.sh
Executable file
10
ci/snap/install.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
sudo apt update
|
||||||
|
sudo /snap/bin/lxd.migrate -yes
|
||||||
|
sudo /snap/bin/lxd waitready
|
||||||
|
sudo /snap/bin/lxd init --auto
|
||||||
|
|
8
ci/snap/script.sh
Executable file
8
ci/snap/script.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
mkdir -p "$TRAVIS_BUILD_DIR/snaps-cache"
|
||||||
|
sudo snapcraft --use-lxd
|
||||||
|
|
BIN
ci/snap/travis_snapcraft.cfg
Normal file
BIN
ci/snap/travis_snapcraft.cfg
Normal file
Binary file not shown.
16
cmake/FindUTF8PROC.cmake
Normal file
16
cmake/FindUTF8PROC.cmake
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# - Try to find utf8proc
|
||||||
|
# Once done this will define
|
||||||
|
# UTF8PROC_FOUND - System has utf8proc
|
||||||
|
# UTF8PROC_INCLUDE_DIRS - The utf8proc include directories
|
||||||
|
# UTF8PROC_LIBRARIES - The libraries needed to use utf8proc
|
||||||
|
|
||||||
|
include(LibFindMacros)
|
||||||
|
|
||||||
|
set(UTF8PROC_NAMES utf8proc)
|
||||||
|
if(MSVC)
|
||||||
|
# "utf8proc_static" is used for MSVC (when built statically from third-party).
|
||||||
|
# https://github.com/JuliaStrings/utf8proc/commit/0975bf9b6.
|
||||||
|
list(APPEND UTF8PROC_NAMES utf8proc_static)
|
||||||
|
endif()
|
||||||
|
libfind_pkg_detect(UTF8PROC utf8proc FIND_PATH utf8proc.h FIND_LIBRARY ${UTF8PROC_NAMES})
|
||||||
|
libfind_process(UTF8PROC REQUIRED)
|
@ -3,6 +3,13 @@ function(get_compile_flags _compile_flags)
|
|||||||
set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS><COMPILE_DEFINITIONS> <INCLUDES>")
|
set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS><COMPILE_DEFINITIONS> <INCLUDES>")
|
||||||
|
|
||||||
# Get C compiler.
|
# Get C compiler.
|
||||||
|
if(CMAKE_C_COMPILER_ARG1)
|
||||||
|
string(REPLACE
|
||||||
|
"<CMAKE_C_COMPILER>"
|
||||||
|
"<CMAKE_C_COMPILER> ${CMAKE_C_COMPILER_ARG1}"
|
||||||
|
compile_flags
|
||||||
|
"${compile_flags}")
|
||||||
|
endif()
|
||||||
string(REPLACE
|
string(REPLACE
|
||||||
"<CMAKE_C_COMPILER>"
|
"<CMAKE_C_COMPILER>"
|
||||||
"${CMAKE_C_COMPILER}"
|
"${CMAKE_C_COMPILER}"
|
||||||
|
@ -1,180 +0,0 @@
|
|||||||
# https://github.com/rpavlik/cmake-modules
|
|
||||||
#
|
|
||||||
# - Returns a version string from Git
|
|
||||||
#
|
|
||||||
# These functions force a re-configure on each git commit so that you can
|
|
||||||
# trust the values of the variables in your build system.
|
|
||||||
#
|
|
||||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the refspec and sha hash of the current head revision
|
|
||||||
#
|
|
||||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the results of git describe on the source tree, and adjusting
|
|
||||||
# the output so that it tests false if an error occurs.
|
|
||||||
#
|
|
||||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the results of git describe --exact-match on the source tree,
|
|
||||||
# and adjusting the output so that it tests false if there was no exact
|
|
||||||
# matching tag.
|
|
||||||
#
|
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
|
||||||
# http://academic.cleardefinition.com
|
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
|
||||||
#
|
|
||||||
# Copyright Iowa State University 2009-2010.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
if(__get_git_revision_description)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(__get_git_revision_description YES)
|
|
||||||
|
|
||||||
# We must run the following at "include" time, not at function call time,
|
|
||||||
# to find the path to this module rather than the path to a calling list file
|
|
||||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
|
||||||
|
|
||||||
function(get_git_dir _gitdir)
|
|
||||||
# check FORCED_GIT_DIR first
|
|
||||||
if(FORCED_GIT_DIR)
|
|
||||||
set(${_gitdir} ${FORCED_GIT_DIR} PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# check GIT_DIR in environment
|
|
||||||
set(GIT_DIR $ENV{GIT_DIR})
|
|
||||||
if(NOT GIT_DIR)
|
|
||||||
set(GIT_PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
set(GIT_DIR ${GIT_PARENT_DIR}/.git)
|
|
||||||
endif()
|
|
||||||
# .git dir not found, search parent directories
|
|
||||||
while(NOT EXISTS ${GIT_DIR})
|
|
||||||
set(GIT_PREVIOUS_PARENT ${GIT_PARENT_DIR})
|
|
||||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
|
||||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(GIT_DIR ${GIT_PARENT_DIR}/.git)
|
|
||||||
endwhile()
|
|
||||||
# check if this is a submodule
|
|
||||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
|
||||||
file(READ ${GIT_DIR} submodule)
|
|
||||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
|
||||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
|
||||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
|
||||||
endif()
|
|
||||||
set(${_gitdir} ${GIT_DIR} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(get_git_head_revision _refspecvar _hashvar)
|
|
||||||
get_git_dir(GIT_DIR)
|
|
||||||
if(NOT GIT_DIR)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(GIT_DATA ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data)
|
|
||||||
if(NOT EXISTS ${GIT_DATA})
|
|
||||||
file(MAKE_DIRECTORY ${GIT_DATA})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT EXISTS ${GIT_DIR}/HEAD)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(HEAD_FILE ${GIT_DATA}/HEAD)
|
|
||||||
configure_file(${GIT_DIR}/HEAD ${HEAD_FILE} COPYONLY)
|
|
||||||
|
|
||||||
configure_file(${_gitdescmoddir}/GetGitRevisionDescription.cmake.in
|
|
||||||
${GIT_DATA}/grabRef.cmake
|
|
||||||
@ONLY)
|
|
||||||
include(${GIT_DATA}/grabRef.cmake)
|
|
||||||
|
|
||||||
set(${_refspecvar} ${HEAD_REF} PARENT_SCOPE)
|
|
||||||
set(${_hashvar} ${HEAD_HASH} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_describe _var)
|
|
||||||
get_git_dir(GIT_DIR)
|
|
||||||
if(NOT GIT_DIR)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
find_package(Git QUIET)
|
|
||||||
endif()
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_git_head_revision(refspec hash)
|
|
||||||
if(NOT hash)
|
|
||||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
execute_process(COMMAND
|
|
||||||
${GIT_EXECUTABLE}
|
|
||||||
describe
|
|
||||||
${hash}
|
|
||||||
${ARGN}
|
|
||||||
WORKING_DIRECTORY
|
|
||||||
${GIT_DIR}
|
|
||||||
RESULT_VARIABLE
|
|
||||||
res
|
|
||||||
OUTPUT_VARIABLE
|
|
||||||
out
|
|
||||||
ERROR_QUIET
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
if(NOT res EQUAL 0)
|
|
||||||
set(out "${out}-${res}-NOTFOUND")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(${_var} ${out} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_timestamp _var)
|
|
||||||
get_git_dir(GIT_DIR)
|
|
||||||
if(NOT GIT_DIR)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
find_package(Git QUIET)
|
|
||||||
endif()
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_git_head_revision(refspec hash)
|
|
||||||
if(NOT hash)
|
|
||||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --format="%ci" ${hash} ${ARGN}
|
|
||||||
WORKING_DIRECTORY ${GIT_DIR}
|
|
||||||
RESULT_VARIABLE res
|
|
||||||
OUTPUT_VARIABLE out
|
|
||||||
ERROR_QUIET
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
if(res EQUAL 0)
|
|
||||||
string(REGEX REPLACE "[-\" :]" "" out ${out})
|
|
||||||
string(SUBSTRING ${out} 0 12 out)
|
|
||||||
else()
|
|
||||||
set(out "${out}-${res}-NOTFOUND")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(${_var} ${out} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_get_exact_tag _var)
|
|
||||||
git_describe(out --exact-match ${ARGN})
|
|
||||||
set(${_var} ${out} PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
@ -1,38 +0,0 @@
|
|||||||
#
|
|
||||||
# Internal file for GetGitRevisionDescription.cmake
|
|
||||||
#
|
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
|
||||||
# http://academic.cleardefinition.com
|
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
|
||||||
#
|
|
||||||
# Copyright Iowa State University 2009-2010.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
set(HEAD_HASH)
|
|
||||||
|
|
||||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
|
||||||
|
|
||||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
|
||||||
if(HEAD_CONTENTS MATCHES "ref")
|
|
||||||
# named branch
|
|
||||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
|
||||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
|
||||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
|
||||||
elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
|
|
||||||
configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
|
||||||
set(HEAD_HASH "${HEAD_REF}")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
# detached HEAD
|
|
||||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT HEAD_HASH)
|
|
||||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
|
||||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
|
||||||
endif()
|
|
@ -25,3 +25,6 @@ coverage:
|
|||||||
changes: no
|
changes: no
|
||||||
|
|
||||||
comment: off
|
comment: off
|
||||||
|
|
||||||
|
ignore:
|
||||||
|
- "src/tree_sitter"
|
||||||
|
@ -5,7 +5,11 @@
|
|||||||
#define NVIM_VERSION_MINOR @NVIM_VERSION_MINOR@
|
#define NVIM_VERSION_MINOR @NVIM_VERSION_MINOR@
|
||||||
#define NVIM_VERSION_PATCH @NVIM_VERSION_PATCH@
|
#define NVIM_VERSION_PATCH @NVIM_VERSION_PATCH@
|
||||||
#define NVIM_VERSION_PRERELEASE "@NVIM_VERSION_PRERELEASE@"
|
#define NVIM_VERSION_PRERELEASE "@NVIM_VERSION_PRERELEASE@"
|
||||||
|
|
||||||
#cmakedefine NVIM_VERSION_MEDIUM "@NVIM_VERSION_MEDIUM@"
|
#cmakedefine NVIM_VERSION_MEDIUM "@NVIM_VERSION_MEDIUM@"
|
||||||
|
#ifndef NVIM_VERSION_MEDIUM
|
||||||
|
# include "auto/versiondef_git.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define NVIM_API_LEVEL @NVIM_API_LEVEL@
|
#define NVIM_API_LEVEL @NVIM_API_LEVEL@
|
||||||
#define NVIM_API_LEVEL_COMPAT @NVIM_API_LEVEL_COMPAT@
|
#define NVIM_API_LEVEL_COMPAT @NVIM_API_LEVEL_COMPAT@
|
||||||
|
@ -25,6 +25,12 @@
|
|||||||
#
|
#
|
||||||
# CMAKE_BUILD_TYPE := Debug
|
# CMAKE_BUILD_TYPE := Debug
|
||||||
|
|
||||||
|
# With non-Debug builds interprocedural optimization (IPO) (which includes
|
||||||
|
# link-time optimization (LTO)) is enabled by default, which causes the link
|
||||||
|
# step to take a significant amout of time, which is relevant when building
|
||||||
|
# often. You can disable it explicitly:
|
||||||
|
# CMAKE_EXTRA_FLAGS += -DENABLE_LTO=OFF
|
||||||
|
|
||||||
# Log levels: 0 (DEBUG), 1 (INFO), 2 (WARNING), 3 (ERROR)
|
# Log levels: 0 (DEBUG), 1 (INFO), 2 (WARNING), 3 (ERROR)
|
||||||
# Default is 1 (INFO) unless CMAKE_BUILD_TYPE is Release or RelWithDebInfo.
|
# Default is 1 (INFO) unless CMAKE_BUILD_TYPE is Release or RelWithDebInfo.
|
||||||
# CMAKE_EXTRA_FLAGS += -DMIN_LOG_LEVEL=1
|
# CMAKE_EXTRA_FLAGS += -DMIN_LOG_LEVEL=1
|
||||||
@ -42,6 +48,7 @@
|
|||||||
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LUAROCKS=OFF
|
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_LUAROCKS=OFF
|
||||||
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_MSGPACK=OFF
|
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_MSGPACK=OFF
|
||||||
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_UNIBILIUM=OFF
|
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_UNIBILIUM=OFF
|
||||||
|
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED_UTF8PROC=OFF
|
||||||
#
|
#
|
||||||
# Or disable all bundled dependencies at once.
|
# Or disable all bundled dependencies at once.
|
||||||
#
|
#
|
||||||
|
@ -38,9 +38,10 @@ endfunction
|
|||||||
" Handler for s:system() function.
|
" Handler for s:system() function.
|
||||||
function! s:system_handler(jobid, data, event) dict abort
|
function! s:system_handler(jobid, data, event) dict abort
|
||||||
if a:event ==# 'stderr'
|
if a:event ==# 'stderr'
|
||||||
let self.stderr .= join(a:data, '')
|
if self.add_stderr_to_output
|
||||||
if !self.ignore_stderr
|
|
||||||
let self.output .= join(a:data, '')
|
let self.output .= join(a:data, '')
|
||||||
|
else
|
||||||
|
let self.stderr .= join(a:data, '')
|
||||||
endif
|
endif
|
||||||
elseif a:event ==# 'stdout'
|
elseif a:event ==# 'stdout'
|
||||||
let self.output .= join(a:data, '')
|
let self.output .= join(a:data, '')
|
||||||
@ -64,7 +65,7 @@ function! s:system(cmd, ...) abort
|
|||||||
let stdin = a:0 ? a:1 : ''
|
let stdin = a:0 ? a:1 : ''
|
||||||
let ignore_error = a:0 > 2 ? a:3 : 0
|
let ignore_error = a:0 > 2 ? a:3 : 0
|
||||||
let opts = {
|
let opts = {
|
||||||
\ 'ignore_stderr': a:0 > 1 ? a:2 : 0,
|
\ 'add_stderr_to_output': a:0 > 1 ? a:2 : 0,
|
||||||
\ 'output': '',
|
\ 'output': '',
|
||||||
\ 'stderr': '',
|
\ 'stderr': '',
|
||||||
\ 'on_stdout': function('s:system_handler'),
|
\ 'on_stdout': function('s:system_handler'),
|
||||||
@ -89,8 +90,15 @@ function! s:system(cmd, ...) abort
|
|||||||
call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd)))
|
call health#report_error(printf('Command timed out: %s', s:shellify(a:cmd)))
|
||||||
call jobstop(jobid)
|
call jobstop(jobid)
|
||||||
elseif s:shell_error != 0 && !ignore_error
|
elseif s:shell_error != 0 && !ignore_error
|
||||||
call health#report_error(printf("Command error (job=%d, exit code %d): `%s` (in %s)\nOutput: %s\nStderr: %s",
|
let emsg = printf("Command error (job=%d, exit code %d): `%s` (in %s)",
|
||||||
\ jobid, s:shell_error, s:shellify(a:cmd), string(getcwd()), opts.output, opts.stderr))
|
\ jobid, s:shell_error, s:shellify(a:cmd), string(getcwd()))
|
||||||
|
if !empty(opts.output)
|
||||||
|
let emsg .= "\noutput: " . opts.output
|
||||||
|
end
|
||||||
|
if !empty(opts.stderr)
|
||||||
|
let emsg .= "\nstderr: " . opts.stderr
|
||||||
|
end
|
||||||
|
call health#report_error(emsg)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
return opts.output
|
return opts.output
|
||||||
@ -194,7 +202,8 @@ function! s:version_info(python) abort
|
|||||||
|
|
||||||
let nvim_path = s:trim(s:system([
|
let nvim_path = s:trim(s:system([
|
||||||
\ a:python, '-c',
|
\ a:python, '-c',
|
||||||
\ 'import sys; sys.path.remove(""); ' .
|
\ 'import sys; ' .
|
||||||
|
\ 'sys.path = list(filter(lambda x: x != "", sys.path)); ' .
|
||||||
\ 'import neovim; print(neovim.__file__)']))
|
\ 'import neovim; print(neovim.__file__)']))
|
||||||
if s:shell_error || empty(nvim_path)
|
if s:shell_error || empty(nvim_path)
|
||||||
return [python_version, 'unable to load neovim Python module', pypi_version,
|
return [python_version, 'unable to load neovim Python module', pypi_version,
|
||||||
@ -257,6 +266,22 @@ function! s:check_bin(bin) abort
|
|||||||
return 1
|
return 1
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
" Check "loaded" var for given a:provider.
|
||||||
|
" Returns 1 if the caller should return (skip checks).
|
||||||
|
function! s:disabled_via_loaded_var(provider) abort
|
||||||
|
let loaded_var = 'g:loaded_'.a:provider.'_provider'
|
||||||
|
if exists(loaded_var) && !exists('*provider#'.a:provider.'#Call')
|
||||||
|
let v = eval(loaded_var)
|
||||||
|
if 0 is v
|
||||||
|
call health#report_info('Disabled ('.loaded_var.'='.v.').')
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
call health#report_info('Disabled ('.loaded_var.'='.v.'). This might be due to some previous error.')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
return 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
function! s:check_python(version) abort
|
function! s:check_python(version) abort
|
||||||
call health#report_start('Python ' . a:version . ' provider (optional)')
|
call health#report_start('Python ' . a:version . ' provider (optional)')
|
||||||
|
|
||||||
@ -264,11 +289,10 @@ function! s:check_python(version) abort
|
|||||||
let python_exe = ''
|
let python_exe = ''
|
||||||
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
|
let venv = exists('$VIRTUAL_ENV') ? resolve($VIRTUAL_ENV) : ''
|
||||||
let host_prog_var = pyname.'_host_prog'
|
let host_prog_var = pyname.'_host_prog'
|
||||||
let loaded_var = 'g:loaded_'.pyname.'_provider'
|
|
||||||
let python_multiple = []
|
let python_multiple = []
|
||||||
|
|
||||||
if exists(loaded_var) && !exists('*provider#'.pyname.'#Call')
|
if s:disabled_via_loaded_var(pyname)
|
||||||
call health#report_info('Disabled ('.loaded_var.'='.eval(loaded_var).'). This might be due to some previous error.')
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let [pyenv, pyenv_root] = s:check_for_pyenv()
|
let [pyenv, pyenv_root] = s:check_for_pyenv()
|
||||||
@ -286,7 +310,7 @@ function! s:check_python(version) abort
|
|||||||
let python_exe = pyname
|
let python_exe = pyname
|
||||||
endif
|
endif
|
||||||
|
|
||||||
" No Python executable could `import neovim`.
|
" No Python executable could `import neovim`, or host_prog_var was used.
|
||||||
if !empty(pythonx_errors)
|
if !empty(pythonx_errors)
|
||||||
call health#report_error('Python provider error:', pythonx_errors)
|
call health#report_error('Python provider error:', pythonx_errors)
|
||||||
|
|
||||||
@ -476,9 +500,7 @@ endfunction
|
|||||||
function! s:check_ruby() abort
|
function! s:check_ruby() abort
|
||||||
call health#report_start('Ruby provider (optional)')
|
call health#report_start('Ruby provider (optional)')
|
||||||
|
|
||||||
let loaded_var = 'g:loaded_ruby_provider'
|
if s:disabled_via_loaded_var('ruby')
|
||||||
if exists(loaded_var) && !exists('*provider#ruby#Call')
|
|
||||||
call health#report_info('Disabled. '.loaded_var.'='.eval(loaded_var))
|
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -532,9 +554,7 @@ endfunction
|
|||||||
function! s:check_node() abort
|
function! s:check_node() abort
|
||||||
call health#report_start('Node.js provider (optional)')
|
call health#report_start('Node.js provider (optional)')
|
||||||
|
|
||||||
let loaded_var = 'g:loaded_node_provider'
|
if s:disabled_via_loaded_var('node')
|
||||||
if exists(loaded_var) && !exists('*provider#node#Call')
|
|
||||||
call health#report_info('Disabled. '.loaded_var.'='.eval(loaded_var))
|
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
" Maintainer: Anmol Sethi <anmol@aubble.com>
|
" Maintainer: Anmol Sethi <hi@nhooyr.io>
|
||||||
|
|
||||||
if exists('s:loaded_man')
|
if exists('s:loaded_man')
|
||||||
finish
|
finish
|
||||||
@ -64,33 +64,20 @@ function! man#open_page(count, count1, mods, ...) abort
|
|||||||
return
|
return
|
||||||
endtry
|
endtry
|
||||||
|
|
||||||
call s:push_tag()
|
let [l:buf, l:save_tfu] = [bufnr(), &tagfunc]
|
||||||
let bufname = 'man://'.name.(empty(sect)?'':'('.sect.')')
|
|
||||||
|
|
||||||
try
|
try
|
||||||
set eventignore+=BufReadCmd
|
set tagfunc=man#goto_tag
|
||||||
|
let l:target = l:name . '(' . l:sect . ')'
|
||||||
if a:mods !~# 'tab' && s:find_man()
|
if a:mods !~# 'tab' && s:find_man()
|
||||||
execute 'silent keepalt edit' fnameescape(bufname)
|
execute 'silent keepalt tag' l:target
|
||||||
else
|
else
|
||||||
execute 'silent keepalt' a:mods 'split' fnameescape(bufname)
|
execute 'silent keepalt' a:mods 'stag' l:target
|
||||||
endif
|
endif
|
||||||
finally
|
finally
|
||||||
set eventignore-=BufReadCmd
|
call setbufvar(l:buf, '&tagfunc', l:save_tfu)
|
||||||
endtry
|
|
||||||
|
|
||||||
try
|
|
||||||
let page = s:get_page(path)
|
|
||||||
catch
|
|
||||||
if a:mods =~# 'tab' || !s:find_man()
|
|
||||||
" a new window was opened
|
|
||||||
close
|
|
||||||
endif
|
|
||||||
call s:error(v:exception)
|
|
||||||
return
|
|
||||||
endtry
|
endtry
|
||||||
|
|
||||||
let b:man_sect = sect
|
let b:man_sect = sect
|
||||||
call s:put_page(page)
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! man#read_page(ref) abort
|
function! man#read_page(ref) abort
|
||||||
@ -152,7 +139,7 @@ function! s:get_page(path) abort
|
|||||||
" Disable hard-wrap by using a big $MANWIDTH (max 1000 on some systems #9065).
|
" Disable hard-wrap by using a big $MANWIDTH (max 1000 on some systems #9065).
|
||||||
" Soft-wrap: ftplugin/man.vim sets wrap/breakindent/….
|
" Soft-wrap: ftplugin/man.vim sets wrap/breakindent/….
|
||||||
" Hard-wrap: driven by `man`.
|
" Hard-wrap: driven by `man`.
|
||||||
let manwidth = !get(g:,'man_hardwrap') ? 999 : (empty($MANWIDTH) ? winwidth(0) : $MANWIDTH)
|
let manwidth = !get(g:,'man_hardwrap', 1) ? 999 : (empty($MANWIDTH) ? winwidth(0) : $MANWIDTH)
|
||||||
" Force MANPAGER=cat to ensure Vim is not recursively invoked (by man-db).
|
" Force MANPAGER=cat to ensure Vim is not recursively invoked (by man-db).
|
||||||
" http://comments.gmane.org/gmane.editors.vim.devel/29085
|
" http://comments.gmane.org/gmane.editors.vim.devel/29085
|
||||||
" Set MAN_KEEP_FORMATTING so Debian man doesn't discard backspaces.
|
" Set MAN_KEEP_FORMATTING so Debian man doesn't discard backspaces.
|
||||||
@ -163,6 +150,9 @@ endfunction
|
|||||||
function! s:put_page(page) abort
|
function! s:put_page(page) abort
|
||||||
setlocal modifiable
|
setlocal modifiable
|
||||||
setlocal noreadonly
|
setlocal noreadonly
|
||||||
|
setlocal noswapfile
|
||||||
|
" git-ls-files(1) is all one keyword/tag-target
|
||||||
|
setlocal iskeyword+=(,)
|
||||||
silent keepjumps %delete _
|
silent keepjumps %delete _
|
||||||
silent put =a:page
|
silent put =a:page
|
||||||
while getline(1) =~# '^\s*$'
|
while getline(1) =~# '^\s*$'
|
||||||
@ -254,24 +244,6 @@ function! s:verify_exists(sect, name) abort
|
|||||||
return s:extract_sect_and_name_path(path) + [path]
|
return s:extract_sect_and_name_path(path) + [path]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
let s:tag_stack = []
|
|
||||||
|
|
||||||
function! s:push_tag() abort
|
|
||||||
let s:tag_stack += [{
|
|
||||||
\ 'buf': bufnr('%'),
|
|
||||||
\ 'lnum': line('.'),
|
|
||||||
\ 'col': col('.'),
|
|
||||||
\ }]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! man#pop_tag() abort
|
|
||||||
if !empty(s:tag_stack)
|
|
||||||
let tag = remove(s:tag_stack, -1)
|
|
||||||
execute 'silent' tag['buf'].'buffer'
|
|
||||||
call cursor(tag['lnum'], tag['col'])
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" extracts the name and sect out of 'path/name.sect'
|
" extracts the name and sect out of 'path/name.sect'
|
||||||
function! s:extract_sect_and_name_path(path) abort
|
function! s:extract_sect_and_name_path(path) abort
|
||||||
let tail = fnamemodify(a:path, ':t')
|
let tail = fnamemodify(a:path, ':t')
|
||||||
@ -284,20 +256,16 @@ function! s:extract_sect_and_name_path(path) abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:find_man() abort
|
function! s:find_man() abort
|
||||||
if &filetype ==# 'man'
|
let l:win = 1
|
||||||
return 1
|
while l:win <= winnr('$')
|
||||||
elseif winnr('$') ==# 1
|
let l:buf = winbufnr(l:win)
|
||||||
return 0
|
if getbufvar(l:buf, '&filetype', '') ==# 'man'
|
||||||
endif
|
execute l:win.'wincmd w'
|
||||||
let thiswin = winnr()
|
|
||||||
while 1
|
|
||||||
wincmd w
|
|
||||||
if &filetype ==# 'man'
|
|
||||||
return 1
|
return 1
|
||||||
elseif thiswin ==# winnr()
|
|
||||||
return 0
|
|
||||||
endif
|
endif
|
||||||
|
let l:win += 1
|
||||||
endwhile
|
endwhile
|
||||||
|
return 0
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:error(msg) abort
|
function! s:error(msg) abort
|
||||||
@ -360,14 +328,18 @@ function! man#complete(arg_lead, cmd_line, cursor_pos) abort
|
|||||||
return s:complete(sect, sect, name)
|
return s:complete(sect, sect, name)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:complete(sect, psect, name) abort
|
function! s:get_paths(sect, name) abort
|
||||||
try
|
try
|
||||||
let mandirs = join(split(s:system(['man', s:find_arg]), ':\|\n'), ',')
|
let mandirs = join(split(s:system(['man', s:find_arg]), ':\|\n'), ',')
|
||||||
catch
|
catch
|
||||||
call s:error(v:exception)
|
call s:error(v:exception)
|
||||||
return
|
return
|
||||||
endtry
|
endtry
|
||||||
let pages = globpath(mandirs,'man?/'.a:name.'*.'.a:sect.'*', 0, 1)
|
return globpath(mandirs,'man?/'.a:name.'*.'.a:sect.'*', 0, 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:complete(sect, psect, name) abort
|
||||||
|
let pages = s:get_paths(a:sect, a:name)
|
||||||
" We remove duplicates in case the same manpage in different languages was found.
|
" We remove duplicates in case the same manpage in different languages was found.
|
||||||
return uniq(sort(map(pages, 's:format_candidate(v:val, a:psect)'), 'i'))
|
return uniq(sort(map(pages, 's:format_candidate(v:val, a:psect)'), 'i'))
|
||||||
endfunction
|
endfunction
|
||||||
@ -387,6 +359,10 @@ function! s:format_candidate(path, psect) abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! man#init_pager() abort
|
function! man#init_pager() abort
|
||||||
|
" https://github.com/neovim/neovim/issues/6828
|
||||||
|
let og_modifiable = &modifiable
|
||||||
|
setlocal modifiable
|
||||||
|
|
||||||
if getline(1) =~# '^\s*$'
|
if getline(1) =~# '^\s*$'
|
||||||
silent keepjumps 1delete _
|
silent keepjumps 1delete _
|
||||||
else
|
else
|
||||||
@ -404,6 +380,31 @@ function! man#init_pager() abort
|
|||||||
if -1 == match(bufname('%'), 'man:\/\/') " Avoid duplicate buffers, E95.
|
if -1 == match(bufname('%'), 'man:\/\/') " Avoid duplicate buffers, E95.
|
||||||
execute 'silent file man://'.tolower(fnameescape(ref))
|
execute 'silent file man://'.tolower(fnameescape(ref))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
let &l:modifiable = og_modifiable
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! man#goto_tag(pattern, flags, info) abort
|
||||||
|
let [l:sect, l:name] = man#extract_sect_and_name_ref(a:pattern)
|
||||||
|
|
||||||
|
let l:paths = s:get_paths(l:sect, l:name)
|
||||||
|
let l:structured = []
|
||||||
|
|
||||||
|
for l:path in l:paths
|
||||||
|
let l:n = s:extract_sect_and_name_path(l:path)[1]
|
||||||
|
let l:structured += [{ 'name': l:n, 'path': l:path }]
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" sort by relevance - exact matches first, then the previous order
|
||||||
|
call sort(l:structured, { a, b -> a.name ==? l:name ? -1 : b.name ==? l:name ? 1 : 0 })
|
||||||
|
|
||||||
|
return map(l:structured, {
|
||||||
|
\ _, entry -> {
|
||||||
|
\ 'name': entry.name,
|
||||||
|
\ 'filename': 'man://' . entry.path,
|
||||||
|
\ 'cmd': '1'
|
||||||
|
\ }
|
||||||
|
\ })
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
call s:init()
|
call s:init()
|
||||||
|
@ -688,10 +688,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
" save registers
|
" save registers
|
||||||
if has("clipboard")
|
|
||||||
sil! let keepregstar = @*
|
|
||||||
sil! let keepregplus = @+
|
|
||||||
endif
|
|
||||||
sil! let keepregslash= @/
|
sil! let keepregslash= @/
|
||||||
|
|
||||||
" if dosplit
|
" if dosplit
|
||||||
@ -915,10 +911,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
" call Decho("..case Nexplore with starpat=".starpat.": (indx=".indx.")",'~'.expand("<slnum>"))
|
" call Decho("..case Nexplore with starpat=".starpat.": (indx=".indx.")",'~'.expand("<slnum>"))
|
||||||
if !exists("w:netrw_explore_list") " sanity check
|
if !exists("w:netrw_explore_list") " sanity check
|
||||||
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Nexplore or <s-down> improperly; see help for netrw-starstar",40)
|
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Nexplore or <s-down> improperly; see help for netrw-starstar",40)
|
||||||
if has("clipboard")
|
|
||||||
sil! let @* = keepregstar
|
|
||||||
sil! let @+ = keepregplus
|
|
||||||
endif
|
|
||||||
sil! let @/ = keepregslash
|
sil! let @/ = keepregslash
|
||||||
" call Dret("netrw#Explore")
|
" call Dret("netrw#Explore")
|
||||||
return
|
return
|
||||||
@ -940,10 +932,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
" call Decho("case Pexplore with starpat=".starpat.": (indx=".indx.")",'~'.expand("<slnum>"))
|
" call Decho("case Pexplore with starpat=".starpat.": (indx=".indx.")",'~'.expand("<slnum>"))
|
||||||
if !exists("w:netrw_explore_list") " sanity check
|
if !exists("w:netrw_explore_list") " sanity check
|
||||||
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Pexplore or <s-up> improperly; see help for netrw-starstar",41)
|
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Pexplore or <s-up> improperly; see help for netrw-starstar",41)
|
||||||
if has("clipboard")
|
|
||||||
sil! let @* = keepregstar
|
|
||||||
sil! let @+ = keepregplus
|
|
||||||
endif
|
|
||||||
sil! let @/ = keepregslash
|
sil! let @/ = keepregslash
|
||||||
" call Dret("netrw#Explore")
|
" call Dret("netrw#Explore")
|
||||||
return
|
return
|
||||||
@ -995,10 +983,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
catch /^Vim\%((\a\+)\)\=:E480/
|
catch /^Vim\%((\a\+)\)\=:E480/
|
||||||
keepalt call netrw#ErrorMsg(s:WARNING,'no files matched pattern<'.pattern.'>',45)
|
keepalt call netrw#ErrorMsg(s:WARNING,'no files matched pattern<'.pattern.'>',45)
|
||||||
if &hls | let keepregslash= s:ExplorePatHls(pattern) | endif
|
if &hls | let keepregslash= s:ExplorePatHls(pattern) | endif
|
||||||
if has("clipboard")
|
|
||||||
sil! let @* = keepregstar
|
|
||||||
sil! let @+ = keepregplus
|
|
||||||
endif
|
|
||||||
sil! let @/ = keepregslash
|
sil! let @/ = keepregslash
|
||||||
" call Dret("netrw#Explore : no files matched pattern")
|
" call Dret("netrw#Explore : no files matched pattern")
|
||||||
return
|
return
|
||||||
@ -1031,10 +1015,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
|
|
||||||
if w:netrw_explore_listlen == 0 || (w:netrw_explore_listlen == 1 && w:netrw_explore_list[0] =~ '\*\*\/')
|
if w:netrw_explore_listlen == 0 || (w:netrw_explore_listlen == 1 && w:netrw_explore_list[0] =~ '\*\*\/')
|
||||||
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"no files matched",42)
|
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"no files matched",42)
|
||||||
if has("clipboard")
|
|
||||||
sil! let @* = keepregstar
|
|
||||||
sil! let @+ = keepregplus
|
|
||||||
endif
|
|
||||||
sil! let @/ = keepregslash
|
sil! let @/ = keepregslash
|
||||||
" call Dret("netrw#Explore : no files matched")
|
" call Dret("netrw#Explore : no files matched")
|
||||||
return
|
return
|
||||||
@ -1079,10 +1059,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
if !exists("g:netrw_quiet")
|
if !exists("g:netrw_quiet")
|
||||||
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"your vim needs the +path_extra feature for Exploring with **!",44)
|
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"your vim needs the +path_extra feature for Exploring with **!",44)
|
||||||
endif
|
endif
|
||||||
if has("clipboard")
|
|
||||||
sil! let @* = keepregstar
|
|
||||||
sil! let @+ = keepregplus
|
|
||||||
endif
|
|
||||||
sil! let @/ = keepregslash
|
sil! let @/ = keepregslash
|
||||||
" call Dret("netrw#Explore : missing +path_extra")
|
" call Dret("netrw#Explore : missing +path_extra")
|
||||||
return
|
return
|
||||||
@ -1152,10 +1128,6 @@ fun! netrw#Explore(indx,dosplit,style,...)
|
|||||||
" there's no danger of a late FocusGained event on initialization.
|
" there's no danger of a late FocusGained event on initialization.
|
||||||
" Consequently, set s:netrw_events to 2.
|
" Consequently, set s:netrw_events to 2.
|
||||||
let s:netrw_events= 2
|
let s:netrw_events= 2
|
||||||
if has("clipboard")
|
|
||||||
sil! let @* = keepregstar
|
|
||||||
sil! let @+ = keepregplus
|
|
||||||
endif
|
|
||||||
sil! let @/ = keepregslash
|
sil! let @/ = keepregslash
|
||||||
" call Dret("netrw#Explore : @/<".@/.">")
|
" call Dret("netrw#Explore : @/<".@/.">")
|
||||||
endfun
|
endfun
|
||||||
@ -9559,10 +9531,6 @@ fun! s:NetrwWideListing()
|
|||||||
let newcolstart = w:netrw_bannercnt + fpc
|
let newcolstart = w:netrw_bannercnt + fpc
|
||||||
let newcolend = newcolstart + fpc - 1
|
let newcolend = newcolstart + fpc - 1
|
||||||
" call Decho("bannercnt=".w:netrw_bannercnt." fpl=".w:netrw_fpl." fpc=".fpc." newcol[".newcolstart.",".newcolend."]",'~'.expand("<slnum>"))
|
" call Decho("bannercnt=".w:netrw_bannercnt." fpl=".w:netrw_fpl." fpc=".fpc." newcol[".newcolstart.",".newcolend."]",'~'.expand("<slnum>"))
|
||||||
if has("clipboard")
|
|
||||||
sil! let keepregstar = @*
|
|
||||||
sil! let keepregplus = @+
|
|
||||||
endif
|
|
||||||
while line("$") >= newcolstart
|
while line("$") >= newcolstart
|
||||||
if newcolend > line("$") | let newcolend= line("$") | endif
|
if newcolend > line("$") | let newcolend= line("$") | endif
|
||||||
let newcolqty= newcolend - newcolstart
|
let newcolqty= newcolend - newcolstart
|
||||||
@ -9575,10 +9543,6 @@ fun! s:NetrwWideListing()
|
|||||||
exe "sil! NetrwKeepj ".newcolstart.','.newcolend.'d _'
|
exe "sil! NetrwKeepj ".newcolstart.','.newcolend.'d _'
|
||||||
exe 'sil! NetrwKeepj '.w:netrw_bannercnt
|
exe 'sil! NetrwKeepj '.w:netrw_bannercnt
|
||||||
endwhile
|
endwhile
|
||||||
if has("clipboard")
|
|
||||||
sil! let @*= keepregstar
|
|
||||||
sil! let @+= keepregplus
|
|
||||||
endif
|
|
||||||
exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$s/\s\+$//e'
|
exe "sil! NetrwKeepj ".w:netrw_bannercnt.',$s/\s\+$//e'
|
||||||
NetrwKeepj call histdel("/",-1)
|
NetrwKeepj call histdel("/",-1)
|
||||||
exe 'nno <buffer> <silent> w :call search(''^.\\|\s\s\zs\S'',''W'')'."\<cr>"
|
exe 'nno <buffer> <silent> w :call search(''^.\\|\s\s\zs\S'',''W'')'."\<cr>"
|
||||||
|
@ -10,7 +10,8 @@ function! provider#pythonx#Require(host) abort
|
|||||||
|
|
||||||
" Python host arguments
|
" Python host arguments
|
||||||
let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
|
let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
|
||||||
let args = [prog, '-c', 'import sys; sys.path.remove(""); import neovim; neovim.start_host()']
|
let args = [prog, '-c', 'import sys; sys.path = list(filter(lambda x: x != "", sys.path)); import neovim; neovim.start_host()']
|
||||||
|
|
||||||
|
|
||||||
" Collect registered Python plugins into args
|
" Collect registered Python plugins into args
|
||||||
let python_plugins = remote#host#PluginsForHost(a:host.name)
|
let python_plugins = remote#host#PluginsForHost(a:host.name)
|
||||||
@ -28,8 +29,8 @@ endfunction
|
|||||||
function! s:get_python_candidates(major_version) abort
|
function! s:get_python_candidates(major_version) abort
|
||||||
return {
|
return {
|
||||||
\ 2: ['python2', 'python2.7', 'python2.6', 'python'],
|
\ 2: ['python2', 'python2.7', 'python2.6', 'python'],
|
||||||
\ 3: ['python3', 'python3.7', 'python3.6', 'python3.5', 'python3.4', 'python3.3',
|
\ 3: ['python3', 'python3.8', 'python3.7', 'python3.6', 'python3.5',
|
||||||
\ 'python']
|
\ 'python3.4', 'python3.3', 'python']
|
||||||
\ }[a:major_version]
|
\ }[a:major_version]
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ function! provider#pythonx#DetectByModule(module, major_version) abort
|
|||||||
let python_exe = s:get_python_executable_from_host_var(a:major_version)
|
let python_exe = s:get_python_executable_from_host_var(a:major_version)
|
||||||
|
|
||||||
if !empty(python_exe)
|
if !empty(python_exe)
|
||||||
return [python_exe, '']
|
return [exepath(expand(python_exe)), '']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let candidates = s:get_python_candidates(a:major_version)
|
let candidates = s:get_python_candidates(a:major_version)
|
||||||
@ -66,7 +67,7 @@ endfunction
|
|||||||
function! s:import_module(prog, module) abort
|
function! s:import_module(prog, module) abort
|
||||||
let prog_version = system([a:prog, '-c' , printf(
|
let prog_version = system([a:prog, '-c' , printf(
|
||||||
\ 'import sys; ' .
|
\ 'import sys; ' .
|
||||||
\ 'sys.path.remove(""); ' .
|
\ 'sys.path = list(filter(lambda x: x != "", sys.path)); ' .
|
||||||
\ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' .
|
\ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' .
|
||||||
\ 'import pkgutil; ' .
|
\ 'import pkgutil; ' .
|
||||||
\ 'exit(2*int(pkgutil.get_loader("%s") is None))',
|
\ 'exit(2*int(pkgutil.get_loader("%s") is None))',
|
||||||
|
@ -13,6 +13,13 @@ let s:spellfile_URL = '' " Start with nothing so that s:donedict is reset.
|
|||||||
|
|
||||||
" This function is used for the spellfile plugin.
|
" This function is used for the spellfile plugin.
|
||||||
function! spellfile#LoadFile(lang)
|
function! spellfile#LoadFile(lang)
|
||||||
|
" Check for sandbox/modeline. #11359
|
||||||
|
try
|
||||||
|
:!
|
||||||
|
catch /\<E12\>/
|
||||||
|
throw 'Cannot download spellfile in sandbox/modeline. Try ":set spell" from the cmdline.'
|
||||||
|
endtry
|
||||||
|
|
||||||
" If the netrw plugin isn't loaded we silently skip everything.
|
" If the netrw plugin isn't loaded we silently skip everything.
|
||||||
if !exists(":Nread")
|
if !exists(":Nread")
|
||||||
if &verbose
|
if &verbose
|
||||||
|
@ -19,6 +19,7 @@ API Usage *api-rpc* *RPC* *rpc*
|
|||||||
*msgpack-rpc*
|
*msgpack-rpc*
|
||||||
RPC is the typical way to control Nvim programmatically. Nvim implements the
|
RPC is the typical way to control Nvim programmatically. Nvim implements the
|
||||||
MessagePack-RPC protocol:
|
MessagePack-RPC protocol:
|
||||||
|
https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md
|
||||||
https://github.com/msgpack/msgpack/blob/0b8f5ac/spec.md
|
https://github.com/msgpack/msgpack/blob/0b8f5ac/spec.md
|
||||||
|
|
||||||
Many clients use the API: user interfaces (GUIs), remote plugins, scripts like
|
Many clients use the API: user interfaces (GUIs), remote plugins, scripts like
|
||||||
@ -438,9 +439,69 @@ Example: create a float with scratch buffer: >
|
|||||||
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
|
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
|
||||||
>
|
>
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Extended marks *api-extended-marks*
|
||||||
|
|
||||||
|
Extended marks (extmarks) represent buffer annotations that track text changes
|
||||||
|
in the buffer. They could be used to represent cursors, folds, misspelled
|
||||||
|
words, and anything else that needs to track a logical location in the buffer
|
||||||
|
over time.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
We will set an extmark at the first row and third column. |api-indexing| is
|
||||||
|
zero-indexed, so we use row=0 and column=2. Passing id=0 creates a new mark
|
||||||
|
and returns the id: >
|
||||||
|
|
||||||
|
let g:mark_ns = nvim_create_namespace('myplugin')
|
||||||
|
let g:mark_id = nvim_buf_set_extmark(0, g:mark_ns, 0, 0, 2, {})
|
||||||
|
|
||||||
|
We can get a mark by its id: >
|
||||||
|
|
||||||
|
echo nvim_buf_get_extmark_by_id(0, g:mark_ns, g:mark_id)
|
||||||
|
=> [0, 2]
|
||||||
|
|
||||||
|
We can get all marks in a buffer for our namespace (or by a range): >
|
||||||
|
|
||||||
|
echo nvim_buf_get_extmarks(0, g:mark_ns, 0, -1, {})
|
||||||
|
=> [[1, 0, 2]]
|
||||||
|
|
||||||
|
Deleting all text surrounding an extmark does not remove the extmark. To
|
||||||
|
remove an extmark use |nvim_buf_del_extmark()|.
|
||||||
|
|
||||||
|
Namespaces allow your plugin to manage only its own extmarks, ignoring those
|
||||||
|
created by another plugin.
|
||||||
|
|
||||||
|
Extmark positions changed by an edit will be restored on undo/redo. Creating
|
||||||
|
and deleting extmarks is not a buffer change, thus new undo states are not
|
||||||
|
created for extmark changes.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
Global Functions *api-global*
|
Global Functions *api-global*
|
||||||
|
|
||||||
|
nvim_exec({src}, {output}) *nvim_exec()*
|
||||||
|
Executes Vimscript (multiline block of Ex-commands), like
|
||||||
|
anonymous |:source|.
|
||||||
|
|
||||||
|
Unlike |nvim_command()| this function supports heredocs,
|
||||||
|
script-scope (s:), etc.
|
||||||
|
|
||||||
|
On execution error: fails with VimL error, does not update
|
||||||
|
v:errmsg.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{src} Vimscript code
|
||||||
|
{output} Capture and return all (non-error, non-shell
|
||||||
|
|:!|) output
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
Output (non-error, non-shell |:!|) if `output` is true,
|
||||||
|
else empty string.
|
||||||
|
|
||||||
|
See also: ~
|
||||||
|
|execute()|
|
||||||
|
|nvim_command()|
|
||||||
|
|
||||||
nvim_command({command}) *nvim_command()*
|
nvim_command({command}) *nvim_command()*
|
||||||
Executes an ex-command.
|
Executes an ex-command.
|
||||||
|
|
||||||
@ -450,6 +511,9 @@ nvim_command({command}) *nvim_command()*
|
|||||||
Parameters: ~
|
Parameters: ~
|
||||||
{command} Ex-command string
|
{command} Ex-command string
|
||||||
|
|
||||||
|
See also: ~
|
||||||
|
|nvim_exec()|
|
||||||
|
|
||||||
nvim_get_hl_by_name({name}, {rgb}) *nvim_get_hl_by_name()*
|
nvim_get_hl_by_name({name}, {rgb}) *nvim_get_hl_by_name()*
|
||||||
Gets a highlight definition by name.
|
Gets a highlight definition by name.
|
||||||
|
|
||||||
@ -571,19 +635,9 @@ nvim_replace_termcodes({str}, {from_part}, {do_lt}, {special})
|
|||||||
replace_termcodes
|
replace_termcodes
|
||||||
cpoptions
|
cpoptions
|
||||||
|
|
||||||
nvim_command_output({command}) *nvim_command_output()*
|
|
||||||
Executes an ex-command and returns its (non-error) output.
|
|
||||||
Shell |:!| output is not captured.
|
|
||||||
|
|
||||||
On execution error: fails with VimL error, does not update
|
|
||||||
v:errmsg.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{command} Ex-command string
|
|
||||||
|
|
||||||
nvim_eval({expr}) *nvim_eval()*
|
nvim_eval({expr}) *nvim_eval()*
|
||||||
Evaluates a VimL expression (:help expression). Dictionaries
|
Evaluates a VimL |expression|. Dictionaries and Lists are
|
||||||
and Lists are recursively expanded.
|
recursively expanded.
|
||||||
|
|
||||||
On execution error: fails with VimL error, does not update
|
On execution error: fails with VimL error, does not update
|
||||||
v:errmsg.
|
v:errmsg.
|
||||||
@ -594,7 +648,7 @@ nvim_eval({expr}) *nvim_eval()*
|
|||||||
Return: ~
|
Return: ~
|
||||||
Evaluation result or expanded object
|
Evaluation result or expanded object
|
||||||
|
|
||||||
nvim_execute_lua({code}, {args}) *nvim_execute_lua()*
|
nvim_exec_lua({code}, {args}) *nvim_exec_lua()*
|
||||||
Execute Lua code. Parameters (if any) are available as `...`
|
Execute Lua code. Parameters (if any) are available as `...`
|
||||||
inside the chunk. The chunk can return a value.
|
inside the chunk. The chunk can return a value.
|
||||||
|
|
||||||
@ -850,10 +904,10 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
|
|||||||
{enter} Enter the window (make it the current window)
|
{enter} Enter the window (make it the current window)
|
||||||
{config} Map defining the window configuration. Keys:
|
{config} Map defining the window configuration. Keys:
|
||||||
• `relative` : Sets the window layout to "floating", placed
|
• `relative` : Sets the window layout to "floating", placed
|
||||||
at (row,col) coordinates relative to one of:
|
at (row,col) coordinates relative to:
|
||||||
• "editor" The global editor grid
|
• "editor" The global editor grid
|
||||||
• "win" Window given by the `win` field, or
|
• "win" Window given by the `win` field, or
|
||||||
current window by default.
|
current window.
|
||||||
• "cursor" Cursor position in current window.
|
• "cursor" Cursor position in current window.
|
||||||
|
|
||||||
• `win` : |window-ID| for relative="win".
|
• `win` : |window-ID| for relative="win".
|
||||||
@ -896,10 +950,11 @@ nvim_open_win({buffer}, {enter}, {config}) *nvim_open_win()*
|
|||||||
'number', 'relativenumber', 'cursorline',
|
'number', 'relativenumber', 'cursorline',
|
||||||
'cursorcolumn', 'foldcolumn', 'spell' and
|
'cursorcolumn', 'foldcolumn', 'spell' and
|
||||||
'list' options. 'signcolumn' is changed to
|
'list' options. 'signcolumn' is changed to
|
||||||
`auto` . The end-of-buffer region is hidden
|
`auto` and 'colorcolumn' is cleared. The
|
||||||
by setting `eob` flag of 'fillchars' to a
|
end-of-buffer region is hidden by setting
|
||||||
space char, and clearing the |EndOfBuffer|
|
`eob` flag of 'fillchars' to a space char,
|
||||||
region in 'winhighlight'.
|
and clearing the |EndOfBuffer| region in
|
||||||
|
'winhighlight'.
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
Window handle, or 0 on error
|
Window handle, or 0 on error
|
||||||
@ -984,7 +1039,7 @@ nvim_put({lines}, {type}, {after}, {follow}) *nvim_put()*
|
|||||||
{type} Edit behavior: any |getregtype()| result, or:
|
{type} Edit behavior: any |getregtype()| result, or:
|
||||||
• "b" |blockwise-visual| mode (may include
|
• "b" |blockwise-visual| mode (may include
|
||||||
width, e.g. "b3")
|
width, e.g. "b3")
|
||||||
• "c" |characterwise| mode
|
• "c" |charwise| mode
|
||||||
• "l" |linewise| mode
|
• "l" |linewise| mode
|
||||||
• "" guess by contents, see |setreg()|
|
• "" guess by contents, see |setreg()|
|
||||||
{after} Insert after cursor (like |p|), or before (like
|
{after} Insert after cursor (like |p|), or before (like
|
||||||
@ -1476,45 +1531,73 @@ nvim_buf_line_count({buffer}) *nvim_buf_line_count()*
|
|||||||
Line count, or 0 for unloaded buffer. |api-buffer|
|
Line count, or 0 for unloaded buffer. |api-buffer|
|
||||||
|
|
||||||
nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
|
nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
|
||||||
Activates buffer-update events on a channel, or as lua
|
Activates buffer-update events on a channel, or as Lua
|
||||||
callbacks.
|
callbacks.
|
||||||
|
|
||||||
|
Example (Lua): capture buffer updates in a global `events` variable (use "print(vim.inspect(events))" to see its
|
||||||
|
contents): >
|
||||||
|
events = {}
|
||||||
|
vim.api.nvim_buf_attach(0, false, {
|
||||||
|
on_lines=function(...) table.insert(events, {...}) end})
|
||||||
|
<
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{buffer} Buffer handle, or 0 for current buffer
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
{send_buffer} Set to true if the initial notification
|
{send_buffer} True if the initial notification should
|
||||||
should contain the whole buffer. If so, the
|
contain the whole buffer: first
|
||||||
first notification will be a
|
notification will be `nvim_buf_lines_event`
|
||||||
`nvim_buf_lines_event` . Otherwise, the
|
. Else the first notification will be
|
||||||
first notification will be a
|
`nvim_buf_changedtick_event` . Not for Lua
|
||||||
`nvim_buf_changedtick_event` . Not used for
|
callbacks.
|
||||||
lua callbacks.
|
|
||||||
{opts} Optional parameters.
|
{opts} Optional parameters.
|
||||||
• `on_lines` : lua callback received on
|
• on_lines: Lua callback invoked on change.
|
||||||
change.
|
Return `true` to detach. Args:
|
||||||
• `on_changedtick` : lua callback received
|
• buffer handle
|
||||||
on changedtick increment without text
|
• b:changedtick
|
||||||
change.
|
• first line that changed (zero-indexed)
|
||||||
• `utf_sizes` : include UTF-32 and UTF-16
|
• last line that was changed
|
||||||
size of the replaced region. See
|
• last line in the updated range
|
||||||
|api-buffer-updates-lua| for more
|
• byte count of previous contents
|
||||||
information
|
• deleted_codepoints (if `utf_sizes` is
|
||||||
|
true)
|
||||||
|
• deleted_codeunits (if `utf_sizes` is
|
||||||
|
true)
|
||||||
|
|
||||||
|
• on_changedtick: Lua callback invoked on
|
||||||
|
changedtick increment without text
|
||||||
|
change. Args:
|
||||||
|
• buffer handle
|
||||||
|
• b:changedtick
|
||||||
|
|
||||||
|
• on_detach: Lua callback invoked on
|
||||||
|
detach. Args:
|
||||||
|
• buffer handle
|
||||||
|
|
||||||
|
• utf_sizes: include UTF-32 and UTF-16 size
|
||||||
|
of the replaced region, as args to
|
||||||
|
`on_lines` .
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
False when updates couldn't be enabled because the buffer
|
False if attach failed (invalid parameter, or buffer isn't
|
||||||
isn't loaded or `opts` contained an invalid key; otherwise
|
loaded); otherwise True. TODO: LUA_API_NO_EVAL
|
||||||
True. TODO: LUA_API_NO_EVAL
|
|
||||||
|
See also: ~
|
||||||
|
|nvim_buf_detach()|
|
||||||
|
|api-buffer-updates-lua|
|
||||||
|
|
||||||
nvim_buf_detach({buffer}) *nvim_buf_detach()*
|
nvim_buf_detach({buffer}) *nvim_buf_detach()*
|
||||||
Deactivates buffer-update events on the channel.
|
Deactivates buffer-update events on the channel.
|
||||||
|
|
||||||
For Lua callbacks see |api-lua-detach|.
|
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{buffer} Buffer handle, or 0 for current buffer
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
False when updates couldn't be disabled because the buffer
|
False if detach failed (because the buffer isn't loaded);
|
||||||
isn't loaded; otherwise True.
|
otherwise True.
|
||||||
|
|
||||||
|
See also: ~
|
||||||
|
|nvim_buf_attach()|
|
||||||
|
|api-lua-detach| for detaching Lua callbacks
|
||||||
|
|
||||||
*nvim_buf_get_lines()*
|
*nvim_buf_get_lines()*
|
||||||
nvim_buf_get_lines({buffer}, {start}, {end}, {strict_indexing})
|
nvim_buf_get_lines({buffer}, {start}, {end}, {strict_indexing})
|
||||||
@ -1726,6 +1809,99 @@ nvim_buf_get_mark({buffer}, {name}) *nvim_buf_get_mark()*
|
|||||||
Return: ~
|
Return: ~
|
||||||
(row, col) tuple
|
(row, col) tuple
|
||||||
|
|
||||||
|
*nvim_buf_get_extmark_by_id()*
|
||||||
|
nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id})
|
||||||
|
Returns position for a given extmark id
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
|
{ns_id} Namespace id from |nvim_create_namespace()|
|
||||||
|
{id} Extmark id
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
(row, col) tuple or empty list () if extmark id was absent
|
||||||
|
|
||||||
|
*nvim_buf_get_extmarks()*
|
||||||
|
nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
|
||||||
|
Gets extmarks in "traversal order" from a |charwise| region
|
||||||
|
defined by buffer positions (inclusive, 0-indexed
|
||||||
|
|api-indexing|).
|
||||||
|
|
||||||
|
Region can be given as (row,col) tuples, or valid extmark ids
|
||||||
|
(whose positions define the bounds). 0 and -1 are understood
|
||||||
|
as (0,0) and (-1,-1) respectively, thus the following are
|
||||||
|
equivalent:
|
||||||
|
>
|
||||||
|
nvim_buf_get_extmarks(0, my_ns, 0, -1, {})
|
||||||
|
nvim_buf_get_extmarks(0, my_ns, [0,0], [-1,-1], {})
|
||||||
|
<
|
||||||
|
|
||||||
|
If `end` is less than `start` , traversal works backwards.
|
||||||
|
(Useful with `limit` , to get the first marks prior to a given
|
||||||
|
position.)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
>
|
||||||
|
local a = vim.api
|
||||||
|
local pos = a.nvim_win_get_cursor(0)
|
||||||
|
local ns = a.nvim_create_namespace('my-plugin')
|
||||||
|
-- Create new extmark at line 1, column 1.
|
||||||
|
local m1 = a.nvim_buf_set_extmark(0, ns, 0, 0, 0, {})
|
||||||
|
-- Create new extmark at line 3, column 1.
|
||||||
|
local m2 = a.nvim_buf_set_extmark(0, ns, 0, 2, 0, {})
|
||||||
|
-- Get extmarks only from line 3.
|
||||||
|
local ms = a.nvim_buf_get_extmarks(0, ns, {2,0}, {2,0}, {})
|
||||||
|
-- Get all marks in this buffer + namespace.
|
||||||
|
local all = a.nvim_buf_get_extmarks(0, ns, 0, -1, {})
|
||||||
|
print(vim.inspect(ms))
|
||||||
|
<
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
|
{ns_id} Namespace id from |nvim_create_namespace()|
|
||||||
|
{start} Start of range, given as (row, col) or valid
|
||||||
|
extmark id (whose position defines the bound)
|
||||||
|
{end} End of range, given as (row, col) or valid
|
||||||
|
extmark id (whose position defines the bound)
|
||||||
|
{opts} Optional parameters. Keys:
|
||||||
|
• limit: Maximum number of marks to return
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
List of [extmark_id, row, col] tuples in "traversal
|
||||||
|
order".
|
||||||
|
|
||||||
|
*nvim_buf_set_extmark()*
|
||||||
|
nvim_buf_set_extmark({buffer}, {ns_id}, {id}, {line}, {col}, {opts})
|
||||||
|
Creates or updates an extmark.
|
||||||
|
|
||||||
|
To create a new extmark, pass id=0. The extmark id will be
|
||||||
|
returned. It is also allowed to create a new mark by passing
|
||||||
|
in a previously unused id, but the caller must then keep track
|
||||||
|
of existing and unused ids itself. (Useful over RPC, to avoid
|
||||||
|
waiting for the return value.)
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
|
{ns_id} Namespace id from |nvim_create_namespace()|
|
||||||
|
{id} Extmark id, or 0 to create new
|
||||||
|
{line} Line number where to place the mark
|
||||||
|
{col} Column where to place the mark
|
||||||
|
{opts} Optional parameters. Currently not used.
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
Id of the created/updated extmark
|
||||||
|
|
||||||
|
nvim_buf_del_extmark({buffer}, {ns_id}, {id}) *nvim_buf_del_extmark()*
|
||||||
|
Removes an extmark.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
|
{ns_id} Namespace id from |nvim_create_namespace()|
|
||||||
|
{id} Extmark id
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
true if the extmark was found, else false
|
||||||
|
|
||||||
*nvim_buf_add_highlight()*
|
*nvim_buf_add_highlight()*
|
||||||
nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line},
|
nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line},
|
||||||
{col_start}, {col_end})
|
{col_start}, {col_end})
|
||||||
@ -1769,8 +1945,8 @@ nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line},
|
|||||||
|
|
||||||
*nvim_buf_clear_namespace()*
|
*nvim_buf_clear_namespace()*
|
||||||
nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end})
|
nvim_buf_clear_namespace({buffer}, {ns_id}, {line_start}, {line_end})
|
||||||
Clears namespaced objects, highlights and virtual text, from a
|
Clears namespaced objects (highlights, extmarks, virtual text)
|
||||||
line range
|
from a region.
|
||||||
|
|
||||||
Lines are 0-indexed. |api-indexing| To clear the namespace in
|
Lines are 0-indexed. |api-indexing| To clear the namespace in
|
||||||
the entire buffer, specify line_start=0 and line_end=-1.
|
the entire buffer, specify line_start=0 and line_end=-1.
|
||||||
@ -1821,6 +1997,27 @@ nvim_buf_set_virtual_text({buffer}, {ns_id}, {line}, {chunks}, {opts})
|
|||||||
Return: ~
|
Return: ~
|
||||||
The ns_id that was used
|
The ns_id that was used
|
||||||
|
|
||||||
|
nvim_buf_get_virtual_text({buffer}, {lnum}) *nvim_buf_get_virtual_text()*
|
||||||
|
Get the virtual text (annotation) for a buffer line.
|
||||||
|
|
||||||
|
The virtual text is returned as list of lists, whereas the
|
||||||
|
inner lists have either one or two elements. The first element
|
||||||
|
is the actual text, the optional second element is the
|
||||||
|
highlight group.
|
||||||
|
|
||||||
|
The format is exactly the same as given to
|
||||||
|
nvim_buf_set_virtual_text().
|
||||||
|
|
||||||
|
If there is no virtual text associated with the given line, an
|
||||||
|
empty list is returned.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{buffer} Buffer handle, or 0 for current buffer
|
||||||
|
{line} Line to get the virtual text from (zero-indexed)
|
||||||
|
|
||||||
|
Return: ~
|
||||||
|
List of virtual text chunks
|
||||||
|
|
||||||
nvim__buf_stats({buffer}) *nvim__buf_stats()*
|
nvim__buf_stats({buffer}) *nvim__buf_stats()*
|
||||||
TODO: Documentation
|
TODO: Documentation
|
||||||
|
|
||||||
|
@ -559,16 +559,14 @@ CmdlineLeave Before leaving the command-line (including
|
|||||||
*CmdwinEnter*
|
*CmdwinEnter*
|
||||||
CmdwinEnter After entering the command-line window.
|
CmdwinEnter After entering the command-line window.
|
||||||
Useful for setting options specifically for
|
Useful for setting options specifically for
|
||||||
this special type of window. This is
|
this special type of window.
|
||||||
triggered _instead_ of BufEnter and WinEnter.
|
|
||||||
<afile> is set to a single character,
|
<afile> is set to a single character,
|
||||||
indicating the type of command-line.
|
indicating the type of command-line.
|
||||||
|cmdwin-char|
|
|cmdwin-char|
|
||||||
*CmdwinLeave*
|
*CmdwinLeave*
|
||||||
CmdwinLeave Before leaving the command-line window.
|
CmdwinLeave Before leaving the command-line window.
|
||||||
Useful to clean up any global setting done
|
Useful to clean up any global setting done
|
||||||
with CmdwinEnter. This is triggered _instead_
|
with CmdwinEnter.
|
||||||
of BufLeave and WinLeave.
|
|
||||||
<afile> is set to a single character,
|
<afile> is set to a single character,
|
||||||
indicating the type of command-line.
|
indicating the type of command-line.
|
||||||
|cmdwin-char|
|
|cmdwin-char|
|
||||||
|
@ -90,7 +90,7 @@ start and end of the motion are not in the same line, and there are only
|
|||||||
blanks before the start and there are no non-blanks after the end of the
|
blanks before the start and there are no non-blanks after the end of the
|
||||||
motion, the delete becomes linewise. This means that the delete also removes
|
motion, the delete becomes linewise. This means that the delete also removes
|
||||||
the line of blanks that you might expect to remain. Use the |o_v| operator to
|
the line of blanks that you might expect to remain. Use the |o_v| operator to
|
||||||
force the motion to be characterwise.
|
force the motion to be charwise.
|
||||||
|
|
||||||
Trying to delete an empty region of text (e.g., "d0" in the first column)
|
Trying to delete an empty region of text (e.g., "d0" in the first column)
|
||||||
is an error when 'cpoptions' includes the 'E' flag.
|
is an error when 'cpoptions' includes the 'E' flag.
|
||||||
@ -1074,7 +1074,7 @@ also use these commands to move text from one file to another, because Vim
|
|||||||
preserves all registers when changing buffers (the CTRL-^ command is a quick
|
preserves all registers when changing buffers (the CTRL-^ command is a quick
|
||||||
way to toggle between two files).
|
way to toggle between two files).
|
||||||
|
|
||||||
*linewise-register* *characterwise-register*
|
*linewise-register* *charwise-register*
|
||||||
You can repeat the put commands with "." (except for :put) and undo them. If
|
You can repeat the put commands with "." (except for :put) and undo them. If
|
||||||
the command that was used to get the text into the register was |linewise|,
|
the command that was used to get the text into the register was |linewise|,
|
||||||
Vim inserts the text below ("p") or above ("P") the line where the cursor is.
|
Vim inserts the text below ("p") or above ("P") the line where the cursor is.
|
||||||
@ -1116,10 +1116,9 @@ this happen. However, if the width of the block is not a multiple of a <Tab>
|
|||||||
width and the text after the inserted block contains <Tab>s, that text may be
|
width and the text after the inserted block contains <Tab>s, that text may be
|
||||||
misaligned.
|
misaligned.
|
||||||
|
|
||||||
Note that after a characterwise yank command, Vim leaves the cursor on the
|
Note that after a charwise yank command, Vim leaves the cursor on the first
|
||||||
first yanked character that is closest to the start of the buffer. This means
|
yanked character that is closest to the start of the buffer. This means that
|
||||||
that "yl" doesn't move the cursor, but "yh" moves the cursor one character
|
"yl" doesn't move the cursor, but "yh" moves the cursor one character left.
|
||||||
left.
|
|
||||||
Rationale: In Vi the "y" command followed by a backwards motion would
|
Rationale: In Vi the "y" command followed by a backwards motion would
|
||||||
sometimes not move the cursor to the first yanked character,
|
sometimes not move the cursor to the first yanked character,
|
||||||
because redisplaying was skipped. In Vim it always moves to
|
because redisplaying was skipped. In Vim it always moves to
|
||||||
|
@ -1122,11 +1122,9 @@ edited as described in |cmdwin-char|.
|
|||||||
|
|
||||||
AUTOCOMMANDS
|
AUTOCOMMANDS
|
||||||
|
|
||||||
Two autocommand events are used: |CmdwinEnter| and |CmdwinLeave|. Since this
|
Two autocommand events are used: |CmdwinEnter| and |CmdwinLeave|. You can use
|
||||||
window is of a special type, the WinEnter, WinLeave, BufEnter and BufLeave
|
the Cmdwin events to do settings specifically for the command-line window.
|
||||||
events are not triggered. You can use the Cmdwin events to do settings
|
Be careful not to cause side effects!
|
||||||
specifically for the command-line window. Be careful not to cause side
|
|
||||||
effects!
|
|
||||||
Example: >
|
Example: >
|
||||||
:au CmdwinEnter : let b:cpt_save = &cpt | set cpt=.
|
:au CmdwinEnter : let b:cpt_save = &cpt | set cpt=.
|
||||||
:au CmdwinLeave : let &cpt = b:cpt_save
|
:au CmdwinLeave : let &cpt = b:cpt_save
|
||||||
|
@ -14,6 +14,8 @@ updated.
|
|||||||
|
|
||||||
API ~
|
API ~
|
||||||
*nvim_buf_clear_highlight()* Use |nvim_buf_clear_namespace()| instead.
|
*nvim_buf_clear_highlight()* Use |nvim_buf_clear_namespace()| instead.
|
||||||
|
*nvim_command_output()* Use |nvim_exec()| instead.
|
||||||
|
*nvim_execute_lua()* Use |nvim_exec_lua()| instead.
|
||||||
|
|
||||||
Commands ~
|
Commands ~
|
||||||
*:rv*
|
*:rv*
|
||||||
|
@ -143,6 +143,87 @@ DOCUMENTATION *dev-doc*
|
|||||||
/// @param dirname The path fragment before `pend`
|
/// @param dirname The path fragment before `pend`
|
||||||
<
|
<
|
||||||
|
|
||||||
|
C docstrings ~
|
||||||
|
|
||||||
|
Nvim API documentation lives in the source code, as docstrings (Doxygen
|
||||||
|
comments) on the function definitions. The |api| :help is generated
|
||||||
|
from the docstrings defined in src/nvim/api/*.c.
|
||||||
|
|
||||||
|
Docstring format:
|
||||||
|
- Lines start with `///`
|
||||||
|
- Special tokens start with `@` followed by the token name:
|
||||||
|
`@note`, `@param`, `@returns`
|
||||||
|
- Limited markdown is supported.
|
||||||
|
- List-items start with `-` (useful to nest or "indent")
|
||||||
|
- Use `<pre>` for code samples.
|
||||||
|
|
||||||
|
Example: the help for |nvim_open_win()| is generated from a docstring defined
|
||||||
|
in src/nvim/api/vim.c like this: >
|
||||||
|
|
||||||
|
/// Opens a new window.
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// Example (Lua): window-relative float
|
||||||
|
/// <pre>
|
||||||
|
/// vim.api.nvim_open_win(0, false,
|
||||||
|
/// {relative='win', row=3, col=3, width=12, height=3})
|
||||||
|
/// </pre>
|
||||||
|
///
|
||||||
|
/// @param buffer Buffer to display
|
||||||
|
/// @param enter Enter the window
|
||||||
|
/// @param config Map defining the window configuration. Keys:
|
||||||
|
/// - relative: Sets the window layout, relative to:
|
||||||
|
/// - "editor" The global editor grid.
|
||||||
|
/// - "win" Window given by the `win` field.
|
||||||
|
/// - "cursor" Cursor position in current window.
|
||||||
|
/// ...
|
||||||
|
/// @param[out] err Error details, if any
|
||||||
|
///
|
||||||
|
/// @return Window handle, or 0 on error
|
||||||
|
|
||||||
|
|
||||||
|
Lua docstrings ~
|
||||||
|
*dev-lua-doc*
|
||||||
|
Lua documentation lives in the source code, as docstrings on the function
|
||||||
|
definitions. The |lua-vim| :help is generated from the docstrings.
|
||||||
|
|
||||||
|
Docstring format:
|
||||||
|
- Lines in the main description start with `---`
|
||||||
|
- Special tokens start with `--@` followed by the token name:
|
||||||
|
`--@see`, `--@param`, `--@returns`
|
||||||
|
- Limited markdown is supported.
|
||||||
|
- List-items start with `-` (useful to nest or "indent")
|
||||||
|
- Use `<pre>` for code samples.
|
||||||
|
|
||||||
|
Example: the help for |vim.paste()| is generated from a docstring decorating
|
||||||
|
vim.paste in src/nvim/lua/vim.lua like this: >
|
||||||
|
|
||||||
|
--- Paste handler, invoked by |nvim_paste()| when a conforming UI
|
||||||
|
--- (such as the |TUI|) pastes text into the editor.
|
||||||
|
---
|
||||||
|
--- Example: To remove ANSI color codes when pasting:
|
||||||
|
--- <pre>
|
||||||
|
--- vim.paste = (function()
|
||||||
|
--- local overridden = vim.paste
|
||||||
|
--- ...
|
||||||
|
--- end)()
|
||||||
|
--- </pre>
|
||||||
|
---
|
||||||
|
--@see |paste|
|
||||||
|
---
|
||||||
|
--@param lines ...
|
||||||
|
--@param phase ...
|
||||||
|
--@returns false if client should cancel the paste.
|
||||||
|
|
||||||
|
|
||||||
|
LUA *dev-lua*
|
||||||
|
|
||||||
|
- Keep the core Lua modules |lua-stdlib| simple. Avoid elaborate OOP or
|
||||||
|
pseudo-OOP designs. Plugin authors just want functions to call, they don't
|
||||||
|
want to learn a big, fancy inheritance hierarchy. So we should avoid complex
|
||||||
|
objects: tables are usually better.
|
||||||
|
|
||||||
|
|
||||||
API *dev-api*
|
API *dev-api*
|
||||||
|
|
||||||
Use this template to name new API functions:
|
Use this template to name new API functions:
|
||||||
@ -155,10 +236,11 @@ with a {thing} that groups functions under a common concept).
|
|||||||
|
|
||||||
Use existing common {action} names if possible:
|
Use existing common {action} names if possible:
|
||||||
add Append to, or insert into, a collection
|
add Append to, or insert into, a collection
|
||||||
get Get a thing (or group of things by query)
|
|
||||||
set Set a thing (or group of things)
|
|
||||||
del Delete a thing (or group of things)
|
del Delete a thing (or group of things)
|
||||||
|
exec Execute code
|
||||||
|
get Get a thing (or group of things by query)
|
||||||
list Get all things
|
list Get all things
|
||||||
|
set Set a thing (or group of things)
|
||||||
|
|
||||||
Use consistent names for {thing} in all API functions. E.g. a buffer is called
|
Use consistent names for {thing} in all API functions. E.g. a buffer is called
|
||||||
"buf" everywhere, not "buffer" in some places and "buf" in others.
|
"buf" everywhere, not "buffer" in some places and "buf" in others.
|
||||||
@ -268,8 +350,8 @@ External UIs are expected to implement these common features:
|
|||||||
chords (<C-,> <C-Enter> <C-S-x> <D-x>) and patterns ("shift shift") that do
|
chords (<C-,> <C-Enter> <C-S-x> <D-x>) and patterns ("shift shift") that do
|
||||||
not potentially conflict with Nvim defaults, plugins, etc.
|
not potentially conflict with Nvim defaults, plugins, etc.
|
||||||
- Consider the "option_set" |ui-global| event as a hint for other GUI
|
- Consider the "option_set" |ui-global| event as a hint for other GUI
|
||||||
behaviors. UI-related options ('guifont', 'ambiwidth', …) are published in
|
behaviors. Various UI-related options ('guifont', 'ambiwidth', …) are
|
||||||
this event.
|
published in this event. See also "mouse_on", "mouse_off".
|
||||||
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
@ -20,7 +20,9 @@ An alternative is using the 'keymap' option.
|
|||||||
1. Defining digraphs *digraphs-define*
|
1. Defining digraphs *digraphs-define*
|
||||||
|
|
||||||
*:dig* *:digraphs*
|
*:dig* *:digraphs*
|
||||||
:dig[raphs] show currently defined digraphs.
|
:dig[raphs][!] Show currently defined digraphs.
|
||||||
|
With [!] headers are used to make it a bit easier to
|
||||||
|
find a specific character.
|
||||||
*E104* *E39*
|
*E104* *E39*
|
||||||
:dig[raphs] {char1}{char2} {number} ...
|
:dig[raphs] {char1}{char2} {number} ...
|
||||||
Add digraph {char1}{char2} to the list. {number} is
|
Add digraph {char1}{char2} to the list. {number} is
|
||||||
|
@ -1217,7 +1217,7 @@ lambda expression *expr-lambda* *lambda*
|
|||||||
{args -> expr1} lambda expression
|
{args -> expr1} lambda expression
|
||||||
|
|
||||||
A lambda expression creates a new unnamed function which returns the result of
|
A lambda expression creates a new unnamed function which returns the result of
|
||||||
evaluating |expr1|. Lambda expressions differ from |user-functions| in
|
evaluating |expr1|. Lambda expressions differ from |user-function|s in
|
||||||
the following ways:
|
the following ways:
|
||||||
|
|
||||||
1. The body of the lambda expression is an |expr1| and not a sequence of |Ex|
|
1. The body of the lambda expression is an |expr1| and not a sequence of |Ex|
|
||||||
@ -1547,10 +1547,12 @@ v:errmsg Last given error message.
|
|||||||
:if v:errmsg != ""
|
:if v:errmsg != ""
|
||||||
: ... handle error
|
: ... handle error
|
||||||
<
|
<
|
||||||
*v:errors* *errors-variable*
|
*v:errors* *errors-variable* *assert-return*
|
||||||
v:errors Errors found by assert functions, such as |assert_true()|.
|
v:errors Errors found by assert functions, such as |assert_true()|.
|
||||||
This is a list of strings.
|
This is a list of strings.
|
||||||
The assert functions append an item when an assert fails.
|
The assert functions append an item when an assert fails.
|
||||||
|
The return value indicates this: a one is returned if an item
|
||||||
|
was added to v:errors, otherwise zero is returned.
|
||||||
To remove old results make it empty: >
|
To remove old results make it empty: >
|
||||||
:let v:errors = []
|
:let v:errors = []
|
||||||
< If v:errors is set to anything but a list it is made an empty
|
< If v:errors is set to anything but a list it is made an empty
|
||||||
@ -1735,6 +1737,10 @@ v:lnum Line number for the 'foldexpr' |fold-expr|, 'formatexpr' and
|
|||||||
expressions is being evaluated. Read-only when in the
|
expressions is being evaluated. Read-only when in the
|
||||||
|sandbox|.
|
|sandbox|.
|
||||||
|
|
||||||
|
*v:lua* *lua-variable*
|
||||||
|
v:lua Prefix for calling Lua functions from expressions.
|
||||||
|
See |v:lua-call| for more information.
|
||||||
|
|
||||||
*v:mouse_win* *mouse_win-variable*
|
*v:mouse_win* *mouse_win-variable*
|
||||||
v:mouse_win Window number for a mouse click obtained with |getchar()|.
|
v:mouse_win Window number for a mouse click obtained with |getchar()|.
|
||||||
First window has number 1, like with |winnr()|. The value is
|
First window has number 1, like with |winnr()|. The value is
|
||||||
@ -1984,9 +1990,12 @@ v:windowid Application-specific window "handle" which may be set by any
|
|||||||
|window-ID|.
|
|window-ID|.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
4. Builtin Functions *functions*
|
4. Builtin Functions *vim-function* *functions*
|
||||||
|
|
||||||
See |function-list| for a list grouped by what the function is used for.
|
The Vimscript subsystem (referred to as "eval" internally) provides the
|
||||||
|
following builtin functions. Scripts can also define |user-function|s.
|
||||||
|
|
||||||
|
See |function-list| to browse functions by topic.
|
||||||
|
|
||||||
(Use CTRL-] on the function name to jump to the full explanation.)
|
(Use CTRL-] on the function name to jump to the full explanation.)
|
||||||
|
|
||||||
@ -2004,24 +2013,26 @@ argidx() Number current index in the argument list
|
|||||||
arglistid([{winnr} [, {tabnr}]]) Number argument list id
|
arglistid([{winnr} [, {tabnr}]]) Number argument list id
|
||||||
argv({nr} [, {winid}]) String {nr} entry of the argument list
|
argv({nr} [, {winid}]) String {nr} entry of the argument list
|
||||||
argv([-1, {winid}]) List the argument list
|
argv([-1, {winid}]) List the argument list
|
||||||
assert_beeps({cmd}) none assert {cmd} causes a beep
|
assert_beeps({cmd}) Number assert {cmd} causes a beep
|
||||||
assert_equal({exp}, {act} [, {msg}])
|
assert_equal({exp}, {act} [, {msg}])
|
||||||
none assert {exp} is equal to {act}
|
Number assert {exp} is equal to {act}
|
||||||
|
assert_equalfile({fname-one}, {fname-two})
|
||||||
|
Number assert file contents is equal
|
||||||
assert_exception({error} [, {msg}])
|
assert_exception({error} [, {msg}])
|
||||||
none assert {error} is in v:exception
|
Number assert {error} is in v:exception
|
||||||
assert_fails({cmd} [, {error}]) none assert {cmd} fails
|
assert_fails({cmd} [, {error}]) Number assert {cmd} fails
|
||||||
assert_false({actual} [, {msg}])
|
assert_false({actual} [, {msg}])
|
||||||
none assert {actual} is false
|
Number assert {actual} is false
|
||||||
assert_inrange({lower}, {upper}, {actual} [, {msg}])
|
assert_inrange({lower}, {upper}, {actual} [, {msg}])
|
||||||
none assert {actual} is inside the range
|
Number assert {actual} is inside the range
|
||||||
assert_match({pat}, {text} [, {msg}])
|
assert_match({pat}, {text} [, {msg}])
|
||||||
none assert {pat} matches {text}
|
Number assert {pat} matches {text}
|
||||||
assert_notequal({exp}, {act} [, {msg}])
|
assert_notequal({exp}, {act} [, {msg}])
|
||||||
none assert {exp} is not equal {act}
|
Number assert {exp} is not equal {act}
|
||||||
assert_notmatch({pat}, {text} [, {msg}])
|
assert_notmatch({pat}, {text} [, {msg}])
|
||||||
none assert {pat} not matches {text}
|
Number assert {pat} not matches {text}
|
||||||
assert_report({msg}) none report a test failure
|
assert_report({msg}) Number report a test failure
|
||||||
assert_true({actual} [, {msg}]) none assert {actual} is true
|
assert_true({actual} [, {msg}]) Number assert {actual} is true
|
||||||
asin({expr}) Float arc sine of {expr}
|
asin({expr}) Float arc sine of {expr}
|
||||||
atan({expr}) Float arc tangent of {expr}
|
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}
|
||||||
@ -2580,12 +2591,13 @@ argv([{nr} [, {winid}])
|
|||||||
assert_beeps({cmd}) *assert_beeps()*
|
assert_beeps({cmd}) *assert_beeps()*
|
||||||
Run {cmd} and add an error message to |v:errors| if it does
|
Run {cmd} and add an error message to |v:errors| if it does
|
||||||
NOT produce a beep or visual bell.
|
NOT produce a beep or visual bell.
|
||||||
Also see |assert_fails()|.
|
Also see |assert_fails()| and |assert-return|.
|
||||||
|
|
||||||
*assert_equal()*
|
*assert_equal()*
|
||||||
assert_equal({expected}, {actual}, [, {msg}])
|
assert_equal({expected}, {actual}, [, {msg}])
|
||||||
When {expected} and {actual} are not equal an error message is
|
When {expected} and {actual} are not equal an error message is
|
||||||
added to |v:errors|.
|
added to |v:errors| and 1 is returned. Otherwise zero is
|
||||||
|
returned |assert-return|.
|
||||||
There is no automatic conversion, the String "4" is different
|
There is no automatic conversion, the String "4" is different
|
||||||
from the Number 4. And the number 4 is different from the
|
from the Number 4. And the number 4 is different from the
|
||||||
Float 4.0. The value of 'ignorecase' is not used here, case
|
Float 4.0. The value of 'ignorecase' is not used here, case
|
||||||
@ -2597,9 +2609,17 @@ assert_equal({expected}, {actual}, [, {msg}])
|
|||||||
< Will result in a string to be added to |v:errors|:
|
< Will result in a string to be added to |v:errors|:
|
||||||
test.vim line 12: Expected 'foo' but got 'bar' ~
|
test.vim line 12: Expected 'foo' but got 'bar' ~
|
||||||
|
|
||||||
|
*assert_equalfile()*
|
||||||
|
assert_equalfile({fname-one}, {fname-two})
|
||||||
|
When the files {fname-one} and {fname-two} do not contain
|
||||||
|
exactly the same text an error message is added to |v:errors|.
|
||||||
|
Also see |assert-return|.
|
||||||
|
When {fname-one} or {fname-two} does not exist the error will
|
||||||
|
mention that.
|
||||||
|
|
||||||
assert_exception({error} [, {msg}]) *assert_exception()*
|
assert_exception({error} [, {msg}]) *assert_exception()*
|
||||||
When v:exception does not contain the string {error} an error
|
When v:exception does not contain the string {error} an error
|
||||||
message is added to |v:errors|.
|
message is added to |v:errors|. Also see |assert-return|.
|
||||||
This can be used to assert that a command throws an exception.
|
This can be used to assert that a command throws an exception.
|
||||||
Using the error number, followed by a colon, avoids problems
|
Using the error number, followed by a colon, avoids problems
|
||||||
with translations: >
|
with translations: >
|
||||||
@ -2612,7 +2632,7 @@ assert_exception({error} [, {msg}]) *assert_exception()*
|
|||||||
|
|
||||||
assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
|
assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
|
||||||
Run {cmd} and add an error message to |v:errors| if it does
|
Run {cmd} and add an error message to |v:errors| if it does
|
||||||
NOT produce an error.
|
NOT produce an error. Also see |assert-return|.
|
||||||
When {error} is given it must match in |v:errmsg|.
|
When {error} is given it must match in |v:errmsg|.
|
||||||
Note that beeping is not considered an error, and some failing
|
Note that beeping is not considered an error, and some failing
|
||||||
commands only beep. Use |assert_beeps()| for those.
|
commands only beep. Use |assert_beeps()| for those.
|
||||||
@ -2620,6 +2640,7 @@ assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
|
|||||||
assert_false({actual} [, {msg}]) *assert_false()*
|
assert_false({actual} [, {msg}]) *assert_false()*
|
||||||
When {actual} is not false an error message is added to
|
When {actual} is not false an error message is added to
|
||||||
|v:errors|, like with |assert_equal()|.
|
|v:errors|, like with |assert_equal()|.
|
||||||
|
Also see |assert-return|.
|
||||||
A value is false when it is zero or |v:false|. When "{actual}"
|
A value is false when it is zero or |v:false|. When "{actual}"
|
||||||
is not a number or |v:false| the assert fails.
|
is not a number or |v:false| the assert fails.
|
||||||
When {msg} is omitted an error in the form
|
When {msg} is omitted an error in the form
|
||||||
@ -2636,7 +2657,7 @@ assert_inrange({lower}, {upper}, {actual} [, {msg}]) *assert_inrange()*
|
|||||||
*assert_match()*
|
*assert_match()*
|
||||||
assert_match({pattern}, {actual} [, {msg}])
|
assert_match({pattern}, {actual} [, {msg}])
|
||||||
When {pattern} does not match {actual} an error message is
|
When {pattern} does not match {actual} an error message is
|
||||||
added to |v:errors|.
|
added to |v:errors|. Also see |assert-return|.
|
||||||
|
|
||||||
{pattern} is used as with |=~|: The matching is always done
|
{pattern} is used as with |=~|: The matching is always done
|
||||||
like 'magic' was set and 'cpoptions' is empty, no matter what
|
like 'magic' was set and 'cpoptions' is empty, no matter what
|
||||||
@ -2657,18 +2678,22 @@ assert_match({pattern}, {actual} [, {msg}])
|
|||||||
assert_notequal({expected}, {actual} [, {msg}])
|
assert_notequal({expected}, {actual} [, {msg}])
|
||||||
The opposite of `assert_equal()`: add an error message to
|
The opposite of `assert_equal()`: add an error message to
|
||||||
|v:errors| when {expected} and {actual} are equal.
|
|v:errors| when {expected} and {actual} are equal.
|
||||||
|
Also see |assert-return|.
|
||||||
|
|
||||||
*assert_notmatch()*
|
*assert_notmatch()*
|
||||||
assert_notmatch({pattern}, {actual} [, {msg}])
|
assert_notmatch({pattern}, {actual} [, {msg}])
|
||||||
The opposite of `assert_match()`: add an error message to
|
The opposite of `assert_match()`: add an error message to
|
||||||
|v:errors| when {pattern} matches {actual}.
|
|v:errors| when {pattern} matches {actual}.
|
||||||
|
Also see |assert-return|.
|
||||||
|
|
||||||
assert_report({msg}) *assert_report()*
|
assert_report({msg}) *assert_report()*
|
||||||
Report a test failure directly, using {msg}.
|
Report a test failure directly, using {msg}.
|
||||||
|
Always returns one.
|
||||||
|
|
||||||
assert_true({actual} [, {msg}]) *assert_true()*
|
assert_true({actual} [, {msg}]) *assert_true()*
|
||||||
When {actual} is not true an error message is added to
|
When {actual} is not true an error message is added to
|
||||||
|v:errors|, like with |assert_equal()|.
|
|v:errors|, like with |assert_equal()|.
|
||||||
|
Also see |assert-return|.
|
||||||
A value is |TRUE| when it is a non-zero number or |v:true|.
|
A value is |TRUE| when it is a non-zero number or |v:true|.
|
||||||
When {actual} is not a number or |v:true| the assert fails.
|
When {actual} is not a number or |v:true| the assert fails.
|
||||||
When {msg} is omitted an error in the form "Expected True but
|
When {msg} is omitted an error in the form "Expected True but
|
||||||
@ -3525,7 +3550,7 @@ exists({expr}) The result is a Number, which is |TRUE| if {expr} is
|
|||||||
string)
|
string)
|
||||||
*funcname built-in function (see |functions|)
|
*funcname built-in function (see |functions|)
|
||||||
or user defined function (see
|
or user defined function (see
|
||||||
|user-functions|). Also works for a
|
|user-function|). Also works for a
|
||||||
variable that is a Funcref.
|
variable that is a Funcref.
|
||||||
varname internal variable (see
|
varname internal variable (see
|
||||||
|internal-variables|). Also works
|
|internal-variables|). Also works
|
||||||
@ -4479,8 +4504,7 @@ getftype({fname}) *getftype()*
|
|||||||
systems that support it. On some systems only "dir" and
|
systems that support it. On some systems only "dir" and
|
||||||
"file" are returned.
|
"file" are returned.
|
||||||
|
|
||||||
*getjumplist()*
|
getjumplist([{winnr} [, {tabnr}]]) *getjumplist()*
|
||||||
getjumplist([{winnr} [, {tabnr}]])
|
|
||||||
Returns the |jumplist| for the specified window.
|
Returns the |jumplist| for the specified window.
|
||||||
|
|
||||||
Without arguments use the current window.
|
Without arguments use the current window.
|
||||||
@ -4536,6 +4560,10 @@ getloclist({nr},[, {what}]) *getloclist()*
|
|||||||
If the optional {what} dictionary argument is supplied, then
|
If the optional {what} dictionary argument is supplied, then
|
||||||
returns the items listed in {what} as a dictionary. Refer to
|
returns the items listed in {what} as a dictionary. Refer to
|
||||||
|getqflist()| for the supported items in {what}.
|
|getqflist()| for the supported items in {what}.
|
||||||
|
If {what} contains 'filewinid', then returns the id of the
|
||||||
|
window used to display files from the location list. This
|
||||||
|
field is applicable only when called from a location list
|
||||||
|
window.
|
||||||
|
|
||||||
getmatches() *getmatches()*
|
getmatches() *getmatches()*
|
||||||
Returns a |List| with all matches previously defined for the
|
Returns a |List| with all matches previously defined for the
|
||||||
@ -4699,7 +4727,7 @@ getreg([{regname} [, 1 [, {list}]]]) *getreg()*
|
|||||||
getregtype([{regname}]) *getregtype()*
|
getregtype([{regname}]) *getregtype()*
|
||||||
The result is a String, which is type of register {regname}.
|
The result is a String, which is type of register {regname}.
|
||||||
The value will be one of:
|
The value will be one of:
|
||||||
"v" for |characterwise| text
|
"v" for |charwise| text
|
||||||
"V" for |linewise| text
|
"V" for |linewise| text
|
||||||
"<CTRL-V>{width}" for |blockwise-visual| text
|
"<CTRL-V>{width}" for |blockwise-visual| text
|
||||||
"" for an empty or unknown register
|
"" for an empty or unknown register
|
||||||
@ -4941,9 +4969,11 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
|
|||||||
< *feature-list*
|
< *feature-list*
|
||||||
List of supported pseudo-feature names:
|
List of supported pseudo-feature names:
|
||||||
acl |ACL| support
|
acl |ACL| support
|
||||||
|
bsd BSD system (not macOS, use "mac" for that).
|
||||||
iconv Can use |iconv()| for conversion.
|
iconv Can use |iconv()| for conversion.
|
||||||
+shellslash Can use backslashes in filenames (Windows)
|
+shellslash Can use backslashes in filenames (Windows)
|
||||||
clipboard |clipboard| provider is available.
|
clipboard |clipboard| provider is available.
|
||||||
|
mac MacOS system.
|
||||||
nvim This is Nvim.
|
nvim This is Nvim.
|
||||||
python2 Legacy Vim |python2| interface. |has-python|
|
python2 Legacy Vim |python2| interface. |has-python|
|
||||||
python3 Legacy Vim |python3| interface. |has-python|
|
python3 Legacy Vim |python3| interface. |has-python|
|
||||||
@ -4953,6 +4983,7 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
|
|||||||
unix Unix system.
|
unix Unix system.
|
||||||
*vim_starting* True during |startup|.
|
*vim_starting* True during |startup|.
|
||||||
win32 Windows system (32 or 64 bit).
|
win32 Windows system (32 or 64 bit).
|
||||||
|
win64 Windows system (64 bit).
|
||||||
wsl WSL (Windows Subsystem for Linux) system
|
wsl WSL (Windows Subsystem for Linux) system
|
||||||
|
|
||||||
*has-patch*
|
*has-patch*
|
||||||
@ -5420,6 +5451,9 @@ jobstart({cmd}[, {opts}]) *jobstart()*
|
|||||||
|on_exit| : exit event handler (function name or |Funcref|)
|
|on_exit| : exit event handler (function name or |Funcref|)
|
||||||
cwd : Working directory of the job; defaults to
|
cwd : Working directory of the job; defaults to
|
||||||
|current-directory|.
|
|current-directory|.
|
||||||
|
env : A dict of strings to append (or replace see
|
||||||
|
|clear_env|) to the current environment.
|
||||||
|
clear_env: If set, use the exact values passed in |env|
|
||||||
rpc : If set, |msgpack-rpc| will be used to communicate
|
rpc : If set, |msgpack-rpc| will be used to communicate
|
||||||
with the job over stdin and stdout. "on_stdout" is
|
with the job over stdin and stdout. "on_stdout" is
|
||||||
then ignored, but "on_stderr" can still be used.
|
then ignored, but "on_stderr" can still be used.
|
||||||
@ -6103,7 +6137,7 @@ mode([expr]) Return a string that indicates the current mode.
|
|||||||
|
|
||||||
n Normal
|
n Normal
|
||||||
no Operator-pending
|
no Operator-pending
|
||||||
nov Operator-pending (forced characterwise |o_v|)
|
nov Operator-pending (forced charwise |o_v|)
|
||||||
noV Operator-pending (forced linewise |o_V|)
|
noV Operator-pending (forced linewise |o_V|)
|
||||||
noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|)
|
noCTRL-V Operator-pending (forced blockwise |o_CTRL-V|)
|
||||||
niI Normal using |i_CTRL-O| in |Insert-mode|
|
niI Normal using |i_CTRL-O| in |Insert-mode|
|
||||||
@ -6640,7 +6674,7 @@ remote_expr({server}, {string} [, {idvar} [, {timeout}]])
|
|||||||
between (not at the end), like with join(expr, "\n").
|
between (not at the end), like with join(expr, "\n").
|
||||||
If {idvar} is present and not empty, it is taken as the name
|
If {idvar} is present and not empty, it is taken as the name
|
||||||
of a variable and a {serverid} for later use with
|
of a variable and a {serverid} for later use with
|
||||||
remote_read() is stored there.
|
|remote_read()| is stored there.
|
||||||
If {timeout} is given the read times out after this many
|
If {timeout} is given the read times out after this many
|
||||||
seconds. Otherwise a timeout of 600 seconds is used.
|
seconds. Otherwise a timeout of 600 seconds is used.
|
||||||
See also |clientserver| |RemoteReply|.
|
See also |clientserver| |RemoteReply|.
|
||||||
@ -7413,7 +7447,7 @@ setreg({regname}, {value} [, {options}])
|
|||||||
If {options} contains "a" or {regname} is upper case,
|
If {options} contains "a" or {regname} is upper case,
|
||||||
then the value is appended.
|
then the value is appended.
|
||||||
{options} can also contain a register type specification:
|
{options} can also contain a register type specification:
|
||||||
"c" or "v" |characterwise| mode
|
"c" or "v" |charwise| mode
|
||||||
"l" or "V" |linewise| mode
|
"l" or "V" |linewise| mode
|
||||||
"b" or "<CTRL-V>" |blockwise-visual| mode
|
"b" or "<CTRL-V>" |blockwise-visual| mode
|
||||||
If a number immediately follows "b" or "<CTRL-V>" then this is
|
If a number immediately follows "b" or "<CTRL-V>" then this is
|
||||||
@ -9222,7 +9256,7 @@ Don't forget that "^" will only match at the first character of the String and
|
|||||||
"\n".
|
"\n".
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
5. Defining functions *user-functions*
|
5. Defining functions *user-function*
|
||||||
|
|
||||||
New functions can be defined. These can be called just like builtin
|
New functions can be defined. These can be called just like builtin
|
||||||
functions. The function executes a sequence of Ex commands. Normal mode
|
functions. The function executes a sequence of Ex commands. Normal mode
|
||||||
@ -9680,7 +9714,7 @@ This does NOT work: >
|
|||||||
register, "@/" for the search pattern.
|
register, "@/" for the search pattern.
|
||||||
If the result of {expr1} ends in a <CR> or <NL>, the
|
If the result of {expr1} ends in a <CR> or <NL>, the
|
||||||
register will be linewise, otherwise it will be set to
|
register will be linewise, otherwise it will be set to
|
||||||
characterwise.
|
charwise.
|
||||||
This can be used to clear the last search pattern: >
|
This can be used to clear the last search pattern: >
|
||||||
:let @/ = ""
|
:let @/ = ""
|
||||||
< This is different from searching for an empty string,
|
< This is different from searching for an empty string,
|
||||||
@ -9762,6 +9796,54 @@ This does NOT work: >
|
|||||||
Like above, but append/add/subtract the value for each
|
Like above, but append/add/subtract the value for each
|
||||||
|List| item.
|
|List| item.
|
||||||
|
|
||||||
|
*:let=<<* *:let-heredoc*
|
||||||
|
*E990* *E991* *E172* *E221*
|
||||||
|
:let {var-name} =<< [trim] {marker}
|
||||||
|
text...
|
||||||
|
text...
|
||||||
|
{marker}
|
||||||
|
Set internal variable {var-name} to a List containing
|
||||||
|
the lines of text bounded by the string {marker}.
|
||||||
|
{marker} cannot start with a lower case character.
|
||||||
|
The last line should end only with the {marker} string
|
||||||
|
without any other character. Watch out for white
|
||||||
|
space after {marker}!
|
||||||
|
|
||||||
|
Without "trim" any white space characters in the lines
|
||||||
|
of text are preserved. If "trim" is specified before
|
||||||
|
{marker}, then indentation is stripped so you can do: >
|
||||||
|
let text =<< trim END
|
||||||
|
if ok
|
||||||
|
echo 'done'
|
||||||
|
endif
|
||||||
|
END
|
||||||
|
< Results in: ["if ok", " echo 'done'", "endif"]
|
||||||
|
The marker must line up with "let" and the indentation
|
||||||
|
of the first line is removed from all the text lines.
|
||||||
|
Specifically: all the leading indentation exactly
|
||||||
|
matching the leading indentation of the first
|
||||||
|
non-empty text line is stripped from the input lines.
|
||||||
|
All leading indentation exactly matching the leading
|
||||||
|
indentation before `let` is stripped from the line
|
||||||
|
containing {marker}. Note that the difference between
|
||||||
|
space and tab matters here.
|
||||||
|
|
||||||
|
If {var-name} didn't exist yet, it is created.
|
||||||
|
Cannot be followed by another command, but can be
|
||||||
|
followed by a comment.
|
||||||
|
|
||||||
|
Examples: >
|
||||||
|
let var1 =<< END
|
||||||
|
Sample text 1
|
||||||
|
Sample text 2
|
||||||
|
Sample text 3
|
||||||
|
END
|
||||||
|
|
||||||
|
let data =<< trim DATA
|
||||||
|
1 2 3 4
|
||||||
|
5 6 7 8
|
||||||
|
DATA
|
||||||
|
<
|
||||||
*E121*
|
*E121*
|
||||||
:let {var-name} .. List the value of variable {var-name}. Multiple
|
:let {var-name} .. List the value of variable {var-name}. Multiple
|
||||||
variable names may be given. Special names recognized
|
variable names may be given. Special names recognized
|
||||||
|
@ -549,7 +549,9 @@ Variables:
|
|||||||
*b:man_default_sects* Comma-separated, ordered list of preferred sections.
|
*b:man_default_sects* Comma-separated, ordered list of preferred sections.
|
||||||
For example in C one usually wants section 3 or 2: >
|
For example in C one usually wants section 3 or 2: >
|
||||||
:let b:man_default_sections = '3,2'
|
:let b:man_default_sections = '3,2'
|
||||||
*g:man_hardwrap* Hard-wrap to $MANWIDTH. May improve layout.
|
*g:man_hardwrap* Hard-wrap to $MANWIDTH or window width if $MANWIDTH is
|
||||||
|
empty. Enabled by default. Set |FALSE| to enable soft
|
||||||
|
wrapping.
|
||||||
|
|
||||||
To use Nvim as a manpager: >
|
To use Nvim as a manpager: >
|
||||||
export MANPAGER='nvim +Man!'
|
export MANPAGER='nvim +Man!'
|
||||||
@ -558,10 +560,13 @@ Note that when running `man` from the shell and with that `MANPAGER` in your
|
|||||||
environment, `man` will pre-format the manpage using `groff`. Thus, Neovim
|
environment, `man` will pre-format the manpage using `groff`. Thus, Neovim
|
||||||
will inevitably display the manual page as it was passed to it from stdin. One
|
will inevitably display the manual page as it was passed to it from stdin. One
|
||||||
of the caveats of this is that the width will _always_ be hard-wrapped and not
|
of the caveats of this is that the width will _always_ be hard-wrapped and not
|
||||||
soft wrapped as with `:Man`. You can set in your environment: >
|
soft wrapped as with `g:man_hardwrap=0`. You can set in your environment: >
|
||||||
export MANWIDTH=999
|
export MANWIDTH=999
|
||||||
|
|
||||||
So `groff`'s pre-formatting output will be the same as with `:Man` i.e soft-wrapped.
|
So `groff`'s pre-formatting output will be the same as with `g:man_hardwrap=0` i.e soft-wrapped.
|
||||||
|
|
||||||
|
To disable bold highlighting: >
|
||||||
|
:highlight link manBold Normal
|
||||||
|
|
||||||
PDF *ft-pdf-plugin*
|
PDF *ft-pdf-plugin*
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ Advanced editing ~
|
|||||||
|autocmd.txt| automatically executing commands on an event
|
|autocmd.txt| automatically executing commands on an event
|
||||||
|eval.txt| expression evaluation, conditional commands
|
|eval.txt| expression evaluation, conditional commands
|
||||||
|fold.txt| hide (fold) ranges of lines
|
|fold.txt| hide (fold) ranges of lines
|
||||||
|
|lua.txt| Lua API
|
||||||
|
|
||||||
Special issues ~
|
Special issues ~
|
||||||
|print.txt| printing
|
|print.txt| printing
|
||||||
@ -157,7 +158,6 @@ GUI ~
|
|||||||
|
|
||||||
Interfaces ~
|
Interfaces ~
|
||||||
|if_cscop.txt| using Cscope with Vim
|
|if_cscop.txt| using Cscope with Vim
|
||||||
|if_lua.txt| Lua interface
|
|
||||||
|if_pyth.txt| Python interface
|
|if_pyth.txt| Python interface
|
||||||
|if_ruby.txt| Ruby interface
|
|if_ruby.txt| Ruby interface
|
||||||
|sign.txt| debugging signs
|
|sign.txt| debugging signs
|
||||||
|
@ -1,668 +1,8 @@
|
|||||||
*if_lua.txt* Nvim
|
|
||||||
|
|
||||||
|
|
||||||
NVIM REFERENCE MANUAL
|
NVIM REFERENCE MANUAL
|
||||||
|
|
||||||
|
Moved to |lua.txt|
|
||||||
Lua engine *lua* *Lua*
|
|
||||||
|
|
||||||
Type |gO| to see the table of contents.
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
Introduction *lua-intro*
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
|
||||||
The Lua 5.1 language is builtin and always available. Try this command to get
|
|
||||||
an idea of what lurks beneath: >
|
|
||||||
|
|
||||||
:lua print(vim.inspect(package.loaded))
|
|
||||||
|
|
||||||
Nvim includes a "standard library" |lua-stdlib| for Lua. It complements the
|
|
||||||
"editor stdlib" (|functions| and Ex commands) and the |API|, all of which can
|
|
||||||
be used from Lua code.
|
|
||||||
|
|
||||||
Module conflicts are resolved by "last wins". For example if both of these
|
|
||||||
are on 'runtimepath':
|
|
||||||
runtime/lua/foo.lua
|
|
||||||
~/.config/nvim/lua/foo.lua
|
|
||||||
then `require('foo')` loads "~/.config/nvim/lua/foo.lua", and
|
|
||||||
"runtime/lua/foo.lua" is not used. See |lua-require| to understand how Nvim
|
|
||||||
finds and loads Lua modules. The conventions are similar to VimL plugins,
|
|
||||||
with some extra features. See |lua-require-example| for a walkthrough.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
Importing Lua modules *lua-require*
|
|
||||||
|
|
||||||
Nvim automatically adjusts `package.path` and `package.cpath` according to
|
|
||||||
effective 'runtimepath' value. Adjustment happens whenever 'runtimepath' is
|
|
||||||
changed. `package.path` is adjusted by simply appending `/lua/?.lua` and
|
|
||||||
`/lua/?/init.lua` to each directory from 'runtimepath' (`/` is actually the
|
|
||||||
first character of `package.config`).
|
|
||||||
|
|
||||||
Similarly to `package.path`, modified directories from 'runtimepath' are also
|
|
||||||
added to `package.cpath`. In this case, instead of appending `/lua/?.lua` and
|
|
||||||
`/lua/?/init.lua` to each runtimepath, all unique `?`-containing suffixes of
|
|
||||||
the existing `package.cpath` are used. Example:
|
|
||||||
|
|
||||||
1. Given that
|
|
||||||
- 'runtimepath' contains `/foo/bar,/xxx;yyy/baz,/abc`;
|
|
||||||
- initial (defined at compile-time or derived from
|
|
||||||
`$LUA_CPATH`/`$LUA_INIT`) `package.cpath` contains
|
|
||||||
`./?.so;/def/ghi/a?d/j/g.elf;/def/?.so`.
|
|
||||||
2. It finds `?`-containing suffixes `/?.so`, `/a?d/j/g.elf` and `/?.so`, in
|
|
||||||
order: parts of the path starting from the first path component containing
|
|
||||||
question mark and preceding path separator.
|
|
||||||
3. The suffix of `/def/?.so`, namely `/?.so` is not unique, as it’s the same
|
|
||||||
as the suffix of the first path from `package.path` (i.e. `./?.so`). Which
|
|
||||||
leaves `/?.so` and `/a?d/j/g.elf`, in this order.
|
|
||||||
4. 'runtimepath' has three paths: `/foo/bar`, `/xxx;yyy/baz` and `/abc`. The
|
|
||||||
second one contains semicolon which is a paths separator so it is out,
|
|
||||||
leaving only `/foo/bar` and `/abc`, in order.
|
|
||||||
5. The cartesian product of paths from 4. and suffixes from 3. is taken,
|
|
||||||
giving four variants. In each variant `/lua` path segment is inserted
|
|
||||||
between path and suffix, leaving
|
|
||||||
|
|
||||||
- `/foo/bar/lua/?.so`
|
|
||||||
- `/foo/bar/lua/a?d/j/g.elf`
|
|
||||||
- `/abc/lua/?.so`
|
|
||||||
- `/abc/lua/a?d/j/g.elf`
|
|
||||||
|
|
||||||
6. New paths are prepended to the original `package.cpath`.
|
|
||||||
|
|
||||||
The result will look like this:
|
|
||||||
|
|
||||||
`/foo/bar,/xxx;yyy/baz,/abc` ('runtimepath')
|
|
||||||
× `./?.so;/def/ghi/a?d/j/g.elf;/def/?.so` (`package.cpath`)
|
|
||||||
|
|
||||||
= `/foo/bar/lua/?.so;/foo/bar/lua/a?d/j/g.elf;/abc/lua/?.so;/abc/lua/a?d/j/g.elf;./?.so;/def/ghi/a?d/j/g.elf;/def/?.so`
|
|
||||||
|
|
||||||
Note:
|
|
||||||
|
|
||||||
- To track 'runtimepath' updates, paths added at previous update are
|
|
||||||
remembered and removed at the next update, while all paths derived from the
|
|
||||||
new 'runtimepath' are prepended as described above. This allows removing
|
|
||||||
paths when path is removed from 'runtimepath', adding paths when they are
|
|
||||||
added and reordering `package.path`/`package.cpath` content if 'runtimepath'
|
|
||||||
was reordered.
|
|
||||||
|
|
||||||
- Although adjustments happen automatically, Nvim does not track current
|
|
||||||
values of `package.path` or `package.cpath`. If you happen to delete some
|
|
||||||
paths from there you can set 'runtimepath' to trigger an update: >
|
|
||||||
let &runtimepath = &runtimepath
|
|
||||||
|
|
||||||
- Skipping paths from 'runtimepath' which contain semicolons applies both to
|
|
||||||
`package.path` and `package.cpath`. Given that there are some badly written
|
|
||||||
plugins using shell which will not work with paths containing semicolons it
|
|
||||||
is better to not have them in 'runtimepath' at all.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
LUA PLUGIN EXAMPLE *lua-require-example*
|
|
||||||
|
|
||||||
The following example plugin adds a command `:MakeCharBlob` which transforms
|
|
||||||
current buffer into a long `unsigned char` array. Lua contains transformation
|
|
||||||
function in a module `lua/charblob.lua` which is imported in
|
|
||||||
`autoload/charblob.vim` (`require("charblob")`). Example plugin is supposed
|
|
||||||
to be put into any directory from 'runtimepath', e.g. `~/.config/nvim` (in
|
|
||||||
this case `lua/charblob.lua` means `~/.config/nvim/lua/charblob.lua`).
|
|
||||||
|
|
||||||
autoload/charblob.vim: >
|
|
||||||
|
|
||||||
function charblob#encode_buffer()
|
|
||||||
call setline(1, luaeval(
|
|
||||||
\ 'require("charblob").encode(unpack(_A))',
|
|
||||||
\ [getline(1, '$'), &textwidth, ' ']))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
plugin/charblob.vim: >
|
|
||||||
|
|
||||||
if exists('g:charblob_loaded')
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:charblob_loaded = 1
|
|
||||||
|
|
||||||
command MakeCharBlob :call charblob#encode_buffer()
|
|
||||||
|
|
||||||
lua/charblob.lua: >
|
|
||||||
|
|
||||||
local function charblob_bytes_iter(lines)
|
|
||||||
local init_s = {
|
|
||||||
next_line_idx = 1,
|
|
||||||
next_byte_idx = 1,
|
|
||||||
lines = lines,
|
|
||||||
}
|
|
||||||
local function next(s, _)
|
|
||||||
if lines[s.next_line_idx] == nil then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
if s.next_byte_idx > #(lines[s.next_line_idx]) then
|
|
||||||
s.next_line_idx = s.next_line_idx + 1
|
|
||||||
s.next_byte_idx = 1
|
|
||||||
return ('\n'):byte()
|
|
||||||
end
|
|
||||||
local ret = lines[s.next_line_idx]:byte(s.next_byte_idx)
|
|
||||||
if ret == ('\n'):byte() then
|
|
||||||
ret = 0 -- See :h NL-used-for-NUL.
|
|
||||||
end
|
|
||||||
s.next_byte_idx = s.next_byte_idx + 1
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
return next, init_s, nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local function charblob_encode(lines, textwidth, indent)
|
|
||||||
local ret = {
|
|
||||||
'const unsigned char blob[] = {',
|
|
||||||
indent,
|
|
||||||
}
|
|
||||||
for byte in charblob_bytes_iter(lines) do
|
|
||||||
-- .- space + number (width 3) + comma
|
|
||||||
if #(ret[#ret]) + 5 > textwidth then
|
|
||||||
ret[#ret + 1] = indent
|
|
||||||
else
|
|
||||||
ret[#ret] = ret[#ret] .. ' '
|
|
||||||
end
|
|
||||||
ret[#ret] = ret[#ret] .. (('%3u,'):format(byte))
|
|
||||||
end
|
|
||||||
ret[#ret + 1] = '};'
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
return {
|
|
||||||
bytes_iter = charblob_bytes_iter,
|
|
||||||
encode = charblob_encode,
|
|
||||||
}
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
Commands *lua-commands*
|
|
||||||
|
|
||||||
*:lua*
|
|
||||||
:[range]lua {chunk}
|
|
||||||
Execute Lua chunk {chunk}.
|
|
||||||
|
|
||||||
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)
|
|
||||||
<
|
|
||||||
|
|
||||||
:[range]lua << [endmarker]
|
|
||||||
{script}
|
|
||||||
{endmarker}
|
|
||||||
Execute Lua script {script}. Useful for including Lua
|
|
||||||
code in Vim scripts.
|
|
||||||
|
|
||||||
The {endmarker} must NOT be preceded by any white space.
|
|
||||||
|
|
||||||
If [endmarker] is omitted from after the "<<", a dot '.' must be used after
|
|
||||||
{script}, like for the |:append| and |:insert| commands.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
>
|
|
||||||
function! CurrentLineInfo()
|
|
||||||
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]
|
|
||||||
print(string.format("Current line [%d] has %d bytes",
|
|
||||||
linenr, #curline))
|
|
||||||
EOF
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
Note that the `local` variables will disappear when block finishes. This is
|
|
||||||
not the case for globals.
|
|
||||||
|
|
||||||
*:luado*
|
|
||||||
:[range]luado {body} Execute Lua function "function (line, linenr) {body}
|
|
||||||
end" for each line in the [range], with the function
|
|
||||||
argument being set to the text of each line in turn,
|
|
||||||
without a trailing <EOL>, and the current line number.
|
|
||||||
If the value returned by the function is a string it
|
|
||||||
becomes the text of the line in the current turn. The
|
|
||||||
default for [range] is the whole file: "1,$".
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
>
|
|
||||||
:luado return string.format("%s\t%d", line:reverse(), #line)
|
|
||||||
|
|
||||||
:lua require"lpeg"
|
|
||||||
:lua -- balanced parenthesis grammar:
|
|
||||||
:lua bp = lpeg.P{ "(" * ((1 - lpeg.S"()") + lpeg.V(1))^0 * ")" }
|
|
||||||
:luado if bp:match(line) then return "-->\t" .. line end
|
|
||||||
<
|
|
||||||
|
|
||||||
*:luafile*
|
|
||||||
:[range]luafile {file}
|
|
||||||
Execute Lua script in {file}.
|
|
||||||
The whole argument is used as a single file name.
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
>
|
|
||||||
:luafile script.lua
|
|
||||||
:luafile %
|
|
||||||
<
|
|
||||||
|
|
||||||
All these commands execute a Lua chunk from either the command line (:lua and
|
|
||||||
:luado) or a file (:luafile) with the given line [range]. Similarly to the Lua
|
|
||||||
interpreter, each chunk has its own scope and so only global variables are
|
|
||||||
shared between command calls. All Lua default libraries are available. In
|
|
||||||
addition, Lua "print" function has its output redirected to the Nvim message
|
|
||||||
area, with arguments separated by a white space instead of a tab.
|
|
||||||
|
|
||||||
Lua uses the "vim" module (see |lua-vim|) to issue commands to Nvim. However,
|
|
||||||
procedures that alter buffer content, open new buffers, and change cursor
|
|
||||||
position are restricted when the command is executed in the |sandbox|.
|
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
luaeval() *lua-eval* *luaeval()*
|
|
||||||
|
|
||||||
The (dual) equivalent of "vim.eval" for passing Lua values to Nvim is
|
|
||||||
"luaeval". "luaeval" takes an expression string and an optional argument used
|
|
||||||
for _A inside expression and returns the result of the expression. It is
|
|
||||||
semantically equivalent in Lua to:
|
|
||||||
>
|
|
||||||
local chunkheader = "local _A = select(1, ...) return "
|
|
||||||
function luaeval (expstr, arg)
|
|
||||||
local chunk = assert(loadstring(chunkheader .. expstr, "luaeval"))
|
|
||||||
return chunk(arg) -- return typval
|
|
||||||
end
|
|
||||||
|
|
||||||
Lua nils, numbers, strings, tables and booleans are converted to their
|
|
||||||
respective VimL types. An error is thrown if conversion of any other Lua types
|
|
||||||
is attempted.
|
|
||||||
|
|
||||||
The magic global "_A" contains the second argument to luaeval().
|
|
||||||
|
|
||||||
Example: >
|
|
||||||
:echo luaeval('_A[1] + _A[2]', [40, 2])
|
|
||||||
42
|
|
||||||
:echo luaeval('string.match(_A, "[a-z]+")', 'XYXfoo123')
|
|
||||||
foo
|
|
||||||
|
|
||||||
Lua tables are used as both dictionaries and lists, so it is impossible to
|
|
||||||
determine whether empty table is meant to be empty list or empty dictionary.
|
|
||||||
Additionally lua does not have integer numbers. To distinguish between these
|
|
||||||
cases there is the following agreement:
|
|
||||||
|
|
||||||
0. Empty table is empty list.
|
|
||||||
1. Table with N incrementally growing integral numbers, starting from 1 and
|
|
||||||
ending with N is considered to be a list.
|
|
||||||
2. Table with string keys, none of which contains NUL byte, is considered to
|
|
||||||
be a dictionary.
|
|
||||||
3. Table with string keys, at least one of which contains NUL byte, is also
|
|
||||||
considered to be a dictionary, but this time it is converted to
|
|
||||||
a |msgpack-special-map|.
|
|
||||||
*lua-special-tbl*
|
|
||||||
4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point
|
|
||||||
value:
|
|
||||||
- `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to
|
|
||||||
a floating-point 1.0. Note that by default integral lua numbers are
|
|
||||||
converted to |Number|s, non-integral are converted to |Float|s. This
|
|
||||||
variant allows integral |Float|s.
|
|
||||||
- `{[vim.type_idx]=vim.types.dictionary}` is converted to an empty
|
|
||||||
dictionary, `{[vim.type_idx]=vim.types.dictionary, [42]=1, a=2}` is
|
|
||||||
converted to a dictionary `{'a': 42}`: non-string keys are ignored.
|
|
||||||
Without `vim.type_idx` key tables with keys not fitting in 1., 2. or 3.
|
|
||||||
are errors.
|
|
||||||
- `{[vim.type_idx]=vim.types.list}` is converted to an empty list. As well
|
|
||||||
as `{[vim.type_idx]=vim.types.list, [42]=1}`: integral keys that do not
|
|
||||||
form a 1-step sequence from 1 to N are ignored, as well as all
|
|
||||||
non-integral keys.
|
|
||||||
|
|
||||||
Examples: >
|
|
||||||
|
|
||||||
:echo luaeval('math.pi')
|
|
||||||
:function Rand(x,y) " random uniform between x and y
|
|
||||||
: return luaeval('(_A.y-_A.x)*math.random()+_A.x', {'x':a:x,'y':a:y})
|
|
||||||
: endfunction
|
|
||||||
:echo Rand(1,10)
|
|
||||||
|
|
||||||
Note that currently second argument to `luaeval` undergoes VimL to lua
|
|
||||||
conversion, so changing containers in lua do not affect values in VimL. Return
|
|
||||||
value is also always converted. When converting, |msgpack-special-dict|s are
|
|
||||||
treated specially.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
Lua standard modules *lua-stdlib*
|
|
||||||
|
|
||||||
The Nvim Lua "standard library" (stdlib) is the `vim` module, which exposes
|
|
||||||
various functions and sub-modules. It is always loaded, thus require("vim")
|
|
||||||
is unnecessary.
|
|
||||||
|
|
||||||
You can peek at the module properties: >
|
|
||||||
|
|
||||||
:lua print(vim.inspect(vim))
|
|
||||||
|
|
||||||
Result is something like this: >
|
|
||||||
|
|
||||||
{
|
|
||||||
_os_proc_children = <function 1>,
|
|
||||||
_os_proc_info = <function 2>,
|
|
||||||
...
|
|
||||||
api = {
|
|
||||||
nvim__id = <function 5>,
|
|
||||||
nvim__id_array = <function 6>,
|
|
||||||
...
|
|
||||||
},
|
|
||||||
deepcopy = <function 106>,
|
|
||||||
gsplit = <function 107>,
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
To find documentation on e.g. the "deepcopy" function: >
|
|
||||||
|
|
||||||
:help vim.deepcopy
|
|
||||||
|
|
||||||
Note that underscore-prefixed functions (e.g. "_os_proc_children") are
|
|
||||||
internal/private and must not be used by plugins.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
VIM.API *lua-api*
|
|
||||||
|
|
||||||
`vim.api` exposes the full Nvim |API| as a table of Lua functions.
|
|
||||||
|
|
||||||
Example: to use the "nvim_get_current_line()" API function, call
|
|
||||||
"vim.api.nvim_get_current_line()": >
|
|
||||||
|
|
||||||
print(tostring(vim.api.nvim_get_current_line()))
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
VIM.LOOP *lua-loop*
|
|
||||||
|
|
||||||
`vim.loop` exposes all features of the Nvim event-loop. This is a low-level
|
|
||||||
API that provides functionality for networking, filesystem, and process
|
|
||||||
management. Try this command to see available functions: >
|
|
||||||
|
|
||||||
:lua print(vim.inspect(vim.loop))
|
|
||||||
|
|
||||||
Reference: http://docs.libuv.org
|
|
||||||
Examples: https://github.com/luvit/luv/tree/master/examples
|
|
||||||
|
|
||||||
*E5560* *lua-loop-callbacks*
|
|
||||||
It is an error to directly invoke `vim.api` functions (except |api-fast|) in
|
|
||||||
`vim.loop` callbacks. For example, this is an error: >
|
|
||||||
|
|
||||||
local timer = vim.loop.new_timer()
|
|
||||||
timer:start(1000, 0, function()
|
|
||||||
vim.api.nvim_command('echomsg "test"')
|
|
||||||
end)
|
|
||||||
|
|
||||||
To avoid the error use |vim.schedule_wrap()| to defer the callback: >
|
|
||||||
|
|
||||||
local timer = vim.loop.new_timer()
|
|
||||||
timer:start(1000, 0, vim.schedule_wrap(function()
|
|
||||||
vim.api.nvim_command('echomsg "test"')
|
|
||||||
end))
|
|
||||||
|
|
||||||
Example: repeating timer
|
|
||||||
1. Save this code to a file.
|
|
||||||
2. Execute it with ":luafile %". >
|
|
||||||
|
|
||||||
-- Create a timer handle (implementation detail: uv_timer_t).
|
|
||||||
local timer = vim.loop.new_timer()
|
|
||||||
local i = 0
|
|
||||||
-- Waits 1000ms, then repeats every 750ms until timer:close().
|
|
||||||
timer:start(1000, 750, function()
|
|
||||||
print('timer invoked! i='..tostring(i))
|
|
||||||
if i > 4 then
|
|
||||||
timer:close() -- Always close handles to avoid leaks.
|
|
||||||
end
|
|
||||||
i = i + 1
|
|
||||||
end)
|
|
||||||
print('sleeping');
|
|
||||||
|
|
||||||
|
|
||||||
Example: TCP echo-server *tcp-server*
|
|
||||||
1. Save this code to a file.
|
|
||||||
2. Execute it with ":luafile %".
|
|
||||||
3. Note the port number.
|
|
||||||
4. Connect from any TCP client (e.g. "nc 0.0.0.0 36795"): >
|
|
||||||
|
|
||||||
local function create_server(host, port, on_connection)
|
|
||||||
local server = vim.loop.new_tcp()
|
|
||||||
server:bind(host, port)
|
|
||||||
server:listen(128, function(err)
|
|
||||||
assert(not err, err) -- Check for errors.
|
|
||||||
local sock = vim.loop.new_tcp()
|
|
||||||
server:accept(sock) -- Accept client connection.
|
|
||||||
on_connection(sock) -- Start reading messages.
|
|
||||||
end)
|
|
||||||
return server
|
|
||||||
end
|
|
||||||
local server = create_server('0.0.0.0', 0, function(sock)
|
|
||||||
sock:read_start(function(err, chunk)
|
|
||||||
assert(not err, err) -- Check for errors.
|
|
||||||
if chunk then
|
|
||||||
sock:write(chunk) -- Echo received messages to the channel.
|
|
||||||
else -- EOF (stream closed).
|
|
||||||
sock:close() -- Always close handles to avoid leaks.
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
print('TCP echo-server listening on port: '..server:getsockname().port)
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
VIM *lua-util*
|
|
||||||
|
|
||||||
vim.in_fast_event() *vim.in_fast_event()*
|
|
||||||
Returns true if the code is executing as part of a "fast" event
|
|
||||||
handler, where most of the API is disabled. These are low-level events
|
|
||||||
(e.g. |lua-loop-callbacks|) which can be invoked whenever Nvim polls
|
|
||||||
for input. When this is `false` most API functions are callable (but
|
|
||||||
may be subject to other restrictions such as |textlock|).
|
|
||||||
|
|
||||||
vim.stricmp({a}, {b}) *vim.stricmp()*
|
|
||||||
Compares strings case-insensitively. Returns 0, 1 or -1 if strings
|
|
||||||
are equal, {a} is greater than {b} or {a} is lesser than {b},
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()*
|
|
||||||
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.
|
|
||||||
|
|
||||||
Embedded NUL bytes are treated as terminating the string. Invalid
|
|
||||||
UTF-8 bytes, and embedded surrogates are counted as one code
|
|
||||||
point each. An {index} in the middle of a UTF-8 sequence is rounded
|
|
||||||
upwards to the end of that sequence.
|
|
||||||
|
|
||||||
vim.str_byteindex({str}, {index}[, {use_utf16}]) *vim.str_byteindex()*
|
|
||||||
Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
|
|
||||||
supplied, it defaults to false (use UTF-32). Returns the byte index.
|
|
||||||
|
|
||||||
Invalid UTF-8 and NUL is treated like by |vim.str_byteindex()|. An {index}
|
|
||||||
in the middle of a UTF-16 sequence is rounded upwards to the end of that
|
|
||||||
sequence.
|
|
||||||
|
|
||||||
vim.schedule({callback}) *vim.schedule()*
|
|
||||||
Schedules {callback} to be invoked soon by the main event-loop. Useful
|
|
||||||
to avoid |textlock| or other temporary restrictions.
|
|
||||||
|
|
||||||
vim.type_idx *vim.type_idx*
|
|
||||||
Type index for use in |lua-special-tbl|. Specifying one of the
|
|
||||||
values from |vim.types| allows typing the empty table (it is
|
|
||||||
unclear whether empty lua table represents empty list or empty array)
|
|
||||||
and forcing integral numbers to be |Float|. See |lua-special-tbl| for
|
|
||||||
more details.
|
|
||||||
|
|
||||||
vim.val_idx *vim.val_idx*
|
|
||||||
Value index for tables representing |Float|s. A table representing
|
|
||||||
floating-point value 1.0 looks like this: >
|
|
||||||
{
|
|
||||||
[vim.type_idx] = vim.types.float,
|
|
||||||
[vim.val_idx] = 1.0,
|
|
||||||
}
|
|
||||||
< See also |vim.type_idx| and |lua-special-tbl|.
|
|
||||||
|
|
||||||
vim.types *vim.types*
|
|
||||||
Table with possible values for |vim.type_idx|. Contains two sets
|
|
||||||
of key-value pairs: first maps possible values for |vim.type_idx|
|
|
||||||
to human-readable strings, second maps human-readable type names to
|
|
||||||
values for |vim.type_idx|. Currently contains pairs for `float`,
|
|
||||||
`array` and `dictionary` types.
|
|
||||||
|
|
||||||
Note: one must expect that values corresponding to `vim.types.float`,
|
|
||||||
`vim.types.array` and `vim.types.dictionary` fall under only two
|
|
||||||
following assumptions:
|
|
||||||
1. Value may serve both as a key and as a value in a table. Given the
|
|
||||||
properties of lua tables this basically means “value is not `nil`”.
|
|
||||||
2. For each value in `vim.types` table `vim.types[vim.types[value]]`
|
|
||||||
is the same as `value`.
|
|
||||||
No other restrictions are put on types, and it is not guaranteed that
|
|
||||||
values corresponding to `vim.types.float`, `vim.types.array` and
|
|
||||||
`vim.types.dictionary` will not change or that `vim.types` table will
|
|
||||||
only contain values for these three types.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
Lua module: vim *lua-vim*
|
|
||||||
|
|
||||||
inspect({object}, {options}) *vim.inspect()*
|
|
||||||
Return a human-readable representation of the given object.
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
https://github.com/kikito/inspect.lua
|
|
||||||
https://github.com/mpeterv/vinspect
|
|
||||||
|
|
||||||
paste({lines}, {phase}) *vim.paste()*
|
|
||||||
Paste handler, invoked by |nvim_paste()| when a conforming UI
|
|
||||||
(such as the |TUI|) pastes text into the editor.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{lines} |readfile()|-style list of lines to paste.
|
|
||||||
|channel-lines|
|
|
||||||
{phase} -1: "non-streaming" paste: the call contains all
|
|
||||||
lines. If paste is "streamed", `phase` indicates the stream state:
|
|
||||||
• 1: starts the paste (exactly once)
|
|
||||||
• 2: continues the paste (zero or more times)
|
|
||||||
• 3: ends the paste (exactly once)
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
false if client should cancel the paste.
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
|paste|
|
|
||||||
|
|
||||||
schedule_wrap({cb}) *vim.schedule_wrap()*
|
|
||||||
Defers callback `cb` until the Nvim API is safe to call.
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
|lua-loop-callbacks|
|
|
||||||
|vim.schedule()|
|
|
||||||
|vim.in_fast_event()|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
deepcopy({orig}) *vim.deepcopy()*
|
|
||||||
Returns a deep copy of the given object. Non-table objects are
|
|
||||||
copied as in a typical Lua assignment, whereas table objects
|
|
||||||
are copied recursively.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{orig} Table to copy
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
New table of copied keys and (nested) values.
|
|
||||||
|
|
||||||
gsplit({s}, {sep}, {plain}) *vim.gsplit()*
|
|
||||||
Splits a string at each instance of a separator.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{s} String to split
|
|
||||||
{sep} Separator string or pattern
|
|
||||||
{plain} If `true` use `sep` literally (passed to
|
|
||||||
String.find)
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
Iterator over the split components
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
|vim.split()|
|
|
||||||
https://www.lua.org/pil/20.2.html
|
|
||||||
http://lua-users.org/wiki/StringLibraryTutorial
|
|
||||||
|
|
||||||
split({s}, {sep}, {plain}) *vim.split()*
|
|
||||||
Splits a string at each instance of a separator.
|
|
||||||
|
|
||||||
Examples: >
|
|
||||||
split(":aa::b:", ":") --> {'','aa','','bb',''}
|
|
||||||
split("axaby", "ab?") --> {'','x','y'}
|
|
||||||
split(x*yz*o, "*", true) --> {'x','yz','o'}
|
|
||||||
<
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{s} String to split
|
|
||||||
{sep} Separator string or pattern
|
|
||||||
{plain} If `true` use `sep` literally (passed to
|
|
||||||
String.find)
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
List-like table of the split components.
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
|vim.gsplit()|
|
|
||||||
|
|
||||||
tbl_contains({t}, {value}) *vim.tbl_contains()*
|
|
||||||
Checks if a list-like (vector) table contains `value` .
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{t} Table to check
|
|
||||||
{value} Value to compare
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
true if `t` contains `value`
|
|
||||||
|
|
||||||
tbl_extend({behavior}, {...}) *vim.tbl_extend()*
|
|
||||||
Merges two or more map-like tables.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{behavior} Decides what to do if a key is found in more
|
|
||||||
than one map:
|
|
||||||
• "error": raise an error
|
|
||||||
• "keep": use value from the leftmost map
|
|
||||||
• "force": use value from the rightmost map
|
|
||||||
{...} Two or more map-like tables.
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
|extend()|
|
|
||||||
|
|
||||||
tbl_flatten({t}) *vim.tbl_flatten()*
|
|
||||||
Creates a copy of a list-like table such that any nested
|
|
||||||
tables are "unrolled" and appended to the result.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{t} List-like table
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
Flattened copy of the given list-like table.
|
|
||||||
|
|
||||||
trim({s}) *vim.trim()*
|
|
||||||
Trim whitespace (Lua pattern "%s") from both sides of a
|
|
||||||
string.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{s} String to trim
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
String with whitespace removed from its beginning and end
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
https://www.lua.org/pil/20.2.html
|
|
||||||
|
|
||||||
pesc({s}) *vim.pesc()*
|
|
||||||
Escapes magic chars in a Lua pattern string.
|
|
||||||
|
|
||||||
Parameters: ~
|
|
||||||
{s} String to escape
|
|
||||||
|
|
||||||
Return: ~
|
|
||||||
%-escaped pattern string
|
|
||||||
|
|
||||||
See also: ~
|
|
||||||
https://github.com/rxi/lume
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
|
||||||
|
@ -404,7 +404,7 @@ tag char note action in Normal mode ~
|
|||||||
|t| t{char} 1 cursor till before Nth occurrence of {char}
|
|t| t{char} 1 cursor till before Nth occurrence of {char}
|
||||||
to the right
|
to the right
|
||||||
|u| u 2 undo changes
|
|u| u 2 undo changes
|
||||||
|v| v start characterwise Visual mode
|
|v| v start charwise Visual mode
|
||||||
|w| w 1 cursor N words forward
|
|w| w 1 cursor N words forward
|
||||||
|x| ["x]x 2 delete N characters under and after the
|
|x| ["x]x 2 delete N characters under and after the
|
||||||
cursor [into register x]
|
cursor [into register x]
|
||||||
@ -767,6 +767,7 @@ tag char note action in Normal mode ~
|
|||||||
|gn| gn 1,2 find the next match with the last used
|
|gn| gn 1,2 find the next match with the last used
|
||||||
search pattern and Visually select it
|
search pattern and Visually select it
|
||||||
|gm| gm 1 go to character at middle of the screenline
|
|gm| gm 1 go to character at middle of the screenline
|
||||||
|
|gM| gM 1 go to character at middle of the text line
|
||||||
|go| go 1 cursor to byte N in the buffer
|
|go| go 1 cursor to byte N in the buffer
|
||||||
|gp| ["x]gp 2 put the text [from register x] after the
|
|gp| ["x]gp 2 put the text [from register x] after the
|
||||||
cursor N times, leave the cursor after it
|
cursor N times, leave the cursor after it
|
||||||
@ -865,7 +866,7 @@ These can be used after an operator, but before a {motion} has been entered.
|
|||||||
|
|
||||||
tag char action in Operator-pending mode ~
|
tag char action in Operator-pending mode ~
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|o_v| v force operator to work characterwise
|
|o_v| v force operator to work charwise
|
||||||
|o_V| V force operator to work linewise
|
|o_V| V force operator to work linewise
|
||||||
|o_CTRL-V| CTRL-V force operator to work blockwise
|
|o_CTRL-V| CTRL-V force operator to work blockwise
|
||||||
|
|
||||||
@ -977,7 +978,7 @@ tag command note action in Visual mode ~
|
|||||||
|v_r| r 2 replace highlighted area with a character
|
|v_r| r 2 replace highlighted area with a character
|
||||||
|v_s| s 2 delete highlighted area and start insert
|
|v_s| s 2 delete highlighted area and start insert
|
||||||
|v_u| u 2 make highlighted area lowercase
|
|v_u| u 2 make highlighted area lowercase
|
||||||
|v_v| v make Visual mode characterwise or stop
|
|v_v| v make Visual mode charwise or stop
|
||||||
Visual mode
|
Visual mode
|
||||||
|v_x| x 2 delete the highlighted area
|
|v_x| x 2 delete the highlighted area
|
||||||
|v_y| y yank the highlighted area
|
|v_y| y yank the highlighted area
|
||||||
@ -1163,11 +1164,13 @@ tag command action ~
|
|||||||
|:cNfile| :cNf[ile] go to last error in previous file
|
|:cNfile| :cNf[ile] go to last error in previous file
|
||||||
|:cabbrev| :ca[bbrev] like ":abbreviate" but for Command-line mode
|
|:cabbrev| :ca[bbrev] like ":abbreviate" but for Command-line mode
|
||||||
|:cabclear| :cabc[lear] clear all abbreviations for Command-line mode
|
|:cabclear| :cabc[lear] clear all abbreviations for Command-line mode
|
||||||
|
|:cabove| :cabo[ve] go to error above current line
|
||||||
|:caddbuffer| :cad[dbuffer] add errors from buffer
|
|:caddbuffer| :cad[dbuffer] add errors from buffer
|
||||||
|:caddexpr| :cadde[xpr] add errors from expr
|
|:caddexpr| :cadde[xpr] add errors from expr
|
||||||
|:caddfile| :caddf[ile] add error message to current quickfix list
|
|:caddfile| :caddf[ile] add error message to current quickfix list
|
||||||
|:call| :cal[l] call a function
|
|:call| :cal[l] call a function
|
||||||
|:catch| :cat[ch] part of a :try command
|
|:catch| :cat[ch] part of a :try command
|
||||||
|
|:cbelow| :cbe[low] go to error below current line
|
||||||
|:cbottom| :cbo[ttom] scroll to the bottom of the quickfix window
|
|:cbottom| :cbo[ttom] scroll to the bottom of the quickfix window
|
||||||
|:cbuffer| :cb[uffer] parse error messages and jump to first error
|
|:cbuffer| :cb[uffer] parse error messages and jump to first error
|
||||||
|:cc| :cc go to specific error
|
|:cc| :cc go to specific error
|
||||||
@ -1324,12 +1327,14 @@ tag command action ~
|
|||||||
|:lNext| :lN[ext] go to previous entry in location list
|
|:lNext| :lN[ext] go to previous entry in location list
|
||||||
|:lNfile| :lNf[ile] go to last entry in previous file
|
|:lNfile| :lNf[ile] go to last entry in previous file
|
||||||
|:list| :l[ist] print lines
|
|:list| :l[ist] print lines
|
||||||
|
|:labove| :lab[ove] go to location above current line
|
||||||
|:laddexpr| :lad[dexpr] add locations from expr
|
|:laddexpr| :lad[dexpr] add locations from expr
|
||||||
|:laddbuffer| :laddb[uffer] add locations from buffer
|
|:laddbuffer| :laddb[uffer] add locations from buffer
|
||||||
|:laddfile| :laddf[ile] add locations to current location list
|
|:laddfile| :laddf[ile] add locations to current location list
|
||||||
|:last| :la[st] go to the last file in the argument list
|
|:last| :la[st] go to the last file in the argument list
|
||||||
|:language| :lan[guage] set the language (locale)
|
|:language| :lan[guage] set the language (locale)
|
||||||
|:later| :lat[er] go to newer change, redo
|
|:later| :lat[er] go to newer change, redo
|
||||||
|
|:lbelow| :lbe[low] go to location below current line
|
||||||
|:lbottom| :lbo[ttom] scroll to the bottom of the location window
|
|:lbottom| :lbo[ttom] scroll to the bottom of the location window
|
||||||
|:lbuffer| :lb[uffer] parse locations and jump to first location
|
|:lbuffer| :lb[uffer] parse locations and jump to first location
|
||||||
|:lcd| :lc[d] change directory locally
|
|:lcd| :lc[d] change directory locally
|
||||||
|
@ -271,7 +271,7 @@ and <> are part of what you type, the context should make this clear.
|
|||||||
operator is pending.
|
operator is pending.
|
||||||
- Ex commands can be used to move the cursor. This can be
|
- Ex commands can be used to move the cursor. This can be
|
||||||
used to call a function that does some complicated motion.
|
used to call a function that does some complicated motion.
|
||||||
The motion is always characterwise exclusive, no matter
|
The motion is always charwise exclusive, no matter
|
||||||
what ":" command is used. This means it's impossible to
|
what ":" command is used. This means it's impossible to
|
||||||
include the last character of a line without the line break
|
include the last character of a line without the line break
|
||||||
(unless 'virtualedit' is set).
|
(unless 'virtualedit' is set).
|
||||||
@ -378,11 +378,11 @@ notation meaning equivalent decimal value(s) ~
|
|||||||
<kEqual> keypad = *keypad-equal*
|
<kEqual> keypad = *keypad-equal*
|
||||||
<kEnter> keypad Enter *keypad-enter*
|
<kEnter> keypad Enter *keypad-enter*
|
||||||
<k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9*
|
<k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9*
|
||||||
<S-...> shift-key *shift* *<S-*
|
<S-…> shift-key *shift* *<S-*
|
||||||
<C-...> control-key *control* *ctrl* *<C-*
|
<C-…> control-key *control* *ctrl* *<C-*
|
||||||
<M-...> alt-key or meta-key *META* *ALT* *<M-*
|
<M-…> alt-key or meta-key *META* *ALT* *<M-*
|
||||||
<A-...> same as <M-...> *<A-*
|
<A-…> same as <M-…> *<A-*
|
||||||
<D-...> command-key or "super" key *<D-*
|
<D-…> command-key or "super" key *<D-*
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
Note: The shifted cursor keys, the help key, and the undo key are only
|
Note: The shifted cursor keys, the help key, and the undo key are only
|
||||||
|
575
runtime/doc/lsp.txt
Normal file
575
runtime/doc/lsp.txt
Normal file
@ -0,0 +1,575 @@
|
|||||||
|
*lsp.txt* Nvim LSP API
|
||||||
|
|
||||||
|
NVIM REFERENCE MANUAL
|
||||||
|
|
||||||
|
|
||||||
|
Nvim Language Server Protocol (LSP) API *lsp*
|
||||||
|
|
||||||
|
Nvim is a client to the Language Server Protocol:
|
||||||
|
|
||||||
|
https://microsoft.github.io/language-server-protocol/
|
||||||
|
|
||||||
|
Type |gO| to see the table of contents.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
LANGUAGE SERVER PROTOCOL (LSP) CLIENT *lsp-intro*
|
||||||
|
|
||||||
|
The `vim.lsp` Lua module provides a flexible API for consuming LSP servers.
|
||||||
|
|
||||||
|
To use LSP in practice, a language server must be installed.
|
||||||
|
https://microsoft.github.io/language-server-protocol/implementors/servers/
|
||||||
|
|
||||||
|
After installing a language server to your machine, you must tell Nvim how to
|
||||||
|
start and interact with that language server.
|
||||||
|
- Easy way: use the configs provided here by the nvim-lsp plugin.
|
||||||
|
https://github.com/neovim/nvim-lsp
|
||||||
|
- Low-level way: use |vim.lsp.start_client()| and |vim.lsp.buf_attach_client()|
|
||||||
|
directly. Useful if you want to build advanced LSP plugins based on the
|
||||||
|
Nvim LSP module. |lsp-advanced-js-example|
|
||||||
|
|
||||||
|
*lsp-config*
|
||||||
|
Nvim LSP client will automatically provide inline diagnostics when available.
|
||||||
|
|lsp-callbacks| But you probably want to use other features too, such as
|
||||||
|
go-to-definition, "hover", etc. Example config: >
|
||||||
|
|
||||||
|
nnoremap <silent> gd <cmd>lua vim.lsp.buf.declaration()<CR>
|
||||||
|
nnoremap <silent> <c-]> <cmd>lua vim.lsp.buf.definition()<CR>
|
||||||
|
nnoremap <silent> K <cmd>lua vim.lsp.buf.hover()<CR>
|
||||||
|
nnoremap <silent> gD <cmd>lua vim.lsp.buf.implementation()<CR>
|
||||||
|
nnoremap <silent> <c-k> <cmd>lua vim.lsp.buf.signature_help()<CR>
|
||||||
|
nnoremap <silent> 1gD <cmd>lua vim.lsp.buf.type_definition()<CR>
|
||||||
|
|
||||||
|
<
|
||||||
|
*vim.lsp.omnifunc()*
|
||||||
|
Nvim provides the vim.lsp.omnifunc 'omnifunc' handler which allows
|
||||||
|
|i_CTRL-X_CTRL-O| to consume LSP completion features. Example config (note the
|
||||||
|
use of |v:lua| to call Lua from Vimscript): >
|
||||||
|
|
||||||
|
" Use LSP omni-completion in Python files.
|
||||||
|
autocmd Filetype python setlocal omnifunc=v:lua.vim.lsp.omnifunc
|
||||||
|
|
||||||
|
|
||||||
|
FAQ ~
|
||||||
|
|
||||||
|
> How to force-reload LSP?
|
||||||
|
|
||||||
|
Stop all clients, then reload the buffer. >
|
||||||
|
|
||||||
|
:lua vim.lsp.stop_all_clients()
|
||||||
|
:edit
|
||||||
|
|
||||||
|
> Why isn't completion working?
|
||||||
|
|
||||||
|
In the buffer where you want to use LSP, check that 'omnifunc' is set to
|
||||||
|
"v:lua.vim.lsp.omnifunc": >
|
||||||
|
|
||||||
|
:verbose set omnifunc?
|
||||||
|
|
||||||
|
Some other plugin may be overriding the option. To avoid that, you could set
|
||||||
|
the option in an |after-directory| ftplugin, e.g. "after/ftplugin/python.vim".
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
*lsp-core-api*
|
||||||
|
These are the core api functions for working with clients. You will mainly be
|
||||||
|
using |vim.lsp.start_client()| and |vim.lsp.buf_attach_client()| for operations
|
||||||
|
and |vim.lsp.get_client_by_id()| to retrieve a client by its id after it has
|
||||||
|
initialized (or {config.on_init}. see below)
|
||||||
|
|
||||||
|
*vim.lsp.start_client()*
|
||||||
|
|
||||||
|
vim.lsp.start_client({config})
|
||||||
|
|
||||||
|
The main function used for starting clients.
|
||||||
|
Start a client and initialize it.
|
||||||
|
|
||||||
|
Its arguments are passed via a configuration object {config}.
|
||||||
|
|
||||||
|
Mandatory parameters:~
|
||||||
|
|
||||||
|
`root_dir`
|
||||||
|
{string} specifying the directory where the LSP server will base
|
||||||
|
as its rootUri on initialization.
|
||||||
|
|
||||||
|
`cmd`
|
||||||
|
{string} or {list} which is the base command to execute for the LSP. A
|
||||||
|
string will be run using |'shell'| and a list will be interpreted as a
|
||||||
|
bare command with arguments passed. This is the same as |jobstart()|.
|
||||||
|
|
||||||
|
Optional parameters:~
|
||||||
|
|
||||||
|
`cmd_cwd`
|
||||||
|
{string} specifying the directory to launch the `cmd` process. This is not
|
||||||
|
related to `root_dir`.
|
||||||
|
By default, |getcwd()| is used.
|
||||||
|
|
||||||
|
`cmd_env`
|
||||||
|
{table} specifying the environment flags to pass to the LSP on spawn.
|
||||||
|
This can be specified using keys like a map or as a list with `k=v` pairs
|
||||||
|
or both. Non-string values are coerced to a string.
|
||||||
|
For example:
|
||||||
|
`{ "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; }`
|
||||||
|
|
||||||
|
`capabilities`
|
||||||
|
A {table} which will be used instead of
|
||||||
|
`vim.lsp.protocol.make_client_capabilities()` which contains Nvim's
|
||||||
|
default capabilities and passed to the language server on initialization.
|
||||||
|
You'll probably want to use make_client_capabilities() and modify the
|
||||||
|
result.
|
||||||
|
NOTE:
|
||||||
|
To send an empty dictionary, you should use
|
||||||
|
`{[vim.type_idx]=vim.types.dictionary}` Otherwise, it will be encoded as
|
||||||
|
an array.
|
||||||
|
|
||||||
|
`callbacks`
|
||||||
|
A {table} of whose keys are language server method names and the values
|
||||||
|
are `function(err, method, params, client_id)` See |lsp-callbacks| for
|
||||||
|
more. This will be combined with |lsp-default-callbacks| to resolve
|
||||||
|
the callbacks for a client as a fallback.
|
||||||
|
|
||||||
|
`init_options`
|
||||||
|
A {table} of values to pass in the initialization request as
|
||||||
|
`initializationOptions`. See the `initialize` in the LSP spec.
|
||||||
|
|
||||||
|
`name`
|
||||||
|
A {string} used in log messages. Defaults to {client_id}
|
||||||
|
|
||||||
|
`offset_encoding`
|
||||||
|
One of "utf-8", "utf-16", or "utf-32" which is the encoding that the LSP
|
||||||
|
server expects.
|
||||||
|
The default encoding for Language Server Protocol is UTF-16, but there are
|
||||||
|
language servers which may use other encodings.
|
||||||
|
By default, it is "utf-16" as specified in the LSP specification. The
|
||||||
|
client does not verify this is correct.
|
||||||
|
|
||||||
|
`on_error(code, ...)`
|
||||||
|
A function for handling errors thrown by client operation. {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.
|
||||||
|
`vim.lsp.client_errors[code]` can be used to retrieve a human
|
||||||
|
understandable string.
|
||||||
|
|
||||||
|
`before_init(initialize_params, config)`
|
||||||
|
A function which is called *before* the request `initialize` is completed.
|
||||||
|
`initialize_params` contains the parameters we are sending to the server
|
||||||
|
and `config` is the config that was passed to `start_client()` for
|
||||||
|
convenience. You can use this to modify parameters before they are sent.
|
||||||
|
|
||||||
|
`on_init(client, initialize_result)`
|
||||||
|
A function which is called after the request `initialize` is completed.
|
||||||
|
`initialize_result` contains `capabilities` and anything else the server
|
||||||
|
may send. For example, `clangd` sends `initialize_result.offsetEncoding`
|
||||||
|
if `capabilities.offsetEncoding` was sent to it. You can *only* modify the
|
||||||
|
`client.offset_encoding` here before any notifications are sent.
|
||||||
|
|
||||||
|
`on_attach(client, bufnr)`
|
||||||
|
A function which is called after the client is attached to a buffer.
|
||||||
|
|
||||||
|
`on_exit(code, signal, client_id)`
|
||||||
|
A function which is called after the client has exited. code is the exit
|
||||||
|
code of the process, and signal is a number describing the signal used to
|
||||||
|
terminate (if any).
|
||||||
|
|
||||||
|
`trace`
|
||||||
|
"off" | "messages" | "verbose" | nil passed directly to the language
|
||||||
|
server in the initialize request.
|
||||||
|
Invalid/empty values will default to "off"
|
||||||
|
|
||||||
|
Returns:~
|
||||||
|
{client_id}
|
||||||
|
You can use |vim.lsp.get_client_by_id()| to get the actual client object.
|
||||||
|
See |lsp-client| for what the client structure will be.
|
||||||
|
|
||||||
|
NOTE: The client is only available *after* it has been initialized, which
|
||||||
|
may happen after a small delay (or never if there is an error). For this
|
||||||
|
reason, you may want to use `on_init` to do any actions once the client has
|
||||||
|
been initialized.
|
||||||
|
|
||||||
|
*lsp-client*
|
||||||
|
|
||||||
|
The client object has some methods and members related to using the client.
|
||||||
|
|
||||||
|
Methods:~
|
||||||
|
|
||||||
|
`request(method, params, [callback])`
|
||||||
|
Send a request to the server. If callback is not specified, it will use
|
||||||
|
{client.callbacks} to try to find a callback. If one is not found there,
|
||||||
|
then an error will occur.
|
||||||
|
This is a thin wrapper around {client.rpc.request} with some additional
|
||||||
|
checking.
|
||||||
|
Returns a boolean to indicate if the notification was successful. If it
|
||||||
|
is false, then it will always be false (the client has shutdown).
|
||||||
|
If it was successful, then it will return the request id as the second
|
||||||
|
result. You can use this with `notify("$/cancel", { id = request_id })`
|
||||||
|
to cancel the request. This helper is made automatically with
|
||||||
|
|vim.lsp.buf_request()|
|
||||||
|
Returns: status, [client_id]
|
||||||
|
|
||||||
|
`notify(method, params)`
|
||||||
|
This is just {client.rpc.notify}()
|
||||||
|
Returns a boolean to indicate if the notification was successful. If it
|
||||||
|
is false, then it will always be false (the client has shutdown).
|
||||||
|
Returns: status
|
||||||
|
|
||||||
|
`cancel_request(id)`
|
||||||
|
This is just {client.rpc.notify}("$/cancelRequest", { id = id })
|
||||||
|
Returns the same as `notify()`.
|
||||||
|
|
||||||
|
`stop([force])`
|
||||||
|
Stop a client, optionally with force.
|
||||||
|
By default, it will just ask the server to shutdown without force.
|
||||||
|
If you request to stop a client which has previously been requested to
|
||||||
|
shutdown, it will automatically escalate and force shutdown.
|
||||||
|
|
||||||
|
`is_stopped()`
|
||||||
|
Returns true if the client is fully stopped.
|
||||||
|
|
||||||
|
Members: ~
|
||||||
|
`id` (number)
|
||||||
|
The id allocated to the client.
|
||||||
|
|
||||||
|
`name` (string)
|
||||||
|
If a name is specified on creation, that will be used. Otherwise it is
|
||||||
|
just the client id. This is used for logs and messages.
|
||||||
|
|
||||||
|
`offset_encoding` (string)
|
||||||
|
The encoding used for communicating with the server. You can modify this
|
||||||
|
in the `on_init` method before text is sent to the server.
|
||||||
|
|
||||||
|
`callbacks` (table)
|
||||||
|
The callbacks used by the client as described in |lsp-callbacks|.
|
||||||
|
|
||||||
|
`config` (table)
|
||||||
|
A copy of the table that was passed by the user to
|
||||||
|
|vim.lsp.start_client()|.
|
||||||
|
|
||||||
|
`server_capabilities` (table)
|
||||||
|
The response from the server sent on `initialize` describing the
|
||||||
|
server's capabilities.
|
||||||
|
|
||||||
|
`resolved_capabilities` (table)
|
||||||
|
A normalized table of capabilities that we have detected based on the
|
||||||
|
initialize response from the server in `server_capabilities`.
|
||||||
|
|
||||||
|
|
||||||
|
*vim.lsp.buf_attach_client()*
|
||||||
|
vim.lsp.buf_attach_client({bufnr}, {client_id})
|
||||||
|
|
||||||
|
Implements the `textDocument/did*` notifications required to track a buffer
|
||||||
|
for any language server.
|
||||||
|
|
||||||
|
Without calling this, the server won't be notified of changes to a buffer.
|
||||||
|
|
||||||
|
*vim.lsp.get_client_by_id()*
|
||||||
|
vim.lsp.get_client_by_id({client_id})
|
||||||
|
|
||||||
|
Look up an active client by its id, returns nil if it is not yet initialized
|
||||||
|
or is not a valid id. Returns |lsp-client|
|
||||||
|
|
||||||
|
*vim.lsp.stop_client()*
|
||||||
|
vim.lsp.stop_client({client_id}, [{force}])
|
||||||
|
|
||||||
|
Stop a client, optionally with force.
|
||||||
|
By default, it will just ask the server to shutdown without force.
|
||||||
|
If you request to stop a client which has previously been requested to
|
||||||
|
shutdown, it will automatically escalate and force shutdown.
|
||||||
|
|
||||||
|
You can also use `client.stop()` if you have access to the client.
|
||||||
|
|
||||||
|
*vim.lsp.stop_all_clients()*
|
||||||
|
vim.lsp.stop_all_clients([{force}])
|
||||||
|
|
||||||
|
|vim.lsp.stop_client()|, but for all active clients.
|
||||||
|
|
||||||
|
*vim.lsp.get_active_clients()*
|
||||||
|
vim.lsp.get_active_clients()
|
||||||
|
|
||||||
|
Return a list of all of the active clients. See |lsp-client| for a
|
||||||
|
description of what a client looks like.
|
||||||
|
|
||||||
|
*vim.lsp.rpc_response_error()*
|
||||||
|
vim.lsp.rpc_response_error({code}, [{message}], [{data}])
|
||||||
|
|
||||||
|
Helper function to create an RPC response object/table. This is an alias for
|
||||||
|
|vim.lsp.rpc.rpc_response_error|. Code must be an RPC error code as
|
||||||
|
described in `vim.lsp.protocol.ErrorCodes`.
|
||||||
|
|
||||||
|
You can describe an optional {message} string or arbitrary {data} to send to
|
||||||
|
the server.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
LSP CALLBACKS *lsp-callbacks*
|
||||||
|
|
||||||
|
DEFAULT CALLBACKS ~
|
||||||
|
*vim.lsp.callbacks*
|
||||||
|
The `vim.lsp.callbacks` table defines default callbacks used when
|
||||||
|
creating a new client. Keys are LSP method names: >
|
||||||
|
|
||||||
|
:lua print(vim.inspect(vim.tbl_keys(vim.lsp.callbacks)))
|
||||||
|
|
||||||
|
These LSP requests/notifications are defined by default:
|
||||||
|
|
||||||
|
textDocument/publishDiagnostics
|
||||||
|
window/logMessage
|
||||||
|
window/showMessage
|
||||||
|
|
||||||
|
You can check these via `vim.tbl_keys(vim.lsp.callbacks)`.
|
||||||
|
|
||||||
|
These will be used preferrentially in `vim.lsp.buf` methods when handling
|
||||||
|
requests. They will also be used when responding to server requests and
|
||||||
|
notifications.
|
||||||
|
|
||||||
|
Use cases:
|
||||||
|
- Users can modify this to customize to their preferences.
|
||||||
|
- UI plugins can modify this by assigning to
|
||||||
|
`vim.lsp.callbacks[method]` so as to provide more specialized
|
||||||
|
handling, allowing you to leverage the UI capabilities available. UIs should
|
||||||
|
try to be conscientious of any existing changes the user may have set
|
||||||
|
already by checking for existing values.
|
||||||
|
|
||||||
|
Any callbacks passed directly to `request` methods on a server client will
|
||||||
|
have the highest precedence, followed by the `callbacks`.
|
||||||
|
|
||||||
|
You can override the default handlers,
|
||||||
|
- globally: by modifying the `vim.lsp.callbacks` table
|
||||||
|
- per-client: by passing the {callbacks} table parameter to
|
||||||
|
|vim.lsp.start_client|
|
||||||
|
|
||||||
|
Each handler has this signature: >
|
||||||
|
|
||||||
|
function(err, method, params, client_id)
|
||||||
|
|
||||||
|
Callbacks are functions which are called in a variety of situations by the
|
||||||
|
client. Their signature is `function(err, method, params, client_id)` They can
|
||||||
|
be set by the {callbacks} parameter for |vim.lsp.start_client| or via the
|
||||||
|
|vim.lsp.callbacks|.
|
||||||
|
|
||||||
|
Handlers are called for:
|
||||||
|
- Notifications from the server (`err` is always `nil`).
|
||||||
|
- Requests initiated by the server (`err` is always `nil`).
|
||||||
|
The handler can respond by returning two values: `result, err`
|
||||||
|
where `err` must be shaped like an RPC error:
|
||||||
|
`{ code, message, data? }`
|
||||||
|
You can use |vim.lsp.rpc_response_error()| to create this object.
|
||||||
|
- Handling requests initiated by the client if the request doesn't explicitly
|
||||||
|
specify a callback (such as in |vim.lsp.buf_request|).
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
VIM.LSP.PROTOCOL *vim.lsp.protocol*
|
||||||
|
|
||||||
|
The `vim.lsp.protocol` module provides constants defined in the LSP
|
||||||
|
specification, and helper functions for creating protocol-related objects.
|
||||||
|
|
||||||
|
https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
|
||||||
|
|
||||||
|
Useful examples are `vim.lsp.protocol.ErrorCodes`. These objects allow reverse
|
||||||
|
lookup by either the number or string name.
|
||||||
|
|
||||||
|
e.g. vim.lsp.protocol.TextDocumentSyncKind.Full == 1
|
||||||
|
vim.lsp.protocol.TextDocumentSyncKind[1] == "Full"
|
||||||
|
|
||||||
|
Utility functions used internally are:
|
||||||
|
`vim.lsp.protocol.make_client_capabilities()`
|
||||||
|
Make a ClientCapabilities object. These are the builtin
|
||||||
|
capabilities.
|
||||||
|
`vim.lsp.protocol.resolve_capabilities(server_capabilites)`
|
||||||
|
Creates a normalized object describing capabilities from the server
|
||||||
|
capabilities.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
*vim.lsp.util*
|
||||||
|
|
||||||
|
TODO: Describe the utils here for handling/applying things from LSP.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
*lsp-buf-methods*
|
||||||
|
There are methods which operate on the buffer level for all of the active
|
||||||
|
clients attached to the buffer.
|
||||||
|
|
||||||
|
*vim.lsp.buf_request()*
|
||||||
|
vim.lsp.buf_request({bufnr}, {method}, {params}, [{callback}])
|
||||||
|
Send a async request for all the clients active and attached to the buffer.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{bufnr}: The buffer handle or 0 for the current buffer.
|
||||||
|
|
||||||
|
{method}: The LSP method name.
|
||||||
|
|
||||||
|
{params}: The parameters to send.
|
||||||
|
|
||||||
|
{callback}: An optional `function(err, method, params, client_id)` which
|
||||||
|
will be called for this request. If you do not specify it, then it will
|
||||||
|
use the client's callback in {client.callbacks}. See |lsp-callbacks| for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
Returns:~
|
||||||
|
|
||||||
|
A table from client id to the request id for all of the successful
|
||||||
|
requests.
|
||||||
|
|
||||||
|
The second result is a function which can be used to cancel all the
|
||||||
|
requests. You can do this individually with `client.cancel_request()`
|
||||||
|
|
||||||
|
*vim.lsp.buf_request_sync()*
|
||||||
|
vim.lsp.buf_request_sync({bufnr}, {method}, {params}, [{timeout_ms}])
|
||||||
|
Calls |vim.lsp.buf_request()|, but it will wait for the result and block Vim
|
||||||
|
in the process.
|
||||||
|
The parameters are the same as |vim.lsp.buf_request()|, but the return
|
||||||
|
result is different.
|
||||||
|
It will wait maximum of {timeout_ms} which defaults to 100ms.
|
||||||
|
|
||||||
|
Returns:~
|
||||||
|
|
||||||
|
If the timeout is exceeded or a cancel is sent or an error, it will cancel
|
||||||
|
the request and return `nil, err` where `err` is a string that describes
|
||||||
|
the reason why it failed.
|
||||||
|
|
||||||
|
If it is successful, it will return a table from client id to result id.
|
||||||
|
|
||||||
|
*vim.lsp.buf_notify()*
|
||||||
|
vim.lsp.buf_notify({bufnr}, {method}, {params})
|
||||||
|
Send a notification to all servers on the buffer.
|
||||||
|
|
||||||
|
Parameters: ~
|
||||||
|
{bufnr}: The buffer handle or 0 for the current buffer.
|
||||||
|
|
||||||
|
{method}: The LSP method name.
|
||||||
|
|
||||||
|
{params}: The parameters to send.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
*lsp-logging*
|
||||||
|
|
||||||
|
*vim.lsp.set_log_level()*
|
||||||
|
vim.lsp.set_log_level({level})
|
||||||
|
You can set the log level for language server client logging.
|
||||||
|
Possible values: "trace", "debug", "info", "warn", "error"
|
||||||
|
|
||||||
|
Default: "warn"
|
||||||
|
|
||||||
|
Example: `lua vim.lsp.set_log_level("debug")`
|
||||||
|
|
||||||
|
*vim.lsp.get_log_path()*
|
||||||
|
vim.lsp.get_log_path()
|
||||||
|
Returns the path that LSP logs are written.
|
||||||
|
|
||||||
|
*vim.lsp.log_levels*
|
||||||
|
vim.lsp.log_levels
|
||||||
|
Log level dictionary with reverse lookup as well.
|
||||||
|
|
||||||
|
Can be used to lookup the number from the name or vice-versa.
|
||||||
|
Levels: "trace" (0), "debug" (1), "info" (2), "warn" (3), "error" (4)
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
LSP EXAMPLE *lsp-advanced-js-example*
|
||||||
|
|
||||||
|
For more advanced configurations where just filtering by filetype isn't
|
||||||
|
sufficient, you can use the `vim.lsp.start_client()` and
|
||||||
|
`vim.lsp.buf_attach_client()` commands to easily customize the configuration
|
||||||
|
however you please. For example, if you want to do your own filtering, or
|
||||||
|
start a new LSP client based on the root directory for if you plan to work
|
||||||
|
with multiple projects in a single session. Below is a fully working Lua
|
||||||
|
example which can do exactly that.
|
||||||
|
|
||||||
|
The example will:
|
||||||
|
1. Check for each new buffer whether or not we want to start an LSP client.
|
||||||
|
2. Try to find a root directory by ascending from the buffer's path.
|
||||||
|
3. Create a new LSP for that root directory if one doesn't exist.
|
||||||
|
4. Attach the buffer to the client for that root directory.
|
||||||
|
|
||||||
|
>
|
||||||
|
-- Some path manipulation utilities
|
||||||
|
local function is_dir(filename)
|
||||||
|
local stat = vim.loop.fs_stat(filename)
|
||||||
|
return stat and stat.type == 'directory' or false
|
||||||
|
end
|
||||||
|
|
||||||
|
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
|
||||||
|
-- Asumes filepath is a file.
|
||||||
|
local function dirname(filepath)
|
||||||
|
local is_changed = false
|
||||||
|
local result = filepath:gsub(path_sep.."([^"..path_sep.."]+)$", function()
|
||||||
|
is_changed = true
|
||||||
|
return ""
|
||||||
|
end)
|
||||||
|
return result, is_changed
|
||||||
|
end
|
||||||
|
|
||||||
|
local function path_join(...)
|
||||||
|
return table.concat(vim.tbl_flatten {...}, path_sep)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ascend the buffer's path until we find the rootdir.
|
||||||
|
-- is_root_path is a function which returns bool
|
||||||
|
local function buffer_find_root_dir(bufnr, is_root_path)
|
||||||
|
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
||||||
|
if vim.fn.filereadable(bufname) == 0 then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local dir = bufname
|
||||||
|
-- Just in case our algo is buggy, don't infinite loop.
|
||||||
|
for _ = 1, 100 do
|
||||||
|
local did_change
|
||||||
|
dir, did_change = dirname(dir)
|
||||||
|
if is_root_path(dir, bufname) then
|
||||||
|
return dir, bufname
|
||||||
|
end
|
||||||
|
-- If we can't ascend further, then stop looking.
|
||||||
|
if not did_change then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- A table to store our root_dir to client_id lookup. We want one LSP per
|
||||||
|
-- root directory, and this is how we assert that.
|
||||||
|
local javascript_lsps = {}
|
||||||
|
-- Which filetypes we want to consider.
|
||||||
|
local javascript_filetypes = {
|
||||||
|
["javascript.jsx"] = true;
|
||||||
|
["javascript"] = true;
|
||||||
|
["typescript"] = true;
|
||||||
|
["typescript.jsx"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Create a template configuration for a server to start, minus the root_dir
|
||||||
|
-- which we will specify later.
|
||||||
|
local javascript_lsp_config = {
|
||||||
|
name = "javascript";
|
||||||
|
cmd = { path_join(os.getenv("JAVASCRIPT_LANGUAGE_SERVER_DIRECTORY"), "lib", "language-server-stdio.js") };
|
||||||
|
}
|
||||||
|
|
||||||
|
-- This needs to be global so that we can call it from the autocmd.
|
||||||
|
function check_start_javascript_lsp()
|
||||||
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
|
-- Filter which files we are considering.
|
||||||
|
if not javascript_filetypes[vim.api.nvim_buf_get_option(bufnr, 'filetype')] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Try to find our root directory. We will define this as a directory which contains
|
||||||
|
-- node_modules. Another choice would be to check for `package.json`, or for `.git`.
|
||||||
|
local root_dir = buffer_find_root_dir(bufnr, function(dir)
|
||||||
|
return is_dir(path_join(dir, 'node_modules'))
|
||||||
|
-- return vim.fn.filereadable(path_join(dir, 'package.json')) == 1
|
||||||
|
-- return is_dir(path_join(dir, '.git'))
|
||||||
|
end)
|
||||||
|
-- We couldn't find a root directory, so ignore this file.
|
||||||
|
if not root_dir then return end
|
||||||
|
|
||||||
|
-- Check if we have a client alredy or start and store it.
|
||||||
|
local client_id = javascript_lsps[root_dir]
|
||||||
|
if not client_id then
|
||||||
|
local new_config = vim.tbl_extend("error", javascript_lsp_config, {
|
||||||
|
root_dir = root_dir;
|
||||||
|
})
|
||||||
|
client_id = vim.lsp.start_client(new_config)
|
||||||
|
javascript_lsps[root_dir] = client_id
|
||||||
|
end
|
||||||
|
-- Finally, attach to the buffer to track changes. This will do nothing if we
|
||||||
|
-- are already attached.
|
||||||
|
vim.lsp.buf_attach_client(bufnr, client_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_command [[autocmd BufReadPost * lua check_start_javascript_lsp()]]
|
||||||
|
<
|
||||||
|
|
||||||
|
vim:tw=78:ts=8:ft=help:norl:
|
1001
runtime/doc/lua.txt
Normal file
1001
runtime/doc/lua.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -786,7 +786,7 @@ g@{motion} Call the function set by the 'operatorfunc' option.
|
|||||||
character of the text.
|
character of the text.
|
||||||
The function is called with one String argument:
|
The function is called with one String argument:
|
||||||
"line" {motion} was |linewise|
|
"line" {motion} was |linewise|
|
||||||
"char" {motion} was |characterwise|
|
"char" {motion} was |charwise|
|
||||||
"block" {motion} was |blockwise-visual|
|
"block" {motion} was |blockwise-visual|
|
||||||
Although "block" would rarely appear, since it can
|
Although "block" would rarely appear, since it can
|
||||||
only result from Visual mode where "g@" is not useful.
|
only result from Visual mode where "g@" is not useful.
|
||||||
|
@ -556,7 +556,8 @@ allowed for the command that was used.
|
|||||||
Vim was not able to create a swap file. You can still edit the file, but if
|
Vim was not able to create a swap file. You can still edit the file, but if
|
||||||
Vim unexpectedly exits the changes will be lost. And Vim may consume a lot of
|
Vim unexpectedly exits the changes will be lost. And Vim may consume a lot of
|
||||||
memory when editing a big file. You may want to change the 'directory' option
|
memory when editing a big file. You may want to change the 'directory' option
|
||||||
to avoid this error. See |swap-file|.
|
to avoid this error. This error is not given when 'directory' is empty. See
|
||||||
|
|swap-file|.
|
||||||
|
|
||||||
*E140* >
|
*E140* >
|
||||||
Use ! to write partial buffer
|
Use ! to write partial buffer
|
||||||
@ -678,8 +679,8 @@ no argument has been specified.
|
|||||||
Invalid argument: {arg}
|
Invalid argument: {arg}
|
||||||
Duplicate argument: {arg}
|
Duplicate argument: {arg}
|
||||||
|
|
||||||
An Ex command or function has been executed, but an invalid argument has been
|
Ex command or function has been executed, but an invalid argument was
|
||||||
specified.
|
specified. Or a non-executable command was given to |system()|.
|
||||||
|
|
||||||
*E488* >
|
*E488* >
|
||||||
Trailing characters
|
Trailing characters
|
||||||
|
@ -60,11 +60,11 @@ After applying the operator the cursor is mostly left at the start of the text
|
|||||||
that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe"
|
that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe"
|
||||||
moves the cursor leftwards to the "e" where the yank started.
|
moves the cursor leftwards to the "e" where the yank started.
|
||||||
|
|
||||||
*linewise* *characterwise*
|
*linewise* *charwise* *characterwise*
|
||||||
The operator either affects whole lines, or the characters between the start
|
The operator either affects whole lines, or the characters between the start
|
||||||
and end position. Generally, motions that move between lines affect lines
|
and end position. Generally, motions that move between lines affect lines
|
||||||
(are linewise), and motions that move within a line affect characters (are
|
(are linewise), and motions that move within a line affect characters (are
|
||||||
characterwise). However, there are some exceptions.
|
charwise). However, there are some exceptions.
|
||||||
|
|
||||||
*exclusive* *inclusive*
|
*exclusive* *inclusive*
|
||||||
Character motion is either inclusive or exclusive. When inclusive, the
|
Character motion is either inclusive or exclusive. When inclusive, the
|
||||||
@ -106,10 +106,10 @@ This cannot be repeated: >
|
|||||||
d:if 1<CR>
|
d:if 1<CR>
|
||||||
call search("f")<CR>
|
call search("f")<CR>
|
||||||
endif<CR>
|
endif<CR>
|
||||||
Note that when using ":" any motion becomes characterwise exclusive.
|
Note that when using ":" any motion becomes charwise exclusive.
|
||||||
|
|
||||||
*forced-motion*
|
*forced-motion*
|
||||||
FORCING A MOTION TO BE LINEWISE, CHARACTERWISE OR BLOCKWISE
|
FORCING A MOTION TO BE LINEWISE, CHARWISE OR BLOCKWISE
|
||||||
|
|
||||||
When a motion is not of the type you would like to use, you can force another
|
When a motion is not of the type you would like to use, you can force another
|
||||||
type by using "v", "V" or CTRL-V just after the operator.
|
type by using "v", "V" or CTRL-V just after the operator.
|
||||||
@ -121,22 +121,22 @@ deletes from the cursor position until the character below the cursor >
|
|||||||
d<C-V>j
|
d<C-V>j
|
||||||
deletes the character under the cursor and the character below the cursor. >
|
deletes the character under the cursor and the character below the cursor. >
|
||||||
|
|
||||||
Be careful with forcing a linewise movement to be used characterwise or
|
Be careful with forcing a linewise movement to be used charwise or blockwise,
|
||||||
blockwise, the column may not always be defined.
|
the column may not always be defined.
|
||||||
|
|
||||||
*o_v*
|
*o_v*
|
||||||
v When used after an operator, before the motion command: Force
|
v When used after an operator, before the motion command: Force
|
||||||
the operator to work characterwise, also when the motion is
|
the operator to work charwise, also when the motion is
|
||||||
linewise. If the motion was linewise, it will become
|
linewise. If the motion was linewise, it will become
|
||||||
|exclusive|.
|
|exclusive|.
|
||||||
If the motion already was characterwise, toggle
|
If the motion already was charwise, toggle
|
||||||
inclusive/exclusive. This can be used to make an exclusive
|
inclusive/exclusive. This can be used to make an exclusive
|
||||||
motion inclusive and an inclusive motion exclusive.
|
motion inclusive and an inclusive motion exclusive.
|
||||||
|
|
||||||
*o_V*
|
*o_V*
|
||||||
V When used after an operator, before the motion command: Force
|
V When used after an operator, before the motion command: Force
|
||||||
the operator to work linewise, also when the motion is
|
the operator to work linewise, also when the motion is
|
||||||
characterwise.
|
charwise.
|
||||||
|
|
||||||
*o_CTRL-V*
|
*o_CTRL-V*
|
||||||
CTRL-V When used after an operator, before the motion command: Force
|
CTRL-V When used after an operator, before the motion command: Force
|
||||||
@ -219,6 +219,12 @@ g^ When lines wrap ('wrap' on): To the first non-blank
|
|||||||
gm Like "g0", but half a screenwidth to the right (or as
|
gm Like "g0", but half a screenwidth to the right (or as
|
||||||
much as possible).
|
much as possible).
|
||||||
|
|
||||||
|
*gM*
|
||||||
|
gM Like "g0", but to halfway the text of the line.
|
||||||
|
With a count: to this percentage of text in the line.
|
||||||
|
Thus "10gM" is near the start of the text and "90gM"
|
||||||
|
is near the end of the text.
|
||||||
|
|
||||||
*g$* *g<End>*
|
*g$* *g<End>*
|
||||||
g$ or g<End> When lines wrap ('wrap' on): To the last character of
|
g$ or g<End> When lines wrap ('wrap' on): To the last character of
|
||||||
the screen line and [count - 1] screen lines downward
|
the screen line and [count - 1] screen lines downward
|
||||||
@ -412,35 +418,35 @@ between Vi and Vim.
|
|||||||
5. Text object motions *object-motions*
|
5. Text object motions *object-motions*
|
||||||
|
|
||||||
*(*
|
*(*
|
||||||
( [count] sentences backward. |exclusive| motion.
|
( [count] |sentence|s backward. |exclusive| motion.
|
||||||
|
|
||||||
*)*
|
*)*
|
||||||
) [count] sentences forward. |exclusive| motion.
|
) [count] |sentence|s forward. |exclusive| motion.
|
||||||
|
|
||||||
*{*
|
*{*
|
||||||
{ [count] paragraphs backward. |exclusive| motion.
|
{ [count] |paragraph|s backward. |exclusive| motion.
|
||||||
|
|
||||||
*}*
|
*}*
|
||||||
} [count] paragraphs forward. |exclusive| motion.
|
} [count] |paragraph|s forward. |exclusive| motion.
|
||||||
|
|
||||||
*]]*
|
*]]*
|
||||||
]] [count] sections forward or to the next '{' in the
|
]] [count] |section|s forward or to the next '{' in the
|
||||||
first column. When used after an operator, then also
|
first column. When used after an operator, then also
|
||||||
stops below a '}' in the first column. |exclusive|
|
stops below a '}' in the first column. |exclusive|
|
||||||
Note that |exclusive-linewise| often applies.
|
Note that |exclusive-linewise| often applies.
|
||||||
|
|
||||||
*][*
|
*][*
|
||||||
][ [count] sections forward or to the next '}' in the
|
][ [count] |section|s forward or to the next '}' in the
|
||||||
first column. |exclusive|
|
first column. |exclusive|
|
||||||
Note that |exclusive-linewise| often applies.
|
Note that |exclusive-linewise| often applies.
|
||||||
|
|
||||||
*[[*
|
*[[*
|
||||||
[[ [count] sections backward or to the previous '{' in
|
[[ [count] |section|s backward or to the previous '{' in
|
||||||
the first column. |exclusive|
|
the first column. |exclusive|
|
||||||
Note that |exclusive-linewise| often applies.
|
Note that |exclusive-linewise| often applies.
|
||||||
|
|
||||||
*[]*
|
*[]*
|
||||||
[] [count] sections backward or to the previous '}' in
|
[] [count] |section|s backward or to the previous '}' in
|
||||||
the first column. |exclusive|
|
the first column. |exclusive|
|
||||||
Note that |exclusive-linewise| often applies.
|
Note that |exclusive-linewise| often applies.
|
||||||
|
|
||||||
@ -502,36 +508,36 @@ aw "a word", select [count] words (see |word|).
|
|||||||
Leading or trailing white space is included, but not
|
Leading or trailing white space is included, but not
|
||||||
counted.
|
counted.
|
||||||
When used in Visual linewise mode "aw" switches to
|
When used in Visual linewise mode "aw" switches to
|
||||||
Visual characterwise mode.
|
Visual charwise mode.
|
||||||
|
|
||||||
*v_iw* *iw*
|
*v_iw* *iw*
|
||||||
iw "inner word", select [count] words (see |word|).
|
iw "inner word", select [count] words (see |word|).
|
||||||
White space between words is counted too.
|
White space between words is counted too.
|
||||||
When used in Visual linewise mode "iw" switches to
|
When used in Visual linewise mode "iw" switches to
|
||||||
Visual characterwise mode.
|
Visual charwise mode.
|
||||||
|
|
||||||
*v_aW* *aW*
|
*v_aW* *aW*
|
||||||
aW "a WORD", select [count] WORDs (see |WORD|).
|
aW "a WORD", select [count] WORDs (see |WORD|).
|
||||||
Leading or trailing white space is included, but not
|
Leading or trailing white space is included, but not
|
||||||
counted.
|
counted.
|
||||||
When used in Visual linewise mode "aW" switches to
|
When used in Visual linewise mode "aW" switches to
|
||||||
Visual characterwise mode.
|
Visual charwise mode.
|
||||||
|
|
||||||
*v_iW* *iW*
|
*v_iW* *iW*
|
||||||
iW "inner WORD", select [count] WORDs (see |WORD|).
|
iW "inner WORD", select [count] WORDs (see |WORD|).
|
||||||
White space between words is counted too.
|
White space between words is counted too.
|
||||||
When used in Visual linewise mode "iW" switches to
|
When used in Visual linewise mode "iW" switches to
|
||||||
Visual characterwise mode.
|
Visual charwise mode.
|
||||||
|
|
||||||
*v_as* *as*
|
*v_as* *as*
|
||||||
as "a sentence", select [count] sentences (see
|
as "a sentence", select [count] sentences (see
|
||||||
|sentence|).
|
|sentence|).
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
*v_is* *is*
|
*v_is* *is*
|
||||||
is "inner sentence", select [count] sentences (see
|
is "inner sentence", select [count] sentences (see
|
||||||
|sentence|).
|
|sentence|).
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
*v_ap* *ap*
|
*v_ap* *ap*
|
||||||
ap "a paragraph", select [count] paragraphs (see
|
ap "a paragraph", select [count] paragraphs (see
|
||||||
@ -552,14 +558,14 @@ a[ "a [] block", select [count] '[' ']' blocks. This
|
|||||||
goes backwards to the [count] unclosed '[', and finds
|
goes backwards to the [count] unclosed '[', and finds
|
||||||
the matching ']'. The enclosed text is selected,
|
the matching ']'. The enclosed text is selected,
|
||||||
including the '[' and ']'.
|
including the '[' and ']'.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
i] *v_i]* *v_i[* *i]* *i[*
|
i] *v_i]* *v_i[* *i]* *i[*
|
||||||
i[ "inner [] block", select [count] '[' ']' blocks. This
|
i[ "inner [] block", select [count] '[' ']' blocks. This
|
||||||
goes backwards to the [count] unclosed '[', and finds
|
goes backwards to the [count] unclosed '[', and finds
|
||||||
the matching ']'. The enclosed text is selected,
|
the matching ']'. The enclosed text is selected,
|
||||||
excluding the '[' and ']'.
|
excluding the '[' and ']'.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
a) *v_a)* *a)* *a(*
|
a) *v_a)* *a)* *a(*
|
||||||
a( *vab* *v_ab* *v_a(* *ab*
|
a( *vab* *v_ab* *v_a(* *ab*
|
||||||
@ -567,54 +573,54 @@ ab "a block", select [count] blocks, from "[count] [(" to
|
|||||||
the matching ')', including the '(' and ')' (see
|
the matching ')', including the '(' and ')' (see
|
||||||
|[(|). Does not include white space outside of the
|
|[(|). Does not include white space outside of the
|
||||||
parenthesis.
|
parenthesis.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
i) *v_i)* *i)* *i(*
|
i) *v_i)* *i)* *i(*
|
||||||
i( *vib* *v_ib* *v_i(* *ib*
|
i( *vib* *v_ib* *v_i(* *ib*
|
||||||
ib "inner block", select [count] blocks, from "[count] [("
|
ib "inner block", select [count] blocks, from "[count] [("
|
||||||
to the matching ')', excluding the '(' and ')' (see
|
to the matching ')', excluding the '(' and ')' (see
|
||||||
|[(|).
|
|[(|).
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
a> *v_a>* *v_a<* *a>* *a<*
|
a> *v_a>* *v_a<* *a>* *a<*
|
||||||
a< "a <> block", select [count] <> blocks, from the
|
a< "a <> block", select [count] <> blocks, from the
|
||||||
[count]'th unmatched '<' backwards to the matching
|
[count]'th unmatched '<' backwards to the matching
|
||||||
'>', including the '<' and '>'.
|
'>', including the '<' and '>'.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
i> *v_i>* *v_i<* *i>* *i<*
|
i> *v_i>* *v_i<* *i>* *i<*
|
||||||
i< "inner <> block", select [count] <> blocks, from
|
i< "inner <> block", select [count] <> blocks, from
|
||||||
the [count]'th unmatched '<' backwards to the matching
|
the [count]'th unmatched '<' backwards to the matching
|
||||||
'>', excluding the '<' and '>'.
|
'>', excluding the '<' and '>'.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
*v_at* *at*
|
*v_at* *at*
|
||||||
at "a tag block", select [count] tag blocks, from the
|
at "a tag block", select [count] tag blocks, from the
|
||||||
[count]'th unmatched "<aaa>" backwards to the matching
|
[count]'th unmatched "<aaa>" backwards to the matching
|
||||||
"</aaa>", including the "<aaa>" and "</aaa>".
|
"</aaa>", including the "<aaa>" and "</aaa>".
|
||||||
See |tag-blocks| about the details.
|
See |tag-blocks| about the details.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
*v_it* *it*
|
*v_it* *it*
|
||||||
it "inner tag block", select [count] tag blocks, from the
|
it "inner tag block", select [count] tag blocks, from the
|
||||||
[count]'th unmatched "<aaa>" backwards to the matching
|
[count]'th unmatched "<aaa>" backwards to the matching
|
||||||
"</aaa>", excluding the "<aaa>" and "</aaa>".
|
"</aaa>", excluding the "<aaa>" and "</aaa>".
|
||||||
See |tag-blocks| about the details.
|
See |tag-blocks| about the details.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
a} *v_a}* *a}* *a{*
|
a} *v_a}* *a}* *a{*
|
||||||
a{ *v_aB* *v_a{* *aB*
|
a{ *v_aB* *v_a{* *aB*
|
||||||
aB "a Block", select [count] Blocks, from "[count] [{" to
|
aB "a Block", select [count] Blocks, from "[count] [{" to
|
||||||
the matching '}', including the '{' and '}' (see
|
the matching '}', including the '{' and '}' (see
|
||||||
|[{|).
|
|[{|).
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
i} *v_i}* *i}* *i{*
|
i} *v_i}* *i}* *i{*
|
||||||
i{ *v_iB* *v_i{* *iB*
|
i{ *v_iB* *v_i{* *iB*
|
||||||
iB "inner Block", select [count] Blocks, from "[count] [{"
|
iB "inner Block", select [count] Blocks, from "[count] [{"
|
||||||
to the matching '}', excluding the '{' and '}' (see
|
to the matching '}', excluding the '{' and '}' (see
|
||||||
|[{|).
|
|[{|).
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
|
|
||||||
a" *v_aquote* *aquote*
|
a" *v_aquote* *aquote*
|
||||||
a' *v_a'* *a'*
|
a' *v_a'* *a'*
|
||||||
@ -628,7 +634,7 @@ a` *v_a`* *a`*
|
|||||||
start of the line.
|
start of the line.
|
||||||
Any trailing white space is included, unless there is
|
Any trailing white space is included, unless there is
|
||||||
none, then leading white space is included.
|
none, then leading white space is included.
|
||||||
When used in Visual mode it is made characterwise.
|
When used in Visual mode it is made charwise.
|
||||||
Repeating this object in Visual mode another string is
|
Repeating this object in Visual mode another string is
|
||||||
included. A count is currently not used.
|
included. A count is currently not used.
|
||||||
|
|
||||||
@ -1077,6 +1083,60 @@ When you split a window, the jumplist will be copied to the new window.
|
|||||||
If you have included the ' item in the 'shada' option the jumplist will be
|
If you have included the ' item in the 'shada' option the jumplist will be
|
||||||
stored in the ShaDa file and restored when starting Vim.
|
stored in the ShaDa file and restored when starting Vim.
|
||||||
|
|
||||||
|
*jumplist-stack*
|
||||||
|
When jumpoptions includes "stack", the jumplist behaves like the history in a
|
||||||
|
web browser and like the tag stack. When jumping to a new location from the
|
||||||
|
middle of the jumplist, the locations after the current position will be
|
||||||
|
discarded.
|
||||||
|
|
||||||
|
This behavior corresponds to the following situation in a web browser.
|
||||||
|
Navigate to first.com, second.com, third.com, fourth.com and then fifth.com.
|
||||||
|
Then navigate backwards twice so that third.com is displayed. At that point,
|
||||||
|
the history is:
|
||||||
|
- first.com
|
||||||
|
- second.com
|
||||||
|
- third.com <--
|
||||||
|
- fourth.com
|
||||||
|
- fifth.com
|
||||||
|
|
||||||
|
Finally, navigate to a different webpage, new.com. The history is
|
||||||
|
- first.com
|
||||||
|
- second.com
|
||||||
|
- third.com
|
||||||
|
- new.com <--
|
||||||
|
|
||||||
|
When the jumpoptions includes "stack", this is the behavior of neovim as well.
|
||||||
|
That is, given a jumplist like the following in which CTRL-O has been used to
|
||||||
|
move back three times to location X
|
||||||
|
|
||||||
|
jump line col file/text
|
||||||
|
2 1260 8 src/nvim/mark.c <-- location X-2
|
||||||
|
1 685 0 src/nvim/option_defs.h <-- location X-1
|
||||||
|
> 0 462 36 src/nvim/option_defs.h <-- location X
|
||||||
|
1 479 39 src/nvim/option_defs.h
|
||||||
|
2 213 2 src/nvim/mark.c
|
||||||
|
3 181 0 src/nvim/mark.c
|
||||||
|
|
||||||
|
jumping to location Y results in the locations after the current locations being
|
||||||
|
removed:
|
||||||
|
|
||||||
|
jump line col file/text
|
||||||
|
3 1260 8 src/nvim/mark.c
|
||||||
|
2 685 0 src/nvim/option_defs.h
|
||||||
|
1 462 36 src/nvim/option_defs.h <-- location X
|
||||||
|
>
|
||||||
|
|
||||||
|
Then, when yet another location Z is jumped to, the new location Y appears
|
||||||
|
directly after location X in the jumplist and location X remains in the same
|
||||||
|
position relative to the locations (X-1, X-2, etc., ...) that had been before it
|
||||||
|
prior to the original jump from X to Y:
|
||||||
|
|
||||||
|
jump line col file/text
|
||||||
|
4 1260 8 src/nvim/mark.c <-- location X-2
|
||||||
|
3 685 0 src/nvim/option_defs.h <-- location X-1
|
||||||
|
2 462 36 src/nvim/option_defs.h <-- location X
|
||||||
|
1 100 0 src/nvim/option_defs.h <-- location Y
|
||||||
|
>
|
||||||
|
|
||||||
CHANGE LIST JUMPS *changelist* *change-list-jumps* *E664*
|
CHANGE LIST JUMPS *changelist* *change-list-jumps* *E664*
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
NVIM REFERENCE MANUAL by Thiago de Arruda
|
NVIM REFERENCE MANUAL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
This document was merged into |api.txt| and |develop.txt|.
|
This document was merged into |api.txt| and |develop.txt|.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
@ -843,6 +843,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
name, precede it with a backslash.
|
name, precede it with a backslash.
|
||||||
- To include a comma in a directory name precede it with a backslash.
|
- To include a comma in a directory name precede it with a backslash.
|
||||||
- A directory name may end in an '/'.
|
- A directory name may end in an '/'.
|
||||||
|
- For Unix and Win32, if a directory ends in two path separators "//",
|
||||||
|
the swap file name will be built from the complete path to the file
|
||||||
|
with all path separators changed to percent '%' signs. This will
|
||||||
|
ensure file name uniqueness in the backup directory.
|
||||||
|
On Win32, it is also possible to end with "\\". However, When a
|
||||||
|
separating comma is following, you must use "//", since "\\" will
|
||||||
|
include the comma in the file name. Therefore it is recommended to
|
||||||
|
use '//', instead of '\\'.
|
||||||
- Environment variables are expanded |:set_env|.
|
- Environment variables are expanded |:set_env|.
|
||||||
- Careful with '\' characters, type one before a space, type two to
|
- Careful with '\' characters, type one before a space, type two to
|
||||||
get one in the option (see |option-backslash|), for example: >
|
get one in the option (see |option-backslash|), for example: >
|
||||||
@ -1875,7 +1883,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
security reasons.
|
security reasons.
|
||||||
|
|
||||||
*'dip'* *'diffopt'*
|
*'dip'* *'diffopt'*
|
||||||
'diffopt' 'dip' string (default "internal,filler")
|
'diffopt' 'dip' string (default "internal,filler,closeoff")
|
||||||
global
|
global
|
||||||
Option settings for diff mode. It can consist of the following items.
|
Option settings for diff mode. It can consist of the following items.
|
||||||
All are optional. Items must be separated by a comma.
|
All are optional. Items must be separated by a comma.
|
||||||
@ -1932,6 +1940,12 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
vertical Start diff mode with vertical splits (unless
|
vertical Start diff mode with vertical splits (unless
|
||||||
explicitly specified otherwise).
|
explicitly specified otherwise).
|
||||||
|
|
||||||
|
closeoff When a window is closed where 'diff' is set
|
||||||
|
and there is only one window remaining in the
|
||||||
|
same tab page with 'diff' set, execute
|
||||||
|
`:diffoff` in that window. This undoes a
|
||||||
|
`:diffsplit` command.
|
||||||
|
|
||||||
hiddenoff Do not use diff mode for a buffer when it
|
hiddenoff Do not use diff mode for a buffer when it
|
||||||
becomes hidden.
|
becomes hidden.
|
||||||
|
|
||||||
@ -1978,7 +1992,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
possible. If it is not possible in any directory, but last
|
possible. If it is not possible in any directory, but last
|
||||||
directory listed in the option does not exist, it is created.
|
directory listed in the option does not exist, it is created.
|
||||||
- Empty means that no swap file will be used (recovery is
|
- Empty means that no swap file will be used (recovery is
|
||||||
impossible!).
|
impossible!) and no |E303| error will be given.
|
||||||
- A directory "." means to put the swap file in the same directory as
|
- A directory "." means to put the swap file in the same directory as
|
||||||
the edited file. On Unix, a dot is prepended to the file name, so
|
the edited file. On Unix, a dot is prepended to the file name, so
|
||||||
it doesn't show in a directory listing. On MS-Windows the "hidden"
|
it doesn't show in a directory listing. On MS-Windows the "hidden"
|
||||||
@ -1986,12 +2000,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
- A directory starting with "./" (or ".\" for Windows) means to
|
- A directory starting with "./" (or ".\" for Windows) means to
|
||||||
put the swap file relative to where the edited file is. The leading
|
put the swap file relative to where the edited file is. The leading
|
||||||
"." is replaced with the path name of the edited file.
|
"." is replaced with the path name of the edited file.
|
||||||
- For Unix and Win32, if a directory ends in two path separators "//"
|
- For Unix and Win32, if a directory ends in two path separators "//",
|
||||||
or "\\", the swap file name will be built from the complete path to
|
the swap file name will be built from the complete path to the file
|
||||||
the file with all path separators substituted to percent '%' signs.
|
with all path separators substituted to percent '%' signs. This will
|
||||||
This will ensure file name uniqueness in the preserve directory.
|
ensure file name uniqueness in the preserve directory.
|
||||||
On Win32, when a separating comma is following, you must use "//",
|
On Win32, it is also possible to end with "\\". However, When a
|
||||||
since "\\" will include the comma in the file name.
|
separating comma is following, you must use "//", since "\\" will
|
||||||
|
include the comma in the file name. Therefore it is recommended to
|
||||||
|
use '//', instead of '\\'.
|
||||||
- Spaces after the comma are ignored, other spaces are considered part
|
- Spaces after the comma are ignored, other spaces are considered part
|
||||||
of the directory name. To have a space at the start of a directory
|
of the directory name. To have a space at the start of a directory
|
||||||
name, precede it with a backslash.
|
name, precede it with a backslash.
|
||||||
@ -2242,8 +2258,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
|
|
||||||
*'fileformat'* *'ff'*
|
*'fileformat'* *'ff'*
|
||||||
'fileformat' 'ff' string (Windows default: "dos",
|
'fileformat' 'ff' string (Windows default: "dos",
|
||||||
Unix default: "unix",
|
Unix default: "unix")
|
||||||
Macintosh default: "mac")
|
|
||||||
local to buffer
|
local to buffer
|
||||||
This gives the <EOL> of the current buffer, which is used for
|
This gives the <EOL> of the current buffer, which is used for
|
||||||
reading/writing the buffer from/to a file:
|
reading/writing the buffer from/to a file:
|
||||||
@ -2265,7 +2280,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
'fileformats' 'ffs' string (default:
|
'fileformats' 'ffs' string (default:
|
||||||
Vim+Vi Win32: "dos,unix",
|
Vim+Vi Win32: "dos,unix",
|
||||||
Vim Unix: "unix,dos",
|
Vim Unix: "unix,dos",
|
||||||
Vim Mac: "mac,unix,dos",
|
|
||||||
Vi others: "")
|
Vi others: "")
|
||||||
global
|
global
|
||||||
This gives the end-of-line (<EOL>) formats that will be tried when
|
This gives the end-of-line (<EOL>) formats that will be tried when
|
||||||
@ -2348,7 +2362,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
|
|
||||||
*'fillchars'* *'fcs'*
|
*'fillchars'* *'fcs'*
|
||||||
'fillchars' 'fcs' string (default "")
|
'fillchars' 'fcs' string (default "")
|
||||||
local to window
|
global or local to window |global-local|
|
||||||
Characters to fill the statuslines and vertical separators.
|
Characters to fill the statuslines and vertical separators.
|
||||||
It is a comma separated list of items:
|
It is a comma separated list of items:
|
||||||
|
|
||||||
@ -3443,6 +3457,17 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
Unprintable and zero-width Unicode characters are displayed as <xxxx>.
|
Unprintable and zero-width Unicode characters are displayed as <xxxx>.
|
||||||
There is no option to specify these characters.
|
There is no option to specify these characters.
|
||||||
|
|
||||||
|
*'jumpoptions'* *'jop'*
|
||||||
|
'jumpoptions' 'jop' string (default "")
|
||||||
|
global
|
||||||
|
List of words that change the behavior of the |jumplist|.
|
||||||
|
stack Make the jumplist behave like the tagstack or like a
|
||||||
|
web browser. Relative location of entries in the
|
||||||
|
jumplist is preserved at the cost of discarding
|
||||||
|
subsequent entries when navigating backwards in the
|
||||||
|
jumplist and then jumping to a location.
|
||||||
|
|jumplist-stack|
|
||||||
|
|
||||||
*'joinspaces'* *'js'* *'nojoinspaces'* *'nojs'*
|
*'joinspaces'* *'js'* *'nojoinspaces'* *'nojs'*
|
||||||
'joinspaces' 'js' boolean (default on)
|
'joinspaces' 'js' boolean (default on)
|
||||||
global
|
global
|
||||||
@ -3657,7 +3682,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*'listchars'* *'lcs'*
|
*'listchars'* *'lcs'*
|
||||||
'listchars' 'lcs' string (default: "tab:> ,trail:-,nbsp:+"
|
'listchars' 'lcs' string (default: "tab:> ,trail:-,nbsp:+"
|
||||||
Vi default: "eol:$")
|
Vi default: "eol:$")
|
||||||
local to window
|
global or local to window |global-local|
|
||||||
Strings to use in 'list' mode and for the |:list| command. It is a
|
Strings to use in 'list' mode and for the |:list| command. It is a
|
||||||
comma separated list of string settings.
|
comma separated list of string settings.
|
||||||
|
|
||||||
@ -3698,9 +3723,9 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
off and the line continues beyond the right of the
|
off and the line continues beyond the right of the
|
||||||
screen.
|
screen.
|
||||||
*lcs-precedes*
|
*lcs-precedes*
|
||||||
precedes:c Character to show in the first column, when 'wrap'
|
precedes:c Character to show in the first visible column of the
|
||||||
is off and there is text preceding the character
|
physical line, when there is text preceding the
|
||||||
visible in the first column.
|
character visible in the first column.
|
||||||
*lcs-conceal*
|
*lcs-conceal*
|
||||||
conceal:c Character to show in place of concealed text, when
|
conceal:c Character to show in place of concealed text, when
|
||||||
'conceallevel' is set to 1. A space when omitted.
|
'conceallevel' is set to 1. A space when omitted.
|
||||||
@ -4583,6 +4608,16 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
RedrawDebugRecompose guibg=Red redraw generated by the
|
RedrawDebugRecompose guibg=Red redraw generated by the
|
||||||
compositor itself, due to a
|
compositor itself, due to a
|
||||||
grid being moved or deleted.
|
grid being moved or deleted.
|
||||||
|
nothrottle Turn off throttling of the message grid. This is an
|
||||||
|
optimization that joins many small scrolls to one
|
||||||
|
larger scroll when drawing the message area (with
|
||||||
|
'display' msgsep flag active).
|
||||||
|
invalid Enable stricter checking (abort) of inconsistencies
|
||||||
|
of the internal screen state. This is mostly
|
||||||
|
useful when running nvim inside a debugger (and
|
||||||
|
the test suite).
|
||||||
|
nodelta Send all internally redrawn cells to the UI, even if
|
||||||
|
they are unchanged from the already displayed state.
|
||||||
|
|
||||||
*'redrawtime'* *'rdt'*
|
*'redrawtime'* *'rdt'*
|
||||||
'redrawtime' 'rdt' number (default 2000)
|
'redrawtime' 'rdt' number (default 2000)
|
||||||
@ -5159,7 +5194,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
unescaping, so to keep yourself sane use |:let-&| like shown above.
|
unescaping, so to keep yourself sane use |:let-&| like shown above.
|
||||||
*shell-powershell*
|
*shell-powershell*
|
||||||
To use powershell (on Windows): >
|
To use powershell (on Windows): >
|
||||||
set shell=powershell shellquote=( shellpipe=\| shellxquote=
|
set shell=powershell shellquote= shellpipe=\| shellxquote=
|
||||||
set shellcmdflag=-NoLogo\ -NoProfile\ -ExecutionPolicy\ RemoteSigned\ -Command
|
set shellcmdflag=-NoLogo\ -NoProfile\ -ExecutionPolicy\ RemoteSigned\ -Command
|
||||||
set shellredir=\|\ Out-File\ -Encoding\ UTF8
|
set shellredir=\|\ Out-File\ -Encoding\ UTF8
|
||||||
|
|
||||||
@ -5722,7 +5757,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
current one. |:vsplit|
|
current one. |:vsplit|
|
||||||
|
|
||||||
*'startofline'* *'sol'* *'nostartofline'* *'nosol'*
|
*'startofline'* *'sol'* *'nostartofline'* *'nosol'*
|
||||||
'startofline' 'sol' boolean (default on)
|
'startofline' 'sol' boolean (default off)
|
||||||
global
|
global
|
||||||
When "on" the commands listed below move the cursor to the first
|
When "on" the commands listed below move the cursor to the first
|
||||||
non-blank of the line. When off the cursor is kept in the same column
|
non-blank of the line. When off the cursor is kept in the same column
|
||||||
@ -5990,6 +6025,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
vsplit Just like "split" but split vertically.
|
vsplit Just like "split" but split vertically.
|
||||||
newtab Like "split", but open a new tab page. Overrules
|
newtab Like "split", but open a new tab page. Overrules
|
||||||
"split" when both are present.
|
"split" when both are present.
|
||||||
|
uselast If included, jump to the previously used window when
|
||||||
|
jumping to errors with |quickfix| commands.
|
||||||
|
|
||||||
*'synmaxcol'* *'smc'*
|
*'synmaxcol'* *'smc'*
|
||||||
'synmaxcol' 'smc' number (default 3000)
|
'synmaxcol' 'smc' number (default 3000)
|
||||||
@ -6149,6 +6186,14 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
match Match case
|
match Match case
|
||||||
smart Ignore case unless an upper case letter is used
|
smart Ignore case unless an upper case letter is used
|
||||||
|
|
||||||
|
*'tagfunc'* *'tfu'*
|
||||||
|
'tagfunc' 'tfu' string (default: empty)
|
||||||
|
local to buffer
|
||||||
|
This option specifies a function to be used to perform tag searches.
|
||||||
|
The function gets the tag pattern and should return a List of matching
|
||||||
|
tags. See |tag-function| for an explanation of how to write the
|
||||||
|
function and an example.
|
||||||
|
|
||||||
*'taglength'* *'tl'*
|
*'taglength'* *'tl'*
|
||||||
'taglength' 'tl' number (default 0)
|
'taglength' 'tl' number (default 0)
|
||||||
global
|
global
|
||||||
@ -6620,22 +6665,18 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*'wildmenu'* *'wmnu'* *'nowildmenu'* *'nowmnu'*
|
*'wildmenu'* *'wmnu'* *'nowildmenu'* *'nowmnu'*
|
||||||
'wildmenu' 'wmnu' boolean (default on)
|
'wildmenu' 'wmnu' boolean (default on)
|
||||||
global
|
global
|
||||||
When 'wildmenu' is on, command-line completion operates in an enhanced
|
Enables "enhanced mode" of command-line completion. When user hits
|
||||||
mode. On pressing 'wildchar' (usually <Tab>) to invoke completion,
|
<Tab> (or 'wildchar') to invoke completion, the possible matches are
|
||||||
the possible matches are shown just above the command line, with the
|
shown in a menu just above the command-line (see 'wildoptions'), with
|
||||||
first match highlighted (overwriting the status line, if there is
|
the first match highlighted (overwriting the statusline). Keys that
|
||||||
one). Keys that show the previous/next match, such as <Tab> or
|
show the previous/next match (<Tab>/CTRL-P/CTRL-N) highlight the
|
||||||
CTRL-P/CTRL-N, cause the highlight to move to the appropriate match.
|
match.
|
||||||
When 'wildmode' is used, "wildmenu" mode is used where "full" is
|
'wildmode' must specify "full": "longest" and "list" do not start
|
||||||
specified. "longest" and "list" do not start "wildmenu" mode.
|
'wildmenu' mode. You can check the current mode with |wildmenumode()|.
|
||||||
You can check the current mode with |wildmenumode()|.
|
The menu is canceled when a key is hit that is not used for selecting
|
||||||
If there are more matches than can fit in the line, a ">" is shown on
|
a completion.
|
||||||
the right and/or a "<" is shown on the left. The status line scrolls
|
|
||||||
as needed.
|
While the menu is active these keys have special meanings:
|
||||||
The "wildmenu" mode is abandoned when a key is hit that is not used
|
|
||||||
for selecting a completion.
|
|
||||||
While the "wildmenu" is active the following keys have special
|
|
||||||
meanings:
|
|
||||||
|
|
||||||
<Left> <Right> - select previous/next match (like CTRL-P/CTRL-N)
|
<Left> <Right> - select previous/next match (like CTRL-P/CTRL-N)
|
||||||
<Down> - in filename/menu name completion: move into a
|
<Down> - in filename/menu name completion: move into a
|
||||||
@ -6645,15 +6686,12 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
<Up> - in filename/menu name completion: move up into
|
<Up> - in filename/menu name completion: move up into
|
||||||
parent directory or parent menu.
|
parent directory or parent menu.
|
||||||
|
|
||||||
This makes the menus accessible from the console |console-menus|.
|
If you want <Left> and <Right> to move the cursor instead of selecting
|
||||||
|
a different match, use this: >
|
||||||
If you prefer the <Left> and <Right> keys to move the cursor instead
|
|
||||||
of selecting a different match, use this: >
|
|
||||||
:cnoremap <Left> <Space><BS><Left>
|
:cnoremap <Left> <Space><BS><Left>
|
||||||
:cnoremap <Right> <Space><BS><Right>
|
:cnoremap <Right> <Space><BS><Right>
|
||||||
<
|
<
|
||||||
The "WildMenu" highlighting is used for displaying the current match
|
|hl-WildMenu| highlights the current match.
|
||||||
|hl-WildMenu|.
|
|
||||||
|
|
||||||
*'wildmode'* *'wim'*
|
*'wildmode'* *'wim'*
|
||||||
'wildmode' 'wim' string (default: "full")
|
'wildmode' 'wim' string (default: "full")
|
||||||
@ -6908,7 +6946,6 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
global
|
global
|
||||||
The number of milliseconds to wait for each character sent to the
|
The number of milliseconds to wait for each character sent to the
|
||||||
screen. When positive, characters are sent to the UI one by one.
|
screen. When positive, characters are sent to the UI one by one.
|
||||||
When negative, all redrawn characters cause a delay, even if the
|
See 'redrawdebug' for more options. For debugging purposes.
|
||||||
character already was displayed by the UI. For debugging purposes.
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
@ -109,6 +109,36 @@ processing a quickfix or location list command, it will be aborted.
|
|||||||
list for the current window is used instead of the
|
list for the current window is used instead of the
|
||||||
quickfix list.
|
quickfix list.
|
||||||
|
|
||||||
|
*:cabo* *:cabove*
|
||||||
|
:[count]cabo[ve] Go to the [count] error above the current line in the
|
||||||
|
current buffer. If [count] is omitted, then 1 is
|
||||||
|
used. If there are no errors, then an error message
|
||||||
|
is displayed. Assumes that the entries in a quickfix
|
||||||
|
list are sorted by their buffer number and line
|
||||||
|
number. If there are multiple errors on the same line,
|
||||||
|
then only the first entry is used. If [count] exceeds
|
||||||
|
the number of entries above the current line, then the
|
||||||
|
first error in the file is selected.
|
||||||
|
|
||||||
|
*:lab* *:labove*
|
||||||
|
:[count]lab[ove] Same as ":cabove", except the location list for the
|
||||||
|
current window is used instead of the quickfix list.
|
||||||
|
|
||||||
|
*:cbe* *:cbelow*
|
||||||
|
:[count]cbe[low] Go to the [count] error below the current line in the
|
||||||
|
current buffer. If [count] is omitted, then 1 is
|
||||||
|
used. If there are no errors, then an error message
|
||||||
|
is displayed. Assumes that the entries in a quickfix
|
||||||
|
list are sorted by their buffer number and line
|
||||||
|
number. If there are multiple errors on the same
|
||||||
|
line, then only the first entry is used. If [count]
|
||||||
|
exceeds the number of entries below the current line,
|
||||||
|
then the last error in the file is selected.
|
||||||
|
|
||||||
|
*:lbe* *:lbelow*
|
||||||
|
:[count]lbe[low] Same as ":cbelow", except the location list for the
|
||||||
|
current window is used instead of the quickfix list.
|
||||||
|
|
||||||
*:cnf* *:cnfile*
|
*:cnf* *:cnfile*
|
||||||
:[count]cnf[ile][!] Display the first error in the [count] next file in
|
:[count]cnf[ile][!] Display the first error in the [count] next file in
|
||||||
the list that includes a file name. If there are no
|
the list that includes a file name. If there are no
|
||||||
|
@ -47,6 +47,7 @@ N is used to indicate an optional count that can be given before the command.
|
|||||||
|g$| N g$ to last character in screen line (differs from "$"
|
|g$| N g$ to last character in screen line (differs from "$"
|
||||||
when lines wrap)
|
when lines wrap)
|
||||||
|gm| gm to middle of the screen line
|
|gm| gm to middle of the screen line
|
||||||
|
|gM| gM to middle of the line
|
||||||
|bar| N | to column N (default: 1)
|
|bar| N | to column N (default: 1)
|
||||||
|f| N f{char} to the Nth occurrence of {char} to the right
|
|f| N f{char} to the Nth occurrence of {char} to the right
|
||||||
|F| N F{char} to the Nth occurrence of {char} to the left
|
|F| N F{char} to the Nth occurrence of {char} to the left
|
||||||
@ -742,6 +743,7 @@ Short explanation of each option: *option-list*
|
|||||||
'iskeyword' 'isk' characters included in keywords
|
'iskeyword' 'isk' characters included in keywords
|
||||||
'isprint' 'isp' printable characters
|
'isprint' 'isp' printable characters
|
||||||
'joinspaces' 'js' two spaces after a period with a join command
|
'joinspaces' 'js' two spaces after a period with a join command
|
||||||
|
'jumpoptions' 'jop' specifies how jumping is done
|
||||||
'keymap' 'kmp' name of a keyboard mapping
|
'keymap' 'kmp' name of a keyboard mapping
|
||||||
'keymodel' 'km' enable starting/stopping selection with keys
|
'keymodel' 'km' enable starting/stopping selection with keys
|
||||||
'keywordprg' 'kp' program to use for the "K" command
|
'keywordprg' 'kp' program to use for the "K" command
|
||||||
|
@ -1270,7 +1270,7 @@ exactly four MessagePack objects:
|
|||||||
Key Type Def Description ~
|
Key Type Def Description ~
|
||||||
rt UInteger 0 Register type:
|
rt UInteger 0 Register type:
|
||||||
No Description ~
|
No Description ~
|
||||||
0 |characterwise-register|
|
0 |charwise-register|
|
||||||
1 |linewise-register|
|
1 |linewise-register|
|
||||||
2 |blockwise-register|
|
2 |blockwise-register|
|
||||||
rw UInteger 0 Register width. Only valid
|
rw UInteger 0 Register width. Only valid
|
||||||
|
@ -4720,18 +4720,19 @@ the same syntax file on all UIs.
|
|||||||
|
|
||||||
*bold* *underline* *undercurl*
|
*bold* *underline* *undercurl*
|
||||||
*inverse* *italic* *standout*
|
*inverse* *italic* *standout*
|
||||||
*strikethrough*
|
*nocombine* *strikethrough*
|
||||||
cterm={attr-list} *attr-list* *highlight-cterm* *E418*
|
cterm={attr-list} *attr-list* *highlight-cterm* *E418*
|
||||||
attr-list is a comma separated list (without spaces) of the
|
attr-list is a comma separated list (without spaces) of the
|
||||||
following items (in any order):
|
following items (in any order):
|
||||||
bold
|
bold
|
||||||
underline
|
underline
|
||||||
undercurl curly underline
|
undercurl curly underline
|
||||||
|
strikethrough
|
||||||
reverse
|
reverse
|
||||||
inverse same as reverse
|
inverse same as reverse
|
||||||
italic
|
italic
|
||||||
standout
|
standout
|
||||||
strikethrough
|
nocombine override attributes instead of combining them
|
||||||
NONE no attributes used (used to reset it)
|
NONE no attributes used (used to reset it)
|
||||||
|
|
||||||
Note that "bold" can be used here and by using a bold font. They
|
Note that "bold" can be used here and by using a bold font. They
|
||||||
|
@ -838,4 +838,70 @@ Common arguments for the commands above:
|
|||||||
< For a ":djump", ":dsplit", ":dlist" and ":dsearch" command the pattern
|
< For a ":djump", ":dsplit", ":dlist" and ":dsearch" command the pattern
|
||||||
is used as a literal string, not as a search pattern.
|
is used as a literal string, not as a search pattern.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
7. Using 'tagfunc' *tag-function*
|
||||||
|
|
||||||
|
It is possible to provide Vim with a function which will generate a list of
|
||||||
|
tags used for commands like |:tag|, |:tselect| and Normal mode tag commands
|
||||||
|
like |CTRL-]|.
|
||||||
|
|
||||||
|
The function used for generating the taglist is specified by setting the
|
||||||
|
'tagfunc' option. The function will be called with three arguments:
|
||||||
|
a:pattern The tag identifier used during the tag search.
|
||||||
|
a:flags List of flags to control the function behavior.
|
||||||
|
a:info Dict containing the following entries:
|
||||||
|
buf_ffname Full filename which can be used for priority.
|
||||||
|
user_data Custom data String, if stored in the tag
|
||||||
|
stack previously by tagfunc.
|
||||||
|
|
||||||
|
Currently two flags may be passed to the tag function:
|
||||||
|
'c' The function was invoked by a normal command being processed
|
||||||
|
(mnemonic: the tag function may use the context around the
|
||||||
|
cursor to perform a better job of generating the tag list.)
|
||||||
|
'i' In Insert mode, the user was completing a tag (with
|
||||||
|
|i_CTRL-X_CTRL-]|).
|
||||||
|
|
||||||
|
Note that when 'tagfunc' is set, the priority of the tags described in
|
||||||
|
|tag-priority| does not apply. Instead, the priority is exactly as the
|
||||||
|
ordering of the elements in the list returned by the function.
|
||||||
|
*E987*
|
||||||
|
The function should return a List of Dict entries. Each Dict must at least
|
||||||
|
include the following entries and each value must be a string:
|
||||||
|
name Name of the tag.
|
||||||
|
filename Name of the file where the tag is defined. It is
|
||||||
|
either relative to the current directory or a full path.
|
||||||
|
cmd Ex command used to locate the tag in the file. This
|
||||||
|
can be either an Ex search pattern or a line number.
|
||||||
|
Note that the format is similar to that of |taglist()|, which makes it possible
|
||||||
|
to use its output to generate the result.
|
||||||
|
The following fields are optional:
|
||||||
|
kind Type of the tag.
|
||||||
|
user_data String of custom data stored in the tag stack which
|
||||||
|
can be used to disambiguate tags between operations.
|
||||||
|
|
||||||
|
If the function returns |v:null| instead of a List, a standard tag lookup will
|
||||||
|
be performed instead.
|
||||||
|
|
||||||
|
It is not allowed to change the tagstack from inside 'tagfunc'. *E986*
|
||||||
|
|
||||||
|
The following is a hypothetical example of a function used for 'tagfunc'. It
|
||||||
|
uses the output of |taglist()| to generate the result: a list of tags in the
|
||||||
|
inverse order of file names.
|
||||||
|
>
|
||||||
|
function! TagFunc(pattern, flags, info)
|
||||||
|
function! CompareFilenames(item1, item2)
|
||||||
|
let f1 = a:item1['filename']
|
||||||
|
let f2 = a:item2['filename']
|
||||||
|
return f1 >=# f2 ?
|
||||||
|
\ -1 : f1 <=# f2 ? 1 : 0
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let result = taglist(a:pattern)
|
||||||
|
call sort(result, "CompareFilenames")
|
||||||
|
|
||||||
|
return result
|
||||||
|
endfunc
|
||||||
|
set tagfunc=TagFunc
|
||||||
|
<
|
||||||
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||||
|
@ -201,8 +201,8 @@ the editor.
|
|||||||
sent from Nvim, like for |ui-cmdline|.
|
sent from Nvim, like for |ui-cmdline|.
|
||||||
|
|
||||||
["mode_change", mode, mode_idx]
|
["mode_change", mode, mode_idx]
|
||||||
The mode changed. The first parameter `mode` is a string representing
|
Editor mode changed. The `mode` parameter is a string representing
|
||||||
the current mode. `mode_idx` is an index into the array received in
|
the current mode. `mode_idx` is an index into the array emitted in
|
||||||
the `mode_info_set` event. UIs should change the cursor style
|
the `mode_info_set` event. UIs should change the cursor style
|
||||||
according to the properties specified in the corresponding item. The
|
according to the properties specified in the corresponding item. The
|
||||||
set of modes reported will change in new versions of Nvim, for
|
set of modes reported will change in new versions of Nvim, for
|
||||||
@ -211,11 +211,11 @@ the editor.
|
|||||||
|
|
||||||
["mouse_on"]
|
["mouse_on"]
|
||||||
["mouse_off"]
|
["mouse_off"]
|
||||||
Tells the client whether mouse support, as determined by |'mouse'|
|
|'mouse'| was enabled/disabled in the current editor mode. Useful for
|
||||||
option, is considered to be active in the current mode. This is mostly
|
a terminal UI, or other situations where Nvim mouse would conflict
|
||||||
useful for a terminal frontend, or other situations where Nvim mouse
|
with other usages of the mouse. UIs may ignore this and always send
|
||||||
would conflict with other usages of the mouse. It is safe for a client
|
mouse input, because 'mouse' decides the behavior of |nvim_input()|
|
||||||
to ignore this and always send mouse events.
|
implicitly.
|
||||||
|
|
||||||
["busy_start"]
|
["busy_start"]
|
||||||
["busy_stop"]
|
["busy_stop"]
|
||||||
|
@ -346,12 +346,13 @@ scroll:
|
|||||||
|
|
||||||
g0 to first visible character in this line
|
g0 to first visible character in this line
|
||||||
g^ to first non-blank visible character in this line
|
g^ to first non-blank visible character in this line
|
||||||
gm to middle of this line
|
gm to middle of screen line
|
||||||
|
gM to middle of the text in this line
|
||||||
g$ to last visible character in this line
|
g$ to last visible character in this line
|
||||||
|
|
||||||
|<-- window -->|
|
|<-- window -->|
|
||||||
some long text, part of which is visible ~
|
some long text, part of which is visible in one line ~
|
||||||
g0 g^ gm g$
|
g0 g^ gm gM g$
|
||||||
|
|
||||||
|
|
||||||
BREAKING AT WORDS *edit-no-break*
|
BREAKING AT WORDS *edit-no-break*
|
||||||
|
@ -55,6 +55,7 @@ the differences.
|
|||||||
- 'showcmd' is enabled
|
- 'showcmd' is enabled
|
||||||
- 'sidescroll' defaults to 1
|
- 'sidescroll' defaults to 1
|
||||||
- 'smarttab' is enabled
|
- 'smarttab' is enabled
|
||||||
|
- 'startofline' is disabled
|
||||||
- 'tabpagemax' defaults to 50
|
- 'tabpagemax' defaults to 50
|
||||||
- 'tags' defaults to "./tags;,tags"
|
- 'tags' defaults to "./tags;,tags"
|
||||||
- 'ttimeoutlen' defaults to 50
|
- 'ttimeoutlen' defaults to 50
|
||||||
@ -168,6 +169,7 @@ Functions:
|
|||||||
|system()|, |systemlist()| can run {cmd} directly (without 'shell')
|
|system()|, |systemlist()| can run {cmd} directly (without 'shell')
|
||||||
|
|
||||||
Highlight groups:
|
Highlight groups:
|
||||||
|
|highlight-blend| controls blend level for a highlight group
|
||||||
|expr-highlight| highlight groups (prefixed with "Nvim")
|
|expr-highlight| highlight groups (prefixed with "Nvim")
|
||||||
|hl-NormalFloat| highlights floating window
|
|hl-NormalFloat| highlights floating window
|
||||||
|hl-NormalNC| highlights non-current windows
|
|hl-NormalNC| highlights non-current windows
|
||||||
@ -206,6 +208,7 @@ Options:
|
|||||||
'statusline' supports unlimited alignment sections
|
'statusline' supports unlimited alignment sections
|
||||||
'tabline' %@Func@foo%X can call any function on mouse-click
|
'tabline' %@Func@foo%X can call any function on mouse-click
|
||||||
'wildoptions' `pum` flag to use popupmenu for wildmode completion
|
'wildoptions' `pum` flag to use popupmenu for wildmode completion
|
||||||
|
'winblend' pseudo-transparency in floating windows |api-floatwin|
|
||||||
'winhighlight' window-local highlights
|
'winhighlight' window-local highlights
|
||||||
|
|
||||||
Signs:
|
Signs:
|
||||||
@ -296,7 +299,7 @@ coerced to strings. See |id()| for more details, currently it uses
|
|||||||
|
|
||||||
|c_CTRL-R| pasting a non-special register into |cmdline| omits the last <CR>.
|
|c_CTRL-R| pasting a non-special register into |cmdline| omits the last <CR>.
|
||||||
|
|
||||||
Lua interface (|if_lua.txt|):
|
Lua interface (|lua.txt|):
|
||||||
|
|
||||||
- `:lua print("a\0b")` will print `a^@b`, like with `:echomsg "a\nb"` . In Vim
|
- `:lua print("a\0b")` will print `a^@b`, like with `:echomsg "a\nb"` . In Vim
|
||||||
that prints `a` and `b` on separate lines, exactly like
|
that prints `a` and `b` on separate lines, exactly like
|
||||||
@ -307,15 +310,15 @@ Lua interface (|if_lua.txt|):
|
|||||||
- Lua package.path and package.cpath are automatically updated according to
|
- Lua package.path and package.cpath are automatically updated according to
|
||||||
'runtimepath': |lua-require|.
|
'runtimepath': |lua-require|.
|
||||||
|
|
||||||
|input()| and |inputdialog()| support for each other’s features (return on
|
|
||||||
cancel and completion respectively) via dictionary argument (replaces all
|
|
||||||
other arguments if used).
|
|
||||||
|
|
||||||
|input()| and |inputdialog()| support user-defined cmdline highlighting.
|
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
|:doautocmd| does not warn about "No matching autocommands".
|
|:doautocmd| does not warn about "No matching autocommands".
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|input()| and |inputdialog()| support for each other’s features (return on
|
||||||
|
cancel and completion respectively) via dictionary argument (replaces all
|
||||||
|
other arguments if used).
|
||||||
|
|input()| and |inputdialog()| support user-defined cmdline highlighting.
|
||||||
|
|
||||||
Highlight groups:
|
Highlight groups:
|
||||||
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
|
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
|
||||||
groups
|
groups
|
||||||
@ -333,6 +336,11 @@ Macro/|recording| behavior
|
|||||||
Motion:
|
Motion:
|
||||||
The |jumplist| avoids useless/phantom jumps.
|
The |jumplist| avoids useless/phantom jumps.
|
||||||
|
|
||||||
|
When the new option |jumpoptions| includes 'stack', the jumplist behaves
|
||||||
|
like the tagstack or history in a web browser--jumping from the middle of
|
||||||
|
the jumplist discards the locations after the jumped-from position
|
||||||
|
(|jumplist-stack|).
|
||||||
|
|
||||||
Normal commands:
|
Normal commands:
|
||||||
|Q| is the same as |gQ|
|
|Q| is the same as |gQ|
|
||||||
|
|
||||||
@ -399,10 +407,10 @@ VimL (Vim script) compatibility:
|
|||||||
|
|
||||||
Some legacy Vim features are not implemented:
|
Some legacy Vim features are not implemented:
|
||||||
|
|
||||||
- |if_py|: *python-bindeval* *python-Function* are not supported
|
- |if_lua|: Nvim Lua API is not compatible with Vim's "if_lua"
|
||||||
- |if_lua|: the `vim` object is missing some legacy methods
|
|
||||||
- *if_perl*
|
|
||||||
- *if_mzscheme*
|
- *if_mzscheme*
|
||||||
|
- *if_perl*
|
||||||
|
- |if_py|: *python-bindeval* *python-Function* are not supported
|
||||||
- *if_tcl*
|
- *if_tcl*
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
@ -524,4 +532,4 @@ TUI:
|
|||||||
always uses 7-bit control sequences.
|
always uses 7-bit control sequences.
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
vim:tw=78:ts=8:sw=2:noet:ft=help:norl:
|
vim:tw=78:ts=8:sw=2:et:ft=help:norl:
|
||||||
|
@ -48,7 +48,7 @@ position.
|
|||||||
==============================================================================
|
==============================================================================
|
||||||
2. Starting and stopping Visual mode *visual-start*
|
2. Starting and stopping Visual mode *visual-start*
|
||||||
|
|
||||||
*v* *characterwise-visual*
|
*v* *charwise-visual*
|
||||||
[count]v Start Visual mode per character.
|
[count]v Start Visual mode per character.
|
||||||
With [count] select the same number of characters or
|
With [count] select the same number of characters or
|
||||||
lines as used for the last Visual operation, but at
|
lines as used for the last Visual operation, but at
|
||||||
@ -74,7 +74,7 @@ position.
|
|||||||
|
|
||||||
If you use <Esc>, click the left mouse button or use any command that
|
If you use <Esc>, click the left mouse button or use any command that
|
||||||
does a jump to another buffer while in Visual mode, the highlighting stops
|
does a jump to another buffer while in Visual mode, the highlighting stops
|
||||||
and no text is affected. Also when you hit "v" in characterwise Visual mode,
|
and no text is affected. Also when you hit "v" in charwise Visual mode,
|
||||||
"CTRL-V" in blockwise Visual mode or "V" in linewise Visual mode. If you hit
|
"CTRL-V" in blockwise Visual mode or "V" in linewise Visual mode. If you hit
|
||||||
CTRL-Z the highlighting stops and the editor is suspended or a new shell is
|
CTRL-Z the highlighting stops and the editor is suspended or a new shell is
|
||||||
started |CTRL-Z|.
|
started |CTRL-Z|.
|
||||||
@ -477,7 +477,7 @@ Commands in Select mode:
|
|||||||
Otherwise, typed characters are handled as in Visual mode.
|
Otherwise, typed characters are handled as in Visual mode.
|
||||||
|
|
||||||
When using an operator in Select mode, and the selection is linewise, the
|
When using an operator in Select mode, and the selection is linewise, the
|
||||||
selected lines are operated upon, but like in characterwise selection. For
|
selected lines are operated upon, but like in charwise selection. For
|
||||||
example, when a whole line is deleted, it can later be pasted in the middle of
|
example, when a whole line is deleted, it can later be pasted in the middle of
|
||||||
a line.
|
a line.
|
||||||
|
|
||||||
@ -510,7 +510,7 @@ gV Avoid the automatic reselection of the Visual area
|
|||||||
selection.
|
selection.
|
||||||
|
|
||||||
*gh*
|
*gh*
|
||||||
gh Start Select mode, characterwise. This is like "v",
|
gh Start Select mode, charwise. This is like "v",
|
||||||
but starts Select mode instead of Visual mode.
|
but starts Select mode instead of Visual mode.
|
||||||
Mnemonic: "get highlighted".
|
Mnemonic: "get highlighted".
|
||||||
|
|
||||||
|
@ -201,9 +201,11 @@ CTRL-W CTRL_N *CTRL-W_CTRL-N*
|
|||||||
|:find|. Doesn't split if {file} is not found.
|
|:find|. Doesn't split if {file} is not found.
|
||||||
|
|
||||||
CTRL-W CTRL-^ *CTRL-W_CTRL-^* *CTRL-W_^*
|
CTRL-W CTRL-^ *CTRL-W_CTRL-^* *CTRL-W_^*
|
||||||
CTRL-W ^ Does ":split #", split window in two and edit alternate file.
|
CTRL-W ^ Split the current window in two and edit the alternate file.
|
||||||
When a count is given, it becomes ":split #N", split window
|
When a count N is given, split the current window and edit
|
||||||
and edit buffer N.
|
buffer N. Similar to ":sp #" and ":sp #N", but it allows the
|
||||||
|
other buffer to be unnamed. This command matches the behavior
|
||||||
|
of |CTRL-^|, except that it splits a window first.
|
||||||
|
|
||||||
CTRL-W ge *CTRL-W_ge*
|
CTRL-W ge *CTRL-W_ge*
|
||||||
Detach the current window as an external window.
|
Detach the current window as an external window.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
" Vim support file to detect file types
|
" Vim support file to detect file types
|
||||||
"
|
"
|
||||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||||
" Last Change: 2019 Aug 26
|
" Last Change: 2019 Nov 26
|
||||||
|
|
||||||
" Listen very carefully, I will say this only once
|
" Listen very carefully, I will say this only once
|
||||||
if exists("did_load_filetypes")
|
if exists("did_load_filetypes")
|
||||||
@ -421,6 +421,9 @@ au BufNewFile,BufRead *.csp,*.fdr setf csp
|
|||||||
au BufNewFile,BufRead *.pld setf cupl
|
au BufNewFile,BufRead *.pld setf cupl
|
||||||
au BufNewFile,BufRead *.si setf cuplsim
|
au BufNewFile,BufRead *.si setf cuplsim
|
||||||
|
|
||||||
|
" Dart
|
||||||
|
au BufRead,BufNewfile *.dart,*.drt setf dart
|
||||||
|
|
||||||
" Debian Control
|
" Debian Control
|
||||||
au BufNewFile,BufRead */debian/control setf debcontrol
|
au BufNewFile,BufRead */debian/control setf debcontrol
|
||||||
au BufNewFile,BufRead control
|
au BufNewFile,BufRead control
|
||||||
@ -793,8 +796,8 @@ au BufNewFile,BufRead *.java,*.jav setf java
|
|||||||
" JavaCC
|
" JavaCC
|
||||||
au BufNewFile,BufRead *.jj,*.jjt setf javacc
|
au BufNewFile,BufRead *.jj,*.jjt setf javacc
|
||||||
|
|
||||||
" JavaScript, ECMAScript
|
" JavaScript, ECMAScript, ES module script, CommonJS script
|
||||||
au BufNewFile,BufRead *.js,*.javascript,*.es,*.mjs setf javascript
|
au BufNewFile,BufRead *.js,*.javascript,*.es,*.mjs,*.cjs setf javascript
|
||||||
|
|
||||||
" JavaScript with React
|
" JavaScript with React
|
||||||
au BufNewFile,BufRead *.jsx setf javascriptreact
|
au BufNewFile,BufRead *.jsx setf javascriptreact
|
||||||
@ -975,6 +978,9 @@ au BufNewFile,BufRead hg-editor-*.txt setf hgcommit
|
|||||||
" Mercurial config (looks like generic config file)
|
" Mercurial config (looks like generic config file)
|
||||||
au BufNewFile,BufRead *.hgrc,*hgrc setf cfg
|
au BufNewFile,BufRead *.hgrc,*hgrc setf cfg
|
||||||
|
|
||||||
|
" Meson Build system config
|
||||||
|
au BufNewFile,BufRead meson.build,meson_options.txt setf meson
|
||||||
|
|
||||||
" Messages (logs mostly)
|
" Messages (logs mostly)
|
||||||
au BufNewFile,BufRead */log/{auth,cron,daemon,debug,kern,lpr,mail,messages,news/news,syslog,user}{,.log,.err,.info,.warn,.crit,.notice}{,.[0-9]*,-[0-9]*} setf messages
|
au BufNewFile,BufRead */log/{auth,cron,daemon,debug,kern,lpr,mail,messages,news/news,syslog,user}{,.log,.err,.info,.warn,.crit,.notice}{,.[0-9]*,-[0-9]*} setf messages
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
" Maintainer: Anmol Sethi <anmol@aubble.com>
|
" Maintainer: Anmol Sethi <hi@nhooyr.io>
|
||||||
" Previous Maintainer: SungHyun Nam <goweol@gmail.com>
|
" Previous Maintainer: SungHyun Nam <goweol@gmail.com>
|
||||||
|
|
||||||
if exists('b:did_ftplugin') || &filetype !=# 'man'
|
if exists('b:did_ftplugin') || &filetype !=# 'man'
|
||||||
@ -20,13 +20,12 @@ setlocal wrap breakindent linebreak
|
|||||||
setlocal nonumber norelativenumber
|
setlocal nonumber norelativenumber
|
||||||
setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable
|
setlocal foldcolumn=0 colorcolumn=0 nolist nofoldenable
|
||||||
|
|
||||||
|
setlocal tagfunc=man#goto_tag
|
||||||
|
|
||||||
if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
|
if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
|
||||||
nnoremap <silent> <buffer> j gj
|
nnoremap <silent> <buffer> j gj
|
||||||
nnoremap <silent> <buffer> k gk
|
nnoremap <silent> <buffer> k gk
|
||||||
nnoremap <silent> <buffer> gO :call man#show_toc()<CR>
|
nnoremap <silent> <buffer> gO :call man#show_toc()<CR>
|
||||||
nnoremap <silent> <buffer> <C-]> :Man<CR>
|
|
||||||
nnoremap <silent> <buffer> K :Man<CR>
|
|
||||||
nnoremap <silent> <buffer> <C-T> :call man#pop_tag()<CR>
|
|
||||||
if 1 == bufnr('%') || s:pager
|
if 1 == bufnr('%') || s:pager
|
||||||
nnoremap <silent> <buffer> <nowait> q :lclose<CR>:q<CR>
|
nnoremap <silent> <buffer> <nowait> q :lclose<CR>:q<CR>
|
||||||
else
|
else
|
||||||
|
14
runtime/indent/Makefile
Normal file
14
runtime/indent/Makefile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Portable Makefile for running indent tests.
|
||||||
|
|
||||||
|
VIM = vim
|
||||||
|
VIMRUNTIME = ..
|
||||||
|
|
||||||
|
# Run the tests that didn't run yet or failed previously.
|
||||||
|
# If a test succeeds a testdir/*.out file will be written.
|
||||||
|
# If a test fails a testdir/*.fail file will be written.
|
||||||
|
test:
|
||||||
|
VIMRUNTIME=$(VIMRUNTIME) $(VIM) --clean --not-a-term -u testdir/runtest.vim
|
||||||
|
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f testdir/*.fail testdir/*.out
|
@ -43,3 +43,5 @@ running. Add a test if the function exists and use ":finish", like this:
|
|||||||
The user may have several options set unlike you, try to write the file such
|
The user may have several options set unlike you, try to write the file such
|
||||||
that it works with any option settings. Also be aware of certain features not
|
that it works with any option settings. Also be aware of certain features not
|
||||||
being compiled in.
|
being compiled in.
|
||||||
|
|
||||||
|
To test the indent file, see testdir/README.txt.
|
||||||
|
97
runtime/indent/testdir/README.txt
Normal file
97
runtime/indent/testdir/README.txt
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
TESTING INDENT SCRIPTS
|
||||||
|
|
||||||
|
We'll use FILETYPE for the filetype name here.
|
||||||
|
|
||||||
|
|
||||||
|
FORMAT OF THE FILETYPE.IN FILE
|
||||||
|
|
||||||
|
First of all, create a FILETYPE.in file. It should contain:
|
||||||
|
|
||||||
|
- A modeline setting the 'filetype' and any other option values.
|
||||||
|
This must work like a comment for FILETYPE. E.g. for vim:
|
||||||
|
" vim: set ft=vim sw=4 :
|
||||||
|
|
||||||
|
- At least one block of lines to indent, prefixed with START_INDENT and
|
||||||
|
followed by END_INDENT. These lines must also look like a comment for your
|
||||||
|
FILETYPE. You would normally leave out all indent, so that the effect of
|
||||||
|
the indent command results in adding indent. Example:
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
func Some()
|
||||||
|
let x = 1
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
If you just want to test normal indenting with default options, you can make
|
||||||
|
this a large number of lines. Just add all kinds of language constructs,
|
||||||
|
nested statements, etc. with valid syntax.
|
||||||
|
|
||||||
|
- Optionally, add lines with INDENT_EXE after START_INDENT, followed by a Vim
|
||||||
|
command. This will be executed before indenting the lines. Example:
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_EXE let g:vim_indent_cont = 6
|
||||||
|
let cmd =
|
||||||
|
\ 'some '
|
||||||
|
\ 'string'
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
Note that the command is not undone, you may need to reverse the effect for
|
||||||
|
the next block of lines.
|
||||||
|
|
||||||
|
- Alternatively to indenting all the lines between START_INDENT and
|
||||||
|
END_INDENT, use an INDENT_AT line, which specifies a pattern to find the
|
||||||
|
line to indent. Example:
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_AT this-line
|
||||||
|
func Some()
|
||||||
|
let f = x " this-line
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
Alternatively you can use INDENT_NEXT to indent the line below the matching
|
||||||
|
pattern. Keep in mind that quite often it will indent relative to the
|
||||||
|
matching line:
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_NEXT next-line
|
||||||
|
func Some()
|
||||||
|
" next-line
|
||||||
|
let f = x
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
Or use INDENT_PREV to indent the line above the matching pattern:
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_PREV prev-line
|
||||||
|
func Some()
|
||||||
|
let f = x
|
||||||
|
" prev-line
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
It's best to keep the whole file valid for FILETYPE, so that syntax
|
||||||
|
highlighting works normally, and any indenting that depends on the syntax
|
||||||
|
highlighting also works.
|
||||||
|
|
||||||
|
|
||||||
|
RUNNING THE TEST
|
||||||
|
|
||||||
|
Before running the test, create a FILETYPE.ok file. You can leave it empty at
|
||||||
|
first.
|
||||||
|
|
||||||
|
Now run "make test" from the parent directory. After Vim has done the
|
||||||
|
indenting you will see a FILETYPE.fail file. This contains the actual result
|
||||||
|
of indenting, and it's different from the FILETYPE.ok file.
|
||||||
|
|
||||||
|
Check the contents of the FILETYPE.fail file. If it is perfectly OK, then
|
||||||
|
rename it to overwrite the FILETYPE.ok file. If you now run "make test" again,
|
||||||
|
the test will pass and create a FILETYPE.out file, which is identical to the
|
||||||
|
FILETYPE.ok file. The FILETYPE.fail file will be deleted.
|
||||||
|
|
||||||
|
If you try to run "make test" again you will notice that nothing happens,
|
||||||
|
because the FILETYPE.out file already exists. Delete it, or do "make clean",
|
||||||
|
so that the text runs again. If you edit the FILETYPE.in file, so that it's
|
||||||
|
newer than the FILETYPE.out file, the test will also run.
|
132
runtime/indent/testdir/runtest.vim
Normal file
132
runtime/indent/testdir/runtest.vim
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
" Runs all the indent tests for which there is no .out file.
|
||||||
|
"
|
||||||
|
" Current directory must be runtime/indent.
|
||||||
|
|
||||||
|
" Only do this with the +eval feature
|
||||||
|
if 1
|
||||||
|
|
||||||
|
set nocp
|
||||||
|
filetype indent on
|
||||||
|
syn on
|
||||||
|
set nowrapscan
|
||||||
|
set report=9999
|
||||||
|
|
||||||
|
au! SwapExists * call HandleSwapExists()
|
||||||
|
func HandleSwapExists()
|
||||||
|
" Ignore finding a swap file for the test input and output, the user might be
|
||||||
|
" editing them and that's OK.
|
||||||
|
if expand('<afile>') =~ '.*\.\(in\|out\|fail\|ok\)'
|
||||||
|
let v:swapchoice = 'e'
|
||||||
|
endif
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
let failed_count = 0
|
||||||
|
for fname in glob('testdir/*.in', 1, 1)
|
||||||
|
let root = substitute(fname, '\.in', '', '')
|
||||||
|
|
||||||
|
" Execute the test if the .out file does not exist of when the .in file is
|
||||||
|
" newer.
|
||||||
|
let in_time = getftime(fname)
|
||||||
|
let out_time = getftime(root . '.out')
|
||||||
|
if out_time < 0 || in_time > out_time
|
||||||
|
call delete(root . '.fail')
|
||||||
|
call delete(root . '.out')
|
||||||
|
|
||||||
|
set sw& ts& filetype=
|
||||||
|
exe 'split ' . fname
|
||||||
|
|
||||||
|
let did_some = 0
|
||||||
|
let failed = 0
|
||||||
|
let end = 1
|
||||||
|
while 1
|
||||||
|
" Indent all the lines between "START_INDENT" and "END_INDENT"
|
||||||
|
exe end
|
||||||
|
let start = search('\<START_INDENT\>')
|
||||||
|
let end = search('\<END_INDENT\>')
|
||||||
|
if start <= 0 || end <= 0 || end <= start
|
||||||
|
if did_some == 0
|
||||||
|
call append(0, 'ERROR: START_INDENT and/or END_INDENT not found')
|
||||||
|
let failed = 1
|
||||||
|
endif
|
||||||
|
break
|
||||||
|
else
|
||||||
|
let did_some = 1
|
||||||
|
|
||||||
|
" Execute all commands marked with INDENT_EXE and find any pattern.
|
||||||
|
let lnum = start
|
||||||
|
let pattern = ''
|
||||||
|
let at = ''
|
||||||
|
while 1
|
||||||
|
exe lnum + 1
|
||||||
|
let lnum_exe = search('\<INDENT_EXE\>')
|
||||||
|
exe lnum + 1
|
||||||
|
let indent_at = search('\<INDENT_\(AT\|NEXT\|PREV\)\>')
|
||||||
|
if lnum_exe > 0 && lnum_exe < end && (indent_at <= 0 || lnum_exe < indent_at)
|
||||||
|
exe substitute(getline(lnum_exe), '.*INDENT_EXE', '', '')
|
||||||
|
let lnum = lnum_exe
|
||||||
|
let start = lnum
|
||||||
|
elseif indent_at > 0 && indent_at < end
|
||||||
|
if pattern != ''
|
||||||
|
call append(indent_at, 'ERROR: duplicate pattern')
|
||||||
|
let failed = 1
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
let text = getline(indent_at)
|
||||||
|
let pattern = substitute(text, '.*INDENT_\S*\s*', '', '')
|
||||||
|
let at = substitute(text, '.*INDENT_\(\S*\).*', '\1', '')
|
||||||
|
let lnum = indent_at
|
||||||
|
let start = lnum
|
||||||
|
else
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
exe start + 1
|
||||||
|
if pattern == ''
|
||||||
|
exe 'normal =' . (end - 1) . 'G'
|
||||||
|
else
|
||||||
|
let lnum = search(pattern)
|
||||||
|
if lnum <= 0
|
||||||
|
call append(indent_at, 'ERROR: pattern not found: ' . pattern)
|
||||||
|
let failed = 1
|
||||||
|
break
|
||||||
|
endif
|
||||||
|
if at == 'AT'
|
||||||
|
exe lnum
|
||||||
|
elseif at == 'NEXT'
|
||||||
|
exe lnum + 1
|
||||||
|
else
|
||||||
|
exe lnum - 1
|
||||||
|
endif
|
||||||
|
normal ==
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endwhile
|
||||||
|
|
||||||
|
if !failed
|
||||||
|
" Check the resulting text equals the .ok file.
|
||||||
|
if getline(1, '$') != readfile(root . '.ok')
|
||||||
|
let failed = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if failed
|
||||||
|
let failed_count += 1
|
||||||
|
exe 'write ' . root . '.fail'
|
||||||
|
echoerr 'Test ' . fname . ' FAILED!'
|
||||||
|
else
|
||||||
|
exe 'write ' . root . '.out'
|
||||||
|
endif
|
||||||
|
|
||||||
|
quit! " close the indented file
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
|
||||||
|
" Matching "if 1" at the start.
|
||||||
|
endif
|
||||||
|
|
||||||
|
if failed_count > 0
|
||||||
|
" have make report an error
|
||||||
|
cquit
|
||||||
|
endif
|
||||||
|
qall!
|
46
runtime/indent/testdir/vim.in
Normal file
46
runtime/indent/testdir/vim.in
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
" vim: set ft=vim sw=4 :
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
|
||||||
|
func Some()
|
||||||
|
let x = 1
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
let cmd =
|
||||||
|
\ 'some '
|
||||||
|
\ 'string'
|
||||||
|
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_EXE let g:vim_indent_cont = 6
|
||||||
|
|
||||||
|
let cmd =
|
||||||
|
\ 'some '
|
||||||
|
\ 'string'
|
||||||
|
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_EXE unlet g:vim_indent_cont
|
||||||
|
" INDENT_AT this-line
|
||||||
|
func Some()
|
||||||
|
let f = x " this-line
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_NEXT next-line
|
||||||
|
func Some()
|
||||||
|
" next-line
|
||||||
|
let f = x
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_PREV prev-line
|
||||||
|
func Some()
|
||||||
|
let f = x
|
||||||
|
" prev-line
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
46
runtime/indent/testdir/vim.ok
Normal file
46
runtime/indent/testdir/vim.ok
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
" vim: set ft=vim sw=4 :
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
|
||||||
|
func Some()
|
||||||
|
let x = 1
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
let cmd =
|
||||||
|
\ 'some '
|
||||||
|
\ 'string'
|
||||||
|
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_EXE let g:vim_indent_cont = 6
|
||||||
|
|
||||||
|
let cmd =
|
||||||
|
\ 'some '
|
||||||
|
\ 'string'
|
||||||
|
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_EXE unlet g:vim_indent_cont
|
||||||
|
" INDENT_AT this-line
|
||||||
|
func Some()
|
||||||
|
let f = x " this-line
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_NEXT next-line
|
||||||
|
func Some()
|
||||||
|
" next-line
|
||||||
|
let f = x
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
||||||
|
|
||||||
|
" START_INDENT
|
||||||
|
" INDENT_PREV prev-line
|
||||||
|
func Some()
|
||||||
|
let f = x
|
||||||
|
" prev-line
|
||||||
|
endfunc
|
||||||
|
" END_INDENT
|
112
runtime/keymap/russian-jcukenwintype.vim
Normal file
112
runtime/keymap/russian-jcukenwintype.vim
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
" Vim Keymap file for russian characters, layout 'jcuken', MS Windows
|
||||||
|
" Typewriter variant (slightly incompatible with XFree86 'ru' keymap -
|
||||||
|
" makes use of NUMERO SIGN)
|
||||||
|
" Useful mainly with utf-8 but may work with other encodings
|
||||||
|
|
||||||
|
" Derived from russian-jcuken.vim by Artem Chuprina <ran@ran.pp.ru>
|
||||||
|
" Typewriter variant of standart russian layout
|
||||||
|
" Maintainer: Denis Proskurin <danwerspb@gmail.com>
|
||||||
|
" Last Changed: 2015 May 15
|
||||||
|
|
||||||
|
" All characters are given literally, conversion to another encoding (e.g.,
|
||||||
|
" UTF-8) should work.
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
let b:keymap_name = "ru"
|
||||||
|
|
||||||
|
loadkeymap
|
||||||
|
F А CYRILLIC CAPITAL LETTER A
|
||||||
|
< Б CYRILLIC CAPITAL LETTER BE
|
||||||
|
D В CYRILLIC CAPITAL LETTER VE
|
||||||
|
U Г CYRILLIC CAPITAL LETTER GHE
|
||||||
|
L Д CYRILLIC CAPITAL LETTER DE
|
||||||
|
T Е CYRILLIC CAPITAL LETTER IE
|
||||||
|
? Ё CYRILLIC CAPITAL LETTER IO
|
||||||
|
: Ж CYRILLIC CAPITAL LETTER ZHE
|
||||||
|
P З CYRILLIC CAPITAL LETTER ZE
|
||||||
|
B И CYRILLIC CAPITAL LETTER I
|
||||||
|
Q Й CYRILLIC CAPITAL LETTER SHORT I
|
||||||
|
R К CYRILLIC CAPITAL LETTER KA
|
||||||
|
K Л CYRILLIC CAPITAL LETTER EL
|
||||||
|
V М CYRILLIC CAPITAL LETTER EM
|
||||||
|
Y Н CYRILLIC CAPITAL LETTER EN
|
||||||
|
J О CYRILLIC CAPITAL LETTER O
|
||||||
|
G П CYRILLIC CAPITAL LETTER PE
|
||||||
|
H Р CYRILLIC CAPITAL LETTER ER
|
||||||
|
C С CYRILLIC CAPITAL LETTER ES
|
||||||
|
N Т CYRILLIC CAPITAL LETTER TE
|
||||||
|
E У CYRILLIC CAPITAL LETTER U
|
||||||
|
A Ф CYRILLIC CAPITAL LETTER EF
|
||||||
|
{ Х CYRILLIC CAPITAL LETTER HA
|
||||||
|
W Ц CYRILLIC CAPITAL LETTER TSE
|
||||||
|
X Ч CYRILLIC CAPITAL LETTER CHE
|
||||||
|
I Ш CYRILLIC CAPITAL LETTER SHA
|
||||||
|
O Щ CYRILLIC CAPITAL LETTER SHCHA
|
||||||
|
} Ъ CYRILLIC CAPITAL LETTER HARD SIGN
|
||||||
|
S Ы CYRILLIC CAPITAL LETTER YERU
|
||||||
|
M Ь CYRILLIC CAPITAL LETTER SOFT SIGN
|
||||||
|
\" Э CYRILLIC CAPITAL LETTER E
|
||||||
|
> Ю CYRILLIC CAPITAL LETTER YU
|
||||||
|
Z Я CYRILLIC CAPITAL LETTER YA
|
||||||
|
f а CYRILLIC SMALL LETTER A
|
||||||
|
, б CYRILLIC SMALL LETTER BE
|
||||||
|
d в CYRILLIC SMALL LETTER VE
|
||||||
|
u г CYRILLIC SMALL LETTER GHE
|
||||||
|
l д CYRILLIC SMALL LETTER DE
|
||||||
|
t е CYRILLIC SMALL LETTER IE
|
||||||
|
/ ё CYRILLIC SMALL LETTER IO
|
||||||
|
; ж CYRILLIC SMALL LETTER ZHE
|
||||||
|
p з CYRILLIC SMALL LETTER ZE
|
||||||
|
b и CYRILLIC SMALL LETTER I
|
||||||
|
q й CYRILLIC SMALL LETTER SHORT I
|
||||||
|
r к CYRILLIC SMALL LETTER KA
|
||||||
|
k л CYRILLIC SMALL LETTER EL
|
||||||
|
v м CYRILLIC SMALL LETTER EM
|
||||||
|
y н CYRILLIC SMALL LETTER EN
|
||||||
|
j о CYRILLIC SMALL LETTER O
|
||||||
|
g п CYRILLIC SMALL LETTER PE
|
||||||
|
h р CYRILLIC SMALL LETTER ER
|
||||||
|
c с CYRILLIC SMALL LETTER ES
|
||||||
|
n т CYRILLIC SMALL LETTER TE
|
||||||
|
e у CYRILLIC SMALL LETTER U
|
||||||
|
a ф CYRILLIC SMALL LETTER EF
|
||||||
|
[ х CYRILLIC SMALL LETTER HA
|
||||||
|
w ц CYRILLIC SMALL LETTER TSE
|
||||||
|
x ч CYRILLIC SMALL LETTER CHE
|
||||||
|
i ш CYRILLIC SMALL LETTER SHA
|
||||||
|
o щ CYRILLIC SMALL LETTER SHCHA
|
||||||
|
] ъ CYRILLIC SMALL LETTER HARD SIGN
|
||||||
|
s ы CYRILLIC SMALL LETTER YERU
|
||||||
|
m ь CYRILLIC SMALL LETTER SOFT SIGN
|
||||||
|
' э CYRILLIC SMALL LETTER E
|
||||||
|
. ю CYRILLIC SMALL LETTER YU
|
||||||
|
z я CYRILLIC SMALL LETTER YA
|
||||||
|
` |
|
||||||
|
1 №
|
||||||
|
2 -
|
||||||
|
3 /
|
||||||
|
4 "
|
||||||
|
5 :
|
||||||
|
6 ,
|
||||||
|
7 .
|
||||||
|
8 _
|
||||||
|
9 ?
|
||||||
|
0 %
|
||||||
|
- !
|
||||||
|
= ;
|
||||||
|
~ +
|
||||||
|
! 1
|
||||||
|
@ 2
|
||||||
|
# 3
|
||||||
|
$ 4
|
||||||
|
% 5
|
||||||
|
^ 6
|
||||||
|
& 7
|
||||||
|
* 8
|
||||||
|
( 9
|
||||||
|
) 0
|
||||||
|
_ =
|
||||||
|
+ \\
|
||||||
|
\\ )
|
||||||
|
\| (
|
@ -289,7 +289,7 @@ function Inspector:putValue(v)
|
|||||||
if tv == 'string' then
|
if tv == 'string' then
|
||||||
self:puts(smartQuote(escape(v)))
|
self:puts(smartQuote(escape(v)))
|
||||||
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
|
||||||
tv == 'cdata' or tv == 'ctype' then
|
tv == 'cdata' or tv == 'ctype' or (vim and v == vim.NIL) then
|
||||||
self:puts(tostring(v))
|
self:puts(tostring(v))
|
||||||
elseif tv == 'table' then
|
elseif tv == 'table' then
|
||||||
self:putTable(v)
|
self:putTable(v)
|
||||||
|
958
runtime/lua/vim/lsp.lua
Normal file
958
runtime/lua/vim/lsp.lua
Normal file
@ -0,0 +1,958 @@
|
|||||||
|
local default_callbacks = require 'vim.lsp.callbacks'
|
||||||
|
local log = require 'vim.lsp.log'
|
||||||
|
local lsp_rpc = require 'vim.lsp.rpc'
|
||||||
|
local protocol = require 'vim.lsp.protocol'
|
||||||
|
local util = require 'vim.lsp.util'
|
||||||
|
|
||||||
|
local vim = vim
|
||||||
|
local nvim_err_writeln, nvim_buf_get_lines, nvim_command, nvim_buf_get_option
|
||||||
|
= vim.api.nvim_err_writeln, vim.api.nvim_buf_get_lines, vim.api.nvim_command, vim.api.nvim_buf_get_option
|
||||||
|
local uv = vim.loop
|
||||||
|
local tbl_isempty, tbl_extend = vim.tbl_isempty, vim.tbl_extend
|
||||||
|
local validate = vim.validate
|
||||||
|
|
||||||
|
local lsp = {
|
||||||
|
protocol = protocol;
|
||||||
|
callbacks = default_callbacks;
|
||||||
|
buf = require'vim.lsp.buf';
|
||||||
|
util = util;
|
||||||
|
-- Allow raw RPC access.
|
||||||
|
rpc = lsp_rpc;
|
||||||
|
-- Export these directly from rpc.
|
||||||
|
rpc_response_error = lsp_rpc.rpc_response_error;
|
||||||
|
-- You probably won't need this directly, since __tostring is set for errors
|
||||||
|
-- by the RPC.
|
||||||
|
-- format_rpc_error = lsp_rpc.format_rpc_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
-- TODO improve handling of scratch buffers with LSP attached.
|
||||||
|
|
||||||
|
local function err_message(...)
|
||||||
|
nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
|
||||||
|
nvim_command("redraw")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function resolve_bufnr(bufnr)
|
||||||
|
validate { bufnr = { bufnr, 'n', true } }
|
||||||
|
if bufnr == nil or bufnr == 0 then
|
||||||
|
return vim.api.nvim_get_current_buf()
|
||||||
|
end
|
||||||
|
return bufnr
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_dir(filename)
|
||||||
|
validate{filename={filename,'s'}}
|
||||||
|
local stat = uv.fs_stat(filename)
|
||||||
|
return stat and stat.type == 'directory' or false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO Use vim.wait when that is available, but provide an alternative for now.
|
||||||
|
local wait = vim.wait or function(timeout_ms, condition, interval)
|
||||||
|
validate {
|
||||||
|
timeout_ms = { timeout_ms, 'n' };
|
||||||
|
condition = { condition, 'f' };
|
||||||
|
interval = { interval, 'n', true };
|
||||||
|
}
|
||||||
|
assert(timeout_ms > 0, "timeout_ms must be > 0")
|
||||||
|
local _ = log.debug() and log.debug("wait.fallback", timeout_ms)
|
||||||
|
interval = interval or 200
|
||||||
|
local interval_cmd = "sleep "..interval.."m"
|
||||||
|
local timeout = timeout_ms + uv.now()
|
||||||
|
-- TODO is there a better way to sync this?
|
||||||
|
while true do
|
||||||
|
uv.update_time()
|
||||||
|
if condition() then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
if uv.now() >= timeout then
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
nvim_command(interval_cmd)
|
||||||
|
-- vim.loop.sleep(10)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local wait_result_reason = { [-1] = "timeout"; [-2] = "interrupted"; [-3] = "error" }
|
||||||
|
|
||||||
|
local valid_encodings = {
|
||||||
|
["utf-8"] = 'utf-8'; ["utf-16"] = 'utf-16'; ["utf-32"] = 'utf-32';
|
||||||
|
["utf8"] = 'utf-8'; ["utf16"] = 'utf-16'; ["utf32"] = 'utf-32';
|
||||||
|
UTF8 = 'utf-8'; UTF16 = 'utf-16'; UTF32 = 'utf-32';
|
||||||
|
}
|
||||||
|
|
||||||
|
local client_index = 0
|
||||||
|
local function next_client_id()
|
||||||
|
client_index = client_index + 1
|
||||||
|
return client_index
|
||||||
|
end
|
||||||
|
-- Tracks all clients created via lsp.start_client
|
||||||
|
local active_clients = {}
|
||||||
|
local all_buffer_active_clients = {}
|
||||||
|
local uninitialized_clients = {}
|
||||||
|
|
||||||
|
local function for_each_buffer_client(bufnr, callback)
|
||||||
|
validate {
|
||||||
|
callback = { callback, 'f' };
|
||||||
|
}
|
||||||
|
bufnr = resolve_bufnr(bufnr)
|
||||||
|
local client_ids = all_buffer_active_clients[bufnr]
|
||||||
|
if not client_ids or tbl_isempty(client_ids) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for client_id in pairs(client_ids) do
|
||||||
|
local client = active_clients[client_id]
|
||||||
|
if client then
|
||||||
|
callback(client, client_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Error codes to be used with `on_error` from |vim.lsp.start_client|.
|
||||||
|
-- Can be used to look up the string from a the number or the number
|
||||||
|
-- from the string.
|
||||||
|
lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_reverse_lookup {
|
||||||
|
ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1;
|
||||||
|
})
|
||||||
|
|
||||||
|
local function validate_encoding(encoding)
|
||||||
|
validate {
|
||||||
|
encoding = { encoding, 's' };
|
||||||
|
}
|
||||||
|
return valid_encodings[encoding:lower()]
|
||||||
|
or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function validate_command(input)
|
||||||
|
local cmd, cmd_args
|
||||||
|
if type(input) == 'string' then
|
||||||
|
-- Use a shell to execute the command if it is a string.
|
||||||
|
cmd = vim.api.nvim_get_option('shell')
|
||||||
|
cmd_args = {vim.api.nvim_get_option('shellcmdflag'), input}
|
||||||
|
elseif vim.tbl_islist(input) then
|
||||||
|
cmd = input[1]
|
||||||
|
cmd_args = {}
|
||||||
|
-- Don't mutate our input.
|
||||||
|
for i, v in ipairs(input) do
|
||||||
|
assert(type(v) == 'string', "input arguments must be strings")
|
||||||
|
if i > 1 then
|
||||||
|
table.insert(cmd_args, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error("cmd type must be string or list.")
|
||||||
|
end
|
||||||
|
return cmd, cmd_args
|
||||||
|
end
|
||||||
|
|
||||||
|
local function optional_validator(fn)
|
||||||
|
return function(v)
|
||||||
|
return v == nil or fn(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function validate_client_config(config)
|
||||||
|
validate {
|
||||||
|
config = { config, 't' };
|
||||||
|
}
|
||||||
|
validate {
|
||||||
|
root_dir = { config.root_dir, is_dir, "directory" };
|
||||||
|
callbacks = { config.callbacks, "t", true };
|
||||||
|
capabilities = { config.capabilities, "t", true };
|
||||||
|
cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), "directory" };
|
||||||
|
cmd_env = { config.cmd_env, "f", true };
|
||||||
|
name = { config.name, 's', true };
|
||||||
|
on_error = { config.on_error, "f", true };
|
||||||
|
on_exit = { config.on_exit, "f", true };
|
||||||
|
on_init = { config.on_init, "f", true };
|
||||||
|
before_init = { config.before_init, "f", true };
|
||||||
|
offset_encoding = { config.offset_encoding, "s", true };
|
||||||
|
}
|
||||||
|
local cmd, cmd_args = validate_command(config.cmd)
|
||||||
|
local offset_encoding = valid_encodings.UTF16
|
||||||
|
if config.offset_encoding then
|
||||||
|
offset_encoding = validate_encoding(config.offset_encoding)
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
cmd = cmd; cmd_args = cmd_args;
|
||||||
|
offset_encoding = offset_encoding;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buf_get_full_text(bufnr)
|
||||||
|
local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n')
|
||||||
|
if nvim_buf_get_option(bufnr, 'eol') then
|
||||||
|
text = text .. '\n'
|
||||||
|
end
|
||||||
|
return text
|
||||||
|
end
|
||||||
|
|
||||||
|
local function text_document_did_open_handler(bufnr, client)
|
||||||
|
if not client.resolved_capabilities.text_document_open_close then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not vim.api.nvim_buf_is_loaded(bufnr) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local params = {
|
||||||
|
textDocument = {
|
||||||
|
version = 0;
|
||||||
|
uri = vim.uri_from_bufnr(bufnr);
|
||||||
|
-- TODO make sure our filetypes are compatible with languageId names.
|
||||||
|
languageId = nvim_buf_get_option(bufnr, 'filetype');
|
||||||
|
text = buf_get_full_text(bufnr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.notify('textDocument/didOpen', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--- Start a client and initialize it.
|
||||||
|
-- Its arguments are passed via a configuration object.
|
||||||
|
--
|
||||||
|
-- Mandatory parameters:
|
||||||
|
--
|
||||||
|
-- root_dir: {string} specifying the directory where the LSP server will base
|
||||||
|
-- as its rootUri on initialization.
|
||||||
|
--
|
||||||
|
-- cmd: {string} or {list} which is the base command to execute for the LSP. A
|
||||||
|
-- string will be run using |'shell'| and a list will be interpreted as a bare
|
||||||
|
-- command with arguments passed. This is the same as |jobstart()|.
|
||||||
|
--
|
||||||
|
-- Optional parameters:
|
||||||
|
|
||||||
|
-- cmd_cwd: {string} specifying the directory to launch the `cmd` process. This
|
||||||
|
-- is not related to `root_dir`. By default, |getcwd()| is used.
|
||||||
|
--
|
||||||
|
-- cmd_env: {table} specifying the environment flags to pass to the LSP on
|
||||||
|
-- spawn. This can be specified using keys like a map or as a list with `k=v`
|
||||||
|
-- pairs or both. Non-string values are coerced to a string.
|
||||||
|
-- For example: `{ "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; }`.
|
||||||
|
--
|
||||||
|
-- capabilities: A {table} which will be used instead of
|
||||||
|
-- `vim.lsp.protocol.make_client_capabilities()` which contains neovim's
|
||||||
|
-- default capabilities and passed to the language server on initialization.
|
||||||
|
-- You'll probably want to use make_client_capabilities() and modify the
|
||||||
|
-- result.
|
||||||
|
-- NOTE:
|
||||||
|
-- To send an empty dictionary, you should use
|
||||||
|
-- `{[vim.type_idx]=vim.types.dictionary}` Otherwise, it will be encoded as
|
||||||
|
-- an array.
|
||||||
|
--
|
||||||
|
-- callbacks: A {table} of whose keys are language server method names and the
|
||||||
|
-- values are `function(err, method, params, client_id)`.
|
||||||
|
-- This will be called for:
|
||||||
|
-- - notifications from the server, where `err` will always be `nil`
|
||||||
|
-- - requests initiated by the server. For these, you can respond by returning
|
||||||
|
-- two values: `result, err`. The err must be in the format of an RPC error,
|
||||||
|
-- which is `{ code, message, data? }`. You can use |vim.lsp.rpc_response_error()|
|
||||||
|
-- to help with this.
|
||||||
|
-- - as a callback for requests initiated by the client if the request doesn't
|
||||||
|
-- explicitly specify a callback.
|
||||||
|
--
|
||||||
|
-- init_options: A {table} of values to pass in the initialization request
|
||||||
|
-- as `initializationOptions`. See the `initialize` in the LSP spec.
|
||||||
|
--
|
||||||
|
-- name: A {string} used in log messages. Defaults to {client_id}
|
||||||
|
--
|
||||||
|
-- offset_encoding: One of 'utf-8', 'utf-16', or 'utf-32' which is the
|
||||||
|
-- encoding that the LSP server expects. By default, it is 'utf-16' as
|
||||||
|
-- specified in the LSP specification. The client does not verify this
|
||||||
|
-- is correct.
|
||||||
|
--
|
||||||
|
-- on_error(code, ...): A function for handling errors thrown by client
|
||||||
|
-- operation. {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. `vim.lsp.client_errors[code]` can be used to retrieve a
|
||||||
|
-- human understandable string.
|
||||||
|
--
|
||||||
|
-- before_init(initialize_params, config): A function which is called *before*
|
||||||
|
-- the request `initialize` is completed. `initialize_params` contains
|
||||||
|
-- the parameters we are sending to the server and `config` is the config that
|
||||||
|
-- was passed to `start_client()` for convenience. You can use this to modify
|
||||||
|
-- parameters before they are sent.
|
||||||
|
--
|
||||||
|
-- on_init(client, initialize_result): A function which is called after the
|
||||||
|
-- request `initialize` is completed. `initialize_result` contains
|
||||||
|
-- `capabilities` and anything else the server may send. For example, `clangd`
|
||||||
|
-- sends `result.offsetEncoding` if `capabilities.offsetEncoding` was sent to
|
||||||
|
-- it.
|
||||||
|
--
|
||||||
|
-- on_exit(code, signal, client_id): A function which is called after the
|
||||||
|
-- client has exited. code is the exit code of the process, and signal is a
|
||||||
|
-- number describing the signal used to terminate (if any).
|
||||||
|
--
|
||||||
|
-- on_attach(client, bufnr): A function which is called after the client is
|
||||||
|
-- attached to a buffer.
|
||||||
|
--
|
||||||
|
-- trace: 'off' | 'messages' | 'verbose' | nil passed directly to the language
|
||||||
|
-- server in the initialize request. Invalid/empty values will default to 'off'
|
||||||
|
--
|
||||||
|
-- @returns client_id You can use |vim.lsp.get_client_by_id()| to get the
|
||||||
|
-- actual client.
|
||||||
|
--
|
||||||
|
-- NOTE: The client is only available *after* it has been initialized, which
|
||||||
|
-- may happen after a small delay (or never if there is an error).
|
||||||
|
-- For this reason, you may want to use `on_init` to do any actions once the
|
||||||
|
-- client has been initialized.
|
||||||
|
function lsp.start_client(config)
|
||||||
|
local cleaned_config = validate_client_config(config)
|
||||||
|
local cmd, cmd_args, offset_encoding = cleaned_config.cmd, cleaned_config.cmd_args, cleaned_config.offset_encoding
|
||||||
|
|
||||||
|
local client_id = next_client_id()
|
||||||
|
|
||||||
|
local callbacks = config.callbacks or {}
|
||||||
|
local name = config.name or tostring(client_id)
|
||||||
|
local log_prefix = string.format("LSP[%s]", name)
|
||||||
|
|
||||||
|
local handlers = {}
|
||||||
|
|
||||||
|
local function resolve_callback(method)
|
||||||
|
return callbacks[method] or default_callbacks[method]
|
||||||
|
end
|
||||||
|
|
||||||
|
function handlers.notification(method, params)
|
||||||
|
local _ = log.debug() and log.debug('notification', method, params)
|
||||||
|
local callback = resolve_callback(method)
|
||||||
|
if callback then
|
||||||
|
-- Method name is provided here for convenience.
|
||||||
|
callback(nil, method, params, client_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function handlers.server_request(method, params)
|
||||||
|
local _ = log.debug() and log.debug('server_request', method, params)
|
||||||
|
local callback = resolve_callback(method)
|
||||||
|
if callback then
|
||||||
|
local _ = log.debug() and log.debug("server_request: found callback for", method)
|
||||||
|
return callback(nil, method, params, client_id)
|
||||||
|
end
|
||||||
|
local _ = log.debug() and log.debug("server_request: no callback found for", method)
|
||||||
|
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
function handlers.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))
|
||||||
|
if config.on_error then
|
||||||
|
local status, usererr = pcall(config.on_error, code, err)
|
||||||
|
if not status then
|
||||||
|
local _ = log.error() and log.error(log_prefix, "user on_error failed", { err = usererr })
|
||||||
|
err_message(log_prefix, ' user on_error failed: ', tostring(usererr))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function handlers.on_exit(code, signal)
|
||||||
|
active_clients[client_id] = nil
|
||||||
|
uninitialized_clients[client_id] = nil
|
||||||
|
local active_buffers = {}
|
||||||
|
for bufnr, client_ids in pairs(all_buffer_active_clients) do
|
||||||
|
if client_ids[client_id] then
|
||||||
|
table.insert(active_buffers, bufnr)
|
||||||
|
end
|
||||||
|
client_ids[client_id] = nil
|
||||||
|
end
|
||||||
|
-- Buffer level cleanup
|
||||||
|
vim.schedule(function()
|
||||||
|
for _, bufnr in ipairs(active_buffers) do
|
||||||
|
util.buf_clear_diagnostics(bufnr)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
if config.on_exit then
|
||||||
|
pcall(config.on_exit, code, signal, client_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Start the RPC client.
|
||||||
|
local rpc = lsp_rpc.start(cmd, cmd_args, handlers, {
|
||||||
|
cwd = config.cmd_cwd;
|
||||||
|
env = config.cmd_env;
|
||||||
|
})
|
||||||
|
|
||||||
|
local client = {
|
||||||
|
id = client_id;
|
||||||
|
name = name;
|
||||||
|
rpc = rpc;
|
||||||
|
offset_encoding = offset_encoding;
|
||||||
|
callbacks = callbacks;
|
||||||
|
config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Store the uninitialized_clients for cleanup in case we exit before
|
||||||
|
-- initialize finishes.
|
||||||
|
uninitialized_clients[client_id] = client;
|
||||||
|
|
||||||
|
local function initialize()
|
||||||
|
local valid_traces = {
|
||||||
|
off = 'off'; messages = 'messages'; verbose = 'verbose';
|
||||||
|
}
|
||||||
|
local initialize_params = {
|
||||||
|
-- The process Id of the parent process that started the server. Is null if
|
||||||
|
-- the process has not been started by another process. If the parent
|
||||||
|
-- process is not alive then the server should exit (see exit notification)
|
||||||
|
-- its process.
|
||||||
|
processId = uv.getpid();
|
||||||
|
-- The rootPath of the workspace. Is null if no folder is open.
|
||||||
|
--
|
||||||
|
-- @deprecated in favour of rootUri.
|
||||||
|
rootPath = nil;
|
||||||
|
-- The rootUri of the workspace. Is null if no folder is open. If both
|
||||||
|
-- `rootPath` and `rootUri` are set `rootUri` wins.
|
||||||
|
rootUri = vim.uri_from_fname(config.root_dir);
|
||||||
|
-- User provided initialization options.
|
||||||
|
initializationOptions = config.init_options;
|
||||||
|
-- The capabilities provided by the client (editor or tool)
|
||||||
|
capabilities = config.capabilities or protocol.make_client_capabilities();
|
||||||
|
-- The initial trace setting. If omitted trace is disabled ('off').
|
||||||
|
-- trace = 'off' | 'messages' | 'verbose';
|
||||||
|
trace = valid_traces[config.trace] or 'off';
|
||||||
|
-- The workspace folders configured in the client when the server starts.
|
||||||
|
-- This property is only available if the client supports workspace folders.
|
||||||
|
-- It can be `null` if the client supports workspace folders but none are
|
||||||
|
-- configured.
|
||||||
|
--
|
||||||
|
-- Since 3.6.0
|
||||||
|
-- workspaceFolders?: WorkspaceFolder[] | null;
|
||||||
|
-- export interface WorkspaceFolder {
|
||||||
|
-- -- The associated URI for this workspace folder.
|
||||||
|
-- uri
|
||||||
|
-- -- The name of the workspace folder. Used to refer to this
|
||||||
|
-- -- workspace folder in the user interface.
|
||||||
|
-- name
|
||||||
|
-- }
|
||||||
|
workspaceFolders = nil;
|
||||||
|
}
|
||||||
|
if config.before_init then
|
||||||
|
-- TODO(ashkan) handle errors here.
|
||||||
|
pcall(config.before_init, initialize_params, config)
|
||||||
|
end
|
||||||
|
local _ = log.debug() and log.debug(log_prefix, "initialize_params", initialize_params)
|
||||||
|
rpc.request('initialize', initialize_params, function(init_err, result)
|
||||||
|
assert(not init_err, tostring(init_err))
|
||||||
|
assert(result, "server sent empty result")
|
||||||
|
rpc.notify('initialized', {[vim.type_idx]=vim.types.dictionary})
|
||||||
|
client.initialized = true
|
||||||
|
uninitialized_clients[client_id] = nil
|
||||||
|
client.server_capabilities = assert(result.capabilities, "initialize result doesn't contain capabilities")
|
||||||
|
-- These are the cleaned up capabilities we use for dynamically deciding
|
||||||
|
-- when to send certain events to clients.
|
||||||
|
client.resolved_capabilities = protocol.resolve_capabilities(client.server_capabilities)
|
||||||
|
if config.on_init then
|
||||||
|
local status, err = pcall(config.on_init, client, result)
|
||||||
|
if not status then
|
||||||
|
pcall(handlers.on_error, lsp.client_errors.ON_INIT_CALLBACK_ERROR, err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local _ = log.debug() and log.debug(log_prefix, "server_capabilities", client.server_capabilities)
|
||||||
|
local _ = log.info() and log.info(log_prefix, "initialized", { resolved_capabilities = client.resolved_capabilities })
|
||||||
|
|
||||||
|
-- Only assign after initialized.
|
||||||
|
active_clients[client_id] = client
|
||||||
|
-- If we had been registered before we start, then send didOpen This can
|
||||||
|
-- happen if we attach to buffers before initialize finishes or if
|
||||||
|
-- someone restarts a client.
|
||||||
|
for bufnr, client_ids in pairs(all_buffer_active_clients) do
|
||||||
|
if client_ids[client_id] then
|
||||||
|
client._on_attach(bufnr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unsupported_method(method)
|
||||||
|
local msg = "server doesn't support "..method
|
||||||
|
local _ = log.warn() and log.warn(msg)
|
||||||
|
err_message(msg)
|
||||||
|
return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Checks capabilities before rpc.request-ing.
|
||||||
|
function client.request(method, params, callback)
|
||||||
|
if not callback then
|
||||||
|
callback = resolve_callback(method)
|
||||||
|
or error("not found: request callback for client "..client.name)
|
||||||
|
end
|
||||||
|
local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, callback)
|
||||||
|
-- TODO keep these checks or just let it go anyway?
|
||||||
|
if (not client.resolved_capabilities.hover and method == 'textDocument/hover')
|
||||||
|
or (not client.resolved_capabilities.signature_help and method == 'textDocument/signatureHelp')
|
||||||
|
or (not client.resolved_capabilities.goto_definition and method == 'textDocument/definition')
|
||||||
|
or (not client.resolved_capabilities.implementation and method == 'textDocument/implementation')
|
||||||
|
then
|
||||||
|
callback(unsupported_method(method), method, nil, client_id)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
return rpc.request(method, params, function(err, result)
|
||||||
|
callback(err, method, result, client_id)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.notify(...)
|
||||||
|
return rpc.notify(...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.cancel_request(id)
|
||||||
|
validate{id = {id, 'n'}}
|
||||||
|
return rpc.notify("$/cancelRequest", { id = id })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Track this so that we can escalate automatically if we've alredy tried a
|
||||||
|
-- graceful shutdown
|
||||||
|
local tried_graceful_shutdown = false
|
||||||
|
function client.stop(force)
|
||||||
|
local handle = rpc.handle
|
||||||
|
if handle:is_closing() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if force or (not client.initialized) or tried_graceful_shutdown then
|
||||||
|
handle:kill(15)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
tried_graceful_shutdown = true
|
||||||
|
-- Sending a signal after a process has exited is acceptable.
|
||||||
|
rpc.request('shutdown', nil, function(err, _)
|
||||||
|
if err == nil then
|
||||||
|
rpc.notify('exit')
|
||||||
|
else
|
||||||
|
-- If there was an error in the shutdown request, then term to be safe.
|
||||||
|
handle:kill(15)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.is_stopped()
|
||||||
|
return rpc.handle:is_closing()
|
||||||
|
end
|
||||||
|
|
||||||
|
function client._on_attach(bufnr)
|
||||||
|
text_document_did_open_handler(bufnr, client)
|
||||||
|
if config.on_attach then
|
||||||
|
-- TODO(ashkan) handle errors.
|
||||||
|
pcall(config.on_attach, client, bufnr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
initialize()
|
||||||
|
|
||||||
|
return client_id
|
||||||
|
end
|
||||||
|
|
||||||
|
local function once(fn)
|
||||||
|
local value
|
||||||
|
return function(...)
|
||||||
|
if not value then value = fn(...) end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local text_document_did_change_handler
|
||||||
|
do
|
||||||
|
local encoding_index = { ["utf-8"] = 1; ["utf-16"] = 2; ["utf-32"] = 3; }
|
||||||
|
text_document_did_change_handler = function(_, bufnr, changedtick,
|
||||||
|
firstline, lastline, new_lastline, old_byte_size, old_utf32_size,
|
||||||
|
old_utf16_size)
|
||||||
|
local _ = log.debug() and log.debug("on_lines", bufnr, changedtick, firstline,
|
||||||
|
lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size, nvim_buf_get_lines(bufnr, firstline, new_lastline, true))
|
||||||
|
if old_byte_size == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Don't do anything if there are no clients attached.
|
||||||
|
if tbl_isempty(all_buffer_active_clients[bufnr] or {}) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Lazy initialize these because clients may not even need them.
|
||||||
|
local incremental_changes = once(function(client)
|
||||||
|
local size_index = encoding_index[client.offset_encoding]
|
||||||
|
local length = select(size_index, old_byte_size, old_utf16_size, old_utf32_size)
|
||||||
|
local lines = nvim_buf_get_lines(bufnr, firstline, new_lastline, true)
|
||||||
|
-- This is necessary because we are specifying the full line including the
|
||||||
|
-- newline in range. Therefore, we must replace the newline as well.
|
||||||
|
if #lines > 0 then
|
||||||
|
table.insert(lines, '')
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
range = {
|
||||||
|
start = { line = firstline, character = 0 };
|
||||||
|
["end"] = { line = lastline, character = 0 };
|
||||||
|
};
|
||||||
|
rangeLength = length;
|
||||||
|
text = table.concat(lines, '\n');
|
||||||
|
};
|
||||||
|
end)
|
||||||
|
local full_changes = once(function()
|
||||||
|
return {
|
||||||
|
text = buf_get_full_text(bufnr);
|
||||||
|
};
|
||||||
|
end)
|
||||||
|
local uri = vim.uri_from_bufnr(bufnr)
|
||||||
|
for_each_buffer_client(bufnr, function(client, _client_id)
|
||||||
|
local text_document_did_change = client.resolved_capabilities.text_document_did_change
|
||||||
|
local changes
|
||||||
|
if text_document_did_change == protocol.TextDocumentSyncKind.None then
|
||||||
|
return
|
||||||
|
--[=[ TODO(ashkan) there seem to be problems with the byte_sizes sent by
|
||||||
|
-- neovim right now so only send the full content for now. In general, we
|
||||||
|
-- can assume that servers *will* support both versions anyway, as there
|
||||||
|
-- is no way to specify the sync capability by the client.
|
||||||
|
-- See https://github.com/palantir/python-language-server/commit/cfd6675bc10d5e8dbc50fc50f90e4a37b7178821#diff-f68667852a14e9f761f6ebf07ba02fc8 for an example of pyls handling both.
|
||||||
|
--]=]
|
||||||
|
elseif true or text_document_did_change == protocol.TextDocumentSyncKind.Full then
|
||||||
|
changes = full_changes(client)
|
||||||
|
elseif text_document_did_change == protocol.TextDocumentSyncKind.Incremental then
|
||||||
|
changes = incremental_changes(client)
|
||||||
|
end
|
||||||
|
client.notify("textDocument/didChange", {
|
||||||
|
textDocument = {
|
||||||
|
uri = uri;
|
||||||
|
version = changedtick;
|
||||||
|
};
|
||||||
|
contentChanges = { changes; }
|
||||||
|
})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Buffer lifecycle handler for textDocument/didSave
|
||||||
|
function lsp._text_document_did_save_handler(bufnr)
|
||||||
|
bufnr = resolve_bufnr(bufnr)
|
||||||
|
local uri = vim.uri_from_bufnr(bufnr)
|
||||||
|
local text = once(function()
|
||||||
|
return table.concat(nvim_buf_get_lines(bufnr, 0, -1, false), '\n')
|
||||||
|
end)
|
||||||
|
for_each_buffer_client(bufnr, function(client, _client_id)
|
||||||
|
if client.resolved_capabilities.text_document_save then
|
||||||
|
local included_text
|
||||||
|
if client.resolved_capabilities.text_document_save_include_text then
|
||||||
|
included_text = text()
|
||||||
|
end
|
||||||
|
client.notify('textDocument/didSave', {
|
||||||
|
textDocument = {
|
||||||
|
uri = uri;
|
||||||
|
text = included_text;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Implements the textDocument/did* notifications required to track a buffer
|
||||||
|
-- for any language server.
|
||||||
|
-- @param bufnr [number] buffer handle or 0 for current
|
||||||
|
-- @param client_id [number] the client id
|
||||||
|
function lsp.buf_attach_client(bufnr, client_id)
|
||||||
|
validate {
|
||||||
|
bufnr = {bufnr, 'n', true};
|
||||||
|
client_id = {client_id, 'n'};
|
||||||
|
}
|
||||||
|
bufnr = resolve_bufnr(bufnr)
|
||||||
|
local buffer_client_ids = all_buffer_active_clients[bufnr]
|
||||||
|
-- This is our first time attaching to this buffer.
|
||||||
|
if not buffer_client_ids then
|
||||||
|
buffer_client_ids = {}
|
||||||
|
all_buffer_active_clients[bufnr] = buffer_client_ids
|
||||||
|
|
||||||
|
local uri = vim.uri_from_bufnr(bufnr)
|
||||||
|
nvim_command(string.format("autocmd BufWritePost <buffer=%d> lua vim.lsp._text_document_did_save_handler(0)", bufnr))
|
||||||
|
-- First time, so attach and set up stuff.
|
||||||
|
vim.api.nvim_buf_attach(bufnr, false, {
|
||||||
|
on_lines = text_document_did_change_handler;
|
||||||
|
on_detach = function()
|
||||||
|
local params = { textDocument = { uri = uri; } }
|
||||||
|
for_each_buffer_client(bufnr, function(client, _client_id)
|
||||||
|
if client.resolved_capabilities.text_document_open_close then
|
||||||
|
client.notify('textDocument/didClose', params)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
all_buffer_active_clients[bufnr] = nil
|
||||||
|
end;
|
||||||
|
-- TODO if we know all of the potential clients ahead of time, then we
|
||||||
|
-- could conditionally set this.
|
||||||
|
-- utf_sizes = size_index > 1;
|
||||||
|
utf_sizes = true;
|
||||||
|
})
|
||||||
|
end
|
||||||
|
if buffer_client_ids[client_id] then return end
|
||||||
|
-- This is our first time attaching this client to this buffer.
|
||||||
|
buffer_client_ids[client_id] = true
|
||||||
|
|
||||||
|
local client = active_clients[client_id]
|
||||||
|
-- Send didOpen for the client if it is initialized. If it isn't initialized
|
||||||
|
-- then it will send didOpen on initialize.
|
||||||
|
if client then
|
||||||
|
client._on_attach(bufnr)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if a buffer is attached for a particular client.
|
||||||
|
-- @param bufnr [number] buffer handle or 0 for current
|
||||||
|
-- @param client_id [number] the client id
|
||||||
|
function lsp.buf_is_attached(bufnr, client_id)
|
||||||
|
return (all_buffer_active_clients[bufnr] or {})[client_id] == true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Look up an active client by its id, returns nil if it is not yet initialized
|
||||||
|
-- or is not a valid id.
|
||||||
|
-- @param client_id number the client id.
|
||||||
|
function lsp.get_client_by_id(client_id)
|
||||||
|
return active_clients[client_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Stop a client by its id, optionally with force.
|
||||||
|
-- You can also use the `stop()` function on a client if you already have
|
||||||
|
-- access to it.
|
||||||
|
-- By default, it will just ask the server to shutdown without force.
|
||||||
|
-- If you request to stop a client which has previously been requested to shutdown,
|
||||||
|
-- it will automatically force shutdown.
|
||||||
|
-- @param client_id number the client id.
|
||||||
|
-- @param force boolean (optional) whether to use force or request shutdown
|
||||||
|
function lsp.stop_client(client_id, force)
|
||||||
|
local client
|
||||||
|
client = active_clients[client_id]
|
||||||
|
if client then
|
||||||
|
client.stop(force)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
client = uninitialized_clients[client_id]
|
||||||
|
if client then
|
||||||
|
client.stop(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns a list of all the active clients.
|
||||||
|
function lsp.get_active_clients()
|
||||||
|
return vim.tbl_values(active_clients)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Stop all the clients, optionally with force.
|
||||||
|
-- You can also use the `stop()` function on a client if you already have
|
||||||
|
-- access to it.
|
||||||
|
-- By default, it will just ask the server to shutdown without force.
|
||||||
|
-- If you request to stop a client which has previously been requested to shutdown,
|
||||||
|
-- it will automatically force shutdown.
|
||||||
|
-- @param force boolean (optional) whether to use force or request shutdown
|
||||||
|
function lsp.stop_all_clients(force)
|
||||||
|
for _, client in pairs(uninitialized_clients) do
|
||||||
|
client.stop(true)
|
||||||
|
end
|
||||||
|
for _, client in pairs(active_clients) do
|
||||||
|
client.stop(force)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function lsp._vim_exit_handler()
|
||||||
|
log.info("exit_handler", active_clients)
|
||||||
|
for _, client in pairs(uninitialized_clients) do
|
||||||
|
client.stop(true)
|
||||||
|
end
|
||||||
|
-- TODO handle v:dying differently?
|
||||||
|
if tbl_isempty(active_clients) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for _, client in pairs(active_clients) do
|
||||||
|
client.stop()
|
||||||
|
end
|
||||||
|
local wait_result = wait(500, function() return tbl_isempty(active_clients) end, 50)
|
||||||
|
if wait_result ~= 0 then
|
||||||
|
for _, client in pairs(active_clients) do
|
||||||
|
client.stop(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
nvim_command("autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()")
|
||||||
|
|
||||||
|
---
|
||||||
|
--- Buffer level client functions.
|
||||||
|
---
|
||||||
|
|
||||||
|
--- Send a request to a server and return the response
|
||||||
|
-- @param bufnr [number] Buffer handle or 0 for current.
|
||||||
|
-- @param method [string] Request method name
|
||||||
|
-- @param params [table|nil] Parameters to send to the server
|
||||||
|
-- @param callback [function|nil] Request callback (or uses the client's callbacks)
|
||||||
|
--
|
||||||
|
-- @returns: client_request_ids, cancel_all_requests
|
||||||
|
function lsp.buf_request(bufnr, method, params, callback)
|
||||||
|
validate {
|
||||||
|
bufnr = { bufnr, 'n', true };
|
||||||
|
method = { method, 's' };
|
||||||
|
callback = { callback, 'f', true };
|
||||||
|
}
|
||||||
|
local client_request_ids = {}
|
||||||
|
for_each_buffer_client(bufnr, function(client, client_id)
|
||||||
|
local request_success, request_id = client.request(method, params, callback)
|
||||||
|
|
||||||
|
-- This could only fail if the client shut down in the time since we looked
|
||||||
|
-- it up and we did the request, which should be rare.
|
||||||
|
if request_success then
|
||||||
|
client_request_ids[client_id] = request_id
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function cancel_all_requests()
|
||||||
|
for client_id, request_id in pairs(client_request_ids) do
|
||||||
|
local client = active_clients[client_id]
|
||||||
|
client.cancel_request(request_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return client_request_ids, cancel_all_requests
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Send a request to a server and wait for the response.
|
||||||
|
-- @param bufnr [number] Buffer handle or 0 for current.
|
||||||
|
-- @param method [string] Request method name
|
||||||
|
-- @param params [string] Parameters to send to the server
|
||||||
|
-- @param timeout_ms [number|100] Maximum ms to wait for a result
|
||||||
|
--
|
||||||
|
-- @returns: The table of {[client_id] = request_result}
|
||||||
|
function lsp.buf_request_sync(bufnr, method, params, timeout_ms)
|
||||||
|
local request_results = {}
|
||||||
|
local result_count = 0
|
||||||
|
local function callback(err, _method, result, client_id)
|
||||||
|
request_results[client_id] = { error = err, result = result }
|
||||||
|
result_count = result_count + 1
|
||||||
|
end
|
||||||
|
local client_request_ids, cancel = lsp.buf_request(bufnr, method, params, callback)
|
||||||
|
local expected_result_count = 0
|
||||||
|
for _ in pairs(client_request_ids) do
|
||||||
|
expected_result_count = expected_result_count + 1
|
||||||
|
end
|
||||||
|
local wait_result = wait(timeout_ms or 100, function()
|
||||||
|
return result_count >= expected_result_count
|
||||||
|
end, 10)
|
||||||
|
if wait_result ~= 0 then
|
||||||
|
cancel()
|
||||||
|
return nil, wait_result_reason[wait_result]
|
||||||
|
end
|
||||||
|
return request_results
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Send a notification to a server
|
||||||
|
-- @param bufnr [number] (optional): The number of the buffer
|
||||||
|
-- @param method [string]: Name of the request method
|
||||||
|
-- @param params [string]: Arguments to send to the server
|
||||||
|
--
|
||||||
|
-- @returns nil
|
||||||
|
function lsp.buf_notify(bufnr, method, params)
|
||||||
|
validate {
|
||||||
|
bufnr = { bufnr, 'n', true };
|
||||||
|
method = { method, 's' };
|
||||||
|
}
|
||||||
|
for_each_buffer_client(bufnr, function(client, _client_id)
|
||||||
|
client.rpc.notify(method, params)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Function which can be called to generate omnifunc compatible completion.
|
||||||
|
function lsp.omnifunc(findstart, base)
|
||||||
|
local _ = log.debug() and log.debug("omnifunc.findstart", { findstart = findstart, base = base })
|
||||||
|
|
||||||
|
local bufnr = resolve_bufnr()
|
||||||
|
local has_buffer_clients = not tbl_isempty(all_buffer_active_clients[bufnr] or {})
|
||||||
|
if not has_buffer_clients then
|
||||||
|
if findstart == 1 then
|
||||||
|
return -1
|
||||||
|
else
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if findstart == 1 then
|
||||||
|
return vim.fn.col('.')
|
||||||
|
else
|
||||||
|
local pos = vim.api.nvim_win_get_cursor(0)
|
||||||
|
local line = assert(nvim_buf_get_lines(bufnr, pos[1]-1, pos[1], false)[1])
|
||||||
|
local _ = log.trace() and log.trace("omnifunc.line", pos, line)
|
||||||
|
local line_to_cursor = line:sub(1, pos[2]+1)
|
||||||
|
local _ = log.trace() and log.trace("omnifunc.line_to_cursor", line_to_cursor)
|
||||||
|
local params = {
|
||||||
|
textDocument = {
|
||||||
|
uri = vim.uri_from_bufnr(bufnr);
|
||||||
|
};
|
||||||
|
position = {
|
||||||
|
-- 0-indexed for both line and character
|
||||||
|
line = pos[1] - 1,
|
||||||
|
character = vim.str_utfindex(line, pos[2]),
|
||||||
|
};
|
||||||
|
-- The completion context. This is only available if the client specifies
|
||||||
|
-- to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
|
||||||
|
-- context = nil or {
|
||||||
|
-- triggerKind = protocol.CompletionTriggerKind.Invoked;
|
||||||
|
-- triggerCharacter = nil or "";
|
||||||
|
-- };
|
||||||
|
}
|
||||||
|
-- TODO handle timeout error differently? Like via an error?
|
||||||
|
local client_responses = lsp.buf_request_sync(bufnr, 'textDocument/completion', params) or {}
|
||||||
|
local matches = {}
|
||||||
|
for _, response in pairs(client_responses) do
|
||||||
|
-- TODO how to handle errors?
|
||||||
|
if not response.error then
|
||||||
|
local data = response.result
|
||||||
|
local completion_items = util.text_document_completion_list_to_complete_items(data or {}, line_to_cursor)
|
||||||
|
local _ = log.trace() and log.trace("omnifunc.completion_items", completion_items)
|
||||||
|
vim.list_extend(matches, completion_items)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return matches
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function lsp.client_is_stopped(client_id)
|
||||||
|
return active_clients[client_id] == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
---
|
||||||
|
--- Miscellaneous utilities.
|
||||||
|
---
|
||||||
|
|
||||||
|
-- Retrieve a map from client_id to client of all active buffer clients.
|
||||||
|
-- @param bufnr [number] (optional): buffer handle or 0 for current
|
||||||
|
function lsp.buf_get_clients(bufnr)
|
||||||
|
bufnr = resolve_bufnr(bufnr)
|
||||||
|
local result = {}
|
||||||
|
for_each_buffer_client(bufnr, function(client, client_id)
|
||||||
|
result[client_id] = client
|
||||||
|
end)
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Print some debug information about the current buffer clients.
|
||||||
|
-- The output of this function should not be relied upon and may change.
|
||||||
|
function lsp.buf_print_debug_info(bufnr)
|
||||||
|
print(vim.inspect(lsp.buf_get_clients(bufnr)))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Print some debug information about all LSP related things.
|
||||||
|
-- The output of this function should not be relied upon and may change.
|
||||||
|
function lsp.print_debug_info()
|
||||||
|
print(vim.inspect({ clients = active_clients }))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
lsp.log_levels = log.levels
|
||||||
|
|
||||||
|
-- Set the log level for lsp logging.
|
||||||
|
-- Levels by name: 'trace', 'debug', 'info', 'warn', 'error'
|
||||||
|
-- Level numbers begin with 'trace' at 0
|
||||||
|
-- @param level [number|string] the case insensitive level name or number @see |vim.lsp.log_levels|
|
||||||
|
function lsp.set_log_level(level)
|
||||||
|
if type(level) == 'string' or type(level) == 'number' then
|
||||||
|
log.set_level(level)
|
||||||
|
else
|
||||||
|
error(string.format("Invalid log level: %q", level))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return the path of the logfile used by the LSP client.
|
||||||
|
function lsp.get_log_path()
|
||||||
|
return log.get_filename()
|
||||||
|
end
|
||||||
|
|
||||||
|
return lsp
|
||||||
|
-- vim:sw=2 ts=2 et
|
136
runtime/lua/vim/lsp/buf.lua
Normal file
136
runtime/lua/vim/lsp/buf.lua
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
local vim = vim
|
||||||
|
local validate = vim.validate
|
||||||
|
local api = vim.api
|
||||||
|
local vfn = vim.fn
|
||||||
|
local util = require 'vim.lsp.util'
|
||||||
|
local list_extend = vim.list_extend
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local function ok_or_nil(status, ...)
|
||||||
|
if not status then return end
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
local function npcall(fn, ...)
|
||||||
|
return ok_or_nil(pcall(fn, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function request(method, params, callback)
|
||||||
|
validate {
|
||||||
|
method = {method, 's'};
|
||||||
|
callback = {callback, 'f', true};
|
||||||
|
}
|
||||||
|
return vim.lsp.buf_request(0, method, params, callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.hover()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/hover', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.peek_definition()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/peekDefinition', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function M.declaration()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/declaration', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.definition()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/definition', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.type_definition()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/typeDefinition', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.implementation()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/implementation', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.signature_help()
|
||||||
|
local params = util.make_position_params()
|
||||||
|
request('textDocument/signatureHelp', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO(ashkan) ?
|
||||||
|
function M.completion(context)
|
||||||
|
local params = util.make_position_params()
|
||||||
|
params.context = context
|
||||||
|
return request('textDocument/completion', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.formatting(options)
|
||||||
|
validate { options = {options, 't', true} }
|
||||||
|
options = vim.tbl_extend('keep', options or {}, {
|
||||||
|
tabSize = vim.bo.tabstop;
|
||||||
|
insertSpaces = vim.bo.expandtab;
|
||||||
|
})
|
||||||
|
local params = {
|
||||||
|
textDocument = { uri = vim.uri_from_bufnr(0) };
|
||||||
|
options = options;
|
||||||
|
}
|
||||||
|
return request('textDocument/formatting', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.range_formatting(options, start_pos, end_pos)
|
||||||
|
validate {
|
||||||
|
options = {options, 't', true};
|
||||||
|
start_pos = {start_pos, 't', true};
|
||||||
|
end_pos = {end_pos, 't', true};
|
||||||
|
}
|
||||||
|
options = vim.tbl_extend('keep', options or {}, {
|
||||||
|
tabSize = vim.bo.tabstop;
|
||||||
|
insertSpaces = vim.bo.expandtab;
|
||||||
|
})
|
||||||
|
local A = list_extend({}, start_pos or api.nvim_buf_get_mark(0, '<'))
|
||||||
|
local B = list_extend({}, end_pos or api.nvim_buf_get_mark(0, '>'))
|
||||||
|
-- convert to 0-index
|
||||||
|
A[1] = A[1] - 1
|
||||||
|
B[1] = B[1] - 1
|
||||||
|
-- account for encoding.
|
||||||
|
if A[2] > 0 then
|
||||||
|
A = {A[1], util.character_offset(0, A[1], A[2])}
|
||||||
|
end
|
||||||
|
if B[2] > 0 then
|
||||||
|
B = {B[1], util.character_offset(0, B[1], B[2])}
|
||||||
|
end
|
||||||
|
local params = {
|
||||||
|
textDocument = { uri = vim.uri_from_bufnr(0) };
|
||||||
|
range = {
|
||||||
|
start = { line = A[1]; character = A[2]; };
|
||||||
|
["end"] = { line = B[1]; character = B[2]; };
|
||||||
|
};
|
||||||
|
options = options;
|
||||||
|
}
|
||||||
|
return request('textDocument/rangeFormatting', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.rename(new_name)
|
||||||
|
-- TODO(ashkan) use prepareRename
|
||||||
|
-- * result: [`Range`](#range) \| `{ range: Range, placeholder: string }` \| `null` describing the range of the string to rename and optionally a placeholder text of the string content to be renamed. If `null` is returned then it is deemed that a 'textDocument/rename' request is not valid at the given position.
|
||||||
|
local params = util.make_position_params()
|
||||||
|
new_name = new_name or npcall(vfn.input, "New Name: ")
|
||||||
|
if not (new_name and #new_name > 0) then return end
|
||||||
|
params.newName = new_name
|
||||||
|
request('textDocument/rename', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.references(context)
|
||||||
|
validate { context = { context, 't', true } }
|
||||||
|
local params = util.make_position_params()
|
||||||
|
params.context = context or {
|
||||||
|
includeDeclaration = true;
|
||||||
|
}
|
||||||
|
params[vim.type_idx] = vim.types.dictionary
|
||||||
|
request('textDocument/references', params)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
|
-- vim:sw=2 ts=2 et
|
223
runtime/lua/vim/lsp/callbacks.lua
Normal file
223
runtime/lua/vim/lsp/callbacks.lua
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
local log = require 'vim.lsp.log'
|
||||||
|
local protocol = require 'vim.lsp.protocol'
|
||||||
|
local util = require 'vim.lsp.util'
|
||||||
|
local vim = vim
|
||||||
|
local api = vim.api
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local function err_message(...)
|
||||||
|
api.nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
|
||||||
|
api.nvim_command("redraw")
|
||||||
|
end
|
||||||
|
|
||||||
|
M['workspace/applyEdit'] = function(_, _, workspace_edit)
|
||||||
|
if not workspace_edit then return end
|
||||||
|
-- TODO(ashkan) Do something more with label?
|
||||||
|
if workspace_edit.label then
|
||||||
|
print("Workspace edit", workspace_edit.label)
|
||||||
|
end
|
||||||
|
util.apply_workspace_edit(workspace_edit.edit)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/publishDiagnostics'] = function(_, _, result)
|
||||||
|
if not result then return end
|
||||||
|
local uri = result.uri
|
||||||
|
local bufnr = vim.uri_to_bufnr(uri)
|
||||||
|
if not bufnr then
|
||||||
|
err_message("LSP.publishDiagnostics: Couldn't find buffer for ", uri)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
util.buf_clear_diagnostics(bufnr)
|
||||||
|
util.buf_diagnostics_save_positions(bufnr, result.diagnostics)
|
||||||
|
util.buf_diagnostics_underline(bufnr, result.diagnostics)
|
||||||
|
util.buf_diagnostics_virtual_text(bufnr, result.diagnostics)
|
||||||
|
-- util.set_loclist(result.diagnostics)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/references'] = function(_, _, result)
|
||||||
|
if not result then return end
|
||||||
|
util.set_qflist(result)
|
||||||
|
api.nvim_command("copen")
|
||||||
|
api.nvim_command("wincmd p")
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/rename'] = function(_, _, result)
|
||||||
|
if not result then return end
|
||||||
|
util.apply_workspace_edit(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/rangeFormatting'] = function(_, _, result)
|
||||||
|
if not result then return end
|
||||||
|
util.apply_text_edits(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/formatting'] = function(_, _, result)
|
||||||
|
if not result then return end
|
||||||
|
util.apply_text_edits(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/completion'] = function(_, _, result)
|
||||||
|
if vim.tbl_isempty(result or {}) then return end
|
||||||
|
local row, col = unpack(api.nvim_win_get_cursor(0))
|
||||||
|
local line = assert(api.nvim_buf_get_lines(0, row-1, row, false)[1])
|
||||||
|
local line_to_cursor = line:sub(col+1)
|
||||||
|
|
||||||
|
local matches = util.text_document_completion_list_to_complete_items(result, line_to_cursor)
|
||||||
|
vim.fn.complete(col, matches)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/hover'] = function(_, method, result)
|
||||||
|
util.focusable_preview(method, function()
|
||||||
|
if not (result and result.contents) then
|
||||||
|
return { 'No information available' }
|
||||||
|
end
|
||||||
|
local markdown_lines = util.convert_input_to_markdown_lines(result.contents)
|
||||||
|
markdown_lines = util.trim_empty_lines(markdown_lines)
|
||||||
|
if vim.tbl_isempty(markdown_lines) then
|
||||||
|
return { 'No information available' }
|
||||||
|
end
|
||||||
|
return markdown_lines, util.try_trim_markdown_code_blocks(markdown_lines)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function location_callback(_, method, result)
|
||||||
|
if result == nil or vim.tbl_isempty(result) then
|
||||||
|
local _ = log.info() and log.info(method, 'No location found')
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
util.jump_to_location(result[1])
|
||||||
|
if #result > 1 then
|
||||||
|
util.set_qflist(result)
|
||||||
|
api.nvim_command("copen")
|
||||||
|
api.nvim_command("wincmd p")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/declaration'] = location_callback
|
||||||
|
M['textDocument/definition'] = location_callback
|
||||||
|
M['textDocument/typeDefinition'] = location_callback
|
||||||
|
M['textDocument/implementation'] = location_callback
|
||||||
|
|
||||||
|
--- Convert SignatureHelp response to preview contents.
|
||||||
|
-- https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_signatureHelp
|
||||||
|
local function signature_help_to_preview_contents(input)
|
||||||
|
if not input.signatures then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
--The active signature. If omitted or the value lies outside the range of
|
||||||
|
--`signatures` the value defaults to zero or is ignored if `signatures.length
|
||||||
|
--=== 0`. Whenever possible implementors should make an active decision about
|
||||||
|
--the active signature and shouldn't rely on a default value.
|
||||||
|
local contents = {}
|
||||||
|
local active_signature = input.activeSignature or 0
|
||||||
|
-- If the activeSignature is not inside the valid range, then clip it.
|
||||||
|
if active_signature >= #input.signatures then
|
||||||
|
active_signature = 0
|
||||||
|
end
|
||||||
|
local signature = input.signatures[active_signature + 1]
|
||||||
|
if not signature then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
vim.list_extend(contents, vim.split(signature.label, '\n', true))
|
||||||
|
if signature.documentation then
|
||||||
|
util.convert_input_to_markdown_lines(signature.documentation, contents)
|
||||||
|
end
|
||||||
|
if input.parameters then
|
||||||
|
local active_parameter = input.activeParameter or 0
|
||||||
|
-- If the activeParameter is not inside the valid range, then clip it.
|
||||||
|
if active_parameter >= #input.parameters then
|
||||||
|
active_parameter = 0
|
||||||
|
end
|
||||||
|
local parameter = signature.parameters and signature.parameters[active_parameter]
|
||||||
|
if parameter then
|
||||||
|
--[=[
|
||||||
|
--Represents a parameter of a callable-signature. A parameter can
|
||||||
|
--have a label and a doc-comment.
|
||||||
|
interface ParameterInformation {
|
||||||
|
--The label of this parameter information.
|
||||||
|
--
|
||||||
|
--Either a string or an inclusive start and exclusive end offsets within its containing
|
||||||
|
--signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
|
||||||
|
--string representation as `Position` and `Range` does.
|
||||||
|
--
|
||||||
|
--*Note*: a label of type string should be a substring of its containing signature label.
|
||||||
|
--Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
|
||||||
|
label: string | [number, number];
|
||||||
|
--The human-readable doc-comment of this parameter. Will be shown
|
||||||
|
--in the UI but can be omitted.
|
||||||
|
documentation?: string | MarkupContent;
|
||||||
|
}
|
||||||
|
--]=]
|
||||||
|
-- TODO highlight parameter
|
||||||
|
if parameter.documentation then
|
||||||
|
util.convert_input_to_markdown_lines(parameter.documentation, contents)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return contents
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/signatureHelp'] = function(_, method, result)
|
||||||
|
util.focusable_preview(method, function()
|
||||||
|
if not (result and result.signatures and result.signatures[1]) then
|
||||||
|
return { 'No signature available' }
|
||||||
|
end
|
||||||
|
-- TODO show popup when signatures is empty?
|
||||||
|
local lines = signature_help_to_preview_contents(result)
|
||||||
|
lines = util.trim_empty_lines(lines)
|
||||||
|
if vim.tbl_isempty(lines) then
|
||||||
|
return { 'No signature available' }
|
||||||
|
end
|
||||||
|
return lines, util.try_trim_markdown_code_blocks(lines)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
M['textDocument/peekDefinition'] = function(_, _, result, _)
|
||||||
|
if not (result and result[1]) then return end
|
||||||
|
local loc = result[1]
|
||||||
|
local bufnr = vim.uri_to_bufnr(loc.uri) or error("not found: "..tostring(loc.uri))
|
||||||
|
local start = loc.range.start
|
||||||
|
local finish = loc.range["end"]
|
||||||
|
util.open_floating_peek_preview(bufnr, start, finish, { offset_x = 1 })
|
||||||
|
local headbuf = util.open_floating_preview({"Peek:"}, nil, {
|
||||||
|
offset_y = -(finish.line - start.line);
|
||||||
|
width = finish.character - start.character + 2;
|
||||||
|
})
|
||||||
|
-- TODO(ashkan) change highlight group?
|
||||||
|
api.nvim_buf_add_highlight(headbuf, -1, 'Keyword', 0, -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function log_message(_, _, result, client_id)
|
||||||
|
local message_type = result.type
|
||||||
|
local message = result.message
|
||||||
|
local client = vim.lsp.get_client_by_id(client_id)
|
||||||
|
local client_name = client and client.name or string.format("id=%d", client_id)
|
||||||
|
if not client then
|
||||||
|
err_message("LSP[", client_name, "] client has shut down after sending the message")
|
||||||
|
end
|
||||||
|
if message_type == protocol.MessageType.Error then
|
||||||
|
err_message("LSP[", client_name, "] ", message)
|
||||||
|
else
|
||||||
|
local message_type_name = protocol.MessageType[message_type]
|
||||||
|
api.nvim_out_write(string.format("LSP[%s][%s] %s\n", client_name, message_type_name, message))
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
M['window/showMessage'] = log_message
|
||||||
|
M['window/logMessage'] = log_message
|
||||||
|
|
||||||
|
-- Add boilerplate error validation and logging for all of these.
|
||||||
|
for k, fn in pairs(M) do
|
||||||
|
M[k] = function(err, method, params, client_id)
|
||||||
|
local _ = log.debug() and log.debug('default_callback', method, { params = params, client_id = client_id, err = err })
|
||||||
|
if err then
|
||||||
|
error(tostring(err))
|
||||||
|
end
|
||||||
|
return fn(err, method, params, client_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
|
-- vim:sw=2 ts=2 et
|
95
runtime/lua/vim/lsp/log.lua
Normal file
95
runtime/lua/vim/lsp/log.lua
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
-- Logger for language client plugin.
|
||||||
|
|
||||||
|
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
|
||||||
|
log.levels = {
|
||||||
|
TRACE = 0;
|
||||||
|
DEBUG = 1;
|
||||||
|
INFO = 2;
|
||||||
|
WARN = 3;
|
||||||
|
ERROR = 4;
|
||||||
|
-- FATAL = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Default log level is warn.
|
||||||
|
local current_log_level = log.levels.WARN
|
||||||
|
local log_date_format = "%FT%H:%M:%SZ%z"
|
||||||
|
|
||||||
|
do
|
||||||
|
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
|
||||||
|
local function path_join(...)
|
||||||
|
return table.concat(vim.tbl_flatten{...}, path_sep)
|
||||||
|
end
|
||||||
|
local logfilename = path_join(vim.fn.stdpath('data'), 'vim-lsp.log')
|
||||||
|
|
||||||
|
--- Return the log filename.
|
||||||
|
function log.get_filename()
|
||||||
|
return logfilename
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.fn.mkdir(vim.fn.stdpath('data'), "p")
|
||||||
|
local logfile = assert(io.open(logfilename, "a+"))
|
||||||
|
for level, levelnr in pairs(log.levels) do
|
||||||
|
-- Also export the log level on the root object.
|
||||||
|
log[level] = levelnr
|
||||||
|
-- Set the lowercase name as the main use function.
|
||||||
|
-- If called without arguments, it will check whether the log level is
|
||||||
|
-- greater than or equal to this one. When called with arguments, it will
|
||||||
|
-- log at that level (if applicable, it is checked either way).
|
||||||
|
--
|
||||||
|
-- Recommended usage:
|
||||||
|
-- ```
|
||||||
|
-- local _ = log.warn() and log.warn("123")
|
||||||
|
-- ```
|
||||||
|
--
|
||||||
|
-- This way you can avoid string allocations if the log level isn't high enough.
|
||||||
|
log[level:lower()] = function(...)
|
||||||
|
local argc = select("#", ...)
|
||||||
|
if levelnr < current_log_level then return false end
|
||||||
|
if argc == 0 then return true end
|
||||||
|
local info = debug.getinfo(2, "Sl")
|
||||||
|
local fileinfo = string.format("%s:%s", info.short_src, info.currentline)
|
||||||
|
local parts = { table.concat({"[", level, "]", os.date(log_date_format), "]", fileinfo, "]"}, " ") }
|
||||||
|
for i = 1, argc do
|
||||||
|
local arg = select(i, ...)
|
||||||
|
if arg == nil then
|
||||||
|
table.insert(parts, "nil")
|
||||||
|
else
|
||||||
|
table.insert(parts, vim.inspect(arg, {newline=''}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
logfile:write(table.concat(parts, '\t'), "\n")
|
||||||
|
logfile:flush()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Add some space to make it easier to distinguish different neovim runs.
|
||||||
|
logfile:write("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is put here on purpose after the loop above so that it doesn't
|
||||||
|
-- interfere with iterating the levels
|
||||||
|
vim.tbl_add_reverse_lookup(log.levels)
|
||||||
|
|
||||||
|
function log.set_level(level)
|
||||||
|
if type(level) == 'string' then
|
||||||
|
current_log_level = assert(log.levels[level:upper()], string.format("Invalid log level: %q", level))
|
||||||
|
else
|
||||||
|
assert(type(level) == 'number', "level must be a number or string")
|
||||||
|
assert(log.levels[level], string.format("Invalid log level: %d", level))
|
||||||
|
current_log_level = level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return whether the level is sufficient for logging.
|
||||||
|
-- @param level number log level
|
||||||
|
function log.should_log(level)
|
||||||
|
return level >= current_log_level
|
||||||
|
end
|
||||||
|
|
||||||
|
return log
|
||||||
|
-- vim:sw=2 ts=2 et
|
922
runtime/lua/vim/lsp/protocol.lua
Normal file
922
runtime/lua/vim/lsp/protocol.lua
Normal file
@ -0,0 +1,922 @@
|
|||||||
|
-- Protocol for the Microsoft Language Server Protocol (mslsp)
|
||||||
|
|
||||||
|
local protocol = {}
|
||||||
|
|
||||||
|
local function ifnil(a, b)
|
||||||
|
if a == nil then return b end
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
-- Useful for interfacing with:
|
||||||
|
-- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
|
||||||
|
function transform_schema_comments()
|
||||||
|
nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]]
|
||||||
|
nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]]
|
||||||
|
end
|
||||||
|
function transform_schema_to_table()
|
||||||
|
transform_schema_comments()
|
||||||
|
nvim.command [[silent! '<,'>s/: \S\+//]]
|
||||||
|
nvim.command [[silent! '<,'>s/export const //]]
|
||||||
|
nvim.command [[silent! '<,'>s/export namespace \(\S*\)\s*{/protocol.\1 = {/]]
|
||||||
|
nvim.command [[silent! '<,'>s/namespace \(\S*\)\s*{/protocol.\1 = {/]]
|
||||||
|
end
|
||||||
|
--]=]
|
||||||
|
|
||||||
|
local constants = {
|
||||||
|
DiagnosticSeverity = {
|
||||||
|
-- Reports an error.
|
||||||
|
Error = 1;
|
||||||
|
-- Reports a warning.
|
||||||
|
Warning = 2;
|
||||||
|
-- Reports an information.
|
||||||
|
Information = 3;
|
||||||
|
-- Reports a hint.
|
||||||
|
Hint = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
MessageType = {
|
||||||
|
-- An error message.
|
||||||
|
Error = 1;
|
||||||
|
-- A warning message.
|
||||||
|
Warning = 2;
|
||||||
|
-- An information message.
|
||||||
|
Info = 3;
|
||||||
|
-- A log message.
|
||||||
|
Log = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- The file event type.
|
||||||
|
FileChangeType = {
|
||||||
|
-- The file got created.
|
||||||
|
Created = 1;
|
||||||
|
-- The file got changed.
|
||||||
|
Changed = 2;
|
||||||
|
-- The file got deleted.
|
||||||
|
Deleted = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- The kind of a completion entry.
|
||||||
|
CompletionItemKind = {
|
||||||
|
Text = 1;
|
||||||
|
Method = 2;
|
||||||
|
Function = 3;
|
||||||
|
Constructor = 4;
|
||||||
|
Field = 5;
|
||||||
|
Variable = 6;
|
||||||
|
Class = 7;
|
||||||
|
Interface = 8;
|
||||||
|
Module = 9;
|
||||||
|
Property = 10;
|
||||||
|
Unit = 11;
|
||||||
|
Value = 12;
|
||||||
|
Enum = 13;
|
||||||
|
Keyword = 14;
|
||||||
|
Snippet = 15;
|
||||||
|
Color = 16;
|
||||||
|
File = 17;
|
||||||
|
Reference = 18;
|
||||||
|
Folder = 19;
|
||||||
|
EnumMember = 20;
|
||||||
|
Constant = 21;
|
||||||
|
Struct = 22;
|
||||||
|
Event = 23;
|
||||||
|
Operator = 24;
|
||||||
|
TypeParameter = 25;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- How a completion was triggered
|
||||||
|
CompletionTriggerKind = {
|
||||||
|
-- Completion was triggered by typing an identifier (24x7 code
|
||||||
|
-- complete), manual invocation (e.g Ctrl+Space) or via API.
|
||||||
|
Invoked = 1;
|
||||||
|
-- Completion was triggered by a trigger character specified by
|
||||||
|
-- the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
|
||||||
|
TriggerCharacter = 2;
|
||||||
|
-- Completion was re-triggered as the current completion list is incomplete.
|
||||||
|
TriggerForIncompleteCompletions = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- A document highlight kind.
|
||||||
|
DocumentHighlightKind = {
|
||||||
|
-- A textual occurrence.
|
||||||
|
Text = 1;
|
||||||
|
-- Read-access of a symbol, like reading a variable.
|
||||||
|
Read = 2;
|
||||||
|
-- Write-access of a symbol, like writing to a variable.
|
||||||
|
Write = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- A symbol kind.
|
||||||
|
SymbolKind = {
|
||||||
|
File = 1;
|
||||||
|
Module = 2;
|
||||||
|
Namespace = 3;
|
||||||
|
Package = 4;
|
||||||
|
Class = 5;
|
||||||
|
Method = 6;
|
||||||
|
Property = 7;
|
||||||
|
Field = 8;
|
||||||
|
Constructor = 9;
|
||||||
|
Enum = 10;
|
||||||
|
Interface = 11;
|
||||||
|
Function = 12;
|
||||||
|
Variable = 13;
|
||||||
|
Constant = 14;
|
||||||
|
String = 15;
|
||||||
|
Number = 16;
|
||||||
|
Boolean = 17;
|
||||||
|
Array = 18;
|
||||||
|
Object = 19;
|
||||||
|
Key = 20;
|
||||||
|
Null = 21;
|
||||||
|
EnumMember = 22;
|
||||||
|
Struct = 23;
|
||||||
|
Event = 24;
|
||||||
|
Operator = 25;
|
||||||
|
TypeParameter = 26;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Represents reasons why a text document is saved.
|
||||||
|
TextDocumentSaveReason = {
|
||||||
|
-- Manually triggered, e.g. by the user pressing save, by starting debugging,
|
||||||
|
-- or by an API call.
|
||||||
|
Manual = 1;
|
||||||
|
-- Automatic after a delay.
|
||||||
|
AfterDelay = 2;
|
||||||
|
-- When the editor lost focus.
|
||||||
|
FocusOut = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorCodes = {
|
||||||
|
-- Defined by JSON RPC
|
||||||
|
ParseError = -32700;
|
||||||
|
InvalidRequest = -32600;
|
||||||
|
MethodNotFound = -32601;
|
||||||
|
InvalidParams = -32602;
|
||||||
|
InternalError = -32603;
|
||||||
|
serverErrorStart = -32099;
|
||||||
|
serverErrorEnd = -32000;
|
||||||
|
ServerNotInitialized = -32002;
|
||||||
|
UnknownErrorCode = -32001;
|
||||||
|
-- Defined by the protocol.
|
||||||
|
RequestCancelled = -32800;
|
||||||
|
ContentModified = -32801;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Describes the content type that a client supports in various
|
||||||
|
-- result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
|
||||||
|
--
|
||||||
|
-- Please note that `MarkupKinds` must not start with a `$`. This kinds
|
||||||
|
-- are reserved for internal usage.
|
||||||
|
MarkupKind = {
|
||||||
|
-- Plain text is supported as a content format
|
||||||
|
PlainText = 'plaintext';
|
||||||
|
-- Markdown is supported as a content format
|
||||||
|
Markdown = 'markdown';
|
||||||
|
};
|
||||||
|
|
||||||
|
ResourceOperationKind = {
|
||||||
|
-- Supports creating new files and folders.
|
||||||
|
Create = 'create';
|
||||||
|
-- Supports renaming existing files and folders.
|
||||||
|
Rename = 'rename';
|
||||||
|
-- Supports deleting existing files and folders.
|
||||||
|
Delete = 'delete';
|
||||||
|
};
|
||||||
|
|
||||||
|
FailureHandlingKind = {
|
||||||
|
-- Applying the workspace change is simply aborted if one of the changes provided
|
||||||
|
-- fails. All operations executed before the failing operation stay executed.
|
||||||
|
Abort = 'abort';
|
||||||
|
-- All operations are executed transactionally. That means they either all
|
||||||
|
-- succeed or no changes at all are applied to the workspace.
|
||||||
|
Transactional = 'transactional';
|
||||||
|
-- If the workspace edit contains only textual file changes they are executed transactionally.
|
||||||
|
-- If resource changes (create, rename or delete file) are part of the change the failure
|
||||||
|
-- handling strategy is abort.
|
||||||
|
TextOnlyTransactional = 'textOnlyTransactional';
|
||||||
|
-- The client tries to undo the operations already executed. But there is no
|
||||||
|
-- guarantee that this succeeds.
|
||||||
|
Undo = 'undo';
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Known error codes for an `InitializeError`;
|
||||||
|
InitializeError = {
|
||||||
|
-- If the protocol version provided by the client can't be handled by the server.
|
||||||
|
-- @deprecated This initialize error got replaced by client capabilities. There is
|
||||||
|
-- no version handshake in version 3.0x
|
||||||
|
unknownProtocolVersion = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Defines how the host (editor) should sync document changes to the language server.
|
||||||
|
TextDocumentSyncKind = {
|
||||||
|
-- Documents should not be synced at all.
|
||||||
|
None = 0;
|
||||||
|
-- Documents are synced by always sending the full content
|
||||||
|
-- of the document.
|
||||||
|
Full = 1;
|
||||||
|
-- Documents are synced by sending the full content on open.
|
||||||
|
-- After that only incremental updates to the document are
|
||||||
|
-- send.
|
||||||
|
Incremental = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
WatchKind = {
|
||||||
|
-- Interested in create events.
|
||||||
|
Create = 1;
|
||||||
|
-- Interested in change events
|
||||||
|
Change = 2;
|
||||||
|
-- Interested in delete events
|
||||||
|
Delete = 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Defines whether the insert text in a completion item should be interpreted as
|
||||||
|
-- plain text or a snippet.
|
||||||
|
InsertTextFormat = {
|
||||||
|
-- The primary text to be inserted is treated as a plain string.
|
||||||
|
PlainText = 1;
|
||||||
|
-- The primary text to be inserted is treated as a snippet.
|
||||||
|
--
|
||||||
|
-- A snippet can define tab stops and placeholders with `$1`, `$2`
|
||||||
|
-- and `${3:foo};`. `$0` defines the final tab stop, it defaults to
|
||||||
|
-- the end of the snippet. Placeholders with equal identifiers are linked,
|
||||||
|
-- that is typing in one will update others too.
|
||||||
|
Snippet = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
-- A set of predefined code action kinds
|
||||||
|
CodeActionKind = {
|
||||||
|
-- Empty kind.
|
||||||
|
Empty = '';
|
||||||
|
-- Base kind for quickfix actions
|
||||||
|
QuickFix = 'quickfix';
|
||||||
|
-- Base kind for refactoring actions
|
||||||
|
Refactor = 'refactor';
|
||||||
|
-- Base kind for refactoring extraction actions
|
||||||
|
--
|
||||||
|
-- Example extract actions:
|
||||||
|
--
|
||||||
|
-- - Extract method
|
||||||
|
-- - Extract function
|
||||||
|
-- - Extract variable
|
||||||
|
-- - Extract interface from class
|
||||||
|
-- - ...
|
||||||
|
RefactorExtract = 'refactor.extract';
|
||||||
|
-- Base kind for refactoring inline actions
|
||||||
|
--
|
||||||
|
-- Example inline actions:
|
||||||
|
--
|
||||||
|
-- - Inline function
|
||||||
|
-- - Inline variable
|
||||||
|
-- - Inline constant
|
||||||
|
-- - ...
|
||||||
|
RefactorInline = 'refactor.inline';
|
||||||
|
-- Base kind for refactoring rewrite actions
|
||||||
|
--
|
||||||
|
-- Example rewrite actions:
|
||||||
|
--
|
||||||
|
-- - Convert JavaScript function to class
|
||||||
|
-- - Add or remove parameter
|
||||||
|
-- - Encapsulate field
|
||||||
|
-- - Make method static
|
||||||
|
-- - Move method to base class
|
||||||
|
-- - ...
|
||||||
|
RefactorRewrite = 'refactor.rewrite';
|
||||||
|
-- Base kind for source actions
|
||||||
|
--
|
||||||
|
-- Source code actions apply to the entire file.
|
||||||
|
Source = 'source';
|
||||||
|
-- Base kind for an organize imports source action
|
||||||
|
SourceOrganizeImports = 'source.organizeImports';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in pairs(constants) do
|
||||||
|
vim.tbl_add_reverse_lookup(v)
|
||||||
|
protocol[k] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
--Text document specific client capabilities.
|
||||||
|
export interface TextDocumentClientCapabilities {
|
||||||
|
synchronization?: {
|
||||||
|
--Whether text document synchronization supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports sending will save notifications.
|
||||||
|
willSave?: boolean;
|
||||||
|
--The client supports sending a will save request and
|
||||||
|
--waits for a response providing text edits which will
|
||||||
|
--be applied to the document before it is saved.
|
||||||
|
willSaveWaitUntil?: boolean;
|
||||||
|
--The client supports did save notifications.
|
||||||
|
didSave?: boolean;
|
||||||
|
}
|
||||||
|
--Capabilities specific to the `textDocument/completion`
|
||||||
|
completion?: {
|
||||||
|
--Whether completion supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports the following `CompletionItem` specific
|
||||||
|
--capabilities.
|
||||||
|
completionItem?: {
|
||||||
|
--The client supports snippets as insert text.
|
||||||
|
--
|
||||||
|
--A snippet can define tab stops and placeholders with `$1`, `$2`
|
||||||
|
--and `${3:foo}`. `$0` defines the final tab stop, it defaults to
|
||||||
|
--the end of the snippet. Placeholders with equal identifiers are linked,
|
||||||
|
--that is typing in one will update others too.
|
||||||
|
snippetSupport?: boolean;
|
||||||
|
--The client supports commit characters on a completion item.
|
||||||
|
commitCharactersSupport?: boolean
|
||||||
|
--The client supports the following content formats for the documentation
|
||||||
|
--property. The order describes the preferred format of the client.
|
||||||
|
documentationFormat?: MarkupKind[];
|
||||||
|
--The client supports the deprecated property on a completion item.
|
||||||
|
deprecatedSupport?: boolean;
|
||||||
|
--The client supports the preselect property on a completion item.
|
||||||
|
preselectSupport?: boolean;
|
||||||
|
}
|
||||||
|
completionItemKind?: {
|
||||||
|
--The completion item kind values the client supports. When this
|
||||||
|
--property exists the client also guarantees that it will
|
||||||
|
--handle values outside its set gracefully and falls back
|
||||||
|
--to a default value when unknown.
|
||||||
|
--
|
||||||
|
--If this property is not present the client only supports
|
||||||
|
--the completion items kinds from `Text` to `Reference` as defined in
|
||||||
|
--the initial version of the protocol.
|
||||||
|
valueSet?: CompletionItemKind[];
|
||||||
|
},
|
||||||
|
--The client supports to send additional context information for a
|
||||||
|
--`textDocument/completion` request.
|
||||||
|
contextSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/hover`
|
||||||
|
hover?: {
|
||||||
|
--Whether hover supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports the follow content formats for the content
|
||||||
|
--property. The order describes the preferred format of the client.
|
||||||
|
contentFormat?: MarkupKind[];
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/signatureHelp`
|
||||||
|
signatureHelp?: {
|
||||||
|
--Whether signature help supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports the following `SignatureInformation`
|
||||||
|
--specific properties.
|
||||||
|
signatureInformation?: {
|
||||||
|
--The client supports the follow content formats for the documentation
|
||||||
|
--property. The order describes the preferred format of the client.
|
||||||
|
documentationFormat?: MarkupKind[];
|
||||||
|
--Client capabilities specific to parameter information.
|
||||||
|
parameterInformation?: {
|
||||||
|
--The client supports processing label offsets instead of a
|
||||||
|
--simple label string.
|
||||||
|
--
|
||||||
|
--Since 3.14.0
|
||||||
|
labelOffsetSupport?: boolean;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/references`
|
||||||
|
references?: {
|
||||||
|
--Whether references supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/documentHighlight`
|
||||||
|
documentHighlight?: {
|
||||||
|
--Whether document highlight supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/documentSymbol`
|
||||||
|
documentSymbol?: {
|
||||||
|
--Whether document symbol supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--Specific capabilities for the `SymbolKind`.
|
||||||
|
symbolKind?: {
|
||||||
|
--The symbol kind values the client supports. When this
|
||||||
|
--property exists the client also guarantees that it will
|
||||||
|
--handle values outside its set gracefully and falls back
|
||||||
|
--to a default value when unknown.
|
||||||
|
--
|
||||||
|
--If this property is not present the client only supports
|
||||||
|
--the symbol kinds from `File` to `Array` as defined in
|
||||||
|
--the initial version of the protocol.
|
||||||
|
valueSet?: SymbolKind[];
|
||||||
|
}
|
||||||
|
--The client supports hierarchical document symbols.
|
||||||
|
hierarchicalDocumentSymbolSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/formatting`
|
||||||
|
formatting?: {
|
||||||
|
--Whether formatting supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/rangeFormatting`
|
||||||
|
rangeFormatting?: {
|
||||||
|
--Whether range formatting supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/onTypeFormatting`
|
||||||
|
onTypeFormatting?: {
|
||||||
|
--Whether on type formatting supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/declaration`
|
||||||
|
declaration?: {
|
||||||
|
--Whether declaration supports dynamic registration. If this is set to `true`
|
||||||
|
--the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||||
|
--return value for the corresponding server capability as well.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports additional metadata in the form of declaration links.
|
||||||
|
--
|
||||||
|
--Since 3.14.0
|
||||||
|
linkSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/definition`.
|
||||||
|
--
|
||||||
|
--Since 3.14.0
|
||||||
|
definition?: {
|
||||||
|
--Whether definition supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports additional metadata in the form of definition links.
|
||||||
|
linkSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/typeDefinition`
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
typeDefinition?: {
|
||||||
|
--Whether typeDefinition supports dynamic registration. If this is set to `true`
|
||||||
|
--the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||||
|
--return value for the corresponding server capability as well.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports additional metadata in the form of definition links.
|
||||||
|
--
|
||||||
|
--Since 3.14.0
|
||||||
|
linkSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/implementation`.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
implementation?: {
|
||||||
|
--Whether implementation supports dynamic registration. If this is set to `true`
|
||||||
|
--the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||||
|
--return value for the corresponding server capability as well.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports additional metadata in the form of definition links.
|
||||||
|
--
|
||||||
|
--Since 3.14.0
|
||||||
|
linkSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/codeAction`
|
||||||
|
codeAction?: {
|
||||||
|
--Whether code action supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client support code action literals as a valid
|
||||||
|
--response of the `textDocument/codeAction` request.
|
||||||
|
--
|
||||||
|
--Since 3.8.0
|
||||||
|
codeActionLiteralSupport?: {
|
||||||
|
--The code action kind is support with the following value
|
||||||
|
--set.
|
||||||
|
codeActionKind: {
|
||||||
|
--The code action kind values the client supports. When this
|
||||||
|
--property exists the client also guarantees that it will
|
||||||
|
--handle values outside its set gracefully and falls back
|
||||||
|
--to a default value when unknown.
|
||||||
|
valueSet: CodeActionKind[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/codeLens`
|
||||||
|
codeLens?: {
|
||||||
|
--Whether code lens supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/documentLink`
|
||||||
|
documentLink?: {
|
||||||
|
--Whether document link supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `textDocument/documentColor` and the
|
||||||
|
--`textDocument/colorPresentation` request.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
colorProvider?: {
|
||||||
|
--Whether colorProvider supports dynamic registration. If this is set to `true`
|
||||||
|
--the client supports the new `(ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||||
|
--return value for the corresponding server capability as well.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
}
|
||||||
|
--Capabilities specific to the `textDocument/rename`
|
||||||
|
rename?: {
|
||||||
|
--Whether rename supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The client supports testing for validity of rename operations
|
||||||
|
--before execution.
|
||||||
|
prepareSupport?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to `textDocument/publishDiagnostics`.
|
||||||
|
publishDiagnostics?: {
|
||||||
|
--Whether the clients accepts diagnostics with related information.
|
||||||
|
relatedInformation?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to `textDocument/foldingRange` requests.
|
||||||
|
--
|
||||||
|
--Since 3.10.0
|
||||||
|
foldingRange?: {
|
||||||
|
--Whether implementation supports dynamic registration for folding range providers. If this is set to `true`
|
||||||
|
--the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)`
|
||||||
|
--return value for the corresponding server capability as well.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--The maximum number of folding ranges that the client prefers to receive per document. The value serves as a
|
||||||
|
--hint, servers are free to follow the limit.
|
||||||
|
rangeLimit?: number;
|
||||||
|
--If set, the client signals that it only supports folding complete lines. If set, client will
|
||||||
|
--ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange.
|
||||||
|
lineFoldingOnly?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
--]=]
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
--Workspace specific client capabilities.
|
||||||
|
export interface WorkspaceClientCapabilities {
|
||||||
|
--The client supports applying batch edits to the workspace by supporting
|
||||||
|
--the request 'workspace/applyEdit'
|
||||||
|
applyEdit?: boolean;
|
||||||
|
--Capabilities specific to `WorkspaceEdit`s
|
||||||
|
workspaceEdit?: {
|
||||||
|
--The client supports versioned document changes in `WorkspaceEdit`s
|
||||||
|
documentChanges?: boolean;
|
||||||
|
--The resource operations the client supports. Clients should at least
|
||||||
|
--support 'create', 'rename' and 'delete' files and folders.
|
||||||
|
resourceOperations?: ResourceOperationKind[];
|
||||||
|
--The failure handling strategy of a client if applying the workspace edit
|
||||||
|
--fails.
|
||||||
|
failureHandling?: FailureHandlingKind;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `workspace/didChangeConfiguration` notification.
|
||||||
|
didChangeConfiguration?: {
|
||||||
|
--Did change configuration notification supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
|
||||||
|
didChangeWatchedFiles?: {
|
||||||
|
--Did change watched files notification supports dynamic registration. Please note
|
||||||
|
--that the current protocol doesn't support static configuration for file changes
|
||||||
|
--from the server side.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `workspace/symbol` request.
|
||||||
|
symbol?: {
|
||||||
|
--Symbol request supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
--Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
|
||||||
|
symbolKind?: {
|
||||||
|
--The symbol kind values the client supports. When this
|
||||||
|
--property exists the client also guarantees that it will
|
||||||
|
--handle values outside its set gracefully and falls back
|
||||||
|
--to a default value when unknown.
|
||||||
|
--
|
||||||
|
--If this property is not present the client only supports
|
||||||
|
--the symbol kinds from `File` to `Array` as defined in
|
||||||
|
--the initial version of the protocol.
|
||||||
|
valueSet?: SymbolKind[];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
--Capabilities specific to the `workspace/executeCommand` request.
|
||||||
|
executeCommand?: {
|
||||||
|
--Execute command supports dynamic registration.
|
||||||
|
dynamicRegistration?: boolean;
|
||||||
|
};
|
||||||
|
--The client has support for workspace folders.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
workspaceFolders?: boolean;
|
||||||
|
--The client supports `workspace/configuration` requests.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
configuration?: boolean;
|
||||||
|
}
|
||||||
|
--]=]
|
||||||
|
|
||||||
|
function protocol.make_client_capabilities()
|
||||||
|
return {
|
||||||
|
textDocument = {
|
||||||
|
synchronization = {
|
||||||
|
dynamicRegistration = false;
|
||||||
|
|
||||||
|
-- TODO(ashkan) Send textDocument/willSave before saving (BufWritePre)
|
||||||
|
willSave = false;
|
||||||
|
|
||||||
|
-- TODO(ashkan) Implement textDocument/willSaveWaitUntil
|
||||||
|
willSaveWaitUntil = false;
|
||||||
|
|
||||||
|
-- Send textDocument/didSave after saving (BufWritePost)
|
||||||
|
didSave = true;
|
||||||
|
};
|
||||||
|
completion = {
|
||||||
|
dynamicRegistration = false;
|
||||||
|
completionItem = {
|
||||||
|
|
||||||
|
-- TODO(tjdevries): Is it possible to implement this in plain lua?
|
||||||
|
snippetSupport = false;
|
||||||
|
commitCharactersSupport = false;
|
||||||
|
preselectSupport = false;
|
||||||
|
deprecatedSupport = false;
|
||||||
|
documentationFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText };
|
||||||
|
};
|
||||||
|
completionItemKind = {
|
||||||
|
valueSet = (function()
|
||||||
|
local res = {}
|
||||||
|
for k in pairs(protocol.CompletionItemKind) do
|
||||||
|
if type(k) == 'number' then table.insert(res, k) end
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end)();
|
||||||
|
};
|
||||||
|
|
||||||
|
-- TODO(tjdevries): Implement this
|
||||||
|
contextSupport = false;
|
||||||
|
};
|
||||||
|
hover = {
|
||||||
|
dynamicRegistration = false;
|
||||||
|
contentFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText };
|
||||||
|
};
|
||||||
|
signatureHelp = {
|
||||||
|
dynamicRegistration = false;
|
||||||
|
signatureInformation = {
|
||||||
|
documentationFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText };
|
||||||
|
-- parameterInformation = {
|
||||||
|
-- labelOffsetSupport = false;
|
||||||
|
-- };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
references = {
|
||||||
|
dynamicRegistration = false;
|
||||||
|
};
|
||||||
|
documentHighlight = {
|
||||||
|
dynamicRegistration = false
|
||||||
|
};
|
||||||
|
-- documentSymbol = {
|
||||||
|
-- dynamicRegistration = false;
|
||||||
|
-- symbolKind = {
|
||||||
|
-- valueSet = (function()
|
||||||
|
-- local res = {}
|
||||||
|
-- for k in pairs(protocol.SymbolKind) do
|
||||||
|
-- if type(k) == 'string' then table.insert(res, k) end
|
||||||
|
-- end
|
||||||
|
-- return res
|
||||||
|
-- end)();
|
||||||
|
-- };
|
||||||
|
-- hierarchicalDocumentSymbolSupport = false;
|
||||||
|
-- };
|
||||||
|
};
|
||||||
|
workspace = nil;
|
||||||
|
experimental = nil;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
export interface DocumentFilter {
|
||||||
|
--A language id, like `typescript`.
|
||||||
|
language?: string;
|
||||||
|
--A Uri [scheme](#Uri.scheme), like `file` or `untitled`.
|
||||||
|
scheme?: string;
|
||||||
|
--A glob pattern, like `*.{ts,js}`.
|
||||||
|
--
|
||||||
|
--Glob patterns can have the following syntax:
|
||||||
|
--- `*` to match one or more characters in a path segment
|
||||||
|
--- `?` to match on one character in a path segment
|
||||||
|
--- `**` to match any number of path segments, including none
|
||||||
|
--- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files)
|
||||||
|
--- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
|
||||||
|
--- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
|
||||||
|
pattern?: string;
|
||||||
|
}
|
||||||
|
--]=]
|
||||||
|
|
||||||
|
--[[
|
||||||
|
--Static registration options to be returned in the initialize request.
|
||||||
|
interface StaticRegistrationOptions {
|
||||||
|
--The id used to register the request. The id can be used to deregister
|
||||||
|
--the request again. See also Registration#id.
|
||||||
|
id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DocumentFilter {
|
||||||
|
--A language id, like `typescript`.
|
||||||
|
language?: string;
|
||||||
|
--A Uri [scheme](#Uri.scheme), like `file` or `untitled`.
|
||||||
|
scheme?: string;
|
||||||
|
--A glob pattern, like `*.{ts,js}`.
|
||||||
|
--
|
||||||
|
--Glob patterns can have the following syntax:
|
||||||
|
--- `*` to match one or more characters in a path segment
|
||||||
|
--- `?` to match on one character in a path segment
|
||||||
|
--- `**` to match any number of path segments, including none
|
||||||
|
--- `{}` to group conditions (e.g. `**/*.{ts,js}` matches all TypeScript and JavaScript files)
|
||||||
|
--- `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)
|
||||||
|
--- `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)
|
||||||
|
pattern?: string;
|
||||||
|
}
|
||||||
|
export type DocumentSelector = DocumentFilter[];
|
||||||
|
export interface TextDocumentRegistrationOptions {
|
||||||
|
--A document selector to identify the scope of the registration. If set to null
|
||||||
|
--the document selector provided on the client side will be used.
|
||||||
|
documentSelector: DocumentSelector | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
--Code Action options.
|
||||||
|
export interface CodeActionOptions {
|
||||||
|
--CodeActionKinds that this server may return.
|
||||||
|
--
|
||||||
|
--The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
|
||||||
|
--may list out every specific kind they provide.
|
||||||
|
codeActionKinds?: CodeActionKind[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ServerCapabilities {
|
||||||
|
--Defines how text documents are synced. Is either a detailed structure defining each notification or
|
||||||
|
--for backwards compatibility the TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`.
|
||||||
|
textDocumentSync?: TextDocumentSyncOptions | number;
|
||||||
|
--The server provides hover support.
|
||||||
|
hoverProvider?: boolean;
|
||||||
|
--The server provides completion support.
|
||||||
|
completionProvider?: CompletionOptions;
|
||||||
|
--The server provides signature help support.
|
||||||
|
signatureHelpProvider?: SignatureHelpOptions;
|
||||||
|
--The server provides goto definition support.
|
||||||
|
definitionProvider?: boolean;
|
||||||
|
--The server provides Goto Type Definition support.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
typeDefinitionProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
|
||||||
|
--The server provides Goto Implementation support.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
implementationProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
|
||||||
|
--The server provides find references support.
|
||||||
|
referencesProvider?: boolean;
|
||||||
|
--The server provides document highlight support.
|
||||||
|
documentHighlightProvider?: boolean;
|
||||||
|
--The server provides document symbol support.
|
||||||
|
documentSymbolProvider?: boolean;
|
||||||
|
--The server provides workspace symbol support.
|
||||||
|
workspaceSymbolProvider?: boolean;
|
||||||
|
--The server provides code actions. The `CodeActionOptions` return type is only
|
||||||
|
--valid if the client signals code action literal support via the property
|
||||||
|
--`textDocument.codeAction.codeActionLiteralSupport`.
|
||||||
|
codeActionProvider?: boolean | CodeActionOptions;
|
||||||
|
--The server provides code lens.
|
||||||
|
codeLensProvider?: CodeLensOptions;
|
||||||
|
--The server provides document formatting.
|
||||||
|
documentFormattingProvider?: boolean;
|
||||||
|
--The server provides document range formatting.
|
||||||
|
documentRangeFormattingProvider?: boolean;
|
||||||
|
--The server provides document formatting on typing.
|
||||||
|
documentOnTypeFormattingProvider?: DocumentOnTypeFormattingOptions;
|
||||||
|
--The server provides rename support. RenameOptions may only be
|
||||||
|
--specified if the client states that it supports
|
||||||
|
--`prepareSupport` in its initial `initialize` request.
|
||||||
|
renameProvider?: boolean | RenameOptions;
|
||||||
|
--The server provides document link support.
|
||||||
|
documentLinkProvider?: DocumentLinkOptions;
|
||||||
|
--The server provides color provider support.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
colorProvider?: boolean | ColorProviderOptions | (ColorProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions);
|
||||||
|
--The server provides folding provider support.
|
||||||
|
--
|
||||||
|
--Since 3.10.0
|
||||||
|
foldingRangeProvider?: boolean | FoldingRangeProviderOptions | (FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions);
|
||||||
|
--The server provides go to declaration support.
|
||||||
|
--
|
||||||
|
--Since 3.14.0
|
||||||
|
declarationProvider?: boolean | (TextDocumentRegistrationOptions & StaticRegistrationOptions);
|
||||||
|
--The server provides execute command support.
|
||||||
|
executeCommandProvider?: ExecuteCommandOptions;
|
||||||
|
--Workspace specific server capabilities
|
||||||
|
workspace?: {
|
||||||
|
--The server supports workspace folder.
|
||||||
|
--
|
||||||
|
--Since 3.6.0
|
||||||
|
workspaceFolders?: {
|
||||||
|
* The server has support for workspace folders
|
||||||
|
supported?: boolean;
|
||||||
|
* Whether the server wants to receive workspace folder
|
||||||
|
* change notifications.
|
||||||
|
*
|
||||||
|
* If a strings is provided the string is treated as a ID
|
||||||
|
* under which the notification is registered on the client
|
||||||
|
* side. The ID can be used to unregister for these events
|
||||||
|
* using the `client/unregisterCapability` request.
|
||||||
|
changeNotifications?: string | boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--Experimental server capabilities.
|
||||||
|
experimental?: any;
|
||||||
|
}
|
||||||
|
--]]
|
||||||
|
function protocol.resolve_capabilities(server_capabilities)
|
||||||
|
local general_properties = {}
|
||||||
|
local text_document_sync_properties
|
||||||
|
do
|
||||||
|
local TextDocumentSyncKind = protocol.TextDocumentSyncKind
|
||||||
|
local textDocumentSync = server_capabilities.textDocumentSync
|
||||||
|
if textDocumentSync == nil then
|
||||||
|
-- Defaults if omitted.
|
||||||
|
text_document_sync_properties = {
|
||||||
|
text_document_open_close = false;
|
||||||
|
text_document_did_change = TextDocumentSyncKind.None;
|
||||||
|
-- text_document_did_change = false;
|
||||||
|
text_document_will_save = false;
|
||||||
|
text_document_will_save_wait_until = false;
|
||||||
|
text_document_save = false;
|
||||||
|
text_document_save_include_text = false;
|
||||||
|
}
|
||||||
|
elseif type(textDocumentSync) == 'number' then
|
||||||
|
-- Backwards compatibility
|
||||||
|
if not TextDocumentSyncKind[textDocumentSync] then
|
||||||
|
return nil, "Invalid server TextDocumentSyncKind for textDocumentSync"
|
||||||
|
end
|
||||||
|
text_document_sync_properties = {
|
||||||
|
text_document_open_close = true;
|
||||||
|
text_document_did_change = textDocumentSync;
|
||||||
|
text_document_will_save = false;
|
||||||
|
text_document_will_save_wait_until = false;
|
||||||
|
text_document_save = false;
|
||||||
|
text_document_save_include_text = false;
|
||||||
|
}
|
||||||
|
elseif type(textDocumentSync) == 'table' then
|
||||||
|
text_document_sync_properties = {
|
||||||
|
text_document_open_close = ifnil(textDocumentSync.openClose, false);
|
||||||
|
text_document_did_change = ifnil(textDocumentSync.change, TextDocumentSyncKind.None);
|
||||||
|
text_document_will_save = ifnil(textDocumentSync.willSave, false);
|
||||||
|
text_document_will_save_wait_until = ifnil(textDocumentSync.willSaveWaitUntil, false);
|
||||||
|
text_document_save = ifnil(textDocumentSync.save, false);
|
||||||
|
text_document_save_include_text = ifnil(textDocumentSync.save and textDocumentSync.save.includeText, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nil, string.format("Invalid type for textDocumentSync: %q", type(textDocumentSync))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
general_properties.hover = server_capabilities.hoverProvider or false
|
||||||
|
general_properties.goto_definition = server_capabilities.definitionProvider or false
|
||||||
|
general_properties.find_references = server_capabilities.referencesProvider or false
|
||||||
|
general_properties.document_highlight = server_capabilities.documentHighlightProvider or false
|
||||||
|
general_properties.document_symbol = server_capabilities.documentSymbolProvider or false
|
||||||
|
general_properties.workspace_symbol = server_capabilities.workspaceSymbolProvider or false
|
||||||
|
general_properties.document_formatting = server_capabilities.documentFormattingProvider or false
|
||||||
|
general_properties.document_range_formatting = server_capabilities.documentRangeFormattingProvider or false
|
||||||
|
|
||||||
|
if server_capabilities.codeActionProvider == nil then
|
||||||
|
general_properties.code_action = false
|
||||||
|
elseif type(server_capabilities.codeActionProvider) == 'boolean' then
|
||||||
|
general_properties.code_action = server_capabilities.codeActionProvider
|
||||||
|
elseif type(server_capabilities.codeActionProvider) == 'table' then
|
||||||
|
-- TODO(ashkan) support CodeActionKind
|
||||||
|
general_properties.code_action = false
|
||||||
|
else
|
||||||
|
error("The server sent invalid codeActionProvider")
|
||||||
|
end
|
||||||
|
|
||||||
|
if server_capabilities.implementationProvider == nil then
|
||||||
|
general_properties.implementation = false
|
||||||
|
elseif type(server_capabilities.implementationProvider) == 'boolean' then
|
||||||
|
general_properties.implementation = server_capabilities.implementationProvider
|
||||||
|
elseif type(server_capabilities.implementationProvider) == 'table' then
|
||||||
|
-- TODO(ashkan) support more detailed implementation options.
|
||||||
|
general_properties.implementation = false
|
||||||
|
else
|
||||||
|
error("The server sent invalid implementationProvider")
|
||||||
|
end
|
||||||
|
|
||||||
|
local signature_help_properties
|
||||||
|
if server_capabilities.signatureHelpProvider == nil then
|
||||||
|
signature_help_properties = {
|
||||||
|
signature_help = false;
|
||||||
|
signature_help_trigger_characters = {};
|
||||||
|
}
|
||||||
|
elseif type(server_capabilities.signatureHelpProvider) == 'table' then
|
||||||
|
signature_help_properties = {
|
||||||
|
signature_help = true;
|
||||||
|
-- The characters that trigger signature help automatically.
|
||||||
|
signature_help_trigger_characters = server_capabilities.signatureHelpProvider.triggerCharacters or {};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error("The server sent invalid signatureHelpProvider")
|
||||||
|
end
|
||||||
|
|
||||||
|
return vim.tbl_extend("error"
|
||||||
|
, text_document_sync_properties
|
||||||
|
, signature_help_properties
|
||||||
|
, general_properties
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
return protocol
|
||||||
|
-- vim:sw=2 ts=2 et
|
452
runtime/lua/vim/lsp/rpc.lua
Normal file
452
runtime/lua/vim/lsp/rpc.lua
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
local uv = vim.loop
|
||||||
|
local log = require('vim.lsp.log')
|
||||||
|
local protocol = require('vim.lsp.protocol')
|
||||||
|
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
|
||||||
|
|
||||||
|
-- TODO replace with a better implementation.
|
||||||
|
local function json_encode(data)
|
||||||
|
local status, result = pcall(vim.fn.json_encode, data)
|
||||||
|
if status then
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return nil, result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function json_decode(data)
|
||||||
|
local status, result = pcall(vim.fn.json_decode, data)
|
||||||
|
if status then
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return nil, result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function is_dir(filename)
|
||||||
|
local stat = vim.loop.fs_stat(filename)
|
||||||
|
return stat and stat.type == 'directory' or false
|
||||||
|
end
|
||||||
|
|
||||||
|
local NIL = vim.NIL
|
||||||
|
local function convert_NIL(v)
|
||||||
|
if v == NIL then return nil end
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If a dictionary is passed in, turn it into a list of string of "k=v"
|
||||||
|
-- Accepts a table which can be composed of k=v strings or map-like
|
||||||
|
-- specification, such as:
|
||||||
|
--
|
||||||
|
-- ```
|
||||||
|
-- {
|
||||||
|
-- "PRODUCTION=false";
|
||||||
|
-- "PATH=/usr/bin/";
|
||||||
|
-- PORT = 123;
|
||||||
|
-- HOST = "0.0.0.0";
|
||||||
|
-- }
|
||||||
|
-- ```
|
||||||
|
--
|
||||||
|
-- Non-string values will be cast with `tostring`
|
||||||
|
local function force_env_list(final_env)
|
||||||
|
if final_env then
|
||||||
|
local env = final_env
|
||||||
|
final_env = {}
|
||||||
|
for k,v in pairs(env) do
|
||||||
|
-- If it's passed in as a dict, then convert to list of "k=v"
|
||||||
|
if type(k) == "string" then
|
||||||
|
table.insert(final_env, k..'='..tostring(v))
|
||||||
|
elseif type(v) == 'string' then
|
||||||
|
table.insert(final_env, v)
|
||||||
|
else
|
||||||
|
-- TODO is this right or should I exception here?
|
||||||
|
-- Try to coerce other values to string.
|
||||||
|
table.insert(final_env, tostring(v))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return final_env
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function format_message_with_content_length(encoded_message)
|
||||||
|
return table.concat {
|
||||||
|
'Content-Length: '; tostring(#encoded_message); '\r\n\r\n';
|
||||||
|
encoded_message;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Parse an LSP Message's header
|
||||||
|
-- @param header: The header to parse.
|
||||||
|
local function parse_headers(header)
|
||||||
|
if type(header) ~= 'string' then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local headers = {}
|
||||||
|
for line in vim.gsplit(header, '\r\n', true) do
|
||||||
|
if line == '' then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
local key, value = line:match("^%s*(%S+)%s*:%s*(.+)%s*$")
|
||||||
|
if key then
|
||||||
|
key = key:lower():gsub('%-', '_')
|
||||||
|
headers[key] = value
|
||||||
|
else
|
||||||
|
local _ = log.error() and log.error("invalid header line %q", line)
|
||||||
|
error(string.format("invalid header line %q", line))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
headers.content_length = tonumber(headers.content_length)
|
||||||
|
or error(string.format("Content-Length not found in headers. %q", header))
|
||||||
|
return headers
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is the start of any possible header patterns. The gsub converts it to a
|
||||||
|
-- case insensitive pattern.
|
||||||
|
local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end)
|
||||||
|
|
||||||
|
local function request_parser_loop()
|
||||||
|
local buffer = ''
|
||||||
|
while true do
|
||||||
|
-- A message can only be complete if it has a double CRLF and also the full
|
||||||
|
-- payload, so first let's check for the CRLFs
|
||||||
|
local start, finish = buffer:find('\r\n\r\n', 1, true)
|
||||||
|
-- Start parsing the headers
|
||||||
|
if start then
|
||||||
|
-- This is a workaround for servers sending initial garbage before
|
||||||
|
-- sending headers, such as if a bash script sends stdout. It assumes
|
||||||
|
-- that we know all of the headers ahead of time. At this moment, the
|
||||||
|
-- only valid headers start with "Content-*", so that's the thing we will
|
||||||
|
-- be searching for.
|
||||||
|
-- TODO(ashkan) I'd like to remove this, but it seems permanent :(
|
||||||
|
local buffer_start = buffer:find(header_start_pattern)
|
||||||
|
local headers = parse_headers(buffer:sub(buffer_start, start-1))
|
||||||
|
buffer = buffer:sub(finish+1)
|
||||||
|
local content_length = headers.content_length
|
||||||
|
-- Keep waiting for data until we have enough.
|
||||||
|
while #buffer < content_length do
|
||||||
|
buffer = buffer..(coroutine.yield()
|
||||||
|
or error("Expected more data for the body. The server may have died.")) -- TODO hmm.
|
||||||
|
end
|
||||||
|
local body = buffer:sub(1, content_length)
|
||||||
|
buffer = buffer:sub(content_length + 1)
|
||||||
|
-- Yield our data.
|
||||||
|
buffer = buffer..(coroutine.yield(headers, body)
|
||||||
|
or error("Expected more data for the body. The server may have died.")) -- TODO hmm.
|
||||||
|
else
|
||||||
|
-- Get more data since we don't have enough.
|
||||||
|
buffer = buffer..(coroutine.yield()
|
||||||
|
or error("Expected more data for the header. The server may have died.")) -- TODO hmm.
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local client_errors = vim.tbl_add_reverse_lookup {
|
||||||
|
INVALID_SERVER_MESSAGE = 1;
|
||||||
|
INVALID_SERVER_JSON = 2;
|
||||||
|
NO_RESULT_CALLBACK_FOUND = 3;
|
||||||
|
READ_ERROR = 4;
|
||||||
|
NOTIFICATION_HANDLER_ERROR = 5;
|
||||||
|
SERVER_REQUEST_HANDLER_ERROR = 6;
|
||||||
|
SERVER_RESULT_CALLBACK_ERROR = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
local function format_rpc_error(err)
|
||||||
|
validate {
|
||||||
|
err = { err, 't' };
|
||||||
|
}
|
||||||
|
local code_name = assert(protocol.ErrorCodes[err.code], "err.code is invalid")
|
||||||
|
local message_parts = {"RPC", code_name}
|
||||||
|
if err.message then
|
||||||
|
table.insert(message_parts, "message = ")
|
||||||
|
table.insert(message_parts, string.format("%q", err.message))
|
||||||
|
end
|
||||||
|
if err.data then
|
||||||
|
table.insert(message_parts, "data = ")
|
||||||
|
table.insert(message_parts, vim.inspect(err.data))
|
||||||
|
end
|
||||||
|
return table.concat(message_parts, ' ')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rpc_response_error(code, message, data)
|
||||||
|
-- TODO should this error or just pick a sane error (like InternalError)?
|
||||||
|
local code_name = assert(protocol.ErrorCodes[code], 'Invalid rpc error code')
|
||||||
|
return setmetatable({
|
||||||
|
code = code;
|
||||||
|
message = message or code_name;
|
||||||
|
data = data;
|
||||||
|
}, {
|
||||||
|
__tostring = format_rpc_error;
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local default_handlers = {}
|
||||||
|
function default_handlers.notification(method, params)
|
||||||
|
local _ = log.debug() and log.debug('notification', method, params)
|
||||||
|
end
|
||||||
|
function default_handlers.server_request(method, params)
|
||||||
|
local _ = log.debug() and log.debug('server_request', method, params)
|
||||||
|
return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound)
|
||||||
|
end
|
||||||
|
function default_handlers.on_exit(code, signal)
|
||||||
|
local _ = log.info() and log.info("client exit", { code = code, signal = signal })
|
||||||
|
end
|
||||||
|
function default_handlers.on_error(code, err)
|
||||||
|
local _ = log.error() and log.error('client_error:', client_errors[code], err)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create and start an RPC client.
|
||||||
|
-- @param cmd [
|
||||||
|
local function create_and_start_client(cmd, cmd_args, handlers, extra_spawn_params)
|
||||||
|
local _ = log.info() and log.info("Starting RPC client", {cmd = cmd, args = cmd_args, extra = extra_spawn_params})
|
||||||
|
validate {
|
||||||
|
cmd = { cmd, 's' };
|
||||||
|
cmd_args = { cmd_args, 't' };
|
||||||
|
handlers = { handlers, 't', true };
|
||||||
|
}
|
||||||
|
|
||||||
|
if not (vim.fn.executable(cmd) == 1) then
|
||||||
|
error(string.format("The given command %q is not executable.", cmd))
|
||||||
|
end
|
||||||
|
if handlers then
|
||||||
|
local user_handlers = handlers
|
||||||
|
handlers = {}
|
||||||
|
for handle_name, default_handler in pairs(default_handlers) do
|
||||||
|
local user_handler = user_handlers[handle_name]
|
||||||
|
if user_handler then
|
||||||
|
if type(user_handler) ~= 'function' then
|
||||||
|
error(string.format("handler.%s must be a function", handle_name))
|
||||||
|
end
|
||||||
|
-- server_request is wrapped elsewhere.
|
||||||
|
if not (handle_name == 'server_request'
|
||||||
|
or handle_name == 'on_exit') -- TODO this blocks the loop exiting for some reason.
|
||||||
|
then
|
||||||
|
user_handler = schedule_wrap(user_handler)
|
||||||
|
end
|
||||||
|
handlers[handle_name] = user_handler
|
||||||
|
else
|
||||||
|
handlers[handle_name] = default_handler
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
handlers = default_handlers
|
||||||
|
end
|
||||||
|
|
||||||
|
local stdin = uv.new_pipe(false)
|
||||||
|
local stdout = uv.new_pipe(false)
|
||||||
|
local stderr = uv.new_pipe(false)
|
||||||
|
|
||||||
|
local message_index = 0
|
||||||
|
local message_callbacks = {}
|
||||||
|
|
||||||
|
local handle, pid
|
||||||
|
do
|
||||||
|
local function onexit(code, signal)
|
||||||
|
stdin:close()
|
||||||
|
stdout:close()
|
||||||
|
stderr:close()
|
||||||
|
handle:close()
|
||||||
|
-- Make sure that message_callbacks can be gc'd.
|
||||||
|
message_callbacks = nil
|
||||||
|
handlers.on_exit(code, signal)
|
||||||
|
end
|
||||||
|
local spawn_params = {
|
||||||
|
args = cmd_args;
|
||||||
|
stdio = {stdin, stdout, stderr};
|
||||||
|
}
|
||||||
|
if extra_spawn_params then
|
||||||
|
spawn_params.cwd = extra_spawn_params.cwd
|
||||||
|
if spawn_params.cwd then
|
||||||
|
assert(is_dir(spawn_params.cwd), "cwd must be a directory")
|
||||||
|
end
|
||||||
|
spawn_params.env = force_env_list(extra_spawn_params.env)
|
||||||
|
end
|
||||||
|
handle, pid = uv.spawn(cmd, spawn_params, onexit)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function encode_and_send(payload)
|
||||||
|
local _ = log.debug() and log.debug("rpc.send.payload", payload)
|
||||||
|
if handle:is_closing() then return false end
|
||||||
|
-- TODO(ashkan) remove this once we have a Lua json_encode
|
||||||
|
schedule(function()
|
||||||
|
local encoded = assert(json_encode(payload))
|
||||||
|
stdin:write(format_message_with_content_length(encoded))
|
||||||
|
end)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function send_notification(method, params)
|
||||||
|
local _ = log.debug() and log.debug("rpc.notify", method, params)
|
||||||
|
return encode_and_send {
|
||||||
|
jsonrpc = "2.0";
|
||||||
|
method = method;
|
||||||
|
params = params;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function send_response(request_id, err, result)
|
||||||
|
return encode_and_send {
|
||||||
|
id = request_id;
|
||||||
|
jsonrpc = "2.0";
|
||||||
|
error = err;
|
||||||
|
result = result;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function send_request(method, params, callback)
|
||||||
|
validate {
|
||||||
|
callback = { callback, 'f' };
|
||||||
|
}
|
||||||
|
message_index = message_index + 1
|
||||||
|
local message_id = message_index
|
||||||
|
local result = encode_and_send {
|
||||||
|
id = message_id;
|
||||||
|
jsonrpc = "2.0";
|
||||||
|
method = method;
|
||||||
|
params = params;
|
||||||
|
}
|
||||||
|
if result then
|
||||||
|
message_callbacks[message_id] = schedule_wrap(callback)
|
||||||
|
return result, message_id
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
stderr:read_start(function(_err, chunk)
|
||||||
|
if chunk then
|
||||||
|
local _ = log.error() and log.error("rpc", cmd, "stderr", chunk)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function on_error(errkind, ...)
|
||||||
|
assert(client_errors[errkind])
|
||||||
|
-- TODO what to do if this fails?
|
||||||
|
pcall(handlers.on_error, errkind, ...)
|
||||||
|
end
|
||||||
|
local function pcall_handler(errkind, status, head, ...)
|
||||||
|
if not status then
|
||||||
|
on_error(errkind, head, ...)
|
||||||
|
return status, head
|
||||||
|
end
|
||||||
|
return status, head, ...
|
||||||
|
end
|
||||||
|
local function try_call(errkind, fn, ...)
|
||||||
|
return pcall_handler(errkind, pcall(fn, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO periodically check message_callbacks for old requests past a certain
|
||||||
|
-- time and log them. This would require storing the timestamp. I could call
|
||||||
|
-- them with an error then, perhaps.
|
||||||
|
|
||||||
|
local function handle_body(body)
|
||||||
|
local decoded, err = json_decode(body)
|
||||||
|
if not decoded then
|
||||||
|
on_error(client_errors.INVALID_SERVER_JSON, err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local _ = log.debug() and log.debug("decoded", decoded)
|
||||||
|
|
||||||
|
if type(decoded.method) == 'string' and decoded.id then
|
||||||
|
-- Server Request
|
||||||
|
decoded.params = convert_NIL(decoded.params)
|
||||||
|
-- Schedule here so that the users functions don't trigger an error and
|
||||||
|
-- we can still use the result.
|
||||||
|
schedule(function()
|
||||||
|
local status, result
|
||||||
|
status, result, err = try_call(client_errors.SERVER_REQUEST_HANDLER_ERROR,
|
||||||
|
handlers.server_request, decoded.method, decoded.params)
|
||||||
|
local _ = log.debug() and log.debug("server_request: callback result", { status = status, result = result, err = err })
|
||||||
|
if status then
|
||||||
|
if not (result or err) then
|
||||||
|
-- TODO this can be a problem if `null` is sent for result. needs vim.NIL
|
||||||
|
error(string.format("method %q: either a result or an error must be sent to the server in response", decoded.method))
|
||||||
|
end
|
||||||
|
if err then
|
||||||
|
assert(type(err) == 'table', "err must be a table. Use rpc_response_error to help format errors.")
|
||||||
|
local code_name = assert(protocol.ErrorCodes[err.code], "Errors must use protocol.ErrorCodes. Use rpc_response_error to help format errors.")
|
||||||
|
err.message = err.message or code_name
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- On an exception, result will contain the error message.
|
||||||
|
err = rpc_response_error(protocol.ErrorCodes.InternalError, result)
|
||||||
|
result = nil
|
||||||
|
end
|
||||||
|
send_response(decoded.id, err, result)
|
||||||
|
end)
|
||||||
|
-- This works because we are expecting vim.NIL here
|
||||||
|
elseif decoded.id and (decoded.result or decoded.error) then
|
||||||
|
-- Server Result
|
||||||
|
decoded.error = convert_NIL(decoded.error)
|
||||||
|
decoded.result = convert_NIL(decoded.result)
|
||||||
|
|
||||||
|
-- We sent a number, so we expect a number.
|
||||||
|
local result_id = tonumber(decoded.id)
|
||||||
|
local callback = message_callbacks[result_id]
|
||||||
|
if callback then
|
||||||
|
message_callbacks[result_id] = nil
|
||||||
|
validate {
|
||||||
|
callback = { callback, 'f' };
|
||||||
|
}
|
||||||
|
if decoded.error then
|
||||||
|
decoded.error = setmetatable(decoded.error, {
|
||||||
|
__tostring = format_rpc_error;
|
||||||
|
})
|
||||||
|
end
|
||||||
|
try_call(client_errors.SERVER_RESULT_CALLBACK_ERROR,
|
||||||
|
callback, decoded.error, decoded.result)
|
||||||
|
else
|
||||||
|
on_error(client_errors.NO_RESULT_CALLBACK_FOUND, decoded)
|
||||||
|
local _ = log.error() and log.error("No callback found for server response id "..result_id)
|
||||||
|
end
|
||||||
|
elseif type(decoded.method) == 'string' then
|
||||||
|
-- Notification
|
||||||
|
decoded.params = convert_NIL(decoded.params)
|
||||||
|
try_call(client_errors.NOTIFICATION_HANDLER_ERROR,
|
||||||
|
handlers.notification, decoded.method, decoded.params)
|
||||||
|
else
|
||||||
|
-- Invalid server message
|
||||||
|
on_error(client_errors.INVALID_SERVER_MESSAGE, decoded)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- TODO(ashkan) remove this once we have a Lua json_decode
|
||||||
|
handle_body = schedule_wrap(handle_body)
|
||||||
|
|
||||||
|
local request_parser = coroutine.wrap(request_parser_loop)
|
||||||
|
request_parser()
|
||||||
|
stdout:read_start(function(err, chunk)
|
||||||
|
if err then
|
||||||
|
-- TODO better handling. Can these be intermittent errors?
|
||||||
|
on_error(client_errors.READ_ERROR, err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- This should signal that we are done reading from the client.
|
||||||
|
if not chunk then return end
|
||||||
|
-- Flush anything in the parser by looping until we don't get a result
|
||||||
|
-- anymore.
|
||||||
|
while true do
|
||||||
|
local headers, body = request_parser(chunk)
|
||||||
|
-- If we successfully parsed, then handle the response.
|
||||||
|
if headers then
|
||||||
|
handle_body(body)
|
||||||
|
-- Set chunk to empty so that we can call request_parser to get
|
||||||
|
-- anything existing in the parser to flush.
|
||||||
|
chunk = ''
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return {
|
||||||
|
pid = pid;
|
||||||
|
handle = handle;
|
||||||
|
request = send_request;
|
||||||
|
notify = send_notification;
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
start = create_and_start_client;
|
||||||
|
rpc_response_error = rpc_response_error;
|
||||||
|
format_rpc_error = format_rpc_error;
|
||||||
|
client_errors = client_errors;
|
||||||
|
}
|
||||||
|
-- vim:sw=2 ts=2 et
|
727
runtime/lua/vim/lsp/util.lua
Normal file
727
runtime/lua/vim/lsp/util.lua
Normal file
@ -0,0 +1,727 @@
|
|||||||
|
local protocol = require 'vim.lsp.protocol'
|
||||||
|
local vim = vim
|
||||||
|
local validate = vim.validate
|
||||||
|
local api = vim.api
|
||||||
|
local list_extend = vim.list_extend
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
local split = vim.split
|
||||||
|
local function split_lines(value)
|
||||||
|
return split(value, '\n', true)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ok_or_nil(status, ...)
|
||||||
|
if not status then return end
|
||||||
|
return ...
|
||||||
|
end
|
||||||
|
local function npcall(fn, ...)
|
||||||
|
return ok_or_nil(pcall(fn, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Find the longest shared prefix between prefix and word.
|
||||||
|
-- e.g. remove_prefix("123tes", "testing") == "ting"
|
||||||
|
local function remove_prefix(prefix, word)
|
||||||
|
local max_prefix_length = math.min(#prefix, #word)
|
||||||
|
local prefix_length = 0
|
||||||
|
for i = 1, max_prefix_length do
|
||||||
|
local current_line_suffix = prefix:sub(-i)
|
||||||
|
local word_prefix = word:sub(1, i)
|
||||||
|
if current_line_suffix == word_prefix then
|
||||||
|
prefix_length = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return word:sub(prefix_length + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO(ashkan) @performance this could do less copying.
|
||||||
|
function M.set_lines(lines, A, B, new_lines)
|
||||||
|
-- 0-indexing to 1-indexing
|
||||||
|
local i_0 = A[1] + 1
|
||||||
|
local i_n = B[1] + 1
|
||||||
|
if not (i_0 >= 1 and i_0 <= #lines and i_n >= 1 and i_n <= #lines) then
|
||||||
|
error("Invalid range: "..vim.inspect{A = A; B = B; #lines, new_lines})
|
||||||
|
end
|
||||||
|
local prefix = ""
|
||||||
|
local suffix = lines[i_n]:sub(B[2]+1)
|
||||||
|
if A[2] > 0 then
|
||||||
|
prefix = lines[i_0]:sub(1, A[2])
|
||||||
|
end
|
||||||
|
local n = i_n - i_0 + 1
|
||||||
|
if n ~= #new_lines then
|
||||||
|
for _ = 1, n - #new_lines do table.remove(lines, i_0) end
|
||||||
|
for _ = 1, #new_lines - n do table.insert(lines, i_0, '') end
|
||||||
|
end
|
||||||
|
for i = 1, #new_lines do
|
||||||
|
lines[i - 1 + i_0] = new_lines[i]
|
||||||
|
end
|
||||||
|
if #suffix > 0 then
|
||||||
|
local i = i_0 + #new_lines - 1
|
||||||
|
lines[i] = lines[i]..suffix
|
||||||
|
end
|
||||||
|
if #prefix > 0 then
|
||||||
|
lines[i_0] = prefix..lines[i_0]
|
||||||
|
end
|
||||||
|
return lines
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sort_by_key(fn)
|
||||||
|
return function(a,b)
|
||||||
|
local ka, kb = fn(a), fn(b)
|
||||||
|
assert(#ka == #kb)
|
||||||
|
for i = 1, #ka do
|
||||||
|
if ka[i] ~= kb[i] then
|
||||||
|
return ka[i] < kb[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- every value must have been equal here, which means it's not less than.
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local edit_sort_key = sort_by_key(function(e)
|
||||||
|
return {e.A[1], e.A[2], e.i}
|
||||||
|
end)
|
||||||
|
|
||||||
|
function M.apply_text_edits(text_edits, bufnr)
|
||||||
|
if not next(text_edits) then return end
|
||||||
|
local start_line, finish_line = math.huge, -1
|
||||||
|
local cleaned = {}
|
||||||
|
for i, e in ipairs(text_edits) do
|
||||||
|
start_line = math.min(e.range.start.line, start_line)
|
||||||
|
finish_line = math.max(e.range["end"].line, finish_line)
|
||||||
|
-- TODO(ashkan) sanity check ranges for overlap.
|
||||||
|
table.insert(cleaned, {
|
||||||
|
i = i;
|
||||||
|
A = {e.range.start.line; e.range.start.character};
|
||||||
|
B = {e.range["end"].line; e.range["end"].character};
|
||||||
|
lines = vim.split(e.newText, '\n', true);
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Reverse sort the orders so we can apply them without interfering with
|
||||||
|
-- eachother. Also add i as a sort key to mimic a stable sort.
|
||||||
|
table.sort(cleaned, edit_sort_key)
|
||||||
|
local lines = api.nvim_buf_get_lines(bufnr, start_line, finish_line + 1, false)
|
||||||
|
local fix_eol = api.nvim_buf_get_option(bufnr, 'fixeol')
|
||||||
|
local set_eol = fix_eol and api.nvim_buf_line_count(bufnr) == finish_line + 1
|
||||||
|
if set_eol and #lines[#lines] ~= 0 then
|
||||||
|
table.insert(lines, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = #cleaned, 1, -1 do
|
||||||
|
local e = cleaned[i]
|
||||||
|
local A = {e.A[1] - start_line, e.A[2]}
|
||||||
|
local B = {e.B[1] - start_line, e.B[2]}
|
||||||
|
lines = M.set_lines(lines, A, B, e.lines)
|
||||||
|
end
|
||||||
|
if set_eol and #lines[#lines] == 0 then
|
||||||
|
table.remove(lines)
|
||||||
|
end
|
||||||
|
api.nvim_buf_set_lines(bufnr, start_line, finish_line + 1, false, lines)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- local valid_windows_path_characters = "[^<>:\"/\\|?*]"
|
||||||
|
-- local valid_unix_path_characters = "[^/]"
|
||||||
|
-- https://github.com/davidm/lua-glob-pattern
|
||||||
|
-- https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
|
||||||
|
-- function M.glob_to_regex(glob)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- textDocument/completion response returns one of CompletionItem[], CompletionList or null.
|
||||||
|
-- https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
|
||||||
|
function M.extract_completion_items(result)
|
||||||
|
if type(result) == 'table' and result.items then
|
||||||
|
return result.items
|
||||||
|
elseif result ~= nil then
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Apply the TextDocumentEdit response.
|
||||||
|
-- @params TextDocumentEdit [table] see https://microsoft.github.io/language-server-protocol/specification
|
||||||
|
function M.apply_text_document_edit(text_document_edit)
|
||||||
|
local text_document = text_document_edit.textDocument
|
||||||
|
local bufnr = vim.uri_to_bufnr(text_document.uri)
|
||||||
|
-- TODO(ashkan) check this is correct.
|
||||||
|
if api.nvim_buf_get_changedtick(bufnr) > text_document.version then
|
||||||
|
print("Buffer ", text_document.uri, " newer than edits.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
M.apply_text_edits(text_document_edit.edits, bufnr)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get_current_line_to_cursor()
|
||||||
|
local pos = api.nvim_win_get_cursor(0)
|
||||||
|
local line = assert(api.nvim_buf_get_lines(0, pos[1]-1, pos[1], false)[1])
|
||||||
|
return line:sub(pos[2]+1)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Getting vim complete-items with incomplete flag.
|
||||||
|
-- @params CompletionItem[], CompletionList or nil (https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
||||||
|
-- @return { matches = complete-items table, incomplete = boolean }
|
||||||
|
function M.text_document_completion_list_to_complete_items(result, line_prefix)
|
||||||
|
local items = M.extract_completion_items(result)
|
||||||
|
if vim.tbl_isempty(items) then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
-- Only initialize if we have some items.
|
||||||
|
if not line_prefix then
|
||||||
|
line_prefix = M.get_current_line_to_cursor()
|
||||||
|
end
|
||||||
|
|
||||||
|
local matches = {}
|
||||||
|
|
||||||
|
for _, completion_item in ipairs(items) do
|
||||||
|
local info = ' '
|
||||||
|
local documentation = completion_item.documentation
|
||||||
|
if documentation then
|
||||||
|
if type(documentation) == 'string' and documentation ~= '' then
|
||||||
|
info = documentation
|
||||||
|
elseif type(documentation) == 'table' and type(documentation.value) == 'string' then
|
||||||
|
info = documentation.value
|
||||||
|
-- else
|
||||||
|
-- TODO(ashkan) Validation handling here?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local word = completion_item.insertText or completion_item.label
|
||||||
|
|
||||||
|
-- Ref: `:h complete-items`
|
||||||
|
table.insert(matches, {
|
||||||
|
word = remove_prefix(line_prefix, word),
|
||||||
|
abbr = completion_item.label,
|
||||||
|
kind = protocol.CompletionItemKind[completion_item.kind] or '',
|
||||||
|
menu = completion_item.detail or '',
|
||||||
|
info = info,
|
||||||
|
icase = 1,
|
||||||
|
dup = 0,
|
||||||
|
empty = 1,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
return matches
|
||||||
|
end
|
||||||
|
|
||||||
|
-- @params WorkspaceEdit [table] see https://microsoft.github.io/language-server-protocol/specification
|
||||||
|
function M.apply_workspace_edit(workspace_edit)
|
||||||
|
if workspace_edit.documentChanges then
|
||||||
|
for _, change in ipairs(workspace_edit.documentChanges) do
|
||||||
|
if change.kind then
|
||||||
|
-- TODO(ashkan) handle CreateFile/RenameFile/DeleteFile
|
||||||
|
error(string.format("Unsupported change: %q", vim.inspect(change)))
|
||||||
|
else
|
||||||
|
M.apply_text_document_edit(change)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local all_changes = workspace_edit.changes
|
||||||
|
if not (all_changes and not vim.tbl_isempty(all_changes)) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for uri, changes in pairs(all_changes) do
|
||||||
|
local bufnr = vim.uri_to_bufnr(uri)
|
||||||
|
M.apply_text_edits(changes, bufnr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Convert any of MarkedString | MarkedString[] | MarkupContent into markdown text lines
|
||||||
|
-- see https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_hover
|
||||||
|
-- Useful for textDocument/hover, textDocument/signatureHelp, and potentially others.
|
||||||
|
function M.convert_input_to_markdown_lines(input, contents)
|
||||||
|
contents = contents or {}
|
||||||
|
-- MarkedString variation 1
|
||||||
|
if type(input) == 'string' then
|
||||||
|
list_extend(contents, split_lines(input))
|
||||||
|
else
|
||||||
|
assert(type(input) == 'table', "Expected a table for Hover.contents")
|
||||||
|
-- MarkupContent
|
||||||
|
if input.kind then
|
||||||
|
-- The kind can be either plaintext or markdown. However, either way we
|
||||||
|
-- will just be rendering markdown, so we handle them both the same way.
|
||||||
|
-- TODO these can have escaped/sanitized html codes in markdown. We
|
||||||
|
-- should make sure we handle this correctly.
|
||||||
|
|
||||||
|
-- Some servers send input.value as empty, so let's ignore this :(
|
||||||
|
-- assert(type(input.value) == 'string')
|
||||||
|
list_extend(contents, split_lines(input.value or ''))
|
||||||
|
-- MarkupString variation 2
|
||||||
|
elseif input.language then
|
||||||
|
-- Some servers send input.value as empty, so let's ignore this :(
|
||||||
|
-- assert(type(input.value) == 'string')
|
||||||
|
table.insert(contents, "```"..input.language)
|
||||||
|
list_extend(contents, split_lines(input.value or ''))
|
||||||
|
table.insert(contents, "```")
|
||||||
|
-- By deduction, this must be MarkedString[]
|
||||||
|
else
|
||||||
|
-- Use our existing logic to handle MarkedString
|
||||||
|
for _, marked_string in ipairs(input) do
|
||||||
|
M.convert_input_to_markdown_lines(marked_string, contents)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if contents[1] == '' or contents[1] == nil then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
return contents
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.make_floating_popup_options(width, height, opts)
|
||||||
|
validate {
|
||||||
|
opts = { opts, 't', true };
|
||||||
|
}
|
||||||
|
opts = opts or {}
|
||||||
|
validate {
|
||||||
|
["opts.offset_x"] = { opts.offset_x, 'n', true };
|
||||||
|
["opts.offset_y"] = { opts.offset_y, 'n', true };
|
||||||
|
}
|
||||||
|
|
||||||
|
local anchor = ''
|
||||||
|
local row, col
|
||||||
|
|
||||||
|
if vim.fn.winline() <= height then
|
||||||
|
anchor = anchor..'N'
|
||||||
|
row = 1
|
||||||
|
else
|
||||||
|
anchor = anchor..'S'
|
||||||
|
row = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
if vim.fn.wincol() + width <= api.nvim_get_option('columns') then
|
||||||
|
anchor = anchor..'W'
|
||||||
|
col = 0
|
||||||
|
else
|
||||||
|
anchor = anchor..'E'
|
||||||
|
col = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
anchor = anchor,
|
||||||
|
col = col + (opts.offset_x or 0),
|
||||||
|
height = height,
|
||||||
|
relative = 'cursor',
|
||||||
|
row = row + (opts.offset_y or 0),
|
||||||
|
style = 'minimal',
|
||||||
|
width = width,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.jump_to_location(location)
|
||||||
|
if location.uri == nil then return end
|
||||||
|
local bufnr = vim.uri_to_bufnr(location.uri)
|
||||||
|
-- Save position in jumplist
|
||||||
|
vim.cmd "normal! m'"
|
||||||
|
-- TODO(ashkan) use tagfunc here to update tagstack.
|
||||||
|
api.nvim_set_current_buf(bufnr)
|
||||||
|
local row = location.range.start.line
|
||||||
|
local col = location.range.start.character
|
||||||
|
local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
|
||||||
|
col = vim.str_byteindex(line, col)
|
||||||
|
api.nvim_win_set_cursor(0, {row + 1, col})
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_window_by_var(name, value)
|
||||||
|
for _, win in ipairs(api.nvim_list_wins()) do
|
||||||
|
if npcall(api.nvim_win_get_var, win, name) == value then
|
||||||
|
return win
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if a window with `unique_name` tagged is associated with the current
|
||||||
|
-- buffer. If not, make a new preview.
|
||||||
|
--
|
||||||
|
-- fn()'s return values will be passed directly to open_floating_preview in the
|
||||||
|
-- case that a new floating window should be created.
|
||||||
|
function M.focusable_preview(unique_name, fn)
|
||||||
|
if npcall(api.nvim_win_get_var, 0, unique_name) then
|
||||||
|
return api.nvim_command("wincmd p")
|
||||||
|
end
|
||||||
|
local bufnr = api.nvim_get_current_buf()
|
||||||
|
do
|
||||||
|
local win = find_window_by_var(unique_name, bufnr)
|
||||||
|
if win then
|
||||||
|
api.nvim_set_current_win(win)
|
||||||
|
api.nvim_command("stopinsert")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local pbufnr, pwinnr = M.open_floating_preview(fn())
|
||||||
|
api.nvim_win_set_var(pwinnr, unique_name, bufnr)
|
||||||
|
return pbufnr, pwinnr
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.open_floating_preview(contents, filetype, opts)
|
||||||
|
validate {
|
||||||
|
contents = { contents, 't' };
|
||||||
|
filetype = { filetype, 's', true };
|
||||||
|
opts = { opts, 't', true };
|
||||||
|
}
|
||||||
|
opts = opts or {}
|
||||||
|
|
||||||
|
-- Trim empty lines from the end.
|
||||||
|
contents = M.trim_empty_lines(contents)
|
||||||
|
|
||||||
|
local width = opts.width
|
||||||
|
local height = opts.height or #contents
|
||||||
|
if not width then
|
||||||
|
width = 0
|
||||||
|
for i, line in ipairs(contents) do
|
||||||
|
-- Clean up the input and add left pad.
|
||||||
|
line = " "..line:gsub("\r", "")
|
||||||
|
-- TODO(ashkan) use nvim_strdisplaywidth if/when that is introduced.
|
||||||
|
local line_width = vim.fn.strdisplaywidth(line)
|
||||||
|
width = math.max(line_width, width)
|
||||||
|
contents[i] = line
|
||||||
|
end
|
||||||
|
-- Add right padding of 1 each.
|
||||||
|
width = width + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local floating_bufnr = api.nvim_create_buf(false, true)
|
||||||
|
if filetype then
|
||||||
|
api.nvim_buf_set_option(floating_bufnr, 'filetype', filetype)
|
||||||
|
end
|
||||||
|
local float_option = M.make_floating_popup_options(width, height, opts)
|
||||||
|
local floating_winnr = api.nvim_open_win(floating_bufnr, false, float_option)
|
||||||
|
if filetype == 'markdown' then
|
||||||
|
api.nvim_win_set_option(floating_winnr, 'conceallevel', 2)
|
||||||
|
end
|
||||||
|
api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents)
|
||||||
|
api.nvim_buf_set_option(floating_bufnr, 'modifiable', false)
|
||||||
|
-- TODO make InsertCharPre disappearing optional?
|
||||||
|
api.nvim_command("autocmd CursorMoved,BufHidden,InsertCharPre <buffer> ++once lua pcall(vim.api.nvim_win_close, "..floating_winnr..", true)")
|
||||||
|
return floating_bufnr, floating_winnr
|
||||||
|
end
|
||||||
|
|
||||||
|
local function validate_lsp_position(pos)
|
||||||
|
validate { pos = {pos, 't'} }
|
||||||
|
validate {
|
||||||
|
line = {pos.line, 'n'};
|
||||||
|
character = {pos.character, 'n'};
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.open_floating_peek_preview(bufnr, start, finish, opts)
|
||||||
|
validate {
|
||||||
|
bufnr = {bufnr, 'n'};
|
||||||
|
start = {start, validate_lsp_position, 'valid start Position'};
|
||||||
|
finish = {finish, validate_lsp_position, 'valid finish Position'};
|
||||||
|
opts = { opts, 't', true };
|
||||||
|
}
|
||||||
|
local width = math.max(finish.character - start.character + 1, 1)
|
||||||
|
local height = math.max(finish.line - start.line + 1, 1)
|
||||||
|
local floating_winnr = api.nvim_open_win(bufnr, false, M.make_floating_popup_options(width, height, opts))
|
||||||
|
api.nvim_win_set_cursor(floating_winnr, {start.line+1, start.character})
|
||||||
|
api.nvim_command("autocmd CursorMoved * ++once lua pcall(vim.api.nvim_win_close, "..floating_winnr..", true)")
|
||||||
|
return floating_winnr
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function highlight_range(bufnr, ns, hiname, start, finish)
|
||||||
|
if start[1] == finish[1] then
|
||||||
|
-- TODO care about encoding here since this is in byte index?
|
||||||
|
api.nvim_buf_add_highlight(bufnr, ns, hiname, start[1], start[2], finish[2])
|
||||||
|
else
|
||||||
|
api.nvim_buf_add_highlight(bufnr, ns, hiname, start[1], start[2], -1)
|
||||||
|
for line = start[1] + 1, finish[1] - 1 do
|
||||||
|
api.nvim_buf_add_highlight(bufnr, ns, hiname, line, 0, -1)
|
||||||
|
end
|
||||||
|
api.nvim_buf_add_highlight(bufnr, ns, hiname, finish[1], 0, finish[2])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local all_buffer_diagnostics = {}
|
||||||
|
|
||||||
|
local diagnostic_ns = api.nvim_create_namespace("vim_lsp_diagnostics")
|
||||||
|
|
||||||
|
local underline_highlight_name = "LspDiagnosticsUnderline"
|
||||||
|
api.nvim_command(string.format("highlight default %s gui=underline cterm=underline", underline_highlight_name))
|
||||||
|
|
||||||
|
local severity_highlights = {}
|
||||||
|
|
||||||
|
local default_severity_highlight = {
|
||||||
|
[protocol.DiagnosticSeverity.Error] = { guifg = "Red" };
|
||||||
|
[protocol.DiagnosticSeverity.Warning] = { guifg = "Orange" };
|
||||||
|
[protocol.DiagnosticSeverity.Information] = { guifg = "LightBlue" };
|
||||||
|
[protocol.DiagnosticSeverity.Hint] = { guifg = "LightGrey" };
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Initialize default severity highlights
|
||||||
|
for severity, hi_info in pairs(default_severity_highlight) do
|
||||||
|
local severity_name = protocol.DiagnosticSeverity[severity]
|
||||||
|
local highlight_name = "LspDiagnostics"..severity_name
|
||||||
|
-- Try to fill in the foreground color with a sane default.
|
||||||
|
local cmd_parts = {"highlight", "default", highlight_name}
|
||||||
|
for k, v in pairs(hi_info) do
|
||||||
|
table.insert(cmd_parts, k.."="..v)
|
||||||
|
end
|
||||||
|
api.nvim_command(table.concat(cmd_parts, ' '))
|
||||||
|
severity_highlights[severity] = highlight_name
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.buf_clear_diagnostics(bufnr)
|
||||||
|
validate { bufnr = {bufnr, 'n', true} }
|
||||||
|
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
|
||||||
|
api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get_severity_highlight_name(severity)
|
||||||
|
return severity_highlights[severity]
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.show_line_diagnostics()
|
||||||
|
local bufnr = api.nvim_get_current_buf()
|
||||||
|
local line = api.nvim_win_get_cursor(0)[1] - 1
|
||||||
|
-- local marks = api.nvim_buf_get_extmarks(bufnr, diagnostic_ns, {line, 0}, {line, -1}, {})
|
||||||
|
-- if #marks == 0 then
|
||||||
|
-- return
|
||||||
|
-- end
|
||||||
|
-- local buffer_diagnostics = all_buffer_diagnostics[bufnr]
|
||||||
|
local lines = {"Diagnostics:"}
|
||||||
|
local highlights = {{0, "Bold"}}
|
||||||
|
|
||||||
|
local buffer_diagnostics = all_buffer_diagnostics[bufnr]
|
||||||
|
if not buffer_diagnostics then return end
|
||||||
|
local line_diagnostics = buffer_diagnostics[line]
|
||||||
|
if not line_diagnostics then return end
|
||||||
|
|
||||||
|
for i, diagnostic in ipairs(line_diagnostics) do
|
||||||
|
-- for i, mark in ipairs(marks) do
|
||||||
|
-- local mark_id = mark[1]
|
||||||
|
-- local diagnostic = buffer_diagnostics[mark_id]
|
||||||
|
|
||||||
|
-- TODO(ashkan) make format configurable?
|
||||||
|
local prefix = string.format("%d. ", i)
|
||||||
|
local hiname = severity_highlights[diagnostic.severity]
|
||||||
|
local message_lines = split_lines(diagnostic.message)
|
||||||
|
table.insert(lines, prefix..message_lines[1])
|
||||||
|
table.insert(highlights, {#prefix + 1, hiname})
|
||||||
|
for j = 2, #message_lines do
|
||||||
|
table.insert(lines, message_lines[j])
|
||||||
|
table.insert(highlights, {0, hiname})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local popup_bufnr, winnr = M.open_floating_preview(lines, 'plaintext')
|
||||||
|
for i, hi in ipairs(highlights) do
|
||||||
|
local prefixlen, hiname = unpack(hi)
|
||||||
|
-- Start highlight after the prefix
|
||||||
|
api.nvim_buf_add_highlight(popup_bufnr, -1, hiname, i-1, prefixlen, -1)
|
||||||
|
end
|
||||||
|
return popup_bufnr, winnr
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.buf_diagnostics_save_positions(bufnr, diagnostics)
|
||||||
|
validate {
|
||||||
|
bufnr = {bufnr, 'n', true};
|
||||||
|
diagnostics = {diagnostics, 't', true};
|
||||||
|
}
|
||||||
|
if not diagnostics then return end
|
||||||
|
bufnr = bufnr == 0 and api.nvim_get_current_buf() or bufnr
|
||||||
|
|
||||||
|
if not all_buffer_diagnostics[bufnr] then
|
||||||
|
-- Clean up our data when the buffer unloads.
|
||||||
|
api.nvim_buf_attach(bufnr, false, {
|
||||||
|
on_detach = function(b)
|
||||||
|
all_buffer_diagnostics[b] = nil
|
||||||
|
end
|
||||||
|
})
|
||||||
|
end
|
||||||
|
all_buffer_diagnostics[bufnr] = {}
|
||||||
|
local buffer_diagnostics = all_buffer_diagnostics[bufnr]
|
||||||
|
|
||||||
|
for _, diagnostic in ipairs(diagnostics) do
|
||||||
|
local start = diagnostic.range.start
|
||||||
|
-- local mark_id = api.nvim_buf_set_extmark(bufnr, diagnostic_ns, 0, start.line, 0, {})
|
||||||
|
-- buffer_diagnostics[mark_id] = diagnostic
|
||||||
|
local line_diagnostics = buffer_diagnostics[start.line]
|
||||||
|
if not line_diagnostics then
|
||||||
|
line_diagnostics = {}
|
||||||
|
buffer_diagnostics[start.line] = line_diagnostics
|
||||||
|
end
|
||||||
|
table.insert(line_diagnostics, diagnostic)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function M.buf_diagnostics_underline(bufnr, diagnostics)
|
||||||
|
for _, diagnostic in ipairs(diagnostics) do
|
||||||
|
local start = diagnostic.range.start
|
||||||
|
local finish = diagnostic.range["end"]
|
||||||
|
|
||||||
|
-- TODO care about encoding here since this is in byte index?
|
||||||
|
highlight_range(bufnr, diagnostic_ns, underline_highlight_name,
|
||||||
|
{start.line, start.character},
|
||||||
|
{finish.line, finish.character}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.buf_diagnostics_virtual_text(bufnr, diagnostics)
|
||||||
|
local buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
|
||||||
|
if not buffer_line_diagnostics then
|
||||||
|
M.buf_diagnostics_save_positions(bufnr, diagnostics)
|
||||||
|
end
|
||||||
|
buffer_line_diagnostics = all_buffer_diagnostics[bufnr]
|
||||||
|
if not buffer_line_diagnostics then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for line, line_diags in pairs(buffer_line_diagnostics) do
|
||||||
|
local virt_texts = {}
|
||||||
|
for i = 1, #line_diags - 1 do
|
||||||
|
table.insert(virt_texts, {"■", severity_highlights[line_diags[i].severity]})
|
||||||
|
end
|
||||||
|
local last = line_diags[#line_diags]
|
||||||
|
-- TODO(ashkan) use first line instead of subbing 2 spaces?
|
||||||
|
table.insert(virt_texts, {"■ "..last.message:gsub("\r", ""):gsub("\n", " "), severity_highlights[last.severity]})
|
||||||
|
api.nvim_buf_set_virtual_text(bufnr, diagnostic_ns, line, virt_texts, {})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local position_sort = sort_by_key(function(v)
|
||||||
|
return {v.line, v.character}
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Returns the items with the byte position calculated correctly and in sorted
|
||||||
|
-- order.
|
||||||
|
function M.locations_to_items(locations)
|
||||||
|
local items = {}
|
||||||
|
local grouped = setmetatable({}, {
|
||||||
|
__index = function(t, k)
|
||||||
|
local v = {}
|
||||||
|
rawset(t, k, v)
|
||||||
|
return v
|
||||||
|
end;
|
||||||
|
})
|
||||||
|
for _, d in ipairs(locations) do
|
||||||
|
local start = d.range.start
|
||||||
|
local fname = assert(vim.uri_to_fname(d.uri))
|
||||||
|
table.insert(grouped[fname], start)
|
||||||
|
end
|
||||||
|
local keys = vim.tbl_keys(grouped)
|
||||||
|
table.sort(keys)
|
||||||
|
-- TODO(ashkan) I wish we could do this lazily.
|
||||||
|
for _, fname in ipairs(keys) do
|
||||||
|
local rows = grouped[fname]
|
||||||
|
table.sort(rows, position_sort)
|
||||||
|
local i = 0
|
||||||
|
for line in io.lines(fname) do
|
||||||
|
for _, pos in ipairs(rows) do
|
||||||
|
local row = pos.line
|
||||||
|
if i == row then
|
||||||
|
local col
|
||||||
|
if pos.character > #line then
|
||||||
|
col = #line
|
||||||
|
else
|
||||||
|
col = vim.str_byteindex(line, pos.character)
|
||||||
|
end
|
||||||
|
table.insert(items, {
|
||||||
|
filename = fname,
|
||||||
|
lnum = row + 1,
|
||||||
|
col = col + 1;
|
||||||
|
text = line;
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
|
-- locations is Location[]
|
||||||
|
-- Only sets for the current window.
|
||||||
|
function M.set_loclist(locations)
|
||||||
|
vim.fn.setloclist(0, {}, ' ', {
|
||||||
|
title = 'Language Server';
|
||||||
|
items = M.locations_to_items(locations);
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- locations is Location[]
|
||||||
|
function M.set_qflist(locations)
|
||||||
|
vim.fn.setqflist({}, ' ', {
|
||||||
|
title = 'Language Server';
|
||||||
|
items = M.locations_to_items(locations);
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Remove empty lines from the beginning and end.
|
||||||
|
function M.trim_empty_lines(lines)
|
||||||
|
local start = 1
|
||||||
|
for i = 1, #lines do
|
||||||
|
if #lines[i] > 0 then
|
||||||
|
start = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local finish = 1
|
||||||
|
for i = #lines, 1, -1 do
|
||||||
|
if #lines[i] > 0 then
|
||||||
|
finish = i
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return vim.list_extend({}, lines, start, finish)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Accepts markdown lines and tries to reduce it to a filetype if it is
|
||||||
|
-- just a single code block.
|
||||||
|
-- Note: This modifies the input.
|
||||||
|
--
|
||||||
|
-- Returns: filetype or 'markdown' if it was unchanged.
|
||||||
|
function M.try_trim_markdown_code_blocks(lines)
|
||||||
|
local language_id = lines[1]:match("^```(.*)")
|
||||||
|
if language_id then
|
||||||
|
local has_inner_code_fence = false
|
||||||
|
for i = 2, (#lines - 1) do
|
||||||
|
local line = lines[i]
|
||||||
|
if line:sub(1,3) == '```' then
|
||||||
|
has_inner_code_fence = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- No inner code fences + starting with code fence = hooray.
|
||||||
|
if not has_inner_code_fence then
|
||||||
|
table.remove(lines, 1)
|
||||||
|
table.remove(lines)
|
||||||
|
return language_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 'markdown'
|
||||||
|
end
|
||||||
|
|
||||||
|
local str_utfindex = vim.str_utfindex
|
||||||
|
function M.make_position_params()
|
||||||
|
local row, col = unpack(api.nvim_win_get_cursor(0))
|
||||||
|
row = row - 1
|
||||||
|
local line = api.nvim_buf_get_lines(0, row, row+1, true)[1]
|
||||||
|
col = str_utfindex(line, col)
|
||||||
|
return {
|
||||||
|
textDocument = { uri = vim.uri_from_bufnr(0) };
|
||||||
|
position = { line = row; character = col; }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- @param buf buffer handle or 0 for current.
|
||||||
|
-- @param row 0-indexed line
|
||||||
|
-- @param col 0-indexed byte offset in line
|
||||||
|
function M.character_offset(buf, row, col)
|
||||||
|
local line = api.nvim_buf_get_lines(buf, row, row+1, true)[1]
|
||||||
|
-- If the col is past the EOL, use the line length.
|
||||||
|
if col > #line then
|
||||||
|
return str_utfindex(line)
|
||||||
|
end
|
||||||
|
return str_utfindex(line, col)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
|
-- vim:sw=2 ts=2 et
|
@ -4,34 +4,37 @@
|
|||||||
-- test-suite. If, in the future, Nvim itself is used to run the test-suite
|
-- test-suite. If, in the future, Nvim itself is used to run the test-suite
|
||||||
-- instead of "vanilla Lua", these functions could move to src/nvim/lua/vim.lua
|
-- instead of "vanilla Lua", these functions could move to src/nvim/lua/vim.lua
|
||||||
|
|
||||||
|
local vim = vim or {}
|
||||||
|
|
||||||
--- Returns a deep copy of the given object. Non-table objects are copied as
|
--- Returns a deep copy of the given object. Non-table objects are copied as
|
||||||
--- in a typical Lua assignment, whereas table objects are copied recursively.
|
--- in a typical Lua assignment, whereas table objects are copied recursively.
|
||||||
---
|
---
|
||||||
--@param orig Table to copy
|
--@param orig Table to copy
|
||||||
--@returns New table of copied keys and (nested) values.
|
--@returns New table of copied keys and (nested) values.
|
||||||
local function deepcopy(orig)
|
function vim.deepcopy(orig) end -- luacheck: no unused
|
||||||
error(orig)
|
vim.deepcopy = (function()
|
||||||
end
|
local function _id(v)
|
||||||
local function _id(v)
|
return v
|
||||||
return v
|
end
|
||||||
end
|
|
||||||
local deepcopy_funcs = {
|
local deepcopy_funcs = {
|
||||||
table = function(orig)
|
table = function(orig)
|
||||||
local copy = {}
|
local copy = {}
|
||||||
for k, v in pairs(orig) do
|
for k, v in pairs(orig) do
|
||||||
copy[deepcopy(k)] = deepcopy(v)
|
copy[vim.deepcopy(k)] = vim.deepcopy(v)
|
||||||
end
|
end
|
||||||
return copy
|
return copy
|
||||||
end,
|
end,
|
||||||
number = _id,
|
number = _id,
|
||||||
string = _id,
|
string = _id,
|
||||||
['nil'] = _id,
|
['nil'] = _id,
|
||||||
boolean = _id,
|
boolean = _id,
|
||||||
}
|
}
|
||||||
deepcopy = function(orig)
|
|
||||||
return deepcopy_funcs[type(orig)](orig)
|
return function(orig)
|
||||||
end
|
return deepcopy_funcs[type(orig)](orig)
|
||||||
|
end
|
||||||
|
end)()
|
||||||
|
|
||||||
--- Splits a string at each instance of a separator.
|
--- Splits a string at each instance of a separator.
|
||||||
---
|
---
|
||||||
@ -43,10 +46,8 @@ end
|
|||||||
--@param sep Separator string or pattern
|
--@param sep Separator string or pattern
|
||||||
--@param plain If `true` use `sep` literally (passed to String.find)
|
--@param plain If `true` use `sep` literally (passed to String.find)
|
||||||
--@returns Iterator over the split components
|
--@returns Iterator over the split components
|
||||||
local function gsplit(s, sep, plain)
|
function vim.gsplit(s, sep, plain)
|
||||||
assert(type(s) == "string")
|
vim.validate{s={s,'s'},sep={sep,'s'},plain={plain,'b',true}}
|
||||||
assert(type(sep) == "string")
|
|
||||||
assert(type(plain) == "boolean" or type(plain) == "nil")
|
|
||||||
|
|
||||||
local start = 1
|
local start = 1
|
||||||
local done = false
|
local done = false
|
||||||
@ -92,20 +93,51 @@ end
|
|||||||
--@param sep Separator string or pattern
|
--@param sep Separator string or pattern
|
||||||
--@param plain If `true` use `sep` literally (passed to String.find)
|
--@param plain If `true` use `sep` literally (passed to String.find)
|
||||||
--@returns List-like table of the split components.
|
--@returns List-like table of the split components.
|
||||||
local function split(s,sep,plain)
|
function vim.split(s,sep,plain)
|
||||||
local t={} for c in gsplit(s, sep, plain) do table.insert(t,c) end
|
local t={} for c in vim.gsplit(s, sep, plain) do table.insert(t,c) end
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Return a list of all keys used in a table.
|
||||||
|
--- However, the order of the return table of keys is not guaranteed.
|
||||||
|
---
|
||||||
|
--@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
|
||||||
|
---
|
||||||
|
--@param t Table
|
||||||
|
--@returns list of keys
|
||||||
|
function vim.tbl_keys(t)
|
||||||
|
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
|
||||||
|
|
||||||
|
local keys = {}
|
||||||
|
for k, _ in pairs(t) do
|
||||||
|
table.insert(keys, k)
|
||||||
|
end
|
||||||
|
return keys
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return a list of all values used in a table.
|
||||||
|
--- However, the order of the return table of values is not guaranteed.
|
||||||
|
---
|
||||||
|
--@param t Table
|
||||||
|
--@returns list of values
|
||||||
|
function vim.tbl_values(t)
|
||||||
|
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
|
||||||
|
|
||||||
|
local values = {}
|
||||||
|
for _, v in pairs(t) do
|
||||||
|
table.insert(values, v)
|
||||||
|
end
|
||||||
|
return values
|
||||||
|
end
|
||||||
|
|
||||||
--- Checks if a list-like (vector) table contains `value`.
|
--- Checks if a list-like (vector) table contains `value`.
|
||||||
---
|
---
|
||||||
--@param t Table to check
|
--@param t Table to check
|
||||||
--@param value Value to compare
|
--@param value Value to compare
|
||||||
--@returns true if `t` contains `value`
|
--@returns true if `t` contains `value`
|
||||||
local function tbl_contains(t, value)
|
function vim.tbl_contains(t, value)
|
||||||
if type(t) ~= 'table' then
|
vim.validate{t={t,'t'}}
|
||||||
error('t must be a table')
|
|
||||||
end
|
|
||||||
for _,v in ipairs(t) do
|
for _,v in ipairs(t) do
|
||||||
if v == value then
|
if v == value then
|
||||||
return true
|
return true
|
||||||
@ -114,6 +146,16 @@ local function tbl_contains(t, value)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns true if the table is empty, and contains no indexed or keyed values.
|
||||||
|
--
|
||||||
|
--@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
|
||||||
|
--
|
||||||
|
--@param t Table to check
|
||||||
|
function vim.tbl_isempty(t)
|
||||||
|
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
|
||||||
|
return next(t) == nil
|
||||||
|
end
|
||||||
|
|
||||||
--- Merges two or more map-like tables.
|
--- Merges two or more map-like tables.
|
||||||
---
|
---
|
||||||
--@see |extend()|
|
--@see |extend()|
|
||||||
@ -123,7 +165,7 @@ end
|
|||||||
--- - "keep": use value from the leftmost map
|
--- - "keep": use value from the leftmost map
|
||||||
--- - "force": use value from the rightmost map
|
--- - "force": use value from the rightmost map
|
||||||
--@param ... Two or more map-like tables.
|
--@param ... Two or more map-like tables.
|
||||||
local function tbl_extend(behavior, ...)
|
function vim.tbl_extend(behavior, ...)
|
||||||
if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then
|
if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then
|
||||||
error('invalid "behavior": '..tostring(behavior))
|
error('invalid "behavior": '..tostring(behavior))
|
||||||
end
|
end
|
||||||
@ -145,13 +187,77 @@ local function tbl_extend(behavior, ...)
|
|||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Deep compare values for equality
|
||||||
|
function vim.deep_equal(a, b)
|
||||||
|
if a == b then return true end
|
||||||
|
if type(a) ~= type(b) then return false end
|
||||||
|
if type(a) == 'table' then
|
||||||
|
-- TODO improve this algorithm's performance.
|
||||||
|
for k, v in pairs(a) do
|
||||||
|
if not vim.deep_equal(v, b[k]) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for k, v in pairs(b) do
|
||||||
|
if not vim.deep_equal(v, a[k]) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add the reverse lookup values to an existing table.
|
||||||
|
--- For example:
|
||||||
|
--- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`
|
||||||
|
--
|
||||||
|
--Do note that it *modifies* the input.
|
||||||
|
--@param o table The table to add the reverse to.
|
||||||
|
function vim.tbl_add_reverse_lookup(o)
|
||||||
|
local keys = vim.tbl_keys(o)
|
||||||
|
for _, k in ipairs(keys) do
|
||||||
|
local v = o[k]
|
||||||
|
if o[v] then
|
||||||
|
error(string.format("The reverse lookup found an existing value for %q while processing key %q", tostring(v), tostring(k)))
|
||||||
|
end
|
||||||
|
o[v] = k
|
||||||
|
end
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Extends a list-like table with the values of another list-like table.
|
||||||
|
---
|
||||||
|
--- NOTE: This mutates dst!
|
||||||
|
---
|
||||||
|
--@see |vim.tbl_extend()|
|
||||||
|
---
|
||||||
|
--@param dst list which will be modified and appended to.
|
||||||
|
--@param src list from which values will be inserted.
|
||||||
|
--@param start Start index on src. defaults to 1
|
||||||
|
--@param finish Final index on src. defaults to #src
|
||||||
|
--@returns dst
|
||||||
|
function vim.list_extend(dst, src, start, finish)
|
||||||
|
vim.validate {
|
||||||
|
dst = {dst, 't'};
|
||||||
|
src = {src, 't'};
|
||||||
|
start = {start, 'n', true};
|
||||||
|
finish = {finish, 'n', true};
|
||||||
|
}
|
||||||
|
for i = start or 1, finish or #src do
|
||||||
|
table.insert(dst, src[i])
|
||||||
|
end
|
||||||
|
return dst
|
||||||
|
end
|
||||||
|
|
||||||
--- Creates a copy of a list-like table such that any nested tables are
|
--- Creates a copy of a list-like table such that any nested tables are
|
||||||
--- "unrolled" and appended to the result.
|
--- "unrolled" and appended to the result.
|
||||||
---
|
---
|
||||||
|
--@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
|
||||||
|
---
|
||||||
--@param t List-like table
|
--@param t List-like table
|
||||||
--@returns Flattened copy of the given list-like table.
|
--@returns Flattened copy of the given list-like table.
|
||||||
local function tbl_flatten(t)
|
function vim.tbl_flatten(t)
|
||||||
-- From https://github.com/premake/premake-core/blob/master/src/base/table.lua
|
|
||||||
local result = {}
|
local result = {}
|
||||||
local function _tbl_flatten(_t)
|
local function _tbl_flatten(_t)
|
||||||
local n = #_t
|
local n = #_t
|
||||||
@ -168,13 +274,39 @@ local function tbl_flatten(t)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Determine whether a Lua table can be treated as an array.
|
||||||
|
---
|
||||||
|
--@params Table
|
||||||
|
--@returns true: A non-empty array, false: A non-empty table, nil: An empty table
|
||||||
|
function vim.tbl_islist(t)
|
||||||
|
if type(t) ~= 'table' then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local count = 0
|
||||||
|
|
||||||
|
for k, _ in pairs(t) do
|
||||||
|
if type(k) == "number" then
|
||||||
|
count = count + 1
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if count > 0 then
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
|
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
|
||||||
---
|
---
|
||||||
--@see https://www.lua.org/pil/20.2.html
|
--@see https://www.lua.org/pil/20.2.html
|
||||||
--@param s String to trim
|
--@param s String to trim
|
||||||
--@returns String with whitespace removed from its beginning and end
|
--@returns String with whitespace removed from its beginning and end
|
||||||
local function trim(s)
|
function vim.trim(s)
|
||||||
assert(type(s) == 'string', 'Only strings can be trimmed')
|
vim.validate{s={s,'s'}}
|
||||||
return s:match('^%s*(.*%S)') or ''
|
return s:match('^%s*(.*%S)') or ''
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -183,19 +315,120 @@ end
|
|||||||
--@see https://github.com/rxi/lume
|
--@see https://github.com/rxi/lume
|
||||||
--@param s String to escape
|
--@param s String to escape
|
||||||
--@returns %-escaped pattern string
|
--@returns %-escaped pattern string
|
||||||
local function pesc(s)
|
function vim.pesc(s)
|
||||||
assert(type(s) == 'string')
|
vim.validate{s={s,'s'}}
|
||||||
return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')
|
return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')
|
||||||
end
|
end
|
||||||
|
|
||||||
local module = {
|
--- Test if `prefix` is a prefix of `s` for strings.
|
||||||
deepcopy = deepcopy,
|
--
|
||||||
gsplit = gsplit,
|
-- @param s String to check
|
||||||
pesc = pesc,
|
-- @param prefix Potential prefix
|
||||||
split = split,
|
-- @return boolean True if prefix is a prefix of s
|
||||||
tbl_contains = tbl_contains,
|
function vim.startswith(s, prefix)
|
||||||
tbl_extend = tbl_extend,
|
vim.validate { s = {s, 's'}; prefix = {prefix, 's'}; }
|
||||||
tbl_flatten = tbl_flatten,
|
return s:sub(1, #prefix) == prefix
|
||||||
trim = trim,
|
end
|
||||||
}
|
|
||||||
return module
|
--- Test if `suffix` is a suffix of `s` for strings.
|
||||||
|
--
|
||||||
|
-- @param s String to check
|
||||||
|
-- @param suffix Potential suffix
|
||||||
|
-- @return boolean True if suffix is a suffix of s
|
||||||
|
function vim.endswith(s, suffix)
|
||||||
|
vim.validate { s = {s, 's'}; suffix = {suffix, 's'}; }
|
||||||
|
return #suffix == 0 or s:sub(-#suffix) == suffix
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Validates a parameter specification (types and values).
|
||||||
|
---
|
||||||
|
--- Usage example:
|
||||||
|
--- <pre>
|
||||||
|
--- function user.new(name, age, hobbies)
|
||||||
|
--- vim.validate{
|
||||||
|
--- name={name, 'string'},
|
||||||
|
--- age={age, 'number'},
|
||||||
|
--- hobbies={hobbies, 'table'},
|
||||||
|
--- }
|
||||||
|
--- ...
|
||||||
|
--- end
|
||||||
|
--- </pre>
|
||||||
|
---
|
||||||
|
--- Examples with explicit argument values (can be run directly):
|
||||||
|
--- <pre>
|
||||||
|
--- vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
|
||||||
|
--- => NOP (success)
|
||||||
|
---
|
||||||
|
--- vim.validate{arg1={1, 'table'}}
|
||||||
|
--- => error('arg1: expected table, got number')
|
||||||
|
---
|
||||||
|
--- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
|
||||||
|
--- => error('arg1: expected even number, got 3')
|
||||||
|
--- </pre>
|
||||||
|
---
|
||||||
|
--@param opt Map of parameter names to validations. Each key is a parameter
|
||||||
|
--- name; each value is a tuple in one of these forms:
|
||||||
|
--- 1. (arg_value, type_name, optional)
|
||||||
|
--- - arg_value: argument value
|
||||||
|
--- - type_name: string type name, one of: ("table", "t", "string",
|
||||||
|
--- "s", "number", "n", "boolean", "b", "function", "f", "nil",
|
||||||
|
--- "thread", "userdata")
|
||||||
|
--- - optional: (optional) boolean, if true, `nil` is valid
|
||||||
|
--- 2. (arg_value, fn, msg)
|
||||||
|
--- - arg_value: argument value
|
||||||
|
--- - fn: any function accepting one argument, returns true if and
|
||||||
|
--- only if the argument is valid
|
||||||
|
--- - msg: (optional) error string if validation fails
|
||||||
|
function vim.validate(opt) end -- luacheck: no unused
|
||||||
|
vim.validate = (function()
|
||||||
|
local type_names = {
|
||||||
|
t='table', s='string', n='number', b='boolean', f='function', c='callable',
|
||||||
|
['table']='table', ['string']='string', ['number']='number',
|
||||||
|
['boolean']='boolean', ['function']='function', ['callable']='callable',
|
||||||
|
['nil']='nil', ['thread']='thread', ['userdata']='userdata',
|
||||||
|
}
|
||||||
|
local function _type_name(t)
|
||||||
|
local tname = type_names[t]
|
||||||
|
if tname == nil then
|
||||||
|
error(string.format('invalid type name: %s', tostring(t)))
|
||||||
|
end
|
||||||
|
return tname
|
||||||
|
end
|
||||||
|
local function _is_type(val, t)
|
||||||
|
return t == 'callable' and vim.is_callable(val) or type(val) == t
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(opt)
|
||||||
|
assert(type(opt) == 'table', string.format('opt: expected table, got %s', type(opt)))
|
||||||
|
for param_name, spec in pairs(opt) do
|
||||||
|
assert(type(spec) == 'table', string.format('%s: expected table, got %s', param_name, type(spec)))
|
||||||
|
|
||||||
|
local val = spec[1] -- Argument value.
|
||||||
|
local t = spec[2] -- Type name, or callable.
|
||||||
|
local optional = (true == spec[3])
|
||||||
|
|
||||||
|
if not vim.is_callable(t) then -- Check type name.
|
||||||
|
if (not optional or val ~= nil) and not _is_type(val, _type_name(t)) then
|
||||||
|
error(string.format("%s: expected %s, got %s", param_name, _type_name(t), type(val)))
|
||||||
|
end
|
||||||
|
elseif not t(val) then -- Check user-provided validation function.
|
||||||
|
error(string.format("%s: expected %s, got %s", param_name, (spec[3] or '?'), val))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)()
|
||||||
|
|
||||||
|
--- Returns true if object `f` can be called as a function.
|
||||||
|
---
|
||||||
|
--@param f Any object
|
||||||
|
--@return true if `f` is callable, else false
|
||||||
|
function vim.is_callable(f)
|
||||||
|
if type(f) == 'function' then return true end
|
||||||
|
local m = getmetatable(f)
|
||||||
|
if m == nil then return false end
|
||||||
|
return type(m.__call) == 'function'
|
||||||
|
end
|
||||||
|
|
||||||
|
return vim
|
||||||
|
-- vim:sw=2 ts=2 et
|
||||||
|
73
runtime/lua/vim/treesitter.lua
Normal file
73
runtime/lua/vim/treesitter.lua
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
local a = vim.api
|
||||||
|
|
||||||
|
-- TODO(bfredl): currently we retain parsers for the lifetime of the buffer.
|
||||||
|
-- Consider use weak references to release parser if all plugins are done with
|
||||||
|
-- it.
|
||||||
|
local parsers = {}
|
||||||
|
|
||||||
|
local Parser = {}
|
||||||
|
Parser.__index = Parser
|
||||||
|
|
||||||
|
function Parser:parse()
|
||||||
|
if self.valid then
|
||||||
|
return self.tree
|
||||||
|
end
|
||||||
|
self.tree = self._parser:parse_buf(self.bufnr)
|
||||||
|
self.valid = true
|
||||||
|
return self.tree
|
||||||
|
end
|
||||||
|
|
||||||
|
function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_size)
|
||||||
|
local start_byte = a.nvim_buf_get_offset(bufnr,start_row)
|
||||||
|
local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row)
|
||||||
|
local old_stop_byte = start_byte + old_byte_size
|
||||||
|
self._parser:edit(start_byte,old_stop_byte,stop_byte,
|
||||||
|
start_row,0,old_stop_row,0,stop_row,0)
|
||||||
|
self.valid = false
|
||||||
|
end
|
||||||
|
|
||||||
|
local module = {
|
||||||
|
add_language=vim._ts_add_language,
|
||||||
|
inspect_language=vim._ts_inspect_language,
|
||||||
|
}
|
||||||
|
|
||||||
|
function module.create_parser(bufnr, ft, id)
|
||||||
|
if bufnr == 0 then
|
||||||
|
bufnr = a.nvim_get_current_buf()
|
||||||
|
end
|
||||||
|
local self = setmetatable({bufnr=bufnr, valid=false}, Parser)
|
||||||
|
self._parser = vim._create_ts_parser(ft)
|
||||||
|
self:parse()
|
||||||
|
-- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is
|
||||||
|
-- using it.
|
||||||
|
local function lines_cb(_, ...)
|
||||||
|
return self:_on_lines(...)
|
||||||
|
end
|
||||||
|
local detach_cb = nil
|
||||||
|
if id ~= nil then
|
||||||
|
detach_cb = function()
|
||||||
|
if parsers[id] == self then
|
||||||
|
parsers[id] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
a.nvim_buf_attach(self.bufnr, false, {on_lines=lines_cb, on_detach=detach_cb})
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function module.get_parser(bufnr, ft)
|
||||||
|
if bufnr == nil or bufnr == 0 then
|
||||||
|
bufnr = a.nvim_get_current_buf()
|
||||||
|
end
|
||||||
|
if ft == nil then
|
||||||
|
ft = a.nvim_buf_get_option(bufnr, "filetype")
|
||||||
|
end
|
||||||
|
local id = tostring(bufnr)..'_'..ft
|
||||||
|
|
||||||
|
if parsers[id] == nil then
|
||||||
|
parsers[id] = module.create_parser(bufnr, ft, id)
|
||||||
|
end
|
||||||
|
return parsers[id]
|
||||||
|
end
|
||||||
|
|
||||||
|
return module
|
94
runtime/lua/vim/uri.lua
Normal file
94
runtime/lua/vim/uri.lua
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
--- TODO: This is implemented only for files now.
|
||||||
|
-- https://tools.ietf.org/html/rfc3986
|
||||||
|
-- https://tools.ietf.org/html/rfc2732
|
||||||
|
-- https://tools.ietf.org/html/rfc2396
|
||||||
|
|
||||||
|
|
||||||
|
local uri_decode
|
||||||
|
do
|
||||||
|
local schar = string.char
|
||||||
|
local function hex_to_char(hex)
|
||||||
|
return schar(tonumber(hex, 16))
|
||||||
|
end
|
||||||
|
uri_decode = function(str)
|
||||||
|
return str:gsub("%%([a-fA-F0-9][a-fA-F0-9])", hex_to_char)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local uri_encode
|
||||||
|
do
|
||||||
|
local PATTERNS = {
|
||||||
|
--- RFC 2396
|
||||||
|
-- https://tools.ietf.org/html/rfc2396#section-2.2
|
||||||
|
rfc2396 = "^A-Za-z0-9%-_.!~*'()";
|
||||||
|
--- RFC 2732
|
||||||
|
-- https://tools.ietf.org/html/rfc2732
|
||||||
|
rfc2732 = "^A-Za-z0-9%-_.!~*'()[]";
|
||||||
|
--- RFC 3986
|
||||||
|
-- https://tools.ietf.org/html/rfc3986#section-2.2
|
||||||
|
rfc3986 = "^A-Za-z0-9%-._~!$&'()*+,;=:@/";
|
||||||
|
}
|
||||||
|
local sbyte, tohex = string.byte
|
||||||
|
if jit then
|
||||||
|
tohex = require'bit'.tohex
|
||||||
|
else
|
||||||
|
tohex = function(b) return string.format("%02x", b) end
|
||||||
|
end
|
||||||
|
local function percent_encode_char(char)
|
||||||
|
return "%"..tohex(sbyte(char), 2)
|
||||||
|
end
|
||||||
|
uri_encode = function(text, rfc)
|
||||||
|
if not text then return end
|
||||||
|
local pattern = PATTERNS[rfc] or PATTERNS.rfc3986
|
||||||
|
return text:gsub("(["..pattern.."])", percent_encode_char)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function is_windows_file_uri(uri)
|
||||||
|
return uri:match('^file:///[a-zA-Z]:') ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function uri_from_fname(path)
|
||||||
|
local volume_path, fname = path:match("^([a-zA-Z]:)(.*)")
|
||||||
|
local is_windows = volume_path ~= nil
|
||||||
|
if is_windows then
|
||||||
|
path = volume_path..uri_encode(fname:gsub("\\", "/"))
|
||||||
|
else
|
||||||
|
path = uri_encode(path)
|
||||||
|
end
|
||||||
|
local uri_parts = {"file://"}
|
||||||
|
if is_windows then
|
||||||
|
table.insert(uri_parts, "/")
|
||||||
|
end
|
||||||
|
table.insert(uri_parts, path)
|
||||||
|
return table.concat(uri_parts)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function uri_from_bufnr(bufnr)
|
||||||
|
return uri_from_fname(vim.api.nvim_buf_get_name(bufnr))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function uri_to_fname(uri)
|
||||||
|
-- TODO improve this.
|
||||||
|
if is_windows_file_uri(uri) then
|
||||||
|
uri = uri:gsub('^file:///', '')
|
||||||
|
uri = uri:gsub('/', '\\')
|
||||||
|
else
|
||||||
|
uri = uri:gsub('^file://', '')
|
||||||
|
end
|
||||||
|
return uri_decode(uri)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Return or create a buffer for a uri.
|
||||||
|
local function uri_to_bufnr(uri)
|
||||||
|
return vim.fn.bufadd((uri_to_fname(uri)))
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
uri_from_fname = uri_from_fname,
|
||||||
|
uri_from_bufnr = uri_from_bufnr,
|
||||||
|
uri_to_fname = uri_to_fname,
|
||||||
|
uri_to_bufnr = uri_to_bufnr,
|
||||||
|
}
|
||||||
|
-- vim:sw=2 ts=2 et
|
@ -1,6 +1,6 @@
|
|||||||
" Script to define the syntax menu in synmenu.vim
|
" Script to define the syntax menu in synmenu.vim
|
||||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||||
" Last Change: 2018 May 17
|
" Last Change: 2019 Dec 07
|
||||||
|
|
||||||
" This is used by "make menu" in the src directory.
|
" This is used by "make menu" in the src directory.
|
||||||
edit <sfile>:p:h/synmenu.vim
|
edit <sfile>:p:h/synmenu.vim
|
||||||
@ -101,6 +101,7 @@ SynMenu AB.AYacc:ayacc
|
|||||||
|
|
||||||
SynMenu AB.B:b
|
SynMenu AB.B:b
|
||||||
SynMenu AB.Baan:baan
|
SynMenu AB.Baan:baan
|
||||||
|
SynMenu AB.Bash:bash
|
||||||
SynMenu AB.Basic.FreeBasic:freebasic
|
SynMenu AB.Basic.FreeBasic:freebasic
|
||||||
SynMenu AB.Basic.IBasic:ibasic
|
SynMenu AB.Basic.IBasic:ibasic
|
||||||
SynMenu AB.Basic.QBasic:basic
|
SynMenu AB.Basic.QBasic:basic
|
||||||
@ -128,8 +129,9 @@ SynMenu C.Century\ Term:cterm
|
|||||||
SynMenu C.CH\ script:ch
|
SynMenu C.CH\ script:ch
|
||||||
SynMenu C.ChaiScript:chaiscript
|
SynMenu C.ChaiScript:chaiscript
|
||||||
SynMenu C.ChangeLog:changelog
|
SynMenu C.ChangeLog:changelog
|
||||||
SynMenu C.Cheetah\ template:cheetah
|
|
||||||
SynMenu C.CHILL:chill
|
SynMenu C.CHILL:chill
|
||||||
|
SynMenu C.Cheetah\ template:cheetah
|
||||||
|
SynMenu C.Chicken:chicken
|
||||||
SynMenu C.ChordPro:chordpro
|
SynMenu C.ChordPro:chordpro
|
||||||
SynMenu C.Clean:clean
|
SynMenu C.Clean:clean
|
||||||
SynMenu C.Clever:cl
|
SynMenu C.Clever:cl
|
||||||
@ -160,6 +162,7 @@ SynMenu C.Cyn++:cynpp
|
|||||||
SynMenu C.Cynlib:cynlib
|
SynMenu C.Cynlib:cynlib
|
||||||
|
|
||||||
SynMenu DE.D:d
|
SynMenu DE.D:d
|
||||||
|
SynMenu DE.Dart:dart
|
||||||
SynMenu DE.Datascript:datascript
|
SynMenu DE.Datascript:datascript
|
||||||
SynMenu DE.Debian.Debian\ ChangeLog:debchangelog
|
SynMenu DE.Debian.Debian\ ChangeLog:debchangelog
|
||||||
SynMenu DE.Debian.Debian\ Control:debcontrol
|
SynMenu DE.Debian.Debian\ Control:debcontrol
|
||||||
@ -192,12 +195,14 @@ SynMenu DE.DTD:dtd
|
|||||||
SynMenu DE.DTML\ (Zope):dtml
|
SynMenu DE.DTML\ (Zope):dtml
|
||||||
SynMenu DE.DTrace:dtrace
|
SynMenu DE.DTrace:dtrace
|
||||||
SynMenu DE.Dts/dtsi:dts
|
SynMenu DE.Dts/dtsi:dts
|
||||||
|
SynMenu DE.Dune:dune
|
||||||
SynMenu DE.Dylan.Dylan:dylan
|
SynMenu DE.Dylan.Dylan:dylan
|
||||||
SynMenu DE.Dylan.Dylan\ interface:dylanintr
|
SynMenu DE.Dylan.Dylan\ interface:dylanintr
|
||||||
SynMenu DE.Dylan.Dylan\ lid:dylanlid
|
SynMenu DE.Dylan.Dylan\ lid:dylanlid
|
||||||
|
|
||||||
SynMenu DE.EDIF:edif
|
SynMenu DE.EDIF:edif
|
||||||
SynMenu DE.Eiffel:eiffel
|
SynMenu DE.Eiffel:eiffel
|
||||||
|
SynMenu DE.Eight:8th
|
||||||
SynMenu DE.Elinks\ config:elinks
|
SynMenu DE.Elinks\ config:elinks
|
||||||
SynMenu DE.Elm\ filter\ rules:elmfilt
|
SynMenu DE.Elm\ filter\ rules:elmfilt
|
||||||
SynMenu DE.Embedix\ Component\ Description:ecd
|
SynMenu DE.Embedix\ Component\ Description:ecd
|
||||||
@ -307,6 +312,7 @@ SynMenu HIJK.Java.JavaCC:javacc
|
|||||||
SynMenu HIJK.Java.Java\ Server\ Pages:jsp
|
SynMenu HIJK.Java.Java\ Server\ Pages:jsp
|
||||||
SynMenu HIJK.Java.Java\ Properties:jproperties
|
SynMenu HIJK.Java.Java\ Properties:jproperties
|
||||||
SynMenu HIJK.JavaScript:javascript
|
SynMenu HIJK.JavaScript:javascript
|
||||||
|
SynMenu HIJK.JavaScriptReact:javascriptreact
|
||||||
SynMenu HIJK.Jess:jess
|
SynMenu HIJK.Jess:jess
|
||||||
SynMenu HIJK.Jgraph:jgraph
|
SynMenu HIJK.Jgraph:jgraph
|
||||||
SynMenu HIJK.Jovial:jovial
|
SynMenu HIJK.Jovial:jovial
|
||||||
@ -365,6 +371,7 @@ SynMenu M.Mathematica:mma
|
|||||||
SynMenu M.Matlab:matlab
|
SynMenu M.Matlab:matlab
|
||||||
SynMenu M.Maxima:maxima
|
SynMenu M.Maxima:maxima
|
||||||
SynMenu M.MEL\ (for\ Maya):mel
|
SynMenu M.MEL\ (for\ Maya):mel
|
||||||
|
SynMenu M.Meson:meson
|
||||||
SynMenu M.Messages\ (/var/log):messages
|
SynMenu M.Messages\ (/var/log):messages
|
||||||
SynMenu M.Metafont:mf
|
SynMenu M.Metafont:mf
|
||||||
SynMenu M.MetaPost:mp
|
SynMenu M.MetaPost:mp
|
||||||
@ -467,6 +474,7 @@ SynMenu R.R.R\ help:rhelp
|
|||||||
SynMenu R.R.R\ noweb:rnoweb
|
SynMenu R.R.R\ noweb:rnoweb
|
||||||
SynMenu R.Racc\ input:racc
|
SynMenu R.Racc\ input:racc
|
||||||
SynMenu R.Radiance:radiance
|
SynMenu R.Radiance:radiance
|
||||||
|
SynMenu R.Raml:raml
|
||||||
SynMenu R.Ratpoison:ratpoison
|
SynMenu R.Ratpoison:ratpoison
|
||||||
SynMenu R.RCS.RCS\ log\ output:rcslog
|
SynMenu R.RCS.RCS\ log\ output:rcslog
|
||||||
SynMenu R.RCS.RCS\ file:rcs
|
SynMenu R.RCS.RCS\ file:rcs
|
||||||
@ -609,6 +617,8 @@ SynMenu T.Trustees:trustees
|
|||||||
SynMenu T.TSS.Command\ Line:tsscl
|
SynMenu T.TSS.Command\ Line:tsscl
|
||||||
SynMenu T.TSS.Geometry:tssgm
|
SynMenu T.TSS.Geometry:tssgm
|
||||||
SynMenu T.TSS.Optics:tssop
|
SynMenu T.TSS.Optics:tssop
|
||||||
|
SynMenu T.Typescript:typescript
|
||||||
|
SynMenu T.TypescriptReact:typescriptreact
|
||||||
|
|
||||||
SynMenu UV.Udev\ config:udevconf
|
SynMenu UV.Udev\ config:udevconf
|
||||||
SynMenu UV.Udev\ permissions:udevperm
|
SynMenu UV.Udev\ permissions:udevperm
|
||||||
@ -637,6 +647,7 @@ SynMenu UV.VSE\ JCL:vsejcl
|
|||||||
SynMenu WXYZ.WEB.CWEB:cweb
|
SynMenu WXYZ.WEB.CWEB:cweb
|
||||||
SynMenu WXYZ.WEB.WEB:web
|
SynMenu WXYZ.WEB.WEB:web
|
||||||
SynMenu WXYZ.WEB.WEB\ Changes:change
|
SynMenu WXYZ.WEB.WEB\ Changes:change
|
||||||
|
SynMenu WXYZ.WebAssembly:wast
|
||||||
SynMenu WXYZ.Webmacro:webmacro
|
SynMenu WXYZ.Webmacro:webmacro
|
||||||
SynMenu WXYZ.Website\ MetaLanguage:wml
|
SynMenu WXYZ.Website\ MetaLanguage:wml
|
||||||
SynMenu WXYZ.wDiff:wdiff
|
SynMenu WXYZ.wDiff:wdiff
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release date="2019-11-06" version="0.4.3"/>
|
||||||
|
<release date="2019-09-15" version="0.4.2"/>
|
||||||
|
<release date="2019-09-15" version="0.4.1"/>
|
||||||
|
<release date="2019-09-15" version="0.4.0"/>
|
||||||
<release date="2019-07-03" version="0.3.8"/>
|
<release date="2019-07-03" version="0.3.8"/>
|
||||||
<release date="2019-04-29" version="0.3.5"/>
|
<release date="2019-04-29" version="0.3.5"/>
|
||||||
<release date="2019-01-13" version="0.3.4"/>
|
<release date="2019-01-13" version="0.3.4"/>
|
||||||
|
@ -300,6 +300,11 @@ call append("$", "tagstack\ta :tag command will use the tagstack")
|
|||||||
call <SID>BinOptionG("tgst", &tgst)
|
call <SID>BinOptionG("tgst", &tgst)
|
||||||
call append("$", "showfulltag\twhen completing tags in Insert mode show more info")
|
call append("$", "showfulltag\twhen completing tags in Insert mode show more info")
|
||||||
call <SID>BinOptionG("sft", &sft)
|
call <SID>BinOptionG("sft", &sft)
|
||||||
|
if has("eval")
|
||||||
|
call append("$", "tagfunc\ta function to be used to perform tag searches")
|
||||||
|
call append("$", "\t(local to buffer)")
|
||||||
|
call <SID>OptionL("tfu")
|
||||||
|
endif
|
||||||
if has("cscope")
|
if has("cscope")
|
||||||
call append("$", "cscopeprg\tcommand for executing cscope")
|
call append("$", "cscopeprg\tcommand for executing cscope")
|
||||||
call <SID>OptionG("csprg", &csprg)
|
call <SID>OptionG("csprg", &csprg)
|
||||||
|
@ -67,8 +67,8 @@ command -nargs=* -complete=file -bang Termdebug call s:StartDebug(<bang>0, <f-ar
|
|||||||
command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>)
|
command -nargs=+ -complete=file -bang TermdebugCommand call s:StartDebugCommand(<bang>0, <f-args>)
|
||||||
|
|
||||||
" Name of the gdb command, defaults to "gdb".
|
" Name of the gdb command, defaults to "gdb".
|
||||||
if !exists('termdebugger')
|
if !exists('g:termdebugger')
|
||||||
let termdebugger = 'gdb'
|
let g:termdebugger = 'gdb'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
let s:pc_id = 12
|
let s:pc_id = 12
|
||||||
@ -106,9 +106,14 @@ endfunc
|
|||||||
|
|
||||||
func s:StartDebug_internal(dict)
|
func s:StartDebug_internal(dict)
|
||||||
if exists('s:gdbwin')
|
if exists('s:gdbwin')
|
||||||
echoerr 'Terminal debugger already running'
|
echoerr 'Terminal debugger already running, cannot run two'
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
|
if !executable(g:termdebugger)
|
||||||
|
echoerr 'Cannot execute debugger program "' .. g:termdebugger .. '"'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
let s:ptywin = 0
|
let s:ptywin = 0
|
||||||
let s:pid = 0
|
let s:pid = 0
|
||||||
|
|
||||||
@ -578,6 +583,7 @@ func s:HandleEvaluate(msg)
|
|||||||
endif
|
endif
|
||||||
let s:evalFromBalloonExprResult = split(s:evalFromBalloonExprResult, '\\n')
|
let s:evalFromBalloonExprResult = split(s:evalFromBalloonExprResult, '\\n')
|
||||||
call s:OpenHoverPreview(s:evalFromBalloonExprResult, v:null)
|
call s:OpenHoverPreview(s:evalFromBalloonExprResult, v:null)
|
||||||
|
let s:evalFromBalloonExprResult = ''
|
||||||
else
|
else
|
||||||
echomsg '"' . s:evalexpr . '": ' . value
|
echomsg '"' . s:evalexpr . '": ' . value
|
||||||
endif
|
endif
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
" Maintainer: Anmol Sethi <anmol@aubble.com>
|
" Maintainer: Anmol Sethi <hi@nhooyr.io>
|
||||||
|
|
||||||
if exists('g:loaded_man')
|
if exists('g:loaded_man')
|
||||||
finish
|
finish
|
||||||
|
@ -87,19 +87,20 @@ an 50.10.580 &Syntax.AB.Awk :cal SetSyn("awk")<CR>
|
|||||||
an 50.10.590 &Syntax.AB.AYacc :cal SetSyn("ayacc")<CR>
|
an 50.10.590 &Syntax.AB.AYacc :cal SetSyn("ayacc")<CR>
|
||||||
an 50.10.610 &Syntax.AB.B :cal SetSyn("b")<CR>
|
an 50.10.610 &Syntax.AB.B :cal SetSyn("b")<CR>
|
||||||
an 50.10.620 &Syntax.AB.Baan :cal SetSyn("baan")<CR>
|
an 50.10.620 &Syntax.AB.Baan :cal SetSyn("baan")<CR>
|
||||||
an 50.10.630 &Syntax.AB.Basic.FreeBasic :cal SetSyn("freebasic")<CR>
|
an 50.10.630 &Syntax.AB.Bash :cal SetSyn("bash")<CR>
|
||||||
an 50.10.640 &Syntax.AB.Basic.IBasic :cal SetSyn("ibasic")<CR>
|
an 50.10.640 &Syntax.AB.Basic.FreeBasic :cal SetSyn("freebasic")<CR>
|
||||||
an 50.10.650 &Syntax.AB.Basic.QBasic :cal SetSyn("basic")<CR>
|
an 50.10.650 &Syntax.AB.Basic.IBasic :cal SetSyn("ibasic")<CR>
|
||||||
an 50.10.660 &Syntax.AB.Basic.Visual\ Basic :cal SetSyn("vb")<CR>
|
an 50.10.660 &Syntax.AB.Basic.QBasic :cal SetSyn("basic")<CR>
|
||||||
an 50.10.670 &Syntax.AB.Bazaar\ commit\ file :cal SetSyn("bzr")<CR>
|
an 50.10.670 &Syntax.AB.Basic.Visual\ Basic :cal SetSyn("vb")<CR>
|
||||||
an 50.10.680 &Syntax.AB.Bazel :cal SetSyn("bzl")<CR>
|
an 50.10.680 &Syntax.AB.Bazaar\ commit\ file :cal SetSyn("bzr")<CR>
|
||||||
an 50.10.690 &Syntax.AB.BC\ calculator :cal SetSyn("bc")<CR>
|
an 50.10.690 &Syntax.AB.Bazel :cal SetSyn("bzl")<CR>
|
||||||
an 50.10.700 &Syntax.AB.BDF\ font :cal SetSyn("bdf")<CR>
|
an 50.10.700 &Syntax.AB.BC\ calculator :cal SetSyn("bc")<CR>
|
||||||
an 50.10.710 &Syntax.AB.BibTeX.Bibliography\ database :cal SetSyn("bib")<CR>
|
an 50.10.710 &Syntax.AB.BDF\ font :cal SetSyn("bdf")<CR>
|
||||||
an 50.10.720 &Syntax.AB.BibTeX.Bibliography\ Style :cal SetSyn("bst")<CR>
|
an 50.10.720 &Syntax.AB.BibTeX.Bibliography\ database :cal SetSyn("bib")<CR>
|
||||||
an 50.10.730 &Syntax.AB.BIND.BIND\ config :cal SetSyn("named")<CR>
|
an 50.10.730 &Syntax.AB.BibTeX.Bibliography\ Style :cal SetSyn("bst")<CR>
|
||||||
an 50.10.740 &Syntax.AB.BIND.BIND\ zone :cal SetSyn("bindzone")<CR>
|
an 50.10.740 &Syntax.AB.BIND.BIND\ config :cal SetSyn("named")<CR>
|
||||||
an 50.10.750 &Syntax.AB.Blank :cal SetSyn("blank")<CR>
|
an 50.10.750 &Syntax.AB.BIND.BIND\ zone :cal SetSyn("bindzone")<CR>
|
||||||
|
an 50.10.760 &Syntax.AB.Blank :cal SetSyn("blank")<CR>
|
||||||
an 50.20.100 &Syntax.C.C :cal SetSyn("c")<CR>
|
an 50.20.100 &Syntax.C.C :cal SetSyn("c")<CR>
|
||||||
an 50.20.110 &Syntax.C.C++ :cal SetSyn("cpp")<CR>
|
an 50.20.110 &Syntax.C.C++ :cal SetSyn("cpp")<CR>
|
||||||
an 50.20.120 &Syntax.C.C# :cal SetSyn("cs")<CR>
|
an 50.20.120 &Syntax.C.C# :cal SetSyn("cs")<CR>
|
||||||
@ -113,89 +114,93 @@ an 50.20.190 &Syntax.C.Century\ Term :cal SetSyn("cterm")<CR>
|
|||||||
an 50.20.200 &Syntax.C.CH\ script :cal SetSyn("ch")<CR>
|
an 50.20.200 &Syntax.C.CH\ script :cal SetSyn("ch")<CR>
|
||||||
an 50.20.210 &Syntax.C.ChaiScript :cal SetSyn("chaiscript")<CR>
|
an 50.20.210 &Syntax.C.ChaiScript :cal SetSyn("chaiscript")<CR>
|
||||||
an 50.20.220 &Syntax.C.ChangeLog :cal SetSyn("changelog")<CR>
|
an 50.20.220 &Syntax.C.ChangeLog :cal SetSyn("changelog")<CR>
|
||||||
an 50.20.230 &Syntax.C.Cheetah\ template :cal SetSyn("cheetah")<CR>
|
an 50.20.230 &Syntax.C.CHILL :cal SetSyn("chill")<CR>
|
||||||
an 50.20.240 &Syntax.C.CHILL :cal SetSyn("chill")<CR>
|
an 50.20.240 &Syntax.C.Cheetah\ template :cal SetSyn("cheetah")<CR>
|
||||||
an 50.20.250 &Syntax.C.ChordPro :cal SetSyn("chordpro")<CR>
|
an 50.20.250 &Syntax.C.Chicken :cal SetSyn("chicken")<CR>
|
||||||
an 50.20.260 &Syntax.C.Clean :cal SetSyn("clean")<CR>
|
an 50.20.260 &Syntax.C.ChordPro :cal SetSyn("chordpro")<CR>
|
||||||
an 50.20.270 &Syntax.C.Clever :cal SetSyn("cl")<CR>
|
an 50.20.270 &Syntax.C.Clean :cal SetSyn("clean")<CR>
|
||||||
an 50.20.280 &Syntax.C.Clipper :cal SetSyn("clipper")<CR>
|
an 50.20.280 &Syntax.C.Clever :cal SetSyn("cl")<CR>
|
||||||
an 50.20.290 &Syntax.C.Clojure :cal SetSyn("clojure")<CR>
|
an 50.20.290 &Syntax.C.Clipper :cal SetSyn("clipper")<CR>
|
||||||
an 50.20.300 &Syntax.C.Cmake :cal SetSyn("cmake")<CR>
|
an 50.20.300 &Syntax.C.Clojure :cal SetSyn("clojure")<CR>
|
||||||
an 50.20.310 &Syntax.C.Cmod :cal SetSyn("cmod")<CR>
|
an 50.20.310 &Syntax.C.Cmake :cal SetSyn("cmake")<CR>
|
||||||
an 50.20.320 &Syntax.C.Cmusrc :cal SetSyn("cmusrc")<CR>
|
an 50.20.320 &Syntax.C.Cmod :cal SetSyn("cmod")<CR>
|
||||||
an 50.20.330 &Syntax.C.Cobol :cal SetSyn("cobol")<CR>
|
an 50.20.330 &Syntax.C.Cmusrc :cal SetSyn("cmusrc")<CR>
|
||||||
an 50.20.340 &Syntax.C.Coco/R :cal SetSyn("coco")<CR>
|
an 50.20.340 &Syntax.C.Cobol :cal SetSyn("cobol")<CR>
|
||||||
an 50.20.350 &Syntax.C.Cold\ Fusion :cal SetSyn("cf")<CR>
|
an 50.20.350 &Syntax.C.Coco/R :cal SetSyn("coco")<CR>
|
||||||
an 50.20.360 &Syntax.C.Conary\ Recipe :cal SetSyn("conaryrecipe")<CR>
|
an 50.20.360 &Syntax.C.Cold\ Fusion :cal SetSyn("cf")<CR>
|
||||||
an 50.20.370 &Syntax.C.Config.Cfg\ Config\ file :cal SetSyn("cfg")<CR>
|
an 50.20.370 &Syntax.C.Conary\ Recipe :cal SetSyn("conaryrecipe")<CR>
|
||||||
an 50.20.380 &Syntax.C.Config.Configure\.in :cal SetSyn("config")<CR>
|
an 50.20.380 &Syntax.C.Config.Cfg\ Config\ file :cal SetSyn("cfg")<CR>
|
||||||
an 50.20.390 &Syntax.C.Config.Generic\ Config\ file :cal SetSyn("conf")<CR>
|
an 50.20.390 &Syntax.C.Config.Configure\.in :cal SetSyn("config")<CR>
|
||||||
an 50.20.400 &Syntax.C.CRM114 :cal SetSyn("crm")<CR>
|
an 50.20.400 &Syntax.C.Config.Generic\ Config\ file :cal SetSyn("conf")<CR>
|
||||||
an 50.20.410 &Syntax.C.Crontab :cal SetSyn("crontab")<CR>
|
an 50.20.410 &Syntax.C.CRM114 :cal SetSyn("crm")<CR>
|
||||||
an 50.20.420 &Syntax.C.CSDL :cal SetSyn("csdl")<CR>
|
an 50.20.420 &Syntax.C.Crontab :cal SetSyn("crontab")<CR>
|
||||||
an 50.20.430 &Syntax.C.CSP :cal SetSyn("csp")<CR>
|
an 50.20.430 &Syntax.C.CSDL :cal SetSyn("csdl")<CR>
|
||||||
an 50.20.440 &Syntax.C.Ctrl-H :cal SetSyn("ctrlh")<CR>
|
an 50.20.440 &Syntax.C.CSP :cal SetSyn("csp")<CR>
|
||||||
an 50.20.450 &Syntax.C.Cucumber :cal SetSyn("cucumber")<CR>
|
an 50.20.450 &Syntax.C.Ctrl-H :cal SetSyn("ctrlh")<CR>
|
||||||
an 50.20.460 &Syntax.C.CUDA :cal SetSyn("cuda")<CR>
|
an 50.20.460 &Syntax.C.Cucumber :cal SetSyn("cucumber")<CR>
|
||||||
an 50.20.470 &Syntax.C.CUPL.CUPL :cal SetSyn("cupl")<CR>
|
an 50.20.470 &Syntax.C.CUDA :cal SetSyn("cuda")<CR>
|
||||||
an 50.20.480 &Syntax.C.CUPL.Simulation :cal SetSyn("cuplsim")<CR>
|
an 50.20.480 &Syntax.C.CUPL.CUPL :cal SetSyn("cupl")<CR>
|
||||||
an 50.20.490 &Syntax.C.CVS.commit\ file :cal SetSyn("cvs")<CR>
|
an 50.20.490 &Syntax.C.CUPL.Simulation :cal SetSyn("cuplsim")<CR>
|
||||||
an 50.20.500 &Syntax.C.CVS.cvsrc :cal SetSyn("cvsrc")<CR>
|
an 50.20.500 &Syntax.C.CVS.commit\ file :cal SetSyn("cvs")<CR>
|
||||||
an 50.20.510 &Syntax.C.Cyn++ :cal SetSyn("cynpp")<CR>
|
an 50.20.510 &Syntax.C.CVS.cvsrc :cal SetSyn("cvsrc")<CR>
|
||||||
an 50.20.520 &Syntax.C.Cynlib :cal SetSyn("cynlib")<CR>
|
an 50.20.520 &Syntax.C.Cyn++ :cal SetSyn("cynpp")<CR>
|
||||||
|
an 50.20.530 &Syntax.C.Cynlib :cal SetSyn("cynlib")<CR>
|
||||||
an 50.30.100 &Syntax.DE.D :cal SetSyn("d")<CR>
|
an 50.30.100 &Syntax.DE.D :cal SetSyn("d")<CR>
|
||||||
an 50.30.110 &Syntax.DE.Datascript :cal SetSyn("datascript")<CR>
|
an 50.30.110 &Syntax.DE.Dart :cal SetSyn("dart")<CR>
|
||||||
an 50.30.120 &Syntax.DE.Debian.Debian\ ChangeLog :cal SetSyn("debchangelog")<CR>
|
an 50.30.120 &Syntax.DE.Datascript :cal SetSyn("datascript")<CR>
|
||||||
an 50.30.130 &Syntax.DE.Debian.Debian\ Control :cal SetSyn("debcontrol")<CR>
|
an 50.30.130 &Syntax.DE.Debian.Debian\ ChangeLog :cal SetSyn("debchangelog")<CR>
|
||||||
an 50.30.140 &Syntax.DE.Debian.Debian\ Copyright :cal SetSyn("debcopyright")<CR>
|
an 50.30.140 &Syntax.DE.Debian.Debian\ Control :cal SetSyn("debcontrol")<CR>
|
||||||
an 50.30.150 &Syntax.DE.Debian.Debian\ Sources\.list :cal SetSyn("debsources")<CR>
|
an 50.30.150 &Syntax.DE.Debian.Debian\ Copyright :cal SetSyn("debcopyright")<CR>
|
||||||
an 50.30.160 &Syntax.DE.Denyhosts :cal SetSyn("denyhosts")<CR>
|
an 50.30.160 &Syntax.DE.Debian.Debian\ Sources\.list :cal SetSyn("debsources")<CR>
|
||||||
an 50.30.170 &Syntax.DE.Desktop :cal SetSyn("desktop")<CR>
|
an 50.30.170 &Syntax.DE.Denyhosts :cal SetSyn("denyhosts")<CR>
|
||||||
an 50.30.180 &Syntax.DE.Dict\ config :cal SetSyn("dictconf")<CR>
|
an 50.30.180 &Syntax.DE.Desktop :cal SetSyn("desktop")<CR>
|
||||||
an 50.30.190 &Syntax.DE.Dictd\ config :cal SetSyn("dictdconf")<CR>
|
an 50.30.190 &Syntax.DE.Dict\ config :cal SetSyn("dictconf")<CR>
|
||||||
an 50.30.200 &Syntax.DE.Diff :cal SetSyn("diff")<CR>
|
an 50.30.200 &Syntax.DE.Dictd\ config :cal SetSyn("dictdconf")<CR>
|
||||||
an 50.30.210 &Syntax.DE.Digital\ Command\ Lang :cal SetSyn("dcl")<CR>
|
an 50.30.210 &Syntax.DE.Diff :cal SetSyn("diff")<CR>
|
||||||
an 50.30.220 &Syntax.DE.Dircolors :cal SetSyn("dircolors")<CR>
|
an 50.30.220 &Syntax.DE.Digital\ Command\ Lang :cal SetSyn("dcl")<CR>
|
||||||
an 50.30.230 &Syntax.DE.Dirpager :cal SetSyn("dirpager")<CR>
|
an 50.30.230 &Syntax.DE.Dircolors :cal SetSyn("dircolors")<CR>
|
||||||
an 50.30.240 &Syntax.DE.Django\ template :cal SetSyn("django")<CR>
|
an 50.30.240 &Syntax.DE.Dirpager :cal SetSyn("dirpager")<CR>
|
||||||
an 50.30.250 &Syntax.DE.DNS/BIND\ zone :cal SetSyn("bindzone")<CR>
|
an 50.30.250 &Syntax.DE.Django\ template :cal SetSyn("django")<CR>
|
||||||
an 50.30.260 &Syntax.DE.Dnsmasq\ config :cal SetSyn("dnsmasq")<CR>
|
an 50.30.260 &Syntax.DE.DNS/BIND\ zone :cal SetSyn("bindzone")<CR>
|
||||||
an 50.30.270 &Syntax.DE.DocBook.auto-detect :cal SetSyn("docbk")<CR>
|
an 50.30.270 &Syntax.DE.Dnsmasq\ config :cal SetSyn("dnsmasq")<CR>
|
||||||
an 50.30.280 &Syntax.DE.DocBook.SGML :cal SetSyn("docbksgml")<CR>
|
an 50.30.280 &Syntax.DE.DocBook.auto-detect :cal SetSyn("docbk")<CR>
|
||||||
an 50.30.290 &Syntax.DE.DocBook.XML :cal SetSyn("docbkxml")<CR>
|
an 50.30.290 &Syntax.DE.DocBook.SGML :cal SetSyn("docbksgml")<CR>
|
||||||
an 50.30.300 &Syntax.DE.Dockerfile :cal SetSyn("dockerfile")<CR>
|
an 50.30.300 &Syntax.DE.DocBook.XML :cal SetSyn("docbkxml")<CR>
|
||||||
an 50.30.310 &Syntax.DE.Dot :cal SetSyn("dot")<CR>
|
an 50.30.310 &Syntax.DE.Dockerfile :cal SetSyn("dockerfile")<CR>
|
||||||
an 50.30.320 &Syntax.DE.Doxygen.C\ with\ doxygen :cal SetSyn("c.doxygen")<CR>
|
an 50.30.320 &Syntax.DE.Dot :cal SetSyn("dot")<CR>
|
||||||
an 50.30.330 &Syntax.DE.Doxygen.C++\ with\ doxygen :cal SetSyn("cpp.doxygen")<CR>
|
an 50.30.330 &Syntax.DE.Doxygen.C\ with\ doxygen :cal SetSyn("c.doxygen")<CR>
|
||||||
an 50.30.340 &Syntax.DE.Doxygen.IDL\ with\ doxygen :cal SetSyn("idl.doxygen")<CR>
|
an 50.30.340 &Syntax.DE.Doxygen.C++\ with\ doxygen :cal SetSyn("cpp.doxygen")<CR>
|
||||||
an 50.30.350 &Syntax.DE.Doxygen.Java\ with\ doxygen :cal SetSyn("java.doxygen")<CR>
|
an 50.30.350 &Syntax.DE.Doxygen.IDL\ with\ doxygen :cal SetSyn("idl.doxygen")<CR>
|
||||||
an 50.30.360 &Syntax.DE.Doxygen.DataScript\ with\ doxygen :cal SetSyn("datascript.doxygen")<CR>
|
an 50.30.360 &Syntax.DE.Doxygen.Java\ with\ doxygen :cal SetSyn("java.doxygen")<CR>
|
||||||
an 50.30.370 &Syntax.DE.Dracula :cal SetSyn("dracula")<CR>
|
an 50.30.370 &Syntax.DE.Doxygen.DataScript\ with\ doxygen :cal SetSyn("datascript.doxygen")<CR>
|
||||||
an 50.30.380 &Syntax.DE.DSSSL :cal SetSyn("dsl")<CR>
|
an 50.30.380 &Syntax.DE.Dracula :cal SetSyn("dracula")<CR>
|
||||||
an 50.30.390 &Syntax.DE.DTD :cal SetSyn("dtd")<CR>
|
an 50.30.390 &Syntax.DE.DSSSL :cal SetSyn("dsl")<CR>
|
||||||
an 50.30.400 &Syntax.DE.DTML\ (Zope) :cal SetSyn("dtml")<CR>
|
an 50.30.400 &Syntax.DE.DTD :cal SetSyn("dtd")<CR>
|
||||||
an 50.30.410 &Syntax.DE.DTrace :cal SetSyn("dtrace")<CR>
|
an 50.30.410 &Syntax.DE.DTML\ (Zope) :cal SetSyn("dtml")<CR>
|
||||||
an 50.30.420 &Syntax.DE.Dts/dtsi :cal SetSyn("dts")<CR>
|
an 50.30.420 &Syntax.DE.DTrace :cal SetSyn("dtrace")<CR>
|
||||||
an 50.30.430 &Syntax.DE.Dylan.Dylan :cal SetSyn("dylan")<CR>
|
an 50.30.430 &Syntax.DE.Dts/dtsi :cal SetSyn("dts")<CR>
|
||||||
an 50.30.440 &Syntax.DE.Dylan.Dylan\ interface :cal SetSyn("dylanintr")<CR>
|
an 50.30.440 &Syntax.DE.Dune :cal SetSyn("dune")<CR>
|
||||||
an 50.30.450 &Syntax.DE.Dylan.Dylan\ lid :cal SetSyn("dylanlid")<CR>
|
an 50.30.450 &Syntax.DE.Dylan.Dylan :cal SetSyn("dylan")<CR>
|
||||||
an 50.30.470 &Syntax.DE.EDIF :cal SetSyn("edif")<CR>
|
an 50.30.460 &Syntax.DE.Dylan.Dylan\ interface :cal SetSyn("dylanintr")<CR>
|
||||||
an 50.30.480 &Syntax.DE.Eiffel :cal SetSyn("eiffel")<CR>
|
an 50.30.470 &Syntax.DE.Dylan.Dylan\ lid :cal SetSyn("dylanlid")<CR>
|
||||||
an 50.30.490 &Syntax.DE.Elinks\ config :cal SetSyn("elinks")<CR>
|
an 50.30.490 &Syntax.DE.EDIF :cal SetSyn("edif")<CR>
|
||||||
an 50.30.500 &Syntax.DE.Elm\ filter\ rules :cal SetSyn("elmfilt")<CR>
|
an 50.30.500 &Syntax.DE.Eiffel :cal SetSyn("eiffel")<CR>
|
||||||
an 50.30.510 &Syntax.DE.Embedix\ Component\ Description :cal SetSyn("ecd")<CR>
|
an 50.30.510 &Syntax.DE.Eight :cal SetSyn("8th")<CR>
|
||||||
an 50.30.520 &Syntax.DE.ERicsson\ LANGuage :cal SetSyn("erlang")<CR>
|
an 50.30.520 &Syntax.DE.Elinks\ config :cal SetSyn("elinks")<CR>
|
||||||
an 50.30.530 &Syntax.DE.ESMTP\ rc :cal SetSyn("esmtprc")<CR>
|
an 50.30.530 &Syntax.DE.Elm\ filter\ rules :cal SetSyn("elmfilt")<CR>
|
||||||
an 50.30.540 &Syntax.DE.ESQL-C :cal SetSyn("esqlc")<CR>
|
an 50.30.540 &Syntax.DE.Embedix\ Component\ Description :cal SetSyn("ecd")<CR>
|
||||||
an 50.30.550 &Syntax.DE.Essbase\ script :cal SetSyn("csc")<CR>
|
an 50.30.550 &Syntax.DE.ERicsson\ LANGuage :cal SetSyn("erlang")<CR>
|
||||||
an 50.30.560 &Syntax.DE.Esterel :cal SetSyn("esterel")<CR>
|
an 50.30.560 &Syntax.DE.ESMTP\ rc :cal SetSyn("esmtprc")<CR>
|
||||||
an 50.30.570 &Syntax.DE.Eterm\ config :cal SetSyn("eterm")<CR>
|
an 50.30.570 &Syntax.DE.ESQL-C :cal SetSyn("esqlc")<CR>
|
||||||
an 50.30.580 &Syntax.DE.Euphoria\ 3 :cal SetSyn("euphoria3")<CR>
|
an 50.30.580 &Syntax.DE.Essbase\ script :cal SetSyn("csc")<CR>
|
||||||
an 50.30.590 &Syntax.DE.Euphoria\ 4 :cal SetSyn("euphoria4")<CR>
|
an 50.30.590 &Syntax.DE.Esterel :cal SetSyn("esterel")<CR>
|
||||||
an 50.30.600 &Syntax.DE.Eviews :cal SetSyn("eviews")<CR>
|
an 50.30.600 &Syntax.DE.Eterm\ config :cal SetSyn("eterm")<CR>
|
||||||
an 50.30.610 &Syntax.DE.Exim\ conf :cal SetSyn("exim")<CR>
|
an 50.30.610 &Syntax.DE.Euphoria\ 3 :cal SetSyn("euphoria3")<CR>
|
||||||
an 50.30.620 &Syntax.DE.Expect :cal SetSyn("expect")<CR>
|
an 50.30.620 &Syntax.DE.Euphoria\ 4 :cal SetSyn("euphoria4")<CR>
|
||||||
an 50.30.630 &Syntax.DE.Exports :cal SetSyn("exports")<CR>
|
an 50.30.630 &Syntax.DE.Eviews :cal SetSyn("eviews")<CR>
|
||||||
|
an 50.30.640 &Syntax.DE.Exim\ conf :cal SetSyn("exim")<CR>
|
||||||
|
an 50.30.650 &Syntax.DE.Expect :cal SetSyn("expect")<CR>
|
||||||
|
an 50.30.660 &Syntax.DE.Exports :cal SetSyn("exports")<CR>
|
||||||
an 50.40.100 &Syntax.FG.Falcon :cal SetSyn("falcon")<CR>
|
an 50.40.100 &Syntax.FG.Falcon :cal SetSyn("falcon")<CR>
|
||||||
an 50.40.110 &Syntax.FG.Fantom :cal SetSyn("fan")<CR>
|
an 50.40.110 &Syntax.FG.Fantom :cal SetSyn("fan")<CR>
|
||||||
an 50.40.120 &Syntax.FG.Fetchmail :cal SetSyn("fetchmail")<CR>
|
an 50.40.120 &Syntax.FG.Fetchmail :cal SetSyn("fetchmail")<CR>
|
||||||
@ -259,43 +264,44 @@ an 50.50.290 &Syntax.HIJK.HTML.XHTML :cal SetSyn("xhtml")<CR>
|
|||||||
an 50.50.300 &Syntax.HIJK.Host\.conf :cal SetSyn("hostconf")<CR>
|
an 50.50.300 &Syntax.HIJK.Host\.conf :cal SetSyn("hostconf")<CR>
|
||||||
an 50.50.310 &Syntax.HIJK.Hosts\ access :cal SetSyn("hostsaccess")<CR>
|
an 50.50.310 &Syntax.HIJK.Hosts\ access :cal SetSyn("hostsaccess")<CR>
|
||||||
an 50.50.320 &Syntax.HIJK.Hyper\ Builder :cal SetSyn("hb")<CR>
|
an 50.50.320 &Syntax.HIJK.Hyper\ Builder :cal SetSyn("hb")<CR>
|
||||||
an 50.50.330 &Syntax.HIJK.Icewm\ menu :cal SetSyn("icemenu")<CR>
|
an 50.50.340 &Syntax.HIJK.Icewm\ menu :cal SetSyn("icemenu")<CR>
|
||||||
an 50.50.340 &Syntax.HIJK.Icon :cal SetSyn("icon")<CR>
|
an 50.50.350 &Syntax.HIJK.Icon :cal SetSyn("icon")<CR>
|
||||||
an 50.50.350 &Syntax.HIJK.IDL\Generic\ IDL :cal SetSyn("idl")<CR>
|
an 50.50.360 &Syntax.HIJK.IDL\Generic\ IDL :cal SetSyn("idl")<CR>
|
||||||
an 50.50.360 &Syntax.HIJK.IDL\Microsoft\ IDL :cal SetSyn("msidl")<CR>
|
an 50.50.370 &Syntax.HIJK.IDL\Microsoft\ IDL :cal SetSyn("msidl")<CR>
|
||||||
an 50.50.370 &Syntax.HIJK.Indent\ profile :cal SetSyn("indent")<CR>
|
an 50.50.380 &Syntax.HIJK.Indent\ profile :cal SetSyn("indent")<CR>
|
||||||
an 50.50.380 &Syntax.HIJK.Inform :cal SetSyn("inform")<CR>
|
an 50.50.390 &Syntax.HIJK.Inform :cal SetSyn("inform")<CR>
|
||||||
an 50.50.390 &Syntax.HIJK.Informix\ 4GL :cal SetSyn("fgl")<CR>
|
an 50.50.400 &Syntax.HIJK.Informix\ 4GL :cal SetSyn("fgl")<CR>
|
||||||
an 50.50.400 &Syntax.HIJK.Initng :cal SetSyn("initng")<CR>
|
an 50.50.410 &Syntax.HIJK.Initng :cal SetSyn("initng")<CR>
|
||||||
an 50.50.410 &Syntax.HIJK.Inittab :cal SetSyn("inittab")<CR>
|
an 50.50.420 &Syntax.HIJK.Inittab :cal SetSyn("inittab")<CR>
|
||||||
an 50.50.420 &Syntax.HIJK.Inno\ setup :cal SetSyn("iss")<CR>
|
an 50.50.430 &Syntax.HIJK.Inno\ setup :cal SetSyn("iss")<CR>
|
||||||
an 50.50.430 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ dat :cal SetSyn("upstreamdat")<CR>
|
an 50.50.440 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ dat :cal SetSyn("upstreamdat")<CR>
|
||||||
an 50.50.440 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ log :cal SetSyn("upstreamlog")<CR>
|
an 50.50.450 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ log :cal SetSyn("upstreamlog")<CR>
|
||||||
an 50.50.450 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ rpt :cal SetSyn("upstreamrpt")<CR>
|
an 50.50.460 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ rpt :cal SetSyn("upstreamrpt")<CR>
|
||||||
an 50.50.460 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ Install\ log :cal SetSyn("upstreaminstalllog")<CR>
|
an 50.50.470 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ Install\ log :cal SetSyn("upstreaminstalllog")<CR>
|
||||||
an 50.50.470 &Syntax.HIJK.Innovation\ Data\ Processing.Usserver\ log :cal SetSyn("usserverlog")<CR>
|
an 50.50.480 &Syntax.HIJK.Innovation\ Data\ Processing.Usserver\ log :cal SetSyn("usserverlog")<CR>
|
||||||
an 50.50.480 &Syntax.HIJK.Innovation\ Data\ Processing.USW2KAgt\ log :cal SetSyn("usw2kagtlog")<CR>
|
an 50.50.490 &Syntax.HIJK.Innovation\ Data\ Processing.USW2KAgt\ log :cal SetSyn("usw2kagtlog")<CR>
|
||||||
an 50.50.490 &Syntax.HIJK.InstallShield\ script :cal SetSyn("ishd")<CR>
|
an 50.50.500 &Syntax.HIJK.InstallShield\ script :cal SetSyn("ishd")<CR>
|
||||||
an 50.50.500 &Syntax.HIJK.Interactive\ Data\ Lang :cal SetSyn("idlang")<CR>
|
an 50.50.510 &Syntax.HIJK.Interactive\ Data\ Lang :cal SetSyn("idlang")<CR>
|
||||||
an 50.50.510 &Syntax.HIJK.IPfilter :cal SetSyn("ipfilter")<CR>
|
an 50.50.520 &Syntax.HIJK.IPfilter :cal SetSyn("ipfilter")<CR>
|
||||||
an 50.50.530 &Syntax.HIJK.J :cal SetSyn("j")<CR>
|
an 50.50.540 &Syntax.HIJK.J :cal SetSyn("j")<CR>
|
||||||
an 50.50.540 &Syntax.HIJK.JAL :cal SetSyn("jal")<CR>
|
an 50.50.550 &Syntax.HIJK.JAL :cal SetSyn("jal")<CR>
|
||||||
an 50.50.550 &Syntax.HIJK.JAM :cal SetSyn("jam")<CR>
|
an 50.50.560 &Syntax.HIJK.JAM :cal SetSyn("jam")<CR>
|
||||||
an 50.50.560 &Syntax.HIJK.Jargon :cal SetSyn("jargon")<CR>
|
an 50.50.570 &Syntax.HIJK.Jargon :cal SetSyn("jargon")<CR>
|
||||||
an 50.50.570 &Syntax.HIJK.Java.Java :cal SetSyn("java")<CR>
|
an 50.50.580 &Syntax.HIJK.Java.Java :cal SetSyn("java")<CR>
|
||||||
an 50.50.580 &Syntax.HIJK.Java.JavaCC :cal SetSyn("javacc")<CR>
|
an 50.50.590 &Syntax.HIJK.Java.JavaCC :cal SetSyn("javacc")<CR>
|
||||||
an 50.50.590 &Syntax.HIJK.Java.Java\ Server\ Pages :cal SetSyn("jsp")<CR>
|
an 50.50.600 &Syntax.HIJK.Java.Java\ Server\ Pages :cal SetSyn("jsp")<CR>
|
||||||
an 50.50.600 &Syntax.HIJK.Java.Java\ Properties :cal SetSyn("jproperties")<CR>
|
an 50.50.610 &Syntax.HIJK.Java.Java\ Properties :cal SetSyn("jproperties")<CR>
|
||||||
an 50.50.610 &Syntax.HIJK.JavaScript :cal SetSyn("javascript")<CR>
|
an 50.50.620 &Syntax.HIJK.JavaScript :cal SetSyn("javascript")<CR>
|
||||||
an 50.50.620 &Syntax.HIJK.Jess :cal SetSyn("jess")<CR>
|
an 50.50.630 &Syntax.HIJK.JavaScriptReact :cal SetSyn("javascriptreact")<CR>
|
||||||
an 50.50.630 &Syntax.HIJK.Jgraph :cal SetSyn("jgraph")<CR>
|
an 50.50.640 &Syntax.HIJK.Jess :cal SetSyn("jess")<CR>
|
||||||
an 50.50.640 &Syntax.HIJK.Jovial :cal SetSyn("jovial")<CR>
|
an 50.50.650 &Syntax.HIJK.Jgraph :cal SetSyn("jgraph")<CR>
|
||||||
an 50.50.650 &Syntax.HIJK.JSON :cal SetSyn("json")<CR>
|
an 50.50.660 &Syntax.HIJK.Jovial :cal SetSyn("jovial")<CR>
|
||||||
an 50.50.670 &Syntax.HIJK.Kconfig :cal SetSyn("kconfig")<CR>
|
an 50.50.670 &Syntax.HIJK.JSON :cal SetSyn("json")<CR>
|
||||||
an 50.50.680 &Syntax.HIJK.KDE\ script :cal SetSyn("kscript")<CR>
|
an 50.50.690 &Syntax.HIJK.Kconfig :cal SetSyn("kconfig")<CR>
|
||||||
an 50.50.690 &Syntax.HIJK.Kimwitu++ :cal SetSyn("kwt")<CR>
|
an 50.50.700 &Syntax.HIJK.KDE\ script :cal SetSyn("kscript")<CR>
|
||||||
an 50.50.700 &Syntax.HIJK.Kivy :cal SetSyn("kivy")<CR>
|
an 50.50.710 &Syntax.HIJK.Kimwitu++ :cal SetSyn("kwt")<CR>
|
||||||
an 50.50.710 &Syntax.HIJK.KixTart :cal SetSyn("kix")<CR>
|
an 50.50.720 &Syntax.HIJK.Kivy :cal SetSyn("kivy")<CR>
|
||||||
|
an 50.50.730 &Syntax.HIJK.KixTart :cal SetSyn("kix")<CR>
|
||||||
an 50.60.100 &Syntax.L.Lace :cal SetSyn("lace")<CR>
|
an 50.60.100 &Syntax.L.Lace :cal SetSyn("lace")<CR>
|
||||||
an 50.60.110 &Syntax.L.LamdaProlog :cal SetSyn("lprolog")<CR>
|
an 50.60.110 &Syntax.L.LamdaProlog :cal SetSyn("lprolog")<CR>
|
||||||
an 50.60.120 &Syntax.L.Latte :cal SetSyn("latte")<CR>
|
an 50.60.120 &Syntax.L.Latte :cal SetSyn("latte")<CR>
|
||||||
@ -343,34 +349,35 @@ an 50.70.240 &Syntax.M.Mathematica :cal SetSyn("mma")<CR>
|
|||||||
an 50.70.250 &Syntax.M.Matlab :cal SetSyn("matlab")<CR>
|
an 50.70.250 &Syntax.M.Matlab :cal SetSyn("matlab")<CR>
|
||||||
an 50.70.260 &Syntax.M.Maxima :cal SetSyn("maxima")<CR>
|
an 50.70.260 &Syntax.M.Maxima :cal SetSyn("maxima")<CR>
|
||||||
an 50.70.270 &Syntax.M.MEL\ (for\ Maya) :cal SetSyn("mel")<CR>
|
an 50.70.270 &Syntax.M.MEL\ (for\ Maya) :cal SetSyn("mel")<CR>
|
||||||
an 50.70.280 &Syntax.M.Messages\ (/var/log) :cal SetSyn("messages")<CR>
|
an 50.70.280 &Syntax.M.Meson :cal SetSyn("meson")<CR>
|
||||||
an 50.70.290 &Syntax.M.Metafont :cal SetSyn("mf")<CR>
|
an 50.70.290 &Syntax.M.Messages\ (/var/log) :cal SetSyn("messages")<CR>
|
||||||
an 50.70.300 &Syntax.M.MetaPost :cal SetSyn("mp")<CR>
|
an 50.70.300 &Syntax.M.Metafont :cal SetSyn("mf")<CR>
|
||||||
an 50.70.310 &Syntax.M.MGL :cal SetSyn("mgl")<CR>
|
an 50.70.310 &Syntax.M.MetaPost :cal SetSyn("mp")<CR>
|
||||||
an 50.70.320 &Syntax.M.MIX :cal SetSyn("mix")<CR>
|
an 50.70.320 &Syntax.M.MGL :cal SetSyn("mgl")<CR>
|
||||||
an 50.70.330 &Syntax.M.MMIX :cal SetSyn("mmix")<CR>
|
an 50.70.330 &Syntax.M.MIX :cal SetSyn("mix")<CR>
|
||||||
an 50.70.340 &Syntax.M.Modconf :cal SetSyn("modconf")<CR>
|
an 50.70.340 &Syntax.M.MMIX :cal SetSyn("mmix")<CR>
|
||||||
an 50.70.350 &Syntax.M.Model :cal SetSyn("model")<CR>
|
an 50.70.350 &Syntax.M.Modconf :cal SetSyn("modconf")<CR>
|
||||||
an 50.70.360 &Syntax.M.Modsim\ III :cal SetSyn("modsim3")<CR>
|
an 50.70.360 &Syntax.M.Model :cal SetSyn("model")<CR>
|
||||||
an 50.70.370 &Syntax.M.Modula\ 2 :cal SetSyn("modula2")<CR>
|
an 50.70.370 &Syntax.M.Modsim\ III :cal SetSyn("modsim3")<CR>
|
||||||
an 50.70.380 &Syntax.M.Modula\ 3 :cal SetSyn("modula3")<CR>
|
an 50.70.380 &Syntax.M.Modula\ 2 :cal SetSyn("modula2")<CR>
|
||||||
an 50.70.390 &Syntax.M.Monk :cal SetSyn("monk")<CR>
|
an 50.70.390 &Syntax.M.Modula\ 3 :cal SetSyn("modula3")<CR>
|
||||||
an 50.70.400 &Syntax.M.Motorola\ S-Record :cal SetSyn("srec")<CR>
|
an 50.70.400 &Syntax.M.Monk :cal SetSyn("monk")<CR>
|
||||||
an 50.70.410 &Syntax.M.Mplayer\ config :cal SetSyn("mplayerconf")<CR>
|
an 50.70.410 &Syntax.M.Motorola\ S-Record :cal SetSyn("srec")<CR>
|
||||||
an 50.70.420 &Syntax.M.MOO :cal SetSyn("moo")<CR>
|
an 50.70.420 &Syntax.M.Mplayer\ config :cal SetSyn("mplayerconf")<CR>
|
||||||
an 50.70.430 &Syntax.M.Mrxvtrc :cal SetSyn("mrxvtrc")<CR>
|
an 50.70.430 &Syntax.M.MOO :cal SetSyn("moo")<CR>
|
||||||
an 50.70.440 &Syntax.M.MS-DOS/Windows.4DOS\ \.bat\ file :cal SetSyn("btm")<CR>
|
an 50.70.440 &Syntax.M.Mrxvtrc :cal SetSyn("mrxvtrc")<CR>
|
||||||
an 50.70.450 &Syntax.M.MS-DOS/Windows.\.bat\/\.cmd\ file :cal SetSyn("dosbatch")<CR>
|
an 50.70.450 &Syntax.M.MS-DOS/Windows.4DOS\ \.bat\ file :cal SetSyn("btm")<CR>
|
||||||
an 50.70.460 &Syntax.M.MS-DOS/Windows.\.ini\ file :cal SetSyn("dosini")<CR>
|
an 50.70.460 &Syntax.M.MS-DOS/Windows.\.bat\/\.cmd\ file :cal SetSyn("dosbatch")<CR>
|
||||||
an 50.70.470 &Syntax.M.MS-DOS/Windows.Message\ text :cal SetSyn("msmessages")<CR>
|
an 50.70.470 &Syntax.M.MS-DOS/Windows.\.ini\ file :cal SetSyn("dosini")<CR>
|
||||||
an 50.70.480 &Syntax.M.MS-DOS/Windows.Module\ Definition :cal SetSyn("def")<CR>
|
an 50.70.480 &Syntax.M.MS-DOS/Windows.Message\ text :cal SetSyn("msmessages")<CR>
|
||||||
an 50.70.490 &Syntax.M.MS-DOS/Windows.Registry :cal SetSyn("registry")<CR>
|
an 50.70.490 &Syntax.M.MS-DOS/Windows.Module\ Definition :cal SetSyn("def")<CR>
|
||||||
an 50.70.500 &Syntax.M.MS-DOS/Windows.Resource\ file :cal SetSyn("rc")<CR>
|
an 50.70.500 &Syntax.M.MS-DOS/Windows.Registry :cal SetSyn("registry")<CR>
|
||||||
an 50.70.510 &Syntax.M.Msql :cal SetSyn("msql")<CR>
|
an 50.70.510 &Syntax.M.MS-DOS/Windows.Resource\ file :cal SetSyn("rc")<CR>
|
||||||
an 50.70.520 &Syntax.M.MuPAD :cal SetSyn("mupad")<CR>
|
an 50.70.520 &Syntax.M.Msql :cal SetSyn("msql")<CR>
|
||||||
an 50.70.530 &Syntax.M.Murphi :cal SetSyn("murphi")<CR>
|
an 50.70.530 &Syntax.M.MuPAD :cal SetSyn("mupad")<CR>
|
||||||
an 50.70.540 &Syntax.M.MUSHcode :cal SetSyn("mush")<CR>
|
an 50.70.540 &Syntax.M.Murphi :cal SetSyn("murphi")<CR>
|
||||||
an 50.70.550 &Syntax.M.Muttrc :cal SetSyn("muttrc")<CR>
|
an 50.70.550 &Syntax.M.MUSHcode :cal SetSyn("mush")<CR>
|
||||||
|
an 50.70.560 &Syntax.M.Muttrc :cal SetSyn("muttrc")<CR>
|
||||||
an 50.80.100 &Syntax.NO.N1QL :cal SetSyn("n1ql")<CR>
|
an 50.80.100 &Syntax.NO.N1QL :cal SetSyn("n1ql")<CR>
|
||||||
an 50.80.110 &Syntax.NO.Nanorc :cal SetSyn("nanorc")<CR>
|
an 50.80.110 &Syntax.NO.Nanorc :cal SetSyn("nanorc")<CR>
|
||||||
an 50.80.120 &Syntax.NO.Nastran\ input/DMAP :cal SetSyn("nastran")<CR>
|
an 50.80.120 &Syntax.NO.Nastran\ input/DMAP :cal SetSyn("nastran")<CR>
|
||||||
@ -442,25 +449,26 @@ an 50.100.110 &Syntax.R.R.R\ help :cal SetSyn("rhelp")<CR>
|
|||||||
an 50.100.120 &Syntax.R.R.R\ noweb :cal SetSyn("rnoweb")<CR>
|
an 50.100.120 &Syntax.R.R.R\ noweb :cal SetSyn("rnoweb")<CR>
|
||||||
an 50.100.130 &Syntax.R.Racc\ input :cal SetSyn("racc")<CR>
|
an 50.100.130 &Syntax.R.Racc\ input :cal SetSyn("racc")<CR>
|
||||||
an 50.100.140 &Syntax.R.Radiance :cal SetSyn("radiance")<CR>
|
an 50.100.140 &Syntax.R.Radiance :cal SetSyn("radiance")<CR>
|
||||||
an 50.100.150 &Syntax.R.Ratpoison :cal SetSyn("ratpoison")<CR>
|
an 50.100.150 &Syntax.R.Raml :cal SetSyn("raml")<CR>
|
||||||
an 50.100.160 &Syntax.R.RCS.RCS\ log\ output :cal SetSyn("rcslog")<CR>
|
an 50.100.160 &Syntax.R.Ratpoison :cal SetSyn("ratpoison")<CR>
|
||||||
an 50.100.170 &Syntax.R.RCS.RCS\ file :cal SetSyn("rcs")<CR>
|
an 50.100.170 &Syntax.R.RCS.RCS\ log\ output :cal SetSyn("rcslog")<CR>
|
||||||
an 50.100.180 &Syntax.R.Readline\ config :cal SetSyn("readline")<CR>
|
an 50.100.180 &Syntax.R.RCS.RCS\ file :cal SetSyn("rcs")<CR>
|
||||||
an 50.100.190 &Syntax.R.Rebol :cal SetSyn("rebol")<CR>
|
an 50.100.190 &Syntax.R.Readline\ config :cal SetSyn("readline")<CR>
|
||||||
an 50.100.200 &Syntax.R.ReDIF :cal SetSyn("redif")<CR>
|
an 50.100.200 &Syntax.R.Rebol :cal SetSyn("rebol")<CR>
|
||||||
an 50.100.210 &Syntax.R.Relax\ NG :cal SetSyn("rng")<CR>
|
an 50.100.210 &Syntax.R.ReDIF :cal SetSyn("redif")<CR>
|
||||||
an 50.100.220 &Syntax.R.Remind :cal SetSyn("remind")<CR>
|
an 50.100.220 &Syntax.R.Relax\ NG :cal SetSyn("rng")<CR>
|
||||||
an 50.100.230 &Syntax.R.Relax\ NG\ compact :cal SetSyn("rnc")<CR>
|
an 50.100.230 &Syntax.R.Remind :cal SetSyn("remind")<CR>
|
||||||
an 50.100.240 &Syntax.R.Renderman.Renderman\ Shader\ Lang :cal SetSyn("sl")<CR>
|
an 50.100.240 &Syntax.R.Relax\ NG\ compact :cal SetSyn("rnc")<CR>
|
||||||
an 50.100.250 &Syntax.R.Renderman.Renderman\ Interface\ Bytestream :cal SetSyn("rib")<CR>
|
an 50.100.250 &Syntax.R.Renderman.Renderman\ Shader\ Lang :cal SetSyn("sl")<CR>
|
||||||
an 50.100.260 &Syntax.R.Resolv\.conf :cal SetSyn("resolv")<CR>
|
an 50.100.260 &Syntax.R.Renderman.Renderman\ Interface\ Bytestream :cal SetSyn("rib")<CR>
|
||||||
an 50.100.270 &Syntax.R.Reva\ Forth :cal SetSyn("reva")<CR>
|
an 50.100.270 &Syntax.R.Resolv\.conf :cal SetSyn("resolv")<CR>
|
||||||
an 50.100.280 &Syntax.R.Rexx :cal SetSyn("rexx")<CR>
|
an 50.100.280 &Syntax.R.Reva\ Forth :cal SetSyn("reva")<CR>
|
||||||
an 50.100.290 &Syntax.R.Robots\.txt :cal SetSyn("robots")<CR>
|
an 50.100.290 &Syntax.R.Rexx :cal SetSyn("rexx")<CR>
|
||||||
an 50.100.300 &Syntax.R.RockLinux\ package\ desc\. :cal SetSyn("desc")<CR>
|
an 50.100.300 &Syntax.R.Robots\.txt :cal SetSyn("robots")<CR>
|
||||||
an 50.100.310 &Syntax.R.Rpcgen :cal SetSyn("rpcgen")<CR>
|
an 50.100.310 &Syntax.R.RockLinux\ package\ desc\. :cal SetSyn("desc")<CR>
|
||||||
an 50.100.320 &Syntax.R.RPL/2 :cal SetSyn("rpl")<CR>
|
an 50.100.320 &Syntax.R.Rpcgen :cal SetSyn("rpcgen")<CR>
|
||||||
an 50.100.330 &Syntax.R.ReStructuredText :cal SetSyn("rst")<CR>
|
an 50.100.330 &Syntax.R.RPL/2 :cal SetSyn("rpl")<CR>
|
||||||
|
an 50.100.340 &Syntax.R.ReStructuredText :cal SetSyn("rst")<CR>
|
||||||
an 50.110.100 &Syntax.M.ReStructuredText\ with\ R\ statements :cal SetSyn("rrst")<CR>
|
an 50.110.100 &Syntax.M.ReStructuredText\ with\ R\ statements :cal SetSyn("rrst")<CR>
|
||||||
an 50.120.100 &Syntax.R.RTF :cal SetSyn("rtf")<CR>
|
an 50.120.100 &Syntax.R.RTF :cal SetSyn("rtf")<CR>
|
||||||
an 50.120.110 &Syntax.R.Ruby :cal SetSyn("ruby")<CR>
|
an 50.120.110 &Syntax.R.Ruby :cal SetSyn("ruby")<CR>
|
||||||
@ -581,6 +589,8 @@ an 50.150.370 &Syntax.T.Trustees :cal SetSyn("trustees")<CR>
|
|||||||
an 50.150.380 &Syntax.T.TSS.Command\ Line :cal SetSyn("tsscl")<CR>
|
an 50.150.380 &Syntax.T.TSS.Command\ Line :cal SetSyn("tsscl")<CR>
|
||||||
an 50.150.390 &Syntax.T.TSS.Geometry :cal SetSyn("tssgm")<CR>
|
an 50.150.390 &Syntax.T.TSS.Geometry :cal SetSyn("tssgm")<CR>
|
||||||
an 50.150.400 &Syntax.T.TSS.Optics :cal SetSyn("tssop")<CR>
|
an 50.150.400 &Syntax.T.TSS.Optics :cal SetSyn("tssop")<CR>
|
||||||
|
an 50.150.410 &Syntax.T.Typescript :cal SetSyn("typescript")<CR>
|
||||||
|
an 50.150.420 &Syntax.T.TypescriptReact :cal SetSyn("typescriptreact")<CR>
|
||||||
an 50.160.100 &Syntax.UV.Udev\ config :cal SetSyn("udevconf")<CR>
|
an 50.160.100 &Syntax.UV.Udev\ config :cal SetSyn("udevconf")<CR>
|
||||||
an 50.160.110 &Syntax.UV.Udev\ permissions :cal SetSyn("udevperm")<CR>
|
an 50.160.110 &Syntax.UV.Udev\ permissions :cal SetSyn("udevperm")<CR>
|
||||||
an 50.160.120 &Syntax.UV.Udev\ rules :cal SetSyn("udevrules")<CR>
|
an 50.160.120 &Syntax.UV.Udev\ rules :cal SetSyn("udevrules")<CR>
|
||||||
@ -607,32 +617,33 @@ an 50.160.330 &Syntax.UV.VSE\ JCL :cal SetSyn("vsejcl")<CR>
|
|||||||
an 50.170.100 &Syntax.WXYZ.WEB.CWEB :cal SetSyn("cweb")<CR>
|
an 50.170.100 &Syntax.WXYZ.WEB.CWEB :cal SetSyn("cweb")<CR>
|
||||||
an 50.170.110 &Syntax.WXYZ.WEB.WEB :cal SetSyn("web")<CR>
|
an 50.170.110 &Syntax.WXYZ.WEB.WEB :cal SetSyn("web")<CR>
|
||||||
an 50.170.120 &Syntax.WXYZ.WEB.WEB\ Changes :cal SetSyn("change")<CR>
|
an 50.170.120 &Syntax.WXYZ.WEB.WEB\ Changes :cal SetSyn("change")<CR>
|
||||||
an 50.170.130 &Syntax.WXYZ.Webmacro :cal SetSyn("webmacro")<CR>
|
an 50.170.130 &Syntax.WXYZ.WebAssembly :cal SetSyn("wast")<CR>
|
||||||
an 50.170.140 &Syntax.WXYZ.Website\ MetaLanguage :cal SetSyn("wml")<CR>
|
an 50.170.140 &Syntax.WXYZ.Webmacro :cal SetSyn("webmacro")<CR>
|
||||||
an 50.170.160 &Syntax.WXYZ.wDiff :cal SetSyn("wdiff")<CR>
|
an 50.170.150 &Syntax.WXYZ.Website\ MetaLanguage :cal SetSyn("wml")<CR>
|
||||||
an 50.170.180 &Syntax.WXYZ.Wget\ config :cal SetSyn("wget")<CR>
|
an 50.170.170 &Syntax.WXYZ.wDiff :cal SetSyn("wdiff")<CR>
|
||||||
an 50.170.190 &Syntax.WXYZ.Whitespace\ (add) :cal SetSyn("whitespace")<CR>
|
an 50.170.190 &Syntax.WXYZ.Wget\ config :cal SetSyn("wget")<CR>
|
||||||
an 50.170.200 &Syntax.WXYZ.WildPackets\ EtherPeek\ Decoder :cal SetSyn("dcd")<CR>
|
an 50.170.200 &Syntax.WXYZ.Whitespace\ (add) :cal SetSyn("whitespace")<CR>
|
||||||
an 50.170.210 &Syntax.WXYZ.WinBatch/Webbatch :cal SetSyn("winbatch")<CR>
|
an 50.170.210 &Syntax.WXYZ.WildPackets\ EtherPeek\ Decoder :cal SetSyn("dcd")<CR>
|
||||||
an 50.170.220 &Syntax.WXYZ.Windows\ Scripting\ Host :cal SetSyn("wsh")<CR>
|
an 50.170.220 &Syntax.WXYZ.WinBatch/Webbatch :cal SetSyn("winbatch")<CR>
|
||||||
an 50.170.230 &Syntax.WXYZ.WSML :cal SetSyn("wsml")<CR>
|
an 50.170.230 &Syntax.WXYZ.Windows\ Scripting\ Host :cal SetSyn("wsh")<CR>
|
||||||
an 50.170.240 &Syntax.WXYZ.WvDial :cal SetSyn("wvdial")<CR>
|
an 50.170.240 &Syntax.WXYZ.WSML :cal SetSyn("wsml")<CR>
|
||||||
an 50.170.260 &Syntax.WXYZ.X\ Keyboard\ Extension :cal SetSyn("xkb")<CR>
|
an 50.170.250 &Syntax.WXYZ.WvDial :cal SetSyn("wvdial")<CR>
|
||||||
an 50.170.270 &Syntax.WXYZ.X\ Pixmap :cal SetSyn("xpm")<CR>
|
an 50.170.270 &Syntax.WXYZ.X\ Keyboard\ Extension :cal SetSyn("xkb")<CR>
|
||||||
an 50.170.280 &Syntax.WXYZ.X\ Pixmap\ (2) :cal SetSyn("xpm2")<CR>
|
an 50.170.280 &Syntax.WXYZ.X\ Pixmap :cal SetSyn("xpm")<CR>
|
||||||
an 50.170.290 &Syntax.WXYZ.X\ resources :cal SetSyn("xdefaults")<CR>
|
an 50.170.290 &Syntax.WXYZ.X\ Pixmap\ (2) :cal SetSyn("xpm2")<CR>
|
||||||
an 50.170.300 &Syntax.WXYZ.XBL :cal SetSyn("xbl")<CR>
|
an 50.170.300 &Syntax.WXYZ.X\ resources :cal SetSyn("xdefaults")<CR>
|
||||||
an 50.170.310 &Syntax.WXYZ.Xinetd\.conf :cal SetSyn("xinetd")<CR>
|
an 50.170.310 &Syntax.WXYZ.XBL :cal SetSyn("xbl")<CR>
|
||||||
an 50.170.320 &Syntax.WXYZ.Xmodmap :cal SetSyn("xmodmap")<CR>
|
an 50.170.320 &Syntax.WXYZ.Xinetd\.conf :cal SetSyn("xinetd")<CR>
|
||||||
an 50.170.330 &Syntax.WXYZ.Xmath :cal SetSyn("xmath")<CR>
|
an 50.170.330 &Syntax.WXYZ.Xmodmap :cal SetSyn("xmodmap")<CR>
|
||||||
an 50.170.340 &Syntax.WXYZ.XML :cal SetSyn("xml")<CR>
|
an 50.170.340 &Syntax.WXYZ.Xmath :cal SetSyn("xmath")<CR>
|
||||||
an 50.170.350 &Syntax.WXYZ.XML\ Schema\ (XSD) :cal SetSyn("xsd")<CR>
|
an 50.170.350 &Syntax.WXYZ.XML :cal SetSyn("xml")<CR>
|
||||||
an 50.170.360 &Syntax.WXYZ.XQuery :cal SetSyn("xquery")<CR>
|
an 50.170.360 &Syntax.WXYZ.XML\ Schema\ (XSD) :cal SetSyn("xsd")<CR>
|
||||||
an 50.170.370 &Syntax.WXYZ.Xslt :cal SetSyn("xslt")<CR>
|
an 50.170.370 &Syntax.WXYZ.XQuery :cal SetSyn("xquery")<CR>
|
||||||
an 50.170.380 &Syntax.WXYZ.XFree86\ Config :cal SetSyn("xf86conf")<CR>
|
an 50.170.380 &Syntax.WXYZ.Xslt :cal SetSyn("xslt")<CR>
|
||||||
an 50.170.400 &Syntax.WXYZ.YAML :cal SetSyn("yaml")<CR>
|
an 50.170.390 &Syntax.WXYZ.XFree86\ Config :cal SetSyn("xf86conf")<CR>
|
||||||
an 50.170.410 &Syntax.WXYZ.Yacc :cal SetSyn("yacc")<CR>
|
an 50.170.410 &Syntax.WXYZ.YAML :cal SetSyn("yaml")<CR>
|
||||||
an 50.170.430 &Syntax.WXYZ.Zimbu :cal SetSyn("zimbu")<CR>
|
an 50.170.420 &Syntax.WXYZ.Yacc :cal SetSyn("yacc")<CR>
|
||||||
|
an 50.170.440 &Syntax.WXYZ.Zimbu :cal SetSyn("zimbu")<CR>
|
||||||
|
|
||||||
" The End Of The Syntax Menu
|
" The End Of The Syntax Menu
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
" Maintainer: Anmol Sethi <anmol@aubble.com>
|
" Maintainer: Anmol Sethi <hi@nhooyr.io>
|
||||||
" Previous Maintainer: SungHyun Nam <goweol@gmail.com>
|
" Previous Maintainer: SungHyun Nam <goweol@gmail.com>
|
||||||
|
|
||||||
if exists('b:current_syntax')
|
if exists('b:current_syntax')
|
||||||
@ -30,6 +30,7 @@ endif
|
|||||||
if !exists('b:man_sect')
|
if !exists('b:man_sect')
|
||||||
call man#init_pager()
|
call man#init_pager()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if b:man_sect =~# '^[023]'
|
if b:man_sect =~# '^[023]'
|
||||||
syntax case match
|
syntax case match
|
||||||
syntax include @c $VIMRUNTIME/syntax/c.vim
|
syntax include @c $VIMRUNTIME/syntax/c.vim
|
||||||
|
@ -558,7 +558,7 @@ syn match vimHiGuiFontname contained "'[a-zA-Z\-* ]\+'"
|
|||||||
syn match vimHiGuiRgb contained "#\x\{6}"
|
syn match vimHiGuiRgb contained "#\x\{6}"
|
||||||
|
|
||||||
" Highlighting: hi group key=arg ... {{{2
|
" Highlighting: hi group key=arg ... {{{2
|
||||||
syn cluster vimHiCluster contains=vimGroup,vimHiGroup,vimHiTerm,vimHiCTerm,vimHiStartStop,vimHiCtermFgBg,vimHiGui,vimHiGuiFont,vimHiGuiFgBg,vimHiKeyError,vimNotation
|
syn cluster vimHiCluster contains=vimGroup,vimHiBlend,vimHiGroup,vimHiTerm,vimHiCTerm,vimHiStartStop,vimHiCtermFgBg,vimHiGui,vimHiGuiFont,vimHiGuiFgBg,vimHiKeyError,vimNotation
|
||||||
syn region vimHiKeyList contained oneline start="\i\+" skip="\\\\\|\\|" end="$\||" contains=@vimHiCluster
|
syn region vimHiKeyList contained oneline start="\i\+" skip="\\\\\|\\|" end="$\||" contains=@vimHiCluster
|
||||||
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_vimhikeyerror")
|
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_vimhikeyerror")
|
||||||
syn match vimHiKeyError contained "\i\+="he=e-1
|
syn match vimHiKeyError contained "\i\+="he=e-1
|
||||||
@ -571,6 +571,7 @@ syn match vimHiGui contained "\cgui="he=e-1 nextgroup=vimHiAttribList
|
|||||||
syn match vimHiGuiFont contained "\cfont="he=e-1 nextgroup=vimHiFontname
|
syn match vimHiGuiFont contained "\cfont="he=e-1 nextgroup=vimHiFontname
|
||||||
syn match vimHiGuiFgBg contained "\cgui\%([fb]g\|sp\)="he=e-1 nextgroup=vimHiGroup,vimHiGuiFontname,vimHiGuiRgb,vimFgBgAttrib
|
syn match vimHiGuiFgBg contained "\cgui\%([fb]g\|sp\)="he=e-1 nextgroup=vimHiGroup,vimHiGuiFontname,vimHiGuiRgb,vimFgBgAttrib
|
||||||
syn match vimHiTermcap contained "\S\+" contains=vimNotation
|
syn match vimHiTermcap contained "\S\+" contains=vimNotation
|
||||||
|
syn match vimHiBlend contained "\cblend="he=e-1 nextgroup=vimHiNmbr
|
||||||
syn match vimHiNmbr contained '\d\+'
|
syn match vimHiNmbr contained '\d\+'
|
||||||
|
|
||||||
" Highlight: clear {{{2
|
" Highlight: clear {{{2
|
||||||
@ -850,6 +851,7 @@ if !exists("skip_vim_syntax_inits")
|
|||||||
hi def link vimGroupSpecial Special
|
hi def link vimGroupSpecial Special
|
||||||
hi def link vimGroup Type
|
hi def link vimGroup Type
|
||||||
hi def link vimHiAttrib PreProc
|
hi def link vimHiAttrib PreProc
|
||||||
|
hi def link vimHiBlend vimHiTerm
|
||||||
hi def link vimHiClear vimHighlight
|
hi def link vimHiClear vimHighlight
|
||||||
hi def link vimHiCtermFgBg vimHiTerm
|
hi def link vimHiCtermFgBg vimHiTerm
|
||||||
hi def link vimHiCTerm vimHiTerm
|
hi def link vimHiCTerm vimHiTerm
|
||||||
|
@ -91,7 +91,7 @@ NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
|
|||||||
|
|
||||||
** Press `x`{normal} to delete the character under the cursor. **
|
** Press `x`{normal} to delete the character under the cursor. **
|
||||||
|
|
||||||
1. Move the cursor to the line below marked --->.
|
1. Move the cursor to the line below marked ✗.
|
||||||
|
|
||||||
2. To fix the errors, move the cursor until it is on top of the
|
2. To fix the errors, move the cursor until it is on top of the
|
||||||
character to be deleted.
|
character to be deleted.
|
||||||
@ -111,7 +111,7 @@ NOTE: As you go through this tutor, do not try to memorize, learn by
|
|||||||
|
|
||||||
** Press `i`{normal} to insert text. **
|
** Press `i`{normal} to insert text. **
|
||||||
|
|
||||||
1. Move the cursor to the first line below marked --->.
|
1. Move the cursor to the first line below marked ✗.
|
||||||
|
|
||||||
2. To make the first line the same as the second, move the cursor on top
|
2. To make the first line the same as the second, move the cursor on top
|
||||||
of the first character AFTER where the text is to be inserted.
|
of the first character AFTER where the text is to be inserted.
|
||||||
@ -130,7 +130,7 @@ There is some text missing from this line.
|
|||||||
|
|
||||||
** Press `A`{normal} to append text. **
|
** Press `A`{normal} to append text. **
|
||||||
|
|
||||||
1. Move the cursor to the first line below marked --->.
|
1. Move the cursor to the first line below marked ✗.
|
||||||
It does not matter on what character the cursor is in that line.
|
It does not matter on what character the cursor is in that line.
|
||||||
|
|
||||||
2. Press [A](A) and type in the necessary additions.
|
2. Press [A](A) and type in the necessary additions.
|
||||||
@ -138,7 +138,7 @@ There is some text missing from this line.
|
|||||||
3. As the text has been appended press `<Esc>`{normal} to return to Normal
|
3. As the text has been appended press `<Esc>`{normal} to return to Normal
|
||||||
mode.
|
mode.
|
||||||
|
|
||||||
4. Move the cursor to the second line marked ---> and repeat
|
4. Move the cursor to the second line marked ✗ and repeat
|
||||||
steps 2 and 3 to correct this sentence.
|
steps 2 and 3 to correct this sentence.
|
||||||
|
|
||||||
There is some text missing from th
|
There is some text missing from th
|
||||||
@ -211,7 +211,7 @@ Now continue with Lesson 2.
|
|||||||
|
|
||||||
1. Press `<Esc>`{normal} to make sure you are in Normal mode.
|
1. Press `<Esc>`{normal} to make sure you are in Normal mode.
|
||||||
|
|
||||||
2. Move the cursor to the line below marked --->.
|
2. Move the cursor to the line below marked ✗.
|
||||||
|
|
||||||
3. Move the cursor to the beginning of a word that needs to be deleted.
|
3. Move the cursor to the beginning of a word that needs to be deleted.
|
||||||
|
|
||||||
@ -227,7 +227,7 @@ There are a some words fun that don't belong paper in this sentence.
|
|||||||
|
|
||||||
1. Press `<Esc>`{normal} to make sure you are in Normal mode.
|
1. Press `<Esc>`{normal} to make sure you are in Normal mode.
|
||||||
|
|
||||||
2. Move the cursor to the line below marked --->.
|
2. Move the cursor to the line below marked ✗.
|
||||||
|
|
||||||
3. Move the cursor to the end of the correct line (AFTER the first . ).
|
3. Move the cursor to the end of the correct line (AFTER the first . ).
|
||||||
|
|
||||||
@ -263,7 +263,7 @@ NOTE: Pressing just the motion while in Normal mode without an operator
|
|||||||
|
|
||||||
** Typing a number before a motion repeats it that many times. **
|
** Typing a number before a motion repeats it that many times. **
|
||||||
|
|
||||||
1. Move the cursor to the start of the line marked ---> below.
|
1. Move the cursor to the start of the line marked ✓ below.
|
||||||
|
|
||||||
2. Type `2w`{normal} to move the cursor two words forward.
|
2. Type `2w`{normal} to move the cursor two words forward.
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ In the combination of the delete operator and a motion mentioned above you
|
|||||||
insert a count before the motion to delete more:
|
insert a count before the motion to delete more:
|
||||||
d number motion
|
d number motion
|
||||||
|
|
||||||
1. Move the cursor to the first UPPER CASE word in the line marked --->.
|
1. Move the cursor to the first UPPER CASE word in the line marked ✗.
|
||||||
|
|
||||||
2. Type `d2w`{normal} to delete the two UPPER CASE words
|
2. Type `d2w`{normal} to delete the two UPPER CASE words
|
||||||
|
|
||||||
@ -318,7 +318,7 @@ it would be easier to simply type two d's to delete a line.
|
|||||||
|
|
||||||
** Press `u`{normal} to undo the last commands, `U`{normal} to fix a whole line. **
|
** Press `u`{normal} to undo the last commands, `U`{normal} to fix a whole line. **
|
||||||
|
|
||||||
1. Move the cursor to the line below marked ---> and place it on the
|
1. Move the cursor to the line below marked ✗ and place it on the
|
||||||
first error.
|
first error.
|
||||||
2. Type `x`{normal} to delete the first unwanted character.
|
2. Type `x`{normal} to delete the first unwanted character.
|
||||||
3. Now type `u`{normal} to undo the last command executed.
|
3. Now type `u`{normal} to undo the last command executed.
|
||||||
@ -359,7 +359,7 @@ Fiix the errors oon thhis line and reeplace them witth undo.
|
|||||||
|
|
||||||
** Type `p`{normal} to put previously deleted text after the cursor. **
|
** Type `p`{normal} to put previously deleted text after the cursor. **
|
||||||
|
|
||||||
1. Move the cursor to the first ---> line below.
|
1. Move the cursor to the first ✓ line below.
|
||||||
|
|
||||||
2. Type `dd`{normal} to delete the line and store it in a Vim register.
|
2. Type `dd`{normal} to delete the line and store it in a Vim register.
|
||||||
|
|
||||||
@ -378,7 +378,7 @@ a) Roses are red,
|
|||||||
|
|
||||||
** Type `rx`{normal} to replace the character at the cursor with x. **
|
** Type `rx`{normal} to replace the character at the cursor with x. **
|
||||||
|
|
||||||
1. Move the cursor to the first line below marked --->.
|
1. Move the cursor to the first line below marked ✗.
|
||||||
|
|
||||||
2. Move the cursor so that it is on top of the first error.
|
2. Move the cursor so that it is on top of the first error.
|
||||||
|
|
||||||
@ -397,7 +397,7 @@ NOTE: Remember that you should be learning by doing, not memorization.
|
|||||||
|
|
||||||
** To change until the end of a word, type `ce`{normal}. **
|
** To change until the end of a word, type `ce`{normal}. **
|
||||||
|
|
||||||
1. Move the cursor to the first line below marked --->.
|
1. Move the cursor to the first line below marked ✗.
|
||||||
|
|
||||||
2. Place the cursor on the "u" in "lubw".
|
2. Place the cursor on the "u" in "lubw".
|
||||||
|
|
||||||
@ -423,7 +423,7 @@ Notice that [c](c)e deletes the word and places you in Insert mode.
|
|||||||
|
|
||||||
2. The motions are the same, such as `w`{normal} (word) and `$`{normal} (end of line).
|
2. The motions are the same, such as `w`{normal} (word) and `$`{normal} (end of line).
|
||||||
|
|
||||||
3. Move to the first line below marked --->.
|
3. Move to the first line below marked ✗.
|
||||||
|
|
||||||
4. Move the cursor to the first error.
|
4. Move the cursor to the first error.
|
||||||
|
|
||||||
@ -503,7 +503,7 @@ NOTE: When the search reaches the end of the file it will continue at the
|
|||||||
|
|
||||||
** Type `%`{normal} to find a matching ),], or }. **
|
** Type `%`{normal} to find a matching ),], or }. **
|
||||||
|
|
||||||
1. Place the cursor on any (, [, or { in the line below marked --->.
|
1. Place the cursor on any (, [, or { in the line below marked ✓.
|
||||||
|
|
||||||
2. Now type the [%](%) character.
|
2. Now type the [%](%) character.
|
||||||
|
|
||||||
@ -521,7 +521,7 @@ NOTE: This is very useful in debugging a program with unmatched parentheses!
|
|||||||
|
|
||||||
** Type `:s/old/new/g` to substitute "new" for "old". **
|
** Type `:s/old/new/g` to substitute "new" for "old". **
|
||||||
|
|
||||||
1. Move the cursor to the line below marked --->.
|
1. Move the cursor to the line below marked ✗.
|
||||||
|
|
||||||
2. Type
|
2. Type
|
||||||
~~~ cmd
|
~~~ cmd
|
||||||
@ -725,7 +725,7 @@ NOTE: You can also read the output of an external command. For example,
|
|||||||
|
|
||||||
** Type `o`{normal} to open a line below the cursor and place you in Insert mode. **
|
** Type `o`{normal} to open a line below the cursor and place you in Insert mode. **
|
||||||
|
|
||||||
1. Move the cursor to the line below marked --->.
|
1. Move the cursor to the line below marked ✓.
|
||||||
|
|
||||||
2. Type the lowercase letter `o`{normal} to [open](o) up a line BELOW the
|
2. Type the lowercase letter `o`{normal} to [open](o) up a line BELOW the
|
||||||
cursor and place you in Insert mode.
|
cursor and place you in Insert mode.
|
||||||
@ -743,7 +743,7 @@ Open up a line above this by typing O while the cursor is on this line.
|
|||||||
|
|
||||||
** Type `a`{normal} to insert text AFTER the cursor. **
|
** Type `a`{normal} to insert text AFTER the cursor. **
|
||||||
|
|
||||||
1. Move the cursor to the start of the line below marked --->.
|
1. Move the cursor to the start of the line below marked ✗.
|
||||||
|
|
||||||
2. Press `e`{normal} until the cursor is on the end of "li".
|
2. Press `e`{normal} until the cursor is on the end of "li".
|
||||||
|
|
||||||
@ -766,7 +766,7 @@ NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only
|
|||||||
|
|
||||||
** Type a capital `R`{normal} to replace more than one character. **
|
** Type a capital `R`{normal} to replace more than one character. **
|
||||||
|
|
||||||
1. Move the cursor to the first line below marked --->. Move the cursor to
|
1. Move the cursor to the first line below marked ✗. Move the cursor to
|
||||||
the beginning of the first "xxx".
|
the beginning of the first "xxx".
|
||||||
|
|
||||||
2. Now press `R`{normal} ([capital R](R)) and type the number below it in the
|
2. Now press `R`{normal} ([capital R](R)) and type the number below it in the
|
||||||
@ -787,7 +787,7 @@ NOTE: Replace mode is like Insert mode, but every typed character deletes an
|
|||||||
|
|
||||||
** Use the `y`{normal} operator to copy text and `p`{normal} to paste it. **
|
** Use the `y`{normal} operator to copy text and `p`{normal} to paste it. **
|
||||||
|
|
||||||
1. Go to the line marked with ---> below and place the cursor after "a)".
|
1. Go to the line marked with ✓ below and place the cursor after "a)".
|
||||||
|
|
||||||
2. Start Visual mode with `v`{normal} and move the cursor to just before
|
2. Start Visual mode with `v`{normal} and move the cursor to just before
|
||||||
"first".
|
"first".
|
||||||
@ -805,7 +805,7 @@ NOTE: Replace mode is like Insert mode, but every typed character deletes an
|
|||||||
end of the next line with `j$`{normal} and put the text there with `p`{normal}
|
end of the next line with `j$`{normal} and put the text there with `p`{normal}
|
||||||
|
|
||||||
a) This is the first item.
|
a) This is the first item.
|
||||||
b)
|
b)
|
||||||
|
|
||||||
NOTE: you can use `y`{normal} as an operator: `yw`{normal} yanks one word.
|
NOTE: you can use `y`{normal} as an operator: `yw`{normal} yanks one word.
|
||||||
|
|
||||||
|
@ -1,43 +1,45 @@
|
|||||||
{
|
{
|
||||||
"expect": {
|
"expect": {
|
||||||
"24": -1,
|
"24": -1,
|
||||||
"103": "The cow jumped over the moon.",
|
"103": "The cow jumped over the moon.",
|
||||||
"124": "There is some text missing from this line.",
|
"124": "There is some text missing from this line.",
|
||||||
"125": "There is some text missing from this line.",
|
"125": "There is some text missing from this line.",
|
||||||
"144": "There is some text missing from this line.",
|
"144": "There is some text missing from this line.",
|
||||||
"145": "There is some text missing from this line.",
|
"145": "There is some text missing from this line.",
|
||||||
"146": "There is also some text missing here.",
|
"146": "There is also some text missing here.",
|
||||||
"147": "There is also some text missing here.",
|
"147": "There is also some text missing here.",
|
||||||
"220": "There are some words that don't belong in this sentence.",
|
"220": "There are some words that don't belong in this sentence.",
|
||||||
"236": "Somebody typed the end of this line twice.",
|
"236": "Somebody typed the end of this line twice.",
|
||||||
"276": -1,
|
"276": -1,
|
||||||
"295": "This line of words is cleaned up.",
|
"295": "This line of words is cleaned up.",
|
||||||
"309": -1,
|
"309": -1,
|
||||||
"310": -1,
|
"310": -1,
|
||||||
"311": -1,
|
"311": -1,
|
||||||
"312": -1,
|
"312": -1,
|
||||||
"313": -1,
|
"313": -1,
|
||||||
"314": -1,
|
"314": -1,
|
||||||
"315": -1,
|
"315": -1,
|
||||||
"332": "Fix the errors on this line and replace them with undo.",
|
"332": "Fix the errors on this line and replace them with undo.",
|
||||||
"372": -1,
|
"372": -1,
|
||||||
"373": -1,
|
"373": -1,
|
||||||
"374": -1,
|
"374": -1,
|
||||||
"375": -1,
|
"375": -1,
|
||||||
"389": "When this line was typed in, someone pressed some wrong keys!",
|
"389": "When this line was typed in, someone pressed some wrong keys!",
|
||||||
"390": "When this line was typed in, someone pressed some wrong keys!",
|
"390": "When this line was typed in, someone pressed some wrong keys!",
|
||||||
"411": "This line has a few words that need changing using the change operator.",
|
"411": "This line has a few words that need changing using the change operator.",
|
||||||
"412": "This line has a few words that need changing using the change operator.",
|
"412": "This line has a few words that need changing using the change operator.",
|
||||||
"432": "The end of this line needs to be corrected using the c$ command.",
|
"432": "The end of this line needs to be corrected using the `c$` command.",
|
||||||
"433": "The end of this line needs to be corrected using the c$ command.",
|
"433": "The end of this line needs to be corrected using the `c$` command.",
|
||||||
"497": -1,
|
"497": -1,
|
||||||
"516": -1,
|
"516": -1,
|
||||||
"541": "Usually the best time to see the flowers is in the spring.",
|
"541": "Usually the best time to see the flowers is in the spring.",
|
||||||
"759": "This line will allow you to practice appending text to a line.",
|
"735": -1,
|
||||||
"760": "This line will allow you to practice appending text to a line.",
|
"740": -1,
|
||||||
"780": "Adding 123 to 456 gives you 579.",
|
"759": "This line will allow you to practice appending text to a line.",
|
||||||
"781": "Adding 123 to 456 gives you 579.",
|
"760": "This line will allow you to practice appending text to a line.",
|
||||||
"807": "a) This is the first item.",
|
"780": "Adding 123 to 456 gives you 579.",
|
||||||
"808": " b) This is the second item."
|
"781": "Adding 123 to 456 gives you 579.",
|
||||||
}
|
"807": "a) This is the first item.",
|
||||||
|
"808": "b) This is the second item."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ and are hidden by default. Links to them look like
|
|||||||
|
|
||||||
\[label\]\(\*anchor\*\)
|
\[label\]\(\*anchor\*\)
|
||||||
|
|
||||||
6. Add the appropiate link:
|
6. Add the appropriate link:
|
||||||
|
|
||||||
A link to the Links section
|
A link to the Links section
|
||||||
A link to the [Links](*links*) section
|
A link to the [Links](*links*) section
|
||||||
|
@ -36,11 +36,12 @@ import shutil
|
|||||||
import textwrap
|
import textwrap
|
||||||
import subprocess
|
import subprocess
|
||||||
import collections
|
import collections
|
||||||
|
import msgpack
|
||||||
|
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
|
||||||
if sys.version_info[0] < 3:
|
if sys.version_info[0] < 3 or sys.version_info[1] < 5:
|
||||||
print("use Python 3")
|
print("requires Python 3.5+")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
DEBUG = ('DEBUG' in os.environ)
|
DEBUG = ('DEBUG' in os.environ)
|
||||||
@ -84,7 +85,7 @@ CONFIG = {
|
|||||||
'append_only': [],
|
'append_only': [],
|
||||||
},
|
},
|
||||||
'lua': {
|
'lua': {
|
||||||
'filename': 'if_lua.txt',
|
'filename': 'lua.txt',
|
||||||
'section_start_token': '*lua-vim*',
|
'section_start_token': '*lua-vim*',
|
||||||
'section_order': [
|
'section_order': [
|
||||||
'vim.lua',
|
'vim.lua',
|
||||||
@ -453,7 +454,7 @@ def parse_source_xml(filename, mode):
|
|||||||
"""
|
"""
|
||||||
global xrefs
|
global xrefs
|
||||||
xrefs = set()
|
xrefs = set()
|
||||||
functions = []
|
functions = {} # Map of func_name:docstring.
|
||||||
deprecated_functions = []
|
deprecated_functions = []
|
||||||
|
|
||||||
dom = minidom.parse(filename)
|
dom = minidom.parse(filename)
|
||||||
@ -577,11 +578,13 @@ def parse_source_xml(filename, mode):
|
|||||||
if 'Deprecated' in xrefs:
|
if 'Deprecated' in xrefs:
|
||||||
deprecated_functions.append(func_doc)
|
deprecated_functions.append(func_doc)
|
||||||
elif name.startswith(CONFIG[mode]['func_name_prefix']):
|
elif name.startswith(CONFIG[mode]['func_name_prefix']):
|
||||||
functions.append(func_doc)
|
functions[name] = func_doc
|
||||||
|
|
||||||
xrefs.clear()
|
xrefs.clear()
|
||||||
|
|
||||||
return '\n\n'.join(functions), '\n\n'.join(deprecated_functions)
|
return ('\n\n'.join(list(functions.values())),
|
||||||
|
'\n\n'.join(deprecated_functions),
|
||||||
|
functions)
|
||||||
|
|
||||||
|
|
||||||
def delete_lines_below(filename, tokenstr):
|
def delete_lines_below(filename, tokenstr):
|
||||||
@ -604,6 +607,13 @@ def gen_docs(config):
|
|||||||
Doxygen is called and configured through stdin.
|
Doxygen is called and configured through stdin.
|
||||||
"""
|
"""
|
||||||
for mode in CONFIG:
|
for mode in CONFIG:
|
||||||
|
functions = {} # Map of func_name:docstring.
|
||||||
|
mpack_file = os.path.join(
|
||||||
|
base_dir, 'runtime', 'doc',
|
||||||
|
CONFIG[mode]['filename'].replace('.txt', '.mpack'))
|
||||||
|
if os.path.exists(mpack_file):
|
||||||
|
os.remove(mpack_file)
|
||||||
|
|
||||||
output_dir = out_dir.format(mode=mode)
|
output_dir = out_dir.format(mode=mode)
|
||||||
p = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE)
|
p = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE)
|
||||||
p.communicate(
|
p.communicate(
|
||||||
@ -645,14 +655,15 @@ def gen_docs(config):
|
|||||||
|
|
||||||
filename = get_text(find_first(compound, 'name'))
|
filename = get_text(find_first(compound, 'name'))
|
||||||
if filename.endswith('.c') or filename.endswith('.lua'):
|
if filename.endswith('.c') or filename.endswith('.lua'):
|
||||||
functions, deprecated = parse_source_xml(
|
functions_text, deprecated_text, fns = parse_source_xml(
|
||||||
os.path.join(base, '%s.xml' %
|
os.path.join(base, '{}.xml'.format(
|
||||||
compound.getAttribute('refid')), mode)
|
compound.getAttribute('refid'))), mode)
|
||||||
|
# Collect functions from all modules (for the current `mode`).
|
||||||
|
functions = {**functions, **fns}
|
||||||
|
|
||||||
if not functions and not deprecated:
|
if not functions_text and not deprecated_text:
|
||||||
continue
|
continue
|
||||||
|
else:
|
||||||
if functions or deprecated:
|
|
||||||
name = os.path.splitext(os.path.basename(filename))[0]
|
name = os.path.splitext(os.path.basename(filename))[0]
|
||||||
if name == 'ui':
|
if name == 'ui':
|
||||||
name = name.upper()
|
name = name.upper()
|
||||||
@ -665,12 +676,12 @@ def gen_docs(config):
|
|||||||
if intro:
|
if intro:
|
||||||
doc += '\n\n' + intro
|
doc += '\n\n' + intro
|
||||||
|
|
||||||
if functions:
|
if functions_text:
|
||||||
doc += '\n\n' + functions
|
doc += '\n\n' + functions_text
|
||||||
|
|
||||||
if INCLUDE_DEPRECATED and deprecated:
|
if INCLUDE_DEPRECATED and deprecated_text:
|
||||||
doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name
|
doc += '\n\n\nDeprecated %s Functions: ~\n\n' % name
|
||||||
doc += deprecated
|
doc += deprecated_text
|
||||||
|
|
||||||
if doc:
|
if doc:
|
||||||
filename = os.path.basename(filename)
|
filename = os.path.basename(filename)
|
||||||
@ -713,6 +724,8 @@ def gen_docs(config):
|
|||||||
delete_lines_below(doc_file, CONFIG[mode]['section_start_token'])
|
delete_lines_below(doc_file, CONFIG[mode]['section_start_token'])
|
||||||
with open(doc_file, 'ab') as fp:
|
with open(doc_file, 'ab') as fp:
|
||||||
fp.write(docs.encode('utf8'))
|
fp.write(docs.encode('utf8'))
|
||||||
|
with open(mpack_file, 'wb') as fp:
|
||||||
|
fp.write(msgpack.packb(functions, use_bin_type=True))
|
||||||
|
|
||||||
shutil.rmtree(output_dir)
|
shutil.rmtree(output_dir)
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ FILTER_PATTERNS = *.lua=lua2dox_filter
|
|||||||
|
|
||||||
Either add them to the end or find the appropriate entry in Doxyfile.
|
Either add them to the end or find the appropriate entry in Doxyfile.
|
||||||
|
|
||||||
There are other lines that you might like to alter, but see futher documentation for details.
|
There are other lines that you might like to alter, but see further documentation for details.
|
||||||
|
|
||||||
<li> When Doxyfile is edited run "doxygen"
|
<li> When Doxyfile is edited run "doxygen"
|
||||||
|
|
||||||
@ -543,7 +543,6 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
|
|||||||
local fn = TString_removeCommentFromLine(string_trim(string.sub(line,pos_fn+8)))
|
local fn = TString_removeCommentFromLine(string_trim(string.sub(line,pos_fn+8)))
|
||||||
if fn_magic then
|
if fn_magic then
|
||||||
fn = fn_magic
|
fn = fn_magic
|
||||||
fn_magic = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if string.sub(fn,1,1)=='(' then
|
if string.sub(fn,1,1)=='(' then
|
||||||
@ -554,49 +553,20 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
|
|||||||
|
|
||||||
-- want to fix for iffy declarations
|
-- want to fix for iffy declarations
|
||||||
local open_paren = string.find(fn,'[%({]')
|
local open_paren = string.find(fn,'[%({]')
|
||||||
local fn0 = fn
|
|
||||||
if open_paren then
|
if open_paren then
|
||||||
fn0 = string.sub(fn,1,open_paren-1)
|
|
||||||
-- we might have a missing close paren
|
-- we might have a missing close paren
|
||||||
if not string.find(fn,'%)') then
|
if not string.find(fn,'%)') then
|
||||||
fn = fn .. ' ___MissingCloseParenHere___)'
|
fn = fn .. ' ___MissingCloseParenHere___)'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local dot = string.find(fn0,'[%.:]')
|
-- add vanilla function
|
||||||
if dot then -- it's a method
|
outStream:writeln(fn_type .. 'function ' .. fn .. '{}')
|
||||||
local klass = string.sub(fn,1,dot-1)
|
|
||||||
local method = string.sub(fn,dot+1)
|
|
||||||
--TCore_IO_writeln('function ' .. klass .. '::' .. method .. ftail .. '{}')
|
|
||||||
--TCore_IO_writeln(klass .. '::' .. method .. ftail .. '{}')
|
|
||||||
outStream:writeln(
|
|
||||||
'/*! \\memberof ' .. klass .. ' */ '
|
|
||||||
.. method .. '{}'
|
|
||||||
)
|
|
||||||
else
|
|
||||||
-- add vanilla function
|
|
||||||
|
|
||||||
outStream:writeln(fn_type .. 'function ' .. fn .. '{}')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
this:warning(inStream:getLineNo(),'something weird here')
|
this:warning(inStream:getLineNo(),'something weird here')
|
||||||
end
|
end
|
||||||
fn_magic = nil -- mustn't indavertently use it again
|
fn_magic = nil -- mustn't indavertently use it again
|
||||||
elseif string.find(line,'=%s*class%(') then
|
|
||||||
state = 'in_class' -- it's a class declaration
|
|
||||||
local tailComment
|
|
||||||
line,tailComment = TString_removeCommentFromLine(line)
|
|
||||||
local equals = string.find(line,'=')
|
|
||||||
local klass = string_trim(string.sub(line,1,equals-1))
|
|
||||||
local tail = string_trim(string.sub(line,equals+1))
|
|
||||||
-- class(wibble wibble)
|
|
||||||
-- ....v.
|
|
||||||
local parent = string.sub(tail,7,-2)
|
|
||||||
if #parent>0 then
|
|
||||||
parent = ' :public ' .. parent
|
|
||||||
end
|
|
||||||
outStream:writeln('class ' .. klass .. parent .. '{};')
|
|
||||||
else
|
else
|
||||||
state = '' -- unknown
|
state = '' -- unknown
|
||||||
if #line>0 then -- we don't know what this line means, so just comment it out
|
if #line>0 then -- we don't know what this line means, so just comment it out
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user