Merge branch 'master' into s-dash-stdin

This commit is contained in:
b-r-o-c-k
2018-04-14 14:17:51 -05:00
473 changed files with 45843 additions and 11569 deletions

13
.gitignore vendored
View File

@@ -1,3 +1,6 @@
# Tools
.ropeproject/
# Build/deps dir # Build/deps dir
/build/ /build/
/cmake-build-debug/ /cmake-build-debug/
@@ -17,13 +20,13 @@ tags
/src/nvim/po/vim.pot /src/nvim/po/vim.pot
/src/nvim/po/*.ck /src/nvim/po/*.ck
# generated by tests with $NVIM_LOG_FILE set. # Generated by tests with $NVIM_LOG_FILE set.
/.nvimlog /.nvimlog
# Files generated by scripts/vim-patch.sh # Generated by scripts/vim-patch.sh
/.vim-src/ /.vim-src/
# Files generated by the tests # Generated by old (Vim) tests.
/src/nvim/testdir/del /src/nvim/testdir/del
/src/nvim/testdir/test*.out /src/nvim/testdir/test*.out
/src/nvim/testdir/test*.res /src/nvim/testdir/test*.res
@@ -36,10 +39,10 @@ tags
/src/nvim/testdir/valgrind.* /src/nvim/testdir/valgrind.*
/src/nvim/testdir/.gdbinit /src/nvim/testdir/.gdbinit
# Folder generated by the unit tests # Generated by unit tests.
/test/includes/post/ /test/includes/post/
# generated by luacheck during `make testlint' # Generated by luacheck during `make testlint'
/test/.luacheckcache /test/.luacheckcache
# local make targets # local make targets

View File

@@ -4,13 +4,8 @@ language: c
env: env:
global: global:
# To force rebuilding of third-party dependencies, set this to 'true'. # Set "false" to force rebuild of third-party dependencies.
- BUILD_NVIM_DEPS=false - CACHE_ENABLE=true
# Travis has 1.5 virtual cores according to
# http://docs.travis-ci.com/user/speeding-up-the-build/#Paralellizing-your-build-on-one-VM
- MAKE_CMD="make -j2"
# Update PATH for pip.
- PATH="$(python2.7 -c 'import site; print(site.getuserbase())')/bin:/usr/lib/llvm-symbolizer-4.0/bin:$PATH"
# Build directory for Neovim. # Build directory for Neovim.
- BUILD_DIR="$TRAVIS_BUILD_DIR/build" - BUILD_DIR="$TRAVIS_BUILD_DIR/build"
# Build directory for third-party dependencies. # Build directory for third-party dependencies.
@@ -41,9 +36,7 @@ env:
- UBSAN_OPTIONS="print_stacktrace=1 log_path=$LOG_DIR/ubsan" - UBSAN_OPTIONS="print_stacktrace=1 log_path=$LOG_DIR/ubsan"
# Environment variables for Valgrind. # Environment variables for Valgrind.
- VALGRIND_LOG="$LOG_DIR/valgrind-%p.log" - VALGRIND_LOG="$LOG_DIR/valgrind-%p.log"
# Cache marker for third-party dependencies cache. # If this file exists, the cache is valid (compile was successful).
# If this file exists, we know that the cache contains compiled
# dependencies and we can use it.
- CACHE_MARKER="$HOME/.cache/nvim-deps/.travis_cache_marker" - CACHE_MARKER="$HOME/.cache/nvim-deps/.travis_cache_marker"
# default target name for functional tests # default target name for functional tests
- FUNCTIONALTEST=functionaltest - FUNCTIONALTEST=functionaltest
@@ -51,40 +44,41 @@ env:
jobs: jobs:
include: include:
- stage: sanitizers - stage: normal builds
os: linux os: linux
compiler: clang-4.0 compiler: clang
env: > env: >
CLANG_SANITIZER=ASAN_UBSAN CLANG_SANITIZER=ASAN_UBSAN
CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
- stage: normal builds sudo: true
os: linux
compiler: gcc-5
env: FUNCTIONALTEST=functionaltest-lua
- os: linux - os: linux
# Travis creates a cache per compiler. compiler: gcc
# Set a different value here to store 32-bit env: >
# dependencies in a separate cache. FUNCTIONALTEST=functionaltest-lua
compiler: gcc-5 -m32 CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
- os: linux
# Travis creates a cache per compiler. Set a different value here to
# store 32-bit dependencies in a separate cache.
compiler: gcc -m32
env: BUILD_32BIT=ON env: BUILD_32BIT=ON
- os: osx - os: osx
compiler: clang compiler: clang
osx_image: xcode7.3 # macOS 10.11 osx_image: xcode7.3 # macOS 10.11
- os: osx - os: osx
compiler: gcc-4.9 compiler: gcc
osx_image: xcode7.3 # macOS 10.11 osx_image: xcode7.3 # macOS 10.11
- stage: lint - os: linux
os: linux
env: CI_TARGET=lint env: CI_TARGET=lint
- stage: Flaky builds - stage: Flaky builds
os: linux os: linux
compiler: gcc-5 compiler: gcc
env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" env: GCOV=gcov CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
- os: linux - os: linux
compiler: clang-4.0 compiler: clang
env: CLANG_SANITIZER=TSAN env: CLANG_SANITIZER=TSAN
allow_failures: allow_failures:
- env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - env: GCOV=gcov CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
- env: CLANG_SANITIZER=TSAN - env: CLANG_SANITIZER=TSAN
fast_finish: true fast_finish: true
@@ -97,27 +91,22 @@ after_success: ci/after_success.sh
addons: addons:
apt: apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-trusty-4.0
packages: packages:
- autoconf - autoconf
- automake - automake
- apport - apport
- build-essential - build-essential
- clang-4.0 - clang
- cmake - cmake
- cscope - cscope
- g++-5-multilib
- g++-multilib - g++-multilib
- gcc-5-multilib
- gcc-multilib - gcc-multilib
- gdb - gdb
- language-pack-tr - language-pack-tr
- libc6-dev-i386 - libc6-dev-i386
- libtool - libtool
- llvm-4.0-dev
- locales - locales
- ninja-build
- pkg-config - pkg-config
- unzip - unzip
- valgrind - valgrind
@@ -132,6 +121,7 @@ cache:
directories: directories:
- "$HOME/.cache/pip" - "$HOME/.cache/pip"
- "$HOME/.cache/nvim-deps" - "$HOME/.cache/nvim-deps"
- "$HOME/.cache/nvim-deps-downloads"
notifications: notifications:
webhooks: webhooks:

View File

@@ -12,7 +12,11 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(PreventInTreeBuilds) include(PreventInTreeBuilds)
# Prefer our bundled versions of dependencies. # Prefer our bundled versions of dependencies.
if(DEFINED ENV{DEPS_BUILD_DIR})
set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies")
else()
set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies") set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies")
endif()
if(CMAKE_CROSSCOMPILING AND NOT UNIX) if(CMAKE_CROSSCOMPILING AND NOT UNIX)
list(INSERT CMAKE_FIND_ROOT_PATH 0 ${DEPS_PREFIX}) list(INSERT CMAKE_FIND_ROOT_PATH 0 ${DEPS_PREFIX})
list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX}/../host/bin) list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX}/../host/bin)
@@ -63,14 +67,14 @@ 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 2) set(NVIM_VERSION_MINOR 3)
set(NVIM_VERSION_PATCH 3) set(NVIM_VERSION_PATCH 0)
set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
# API level # API level
set(NVIM_API_LEVEL 3) # Bump this after any API change. set(NVIM_API_LEVEL 4) # 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) file(TO_CMAKE_PATH ${CMAKE_CURRENT_LIST_DIR}/.git FORCED_GIT_DIR)
include(GetGitRevisionDescription) include(GetGitRevisionDescription)
@@ -204,6 +208,7 @@ int main(void)
if(MSVC) if(MSVC)
# XXX: /W4 gives too many warnings. #3241 # XXX: /W4 gives too many warnings. #3241
add_definitions(/W3 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) add_definitions(/W3 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
add_definitions(-DWIN32)
else() else()
add_definitions(-Wall -Wextra -pedantic -Wno-unused-parameter add_definitions(-Wall -Wextra -pedantic -Wno-unused-parameter
-Wstrict-prototypes -std=gnu99) -Wstrict-prototypes -std=gnu99)
@@ -223,6 +228,9 @@ endif()
if(MINGW) if(MINGW)
# Use POSIX compatible stdio in Mingw # Use POSIX compatible stdio in Mingw
add_definitions(-D__USE_MINGW_ANSI_STDIO) add_definitions(-D__USE_MINGW_ANSI_STDIO)
endif()
if(WIN32)
# Windows Vista is the minimum supported version
add_definitions(-D_WIN32_WINNT=0x0600) add_definitions(-D_WIN32_WINNT=0x0600)
endif() endif()
@@ -250,13 +258,14 @@ if(HAS_DIAG_COLOR_FLAG)
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.5") # 1. Array-bounds testing is broken in some GCC versions before 4.8.5.
# Array-bounds testing is broken in some GCC versions before 4.8.5. # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273 # 2. But _Pragma("...ignored") is broken (unresolved) in GCC 5+:
check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099
if(HAS_NO_ARRAY_BOUNDS_FLAG) # So we must disable -Warray-bounds globally for GCC (for kbtree.h, #7083).
add_definitions(-Wno-array-bounds) check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG)
endif() if(HAS_NO_ARRAY_BOUNDS_FLAG)
add_definitions(-Wno-array-bounds)
endif() endif()
endif() endif()
@@ -277,6 +286,8 @@ else()
set(DEBUG 0) set(DEBUG 0)
endif() endif()
option(LOG_LIST_ACTIONS "Add list actions logging" OFF)
add_definitions(-DINCLUDE_GENERATED_DECLARATIONS) add_definitions(-DINCLUDE_GENERATED_DECLARATIONS)
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
@@ -505,17 +516,6 @@ if(BUSTED_PRG)
get_property(TEST_INCLUDE_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} get_property(TEST_INCLUDE_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY INCLUDE_DIRECTORIES) PROPERTY INCLUDE_DIRECTORIES)
# Set policy CMP0026 to OLD so we avoid CMake warnings on newer
# versions of cmake.
if(POLICY CMP0026)
cmake_policy(SET CMP0026 OLD)
endif()
if(CMAKE_GENERATOR MATCHES "Visual Studio")
set(TEST_LIBNVIM_PATH ${CMAKE_BINARY_DIR}/lib/nvim-test.dll)
else()
get_target_property(TEST_LIBNVIM_PATH nvim-test LOCATION)
endif()
# When running tests from 'ninja' we need to use the # When running tests from 'ninja' we need to use the
# console pool: to do so we need to use the USES_TERMINAL # console pool: to do so we need to use the USES_TERMINAL
# option, but this is only available in CMake 3.2 # option, but this is only available in CMake 3.2
@@ -524,10 +524,6 @@ if(BUSTED_PRG)
list(APPEND TEST_TARGET_ARGS "USES_TERMINAL") list(APPEND TEST_TARGET_ARGS "USES_TERMINAL")
endif() endif()
configure_file(
test/config/paths.lua.in
${CMAKE_BINARY_DIR}/test/config/paths.lua)
set(UNITTEST_PREREQS nvim-test unittest-headers) set(UNITTEST_PREREQS nvim-test unittest-headers)
set(FUNCTIONALTEST_PREREQS nvim printargs-test shell-test) set(FUNCTIONALTEST_PREREQS nvim printargs-test shell-test)
if(NOT WIN32) if(NOT WIN32)
@@ -564,6 +560,32 @@ if(BUSTED_PRG)
message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}") message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}")
endif() endif()
if(${CMAKE_VERSION} VERSION_LESS 2.8.12)
if(CMAKE_GENERATOR MATCHES "Visual Studio")
set(TEST_LIBNVIM_PATH ${CMAKE_BINARY_DIR}/lib/nvim-test.dll)
else()
get_target_property(TEST_LIBNVIM_PATH nvim-test LOCATION)
endif()
configure_file(
${CMAKE_SOURCE_DIR}/test/config/paths.lua.in
${CMAKE_BINARY_DIR}/test/config/paths.lua)
else()
# To avoid duplicating paths.lua.in while we still support CMake < 2.8.12,
# use configure_file() to add the generator expression and then generate
# the final file
if(LUA_HAS_FFI)
set(TEST_LIBNVIM_PATH $<TARGET_FILE:nvim-test>)
else()
set(TEST_LIBNVIM_PATH "")
endif()
configure_file(
${CMAKE_SOURCE_DIR}/test/config/paths.lua.in
${CMAKE_BINARY_DIR}/test/config/paths.lua.gen)
file(GENERATE
OUTPUT ${CMAKE_BINARY_DIR}/test/config/paths.lua
INPUT ${CMAKE_BINARY_DIR}/test/config/paths.lua.gen)
endif()
add_custom_target(functionaltest add_custom_target(functionaltest
COMMAND ${CMAKE_COMMAND} COMMAND ${CMAKE_COMMAND}
-DBUSTED_PRG=${BUSTED_PRG} -DBUSTED_PRG=${BUSTED_PRG}

View File

@@ -14,7 +14,7 @@ low-risk/isolated tasks:
Developer guidelines Developer guidelines
-------------------- --------------------
- Nvim developers should read `:help dev-help`. - Nvim developers should read `:help dev`.
- External UI developers should read `:help dev-ui`. - External UI developers should read `:help dev-ui`.
Reporting problems Reporting problems
@@ -24,7 +24,7 @@ Reporting problems
- Search [existing issues][github-issues] (including closed!) - Search [existing issues][github-issues] (including closed!)
- Update Neovim to the latest version to see if your problem persists. - Update Neovim to the latest version to see if your problem persists.
- Disable plugins incrementally, to narrow down the cause of the issue. - Disable plugins incrementally, to narrow down the cause of the issue.
- When reporting a crash, include a stacktrace. - When reporting a crash, [include a stacktrace](https://github.com/neovim/neovim/wiki/Development-tips#backtrace-linux).
- [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful. - [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful.
- Check `$NVIM_LOG_FILE`, if it exists. - Check `$NVIM_LOG_FILE`, if it exists.
- Include `cmake --system-information` for **build** issues. - Include `cmake --system-information` for **build** issues.
@@ -92,7 +92,7 @@ and [AppVeyor].
- CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings - CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings
will fail the build. will fail the build.
- If any tests fail, the build will fail. - If any tests fail, the build will fail.
See [Building Neovim#running-tests][wiki-run-tests] to run tests locally. See [test/README.md#running-tests][run-tests] to run tests locally.
Passing locally doesn't guarantee passing the CI build, because of the Passing locally doesn't guarantee passing the CI build, because of the
different compilers and platforms tested against. different compilers and platforms tested against.
- CI runs [ASan] and other analyzers. - CI runs [ASan] and other analyzers.
@@ -168,7 +168,7 @@ as context, use the `-W` argument as well.
[hygiene]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html [hygiene]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[style-guide]: http://neovim.io/develop/style-guide.xml [style-guide]: http://neovim.io/develop/style-guide.xml
[ASan]: http://clang.llvm.org/docs/AddressSanitizer.html [ASan]: http://clang.llvm.org/docs/AddressSanitizer.html
[wiki-run-tests]: https://github.com/neovim/neovim/wiki/Building-Neovim#running-tests [run-tests]: https://github.com/neovim/neovim/blob/master/test/README.md#running-tests
[wiki-faq]: https://github.com/neovim/neovim/wiki/FAQ [wiki-faq]: https://github.com/neovim/neovim/wiki/FAQ
[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

View File

@@ -1,3 +1,4 @@
THIS_DIR = $(shell pwd)
filter-false = $(strip $(filter-out 0 off OFF false FALSE,$1)) filter-false = $(strip $(filter-out 0 off OFF false FALSE,$1))
filter-true = $(strip $(filter-out 1 on ON true TRUE,$1)) filter-true = $(strip $(filter-out 1 on ON true TRUE,$1))
@@ -8,11 +9,14 @@ CMAKE_PRG ?= $(shell (command -v cmake3 || echo cmake))
CMAKE_BUILD_TYPE ?= Debug CMAKE_BUILD_TYPE ?= Debug
CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
DOC_DOWNLOAD_URL_BASE := https://raw.githubusercontent.com/neovim/doc/gh-pages
CLINT_ERRORS_FILE_PATH := /reports/clint/errors.json
BUILD_TYPE ?= $(shell (type ninja > /dev/null 2>&1 && echo "Ninja") || \ BUILD_TYPE ?= $(shell (type ninja > /dev/null 2>&1 && echo "Ninja") || \
echo "Unix Makefiles") echo "Unix Makefiles")
DEPS_BUILD_DIR ?= .deps
ifneq (1,$(words [$(DEPS_BUILD_DIR)]))
$(error DEPS_BUILD_DIR must not contain whitespace)
endif
ifeq (,$(BUILD_TOOL)) ifeq (,$(BUILD_TOOL))
ifeq (Ninja,$(BUILD_TYPE)) ifeq (Ninja,$(BUILD_TYPE))
@@ -48,7 +52,7 @@ endif
ifneq (,$(findstring functionaltest-lua,$(MAKECMDGOALS))) ifneq (,$(findstring functionaltest-lua,$(MAKECMDGOALS)))
BUNDLED_LUA_CMAKE_FLAG := -DUSE_BUNDLED_LUA=ON BUNDLED_LUA_CMAKE_FLAG := -DUSE_BUNDLED_LUA=ON
$(shell [ -x .deps/usr/bin/lua ] || rm build/.ran-*) $(shell [ -x $(DEPS_BUILD_DIR)/usr/bin/lua ] || rm build/.ran-*)
endif endif
# For use where we want to make sure only a single job is run. This does issue # For use where we want to make sure only a single job is run. This does issue
@@ -68,20 +72,20 @@ cmake:
$(MAKE) build/.ran-cmake $(MAKE) build/.ran-cmake
build/.ran-cmake: | deps build/.ran-cmake: | deps
cd build && $(CMAKE_PRG) -G '$(BUILD_TYPE)' $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) .. cd build && $(CMAKE_PRG) -G '$(BUILD_TYPE)' $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) $(THIS_DIR)
touch $@ touch $@
deps: | build/.ran-third-party-cmake deps: | build/.ran-third-party-cmake
ifeq ($(call filter-true,$(USE_BUNDLED_DEPS)),) ifeq ($(call filter-true,$(USE_BUNDLED_DEPS)),)
+$(BUILD_CMD) -C .deps +$(BUILD_CMD) -C $(DEPS_BUILD_DIR)
endif endif
build/.ran-third-party-cmake: build/.ran-third-party-cmake:
ifeq ($(call filter-true,$(USE_BUNDLED_DEPS)),) ifeq ($(call filter-true,$(USE_BUNDLED_DEPS)),)
mkdir -p .deps mkdir -p $(DEPS_BUILD_DIR)
cd .deps && \ cd $(DEPS_BUILD_DIR) && \
$(CMAKE_PRG) -G '$(BUILD_TYPE)' $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) \ $(CMAKE_PRG) -G '$(BUILD_TYPE)' $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) \
$(DEPS_CMAKE_FLAGS) ../third-party $(DEPS_CMAKE_FLAGS) $(THIS_DIR)/third-party
endif endif
mkdir -p build mkdir -p build
touch $@ touch $@
@@ -124,7 +128,7 @@ clean:
$(MAKE) -C runtime/doc clean $(MAKE) -C runtime/doc clean
distclean: clean distclean: clean
rm -rf .deps build rm -rf $(DEPS_BUILD_DIR) build
install: | nvim install: | nvim
+$(BUILD_CMD) -C build install +$(BUILD_CMD) -C build install
@@ -141,6 +145,11 @@ check-single-includes: build/.ran-cmake
appimage: appimage:
bash scripts/genappimage.sh bash scripts/genappimage.sh
# Build an appimage with embedded update information appimage-nightly for
# nightly builds or appimage-latest for a release
appimage-%:
bash scripts/genappimage.sh $*
lint: check-single-includes clint testlint lualint lint: check-single-includes clint testlint lualint
.PHONY: test testlint lualint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage .PHONY: test testlint lualint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage

View File

@@ -14,7 +14,7 @@
[![PVS-studio Check](https://neovim.io/doc/reports/pvs/badge.svg)](https://neovim.io/doc/reports/pvs) [![PVS-studio Check](https://neovim.io/doc/reports/pvs/badge.svg)](https://neovim.io/doc/reports/pvs)
[![Debian CI](https://badges.debian.net/badges/debian/testing/neovim/version.svg)](https://buildd.debian.org/neovim) [![Debian CI](https://badges.debian.net/badges/debian/testing/neovim/version.svg)](https://buildd.debian.org/neovim)
[![Downloads](https://img.shields.io/github/downloads/neovim/neovim/total.svg?maxAge=2592000)](https://github.com/neovim/neovim/releases/) [![Downloads](https://img.shields.io/github/downloads/neovim/neovim/total.svg?maxAge=2592001)](https://github.com/neovim/neovim/releases/)
Neovim is a project that seeks to aggressively refactor Vim in order to: Neovim is a project that seeks to aggressively refactor Vim in order to:
@@ -34,11 +34,15 @@ Install from source
make CMAKE_BUILD_TYPE=RelWithDebInfo make CMAKE_BUILD_TYPE=RelWithDebInfo
sudo make install sudo make install
To install to a non-default location, specify `CMAKE_INSTALL_PREFIX`: To install to a non-default location, set `CMAKE_INSTALL_PREFIX`:
make CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=/full/path/" make CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=/full/path/"
make install make install
To list all targets:
cmake --build build --target help
See [the wiki](https://github.com/neovim/neovim/wiki/Building-Neovim) for details. See [the wiki](https://github.com/neovim/neovim/wiki/Building-Neovim) for details.
Install from package Install from package

View File

@@ -1,7 +1,10 @@
version: '{build}' version: '{build}'
environment: environment:
APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9" APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9"
image: Visual Studio 2017
configuration: configuration:
- MSVC_64
- MSVC_32
- MINGW_64 - MINGW_64
- MINGW_32 - MINGW_32
- MINGW_64-gcov - MINGW_64-gcov
@@ -9,10 +12,12 @@ matrix:
allow_failures: allow_failures:
- configuration: MINGW_64-gcov - configuration: MINGW_64-gcov
install: [] install: []
before_build:
- ps: Install-Product node 8
build_script: build_script:
- call ci\build.bat - powershell ci\build.ps1
cache: cache:
- C:\msys64\var\cache\pacman\pkg -> ci\build.bat - C:\msys64\var\cache\pacman\pkg -> ci\build.ps1
- .deps -> third-party\** - .deps -> third-party\**
artifacts: artifacts:
- path: build/Neovim.zip - path: build/Neovim.zip

View File

@@ -1,9 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
if [[ -n "${GCOV}" ]]; then
coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.'
bash <(curl -s https://codecov.io/bash) || echo 'codecov upload failed.'
fi

View File

@@ -4,16 +4,24 @@ set -e
set -o pipefail set -o pipefail
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/suite.sh" source "${CI_DIR}/common/suite.sh"
# Don't cache pip's log and selfcheck. # Don't cache pip's log and selfcheck.
rm -rf "${HOME}/.cache/pip/log" rm -rf "${HOME}/.cache/pip/log"
rm -f "${HOME}/.cache/pip/selfcheck.json" rm -f "${HOME}/.cache/pip/selfcheck.json"
echo "before_cache.sh: cache size"
du -d 2 "${HOME}/.cache" | sort -n
# Update the third-party dependency cache only if the build was successful. # Update the third-party dependency cache only if the build was successful.
if ended_successfully; then if ended_successfully; then
rm -rf "${HOME}/.cache/nvim-deps" rm -rf "${HOME}/.cache/nvim-deps"
mv "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps" mv "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps"
rm -rf "${HOME}/.cache/nvim-deps-downloads"
mv "${DEPS_DOWNLOAD_DIR}" "${HOME}/.cache/nvim-deps-downloads"
touch "${CACHE_MARKER}" touch "${CACHE_MARKER}"
echo "Updated third-party dependencies (timestamp: $(stat -c '%y' "${CACHE_MARKER}"))." echo "Updated third-party dependencies (timestamp: $(_stat "${CACHE_MARKER}"))."
fi fi

View File

@@ -23,17 +23,26 @@ echo 'python info:'
2>&1 pyenv versions || true 2>&1 pyenv versions || true
) | sed 's/^/ /' ) | sed 's/^/ /'
echo "Upgrade Python 2 pip."
pip2.7 -q install --user --upgrade pip
if [[ "${TRAVIS_OS_NAME}" == osx ]]; then if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
echo "Install Python 3." echo "Upgrade Python 3."
brew install python3 brew upgrade python
echo "Upgrade Python 3 pip." echo "Upgrade Python 3 pip."
pip3 -q install --user --upgrade pip pip3 -q install --user --upgrade pip
else else
echo "Upgrade Python 2 pip."
pip2.7 -q install --user --upgrade pip
echo "Upgrade Python 3 pip." echo "Upgrade Python 3 pip."
# Allow failure. pyenv pip3 on travis is broken: # Allow failure. pyenv pip3 on travis is broken:
# https://github.com/travis-ci/travis-ci/issues/8363 # https://github.com/travis-ci/travis-ci/issues/8363
pip3 -q install --user --upgrade pip || true pip3 -q install --user --upgrade pip || true
fi fi
echo "Install node (LTS)"
if [[ "${TRAVIS_OS_NAME}" == osx ]] || [ ! -f ~/.nvm/nvm.sh ]; then
curl -o ~/.nvm/nvm.sh https://raw.githubusercontent.com/creationix/nvm/master/nvm.sh
fi
source ~/.nvm/nvm.sh
nvm install --lts
nvm use --lts

View File

@@ -1,62 +0,0 @@
:: These are native MinGW builds, but they use the toolchain inside
:: MSYS2, this allows using all the dependencies and tools available
:: in MSYS2, but we cannot build inside the MSYS2 shell.
echo on
if "%CONFIGURATION%" == "MINGW_32" (
set ARCH=i686
set BITS=32
) else (
set ARCH=x86_64
set BITS=64
)
if "%CONFIGURATION%" == "MINGW_64-gcov" (
set USE_GCOV="-DUSE_GCOV=ON"
)
:: We cannot have sh.exe in the PATH (MinGW)
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
set PATH=C:\msys64\mingw%BITS%\bin;C:\Windows\System32;C:\Windows;%PATH%
:: The default cpack in the PATH is not CMake
set PATH=C:\Program Files (x86)\CMake\bin\cpack.exe;%PATH%
:: Build third-party dependencies
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" || goto :error
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-%ARCH%-cmake mingw-w64-%ARCH%-perl mingw-w64-%ARCH%-diffutils mingw-w64-%ARCH%-unibilium gperf" || goto :error
:: Setup python (use AppVeyor system python)
C:\Python27\python.exe -m pip install neovim || goto :error
C:\Python35\python.exe -m pip install neovim || goto :error
:: Disambiguate python3
move c:\Python35\python.exe c:\Python35\python3.exe
set PATH=C:\Python35;C:\Python27;%PATH%
:: Sanity check
python -c "import neovim; print(str(neovim))" || goto :error
python3 -c "import neovim; print(str(neovim))" || goto :error
mkdir .deps
cd .deps
cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo ..\third-party\ || goto :error
mingw32-make VERBOSE=1 || goto :error
cd ..
:: Build Neovim
mkdir build
cd build
cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUSTED_OUTPUT_TYPE=nvim %USE_GCOV% -DGPERF_PRG="C:\msys64\usr\bin\gperf.exe" .. || goto :error
mingw32-make VERBOSE=1 || goto :error
bin\nvim --version || goto :error
:: Functional tests
mingw32-make functionaltest VERBOSE=1 || goto :error
if defined USE_GCOV (
C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) || echo 'codecov upload failed.'"
)
:: Build artifacts
cpack -G ZIP -C RelWithDebInfo
if defined APPVEYOR_REPO_TAG_NAME cpack -G NSIS -C RelWithDebInfo
goto :EOF
:error
exit /b %errorlevel%

128
ci/build.ps1 Normal file
View File

@@ -0,0 +1,128 @@
Set-PSDebug -Trace 1
$env:CONFIGURATION -match '^(?<compiler>\w+)_(?<bits>32|64)(?:-(?<option>\w+))?$'
$compiler = $Matches.compiler
$compileOption = $Matches.option
$bits = $Matches.bits
$cmakeBuildType = 'RelWithDebInfo'
$depsCmakeVars = @{
CMAKE_BUILD_TYPE = $cmakeBuildType;
}
$nvimCmakeVars = @{
CMAKE_BUILD_TYPE = $cmakeBuildType;
BUSTED_OUTPUT_TYPE = 'nvim';
}
# For pull requests, skip some build configurations to save time.
if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32)$') {
exit 0
}
function exitIfFailed() {
if ($LastExitCode -ne 0) {
exit $LastExitCode
}
}
if ($compiler -eq 'MINGW') {
if ($bits -eq 32) {
$arch = 'i686'
}
elseif ($bits -eq 64) {
$arch = 'x86_64'
}
if ($compileOption -eq 'gcov') {
$nvimCmakeVars['USE_GCOV'] = 'ON'
$uploadToCodecov = $true
}
# These are native MinGW builds, but they use the toolchain inside
# MSYS2, this allows using all the dependencies and tools available
# in MSYS2, but we cannot build inside the MSYS2 shell.
$cmakeGenerator = 'MinGW Makefiles'
$cmakeGeneratorArgs = 'VERBOSE=1'
# Add MinGW to the PATH
$env:PATH = "C:\msys64\mingw$bits\bin;$env:PATH"
# Build third-party dependencies
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" ; exitIfFailed
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-$arch-cmake mingw-w64-$arch-perl mingw-w64-$arch-diffutils mingw-w64-$arch-unibilium" ; exitIfFailed
}
elseif ($compiler -eq 'MSVC') {
$cmakeGeneratorArgs = '/verbosity:normal'
if ($bits -eq 32) {
$cmakeGenerator = 'Visual Studio 15 2017'
}
elseif ($bits -eq 64) {
$cmakeGenerator = 'Visual Studio 15 2017 Win64'
}
}
# Remove Git Unix utilities from the PATH
$env:PATH = $env:PATH.Replace('C:\Program Files\Git\usr\bin', '')
# Setup python (use AppVeyor system python)
C:\Python27\python.exe -m pip install neovim ; exitIfFailed
C:\Python35\python.exe -m pip install neovim ; exitIfFailed
# Disambiguate python3
move c:\Python35\python.exe c:\Python35\python3.exe
$env:PATH = "C:\Python35;C:\Python27;$env:PATH"
# Sanity check
python -c "import neovim; print(str(neovim))" ; exitIfFailed
python3 -c "import neovim; print(str(neovim))" ; exitIfFailed
$env:PATH = "C:\Ruby24\bin;$env:PATH"
cmd /c gem.cmd install neovim ; exitIfFailed
where.exe neovim-ruby-host.bat ; exitIfFailed
cmd /c npm.cmd install -g neovim ; exitIfFailed
where.exe neovim-node-host.cmd ; exitIfFailed
function convertToCmakeArgs($vars) {
return $vars.GetEnumerator() | foreach { "-D$($_.Key)=$($_.Value)" }
}
mkdir .deps
cd .deps
cmake -G $cmakeGenerator $(convertToCmakeArgs($depsCmakeVars)) ..\third-party\ ; exitIfFailed
cmake --build . --config $cmakeBuildType -- $cmakeGeneratorArgs ; exitIfFailed
cd ..
# Build Neovim
mkdir build
cd build
cmake -G $cmakeGenerator $(convertToCmakeArgs($nvimCmakeVars)) .. ; exitIfFailed
cmake --build . --config $cmakeBuildType -- $cmakeGeneratorArgs ; exitIfFailed
bin\nvim --version ; exitIfFailed
# Functional tests
# The $LastExitCode from MSBuild can't be trusted
$failed = $false
# Temporarily turn off tracing to reduce log file output
Set-PSDebug -Off
cmake --build . --config $cmakeBuildType --target functionaltest -- $cmakeGeneratorArgs |
foreach { $failed = $failed -or
$_ -match 'Running functional tests failed with error'; $_ }
Set-PSDebug -Trace 1
if ($failed) {
exit $LastExitCode
}
if ($uploadToCodecov) {
C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F functionaltest || echo 'codecov upload failed.'"
}
# Old tests
$env:PATH += ';C:\msys64\usr\bin'
& "C:\msys64\mingw$bits\bin\mingw32-make.exe" -C $(Convert-Path ..\src\nvim\testdir) VERBOSE=1
if ($uploadToCodecov) {
C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F oldtest || echo 'codecov upload failed.'"
}
# Build artifacts
cpack -G ZIP -C RelWithDebInfo
if ($env:APPVEYOR_REPO_TAG_NAME -ne $null) {
cpack -G NSIS -C RelWithDebInfo
}

View File

@@ -1,5 +1,16 @@
_stat() {
if test "${TRAVIS_OS_NAME}" = osx ; then
stat -f %Sm "${@}"
else
stat -c %y "${@}"
fi
}
top_make() { top_make() {
${MAKE_CMD} "$@" echo '================================================================================'
# Travis has 1.5 virtual cores according to:
# http://docs.travis-ci.com/user/speeding-up-the-build/#Paralellizing-your-build-on-one-VM
ninja "$@"
} }
build_make() { build_make() {
@@ -15,28 +26,21 @@ build_deps() {
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} -DUSE_BUNDLED_LUA=ON" DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} -DUSE_BUNDLED_LUA=ON"
fi fi
rm -rf "${DEPS_BUILD_DIR}" mkdir -p "${DEPS_BUILD_DIR}"
mkdir -p "${DEPS_DOWNLOAD_DIR}"
# If there is a valid cache and we're not forced to recompile, # Use cached dependencies if $CACHE_MARKER exists.
# use cached third-party dependencies. if test -f "${CACHE_MARKER}" && ! test "${CACHE_ENABLE}" = "false" ; then
if test -f "${CACHE_MARKER}" && test "${BUILD_NVIM_DEPS}" != "true" ; then echo "Using third-party dependencies from Travis cache (last update: $(_stat "${CACHE_MARKER}"))."
local statcmd="stat -c '%y'" cp -r "${HOME}/.cache/nvim-deps" "${DEPS_BUILD_DIR}"
if test "${TRAVIS_OS_NAME}" = osx ; then cp -r "${HOME}/.cache/nvim-deps-downloads" "${DEPS_DOWNLOAD_DIR}"
statcmd="stat -f '%Sm'"
fi
echo "Using third-party dependencies from Travis's cache (last updated: $(${statcmd} "${CACHE_MARKER}"))."
mkdir -p "$(dirname "${DEPS_BUILD_DIR}")"
mv "${HOME}/.cache/nvim-deps" "${DEPS_BUILD_DIR}"
else
mkdir -p "${DEPS_BUILD_DIR}"
fi fi
# Even if we're using cached dependencies, run CMake and make to # Even if we're using cached dependencies, run CMake and make to
# update CMake configuration and update to newer deps versions. # update CMake configuration and update to newer deps versions.
cd "${DEPS_BUILD_DIR}" cd "${DEPS_BUILD_DIR}"
echo "Configuring with '${DEPS_CMAKE_FLAGS}'." echo "Configuring with '${DEPS_CMAKE_FLAGS}'."
CC= cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/" CC= cmake -G Ninja ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/"
if ! top_make; then if ! top_make; then
exit 1 exit 1
@@ -56,7 +60,7 @@ prepare_build() {
mkdir -p "${BUILD_DIR}" mkdir -p "${BUILD_DIR}"
cd "${BUILD_DIR}" cd "${BUILD_DIR}"
echo "Configuring with '${CMAKE_FLAGS} $@'." echo "Configuring with '${CMAKE_FLAGS} $@'."
cmake ${CMAKE_FLAGS} "$@" "${TRAVIS_BUILD_DIR}" cmake -G Ninja ${CMAKE_FLAGS} "$@" "${TRAVIS_BUILD_DIR}"
} }
build_nvim() { build_nvim() {
@@ -71,9 +75,11 @@ build_nvim() {
exit 1 exit 1
fi fi
echo "Building nvim-test." if test "${FUNCTIONALTEST}" != "functionaltest-lua"; then
if ! top_make nvim-test ; then echo "Building nvim-test."
exit 1 if ! top_make nvim-test ; then
exit 1
fi
fi fi
fi fi
@@ -87,3 +93,12 @@ build_nvim() {
cd "${TRAVIS_BUILD_DIR}" cd "${TRAVIS_BUILD_DIR}"
} }
macos_rvm_dance() {
# neovim-ruby gem requires a ruby newer than the macOS default.
source ~/.rvm/scripts/rvm
rvm get stable --auto-dotfiles
rvm reload
rvm use 2.2.5
rvm use
}

View File

@@ -1,6 +1,15 @@
. "${CI_DIR}/common/build.sh" . "${CI_DIR}/common/build.sh"
. "${CI_DIR}/common/suite.sh" . "${CI_DIR}/common/suite.sh"
submit_coverage() {
if [ -n "${GCOV}" ]; then
if curl --fail --output codecov.bash --silent https://codecov.io/bash; then
bash codecov.bash -c -F "$1" || echo "codecov upload failed."
rm -f codecov.bash
fi
fi
}
print_core() { print_core() {
local app="$1" local app="$1"
local core="$2" local core="$2"
@@ -71,7 +80,9 @@ valgrind_check() {
} }
asan_check() { asan_check() {
check_logs "${1}" "*san.*" if test "${CLANG_SANITIZER}" = "ASAN_UBSAN" ; then
check_logs "${1}" "*san.*" | asan_symbolize
fi
} }
run_unittests() {( run_unittests() {(
@@ -80,6 +91,7 @@ run_unittests() {(
if ! build_make unittest ; then if ! build_make unittest ; then
fail 'unittests' F 'Unit tests failed' fail 'unittests' F 'Unit tests failed'
fi fi
submit_coverage unittest
check_core_dumps "$(which luajit)" check_core_dumps "$(which luajit)"
exit_suite exit_suite
)} )}
@@ -90,6 +102,7 @@ run_functionaltests() {(
if ! build_make ${FUNCTIONALTEST}; then if ! build_make ${FUNCTIONALTEST}; then
fail 'functionaltests' F 'Functional tests failed' fail 'functionaltests' F 'Functional tests failed'
fi fi
submit_coverage functionaltest
asan_check "${LOG_DIR}" asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}" valgrind_check "${LOG_DIR}"
check_core_dumps check_core_dumps
@@ -103,6 +116,7 @@ run_oldtests() {(
reset reset
fail 'oldtests' F 'Legacy tests failed' fail 'oldtests' F 'Legacy tests failed'
fi fi
submit_coverage oldtest
asan_check "${LOG_DIR}" asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}" valgrind_check "${LOG_DIR}"
check_core_dumps check_core_dumps

View File

@@ -8,18 +8,26 @@ if [[ "${CI_TARGET}" == lint ]]; then
fi fi
if [[ "${TRAVIS_OS_NAME}" == osx ]]; then if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
brew install ninja
brew install gettext brew install gettext
brew reinstall -s libtool brew reinstall -s libtool
fi fi
# Use default CC to avoid compilation problems when installing Python modules.
echo "Install neovim module and coveralls for Python 2."
CC=cc pip2.7 -q install --user --upgrade neovim cpp-coveralls
echo "Install neovim module for Python 3." echo "Install neovim module for Python 3."
# Allow failure. pyenv pip3 on travis is broken: # Allow failure. pyenv pip3 on travis is broken:
# https://github.com/travis-ci/travis-ci/issues/8363 # https://github.com/travis-ci/travis-ci/issues/8363
CC=cc pip3 -q install --user --upgrade neovim || true CC=cc pip3 -q install --user --upgrade neovim || true
echo "Install neovim RubyGem." if ! [ "${TRAVIS_OS_NAME}" = osx ] ; then
gem install --no-document --version ">= 0.2.0" neovim # Update PATH for pip.
export PATH="$(python2.7 -c 'import site; print(site.getuserbase())')/bin:$PATH"
# Use default CC to avoid compilation problems when installing Python modules.
echo "Install neovim module for Python 2."
CC=cc pip2.7 -q install --user --upgrade neovim
echo "Install neovim RubyGem."
gem install --no-document --version ">= 0.2.0" neovim
fi
echo "Install neovim npm package"
npm install -g neovim

View File

@@ -10,19 +10,19 @@ source "${CI_DIR}/common/suite.sh"
enter_suite 'clint' enter_suite 'clint'
run_test 'top_make clint-full' clint run_test 'make clint-full' clint
exit_suite --continue exit_suite --continue
enter_suite 'testlint' enter_suite 'testlint'
run_test 'top_make testlint' testlint run_test 'make testlint' testlint
exit_suite --continue exit_suite --continue
enter_suite 'lualint' enter_suite 'lualint'
run_test 'top_make lualint' lualint run_test 'make lualint' lualint
exit_suite --continue exit_suite --continue
@@ -31,7 +31,7 @@ enter_suite single-includes
CLICOLOR_FORCE=1 run_test_wd \ CLICOLOR_FORCE=1 run_test_wd \
--allow-hang \ --allow-hang \
10s \ 10s \
'top_make check-single-includes' \ 'make check-single-includes' \
'csi_clean' \ 'csi_clean' \
single-includes single-includes

View File

@@ -22,7 +22,9 @@ enter_suite tests
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
run_test run_unittests if test "${FUNCTIONALTEST}" != "functionaltest-lua"; then
run_test run_unittests
fi
run_test run_functionaltests run_test run_functionaltests
fi fi
run_test run_oldtests run_test run_oldtests

View File

@@ -27,7 +27,7 @@ find_path(LibIntl_INCLUDE_DIR
) )
find_library(LibIntl_LIBRARY find_library(LibIntl_LIBRARY
NAMES intl libintl.a NAMES intl libintl
) )
if (LibIntl_INCLUDE_DIR) if (LibIntl_INCLUDE_DIR)

View File

@@ -44,7 +44,7 @@ endif()
if(MSVC) if(MSVC)
# The import library for the msgpack DLL has a different name # The import library for the msgpack DLL has a different name
list(APPEND MSGPACK_NAMES msgpack_import) list(APPEND MSGPACK_NAMES msgpackc_import)
else() else()
list(APPEND MSGPACK_NAMES msgpackc msgpack) list(APPEND MSGPACK_NAMES msgpackc msgpack)
endif() endif()

View File

@@ -38,6 +38,7 @@ function(get_compile_flags _compile_flags)
get_directory_property(include_directories_list get_directory_property(include_directories_list
DIRECTORY "src/nvim" DIRECTORY "src/nvim"
INCLUDE_DIRECTORIES) INCLUDE_DIRECTORIES)
list(REMOVE_DUPLICATES include_directories_list)
foreach(include_directory ${include_directories_list}) foreach(include_directory ${include_directories_list})
set(include_directories "${include_directories} -I${include_directory}") set(include_directories "${include_directories} -I${include_directory}")
endforeach() endforeach()

View File

@@ -4,9 +4,8 @@
# Check if a module is available in Lua # Check if a module is available in Lua
function(check_lua_module LUA_PRG_PATH MODULE RESULT_VAR) function(check_lua_module LUA_PRG_PATH MODULE RESULT_VAR)
execute_process(COMMAND ${LUA_PRG_PATH} -e "require('${MODULE}')" execute_process(COMMAND ${LUA_PRG_PATH} -l "${MODULE}" -e ""
RESULT_VARIABLE module_missing RESULT_VARIABLE module_missing)
ERROR_QUIET)
if(module_missing) if(module_missing)
set(${RESULT_VAR} False PARENT_SCOPE) set(${RESULT_VAR} False PARENT_SCOPE)
else() else()

View File

@@ -38,7 +38,7 @@ set(ENV{SYSTEM_NAME} ${SYSTEM_NAME})
execute_process( execute_process(
COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE} COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE}
--lua=${LUA_PRG} --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua --lua=${LUA_PRG} --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
--lpath=${BUILD_DIR}/?.lua ${TEST_PATH} --lpath=${BUILD_DIR}/?.lua --lpath=?.lua ${TEST_PATH}
WORKING_DIRECTORY ${WORKING_DIR} WORKING_DIRECTORY ${WORKING_DIR}
ERROR_VARIABLE err ERROR_VARIABLE err
RESULT_VARIABLE res RESULT_VARIABLE res

View File

@@ -1,6 +1,6 @@
codecov: codecov:
notify: notify:
require_ci_to_pass: yes require_ci_to_pass: no
ci: ci:
- appveyor - appveyor
- travis - travis

View File

@@ -12,6 +12,11 @@ check_type_size("size_t" SIZEOF_SIZE_T)
check_type_size("long long" SIZEOF_LONG_LONG) check_type_size("long long" SIZEOF_LONG_LONG)
check_type_size("void *" SIZEOF_VOID_PTR) check_type_size("void *" SIZEOF_VOID_PTR)
if (CMAKE_HOST_SYSTEM_VERSION MATCHES ".*-Microsoft")
# Windows Subsystem for Linux
set(HAVE_WSL 1)
endif()
check_symbol_exists(_NSGetEnviron crt_externs.h HAVE__NSGETENVIRON) check_symbol_exists(_NSGetEnviron crt_externs.h HAVE__NSGETENVIRON)
# Headers # Headers

View File

@@ -48,6 +48,7 @@
#cmakedefine HAVE_UTIME_H #cmakedefine HAVE_UTIME_H
#cmakedefine HAVE_UTIMES #cmakedefine HAVE_UTIMES
#cmakedefine HAVE_WORKING_LIBINTL #cmakedefine HAVE_WORKING_LIBINTL
#cmakedefine HAVE_WSL
#cmakedefine UNIX #cmakedefine UNIX
#cmakedefine USE_FNAME_CASE #cmakedefine USE_FNAME_CASE
#cmakedefine HAVE_SYS_UIO_H #cmakedefine HAVE_SYS_UIO_H
@@ -62,6 +63,7 @@
#ifndef UNIT_TESTING #ifndef UNIT_TESTING
#cmakedefine HAVE_JEMALLOC #cmakedefine HAVE_JEMALLOC
#cmakedefine LOG_LIST_ACTIONS
#endif #endif
#cmakedefine HAVE_BE64TOH #cmakedefine HAVE_BE64TOH

View File

@@ -25,7 +25,7 @@ To enter commands in
type a colon type a colon
.Pq Sq \&: .Pq Sq \&:
which is also used in this manual to denote commands. which is also used in this manual to denote commands.
For more information, consult the on-line help system with the For more information, consult the online help system with the
.Ic :help .Ic :help
command. command.
.Bl -tag -width Fl .Bl -tag -width Fl
@@ -329,6 +329,8 @@ Implies
.Fl -headless . .Fl -headless .
.It Fl -headless .It Fl -headless
Do not start a user interface. Do not start a user interface.
.It Fl -listen Ar address
Start RPC server on this pipe or TCP socket.
.It Fl h , -help .It Fl h , -help
Print usage information and exit. Print usage information and exit.
.It Fl v , -version .It Fl v , -version
@@ -337,12 +339,12 @@ Print version information and exit.
.Sh ENVIRONMENT .Sh ENVIRONMENT
.Bl -tag -width Fl .Bl -tag -width Fl
.It Ev VIM .It Ev VIM
Used to locate various user files, such as the user's init.vim. Used to locate various user files, such as init.vim.
.It Ev VIMRUNTIME .It Ev VIMRUNTIME
Used to locate run time files, such as on-line documentation and Used to locate runtime files, such as online documentation and
syntax highlighting definitions. syntax highlighting definitions.
.It Ev XDG_CONFIG_HOME .It Ev XDG_CONFIG_HOME
Path to use for the user-local configuration directory, see Path to the user-local configuration directory, see
.Sx FILES . .Sx FILES .
Defaults to Defaults to
.Pa ~/.config .Pa ~/.config
@@ -356,7 +358,7 @@ Defaults to
.Pa ~/.local/share .Pa ~/.local/share
if not set. if not set.
.It Ev VIMINIT .It Ev VIMINIT
A string of Ex commands to be executed at startup. Ex commands to be executed at startup.
For example, the command to quit is For example, the command to quit is
.Ic :q , .Ic :q ,
so to have so to have
@@ -375,41 +377,32 @@ command.
.Sh FILES .Sh FILES
.Bl -tag -width "~/.config/nvim/init.vim" .Bl -tag -width "~/.config/nvim/init.vim"
.It Pa ~/.config/nvim/init.vim .It Pa ~/.config/nvim/init.vim
The user-local User-local
.Nm .Nm
configuration file. configuration file.
See
.Ev XDG_CONFIG_HOME
above.
.It Pa ~/.config/nvim .It Pa ~/.config/nvim
The user-local User-local
.Nm .Nm
configuration directory. configuration directory.
See See also
.Ev XDG_CONFIG_HOME .Ev XDG_CONFIG_HOME .
above.
.It Pa $VIM/sysinit.vim .It Pa $VIM/sysinit.vim
The system-global System-global
.Nm .Nm
configuration file. configuration file.
.It Pa /usr/local/share/nvim .It Pa /usr/local/share/nvim
The system-global System-global
.Nm .Nm
runtime directory. runtime directory.
.El .El
.Sh AUTHORS .Sh AUTHORS
.Nm Nvim was started by
was started by .An Thiago de Arruda .
.An Thiago de Arruda ,
with a lot of help from others.
.Pp
Most of Vim was written by Most of Vim was written by
.An -nosplit .An -nosplit
.An Bram Moolenaar , .An Bram Moolenaar .
with a lot of help from others.
See See
.Ic :help credits . .Ic :help credits .
.Pp
Vim is based on Stevie, worked on by Vim is based on Stevie, worked on by
.An Tim Thompson , .An Tim Thompson ,
.An Tony Andrews , .An Tony Andrews ,

View File

@@ -42,6 +42,7 @@ foreach(PACKAGE ${PACKAGES})
nvim nvim
WORKING_DIRECTORY "${GENERATED_PACKAGE_DIR}/${PACKNAME}" WORKING_DIRECTORY "${GENERATED_PACKAGE_DIR}/${PACKNAME}"
) )
add_dependencies(${PACKNAME}-tags nvim_runtime_deps)
add_custom_command(OUTPUT "${GENERATED_PACKAGE_DIR}/${PACKNAME}/doc/tags" add_custom_command(OUTPUT "${GENERATED_PACKAGE_DIR}/${PACKNAME}/doc/tags"
DEPENDS DEPENDS
@@ -71,7 +72,7 @@ foreach(DF ${DOCFILES})
endforeach() endforeach()
add_custom_target(helptags add_custom_target(helptags
COMMAND ${CMAKE_COMMAND} -E remove_directory ${GENERATED_RUNTIME_DIR}/doc COMMAND ${CMAKE_COMMAND} -E remove ${GENERATED_RUNTIME_DIR}/doc/*
COMMAND ${CMAKE_COMMAND} -E copy_directory COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc ${PROJECT_SOURCE_DIR}/runtime/doc ${GENERATED_RUNTIME_DIR}/doc
COMMAND "${PROJECT_BINARY_DIR}/bin/nvim" COMMAND "${PROJECT_BINARY_DIR}/bin/nvim"
@@ -80,6 +81,7 @@ add_custom_target(helptags
nvim nvim
WORKING_DIRECTORY "${GENERATED_RUNTIME_DIR}" WORKING_DIRECTORY "${GENERATED_RUNTIME_DIR}"
) )
add_dependencies(helptags nvim_runtime_deps)
add_custom_command(OUTPUT ${GENERATED_HELP_TAGS} add_custom_command(OUTPUT ${GENERATED_HELP_TAGS}
DEPENDS DEPENDS
@@ -138,7 +140,7 @@ endforeach()
file(GLOB_RECURSE RUNTIME_FILES file(GLOB_RECURSE RUNTIME_FILES
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
rgb.txt rgb.txt
*.vim *.dict *.py *.rb *.ps *.tutor) *.vim *.lua *.dict *.py *.rb *.ps *.spl *.tutor *.tutor.json)
foreach(F ${RUNTIME_FILES}) foreach(F ${RUNTIME_FILES})
get_filename_component(BASEDIR ${F} PATH) get_filename_component(BASEDIR ${F} PATH)

741
runtime/autoload/dist/ft.vim vendored Normal file
View File

@@ -0,0 +1,741 @@
" Vim functions for file type detection
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2017 Nov 11
" These functions are moved here from runtime/filetype.vim to make startup
" faster.
" Line continuation is used here, remove 'C' from 'cpoptions'
let s:cpo_save = &cpo
set cpo&vim
func dist#ft#Check_inp()
if getline(1) =~ '^\*'
setf abaqus
else
let n = 1
if line("$") > 500
let nmax = 500
else
let nmax = line("$")
endif
while n <= nmax
if getline(n) =~? "^header surface data"
setf trasys
break
endif
let n = n + 1
endwhile
endif
endfunc
" This function checks for the kind of assembly that is wanted by the user, or
" can be detected from the first five lines of the file.
func dist#ft#FTasm()
" make sure b:asmsyntax exists
if !exists("b:asmsyntax")
let b:asmsyntax = ""
endif
if b:asmsyntax == ""
call dist#ft#FTasmsyntax()
endif
" if b:asmsyntax still isn't set, default to asmsyntax or GNU
if b:asmsyntax == ""
if exists("g:asmsyntax")
let b:asmsyntax = g:asmsyntax
else
let b:asmsyntax = "asm"
endif
endif
exe "setf " . fnameescape(b:asmsyntax)
endfunc
func dist#ft#FTasmsyntax()
" see if file contains any asmsyntax=foo overrides. If so, change
" b:asmsyntax appropriately
let head = " ".getline(1)." ".getline(2)." ".getline(3)." ".getline(4).
\" ".getline(5)." "
let match = matchstr(head, '\sasmsyntax=\zs[a-zA-Z0-9]\+\ze\s')
if match != ''
let b:asmsyntax = match
elseif ((head =~? '\.title') || (head =~? '\.ident') || (head =~? '\.macro') || (head =~? '\.subtitle') || (head =~? '\.library'))
let b:asmsyntax = "vmasm"
endif
endfunc
" Check if one of the first five lines contains "VB_Name". In that case it is
" probably a Visual Basic file. Otherwise it's assumed to be "alt" filetype.
func dist#ft#FTVB(alt)
if getline(1).getline(2).getline(3).getline(4).getline(5) =~? 'VB_Name\|Begin VB\.\(Form\|MDIForm\|UserControl\)'
setf vb
else
exe "setf " . a:alt
endif
endfunc
func dist#ft#FTbtm()
if exists("g:dosbatch_syntax_for_btm") && g:dosbatch_syntax_for_btm
setf dosbatch
else
setf btm
endif
endfunc
func dist#ft#BindzoneCheck(default)
if getline(1).getline(2).getline(3).getline(4) =~ '^; <<>> DiG [0-9.]\+.* <<>>\|$ORIGIN\|$TTL\|IN\s\+SOA'
setf bindzone
elseif a:default != ''
exe 'setf ' . a:default
endif
endfunc
func dist#ft#FTlpc()
if exists("g:lpc_syntax_for_c")
let lnum = 1
while lnum <= 12
if getline(lnum) =~# '^\(//\|inherit\|private\|protected\|nosave\|string\|object\|mapping\|mixed\)'
setf lpc
return
endif
let lnum = lnum + 1
endwhile
endif
setf c
endfunc
func dist#ft#FTheader()
if match(getline(1, min([line("$"), 200])), '^@\(interface\|end\|class\)') > -1
if exists("g:c_syntax_for_h")
setf objc
else
setf objcpp
endif
elseif exists("g:c_syntax_for_h")
setf c
elseif exists("g:ch_syntax_for_h")
setf ch
else
setf cpp
endif
endfunc
" This function checks if one of the first ten lines start with a '@'. In
" that case it is probably a change file.
" If the first line starts with # or ! it's probably a ch file.
" If a line has "main", "include", "//" ir "/*" it's probably ch.
" Otherwise CHILL is assumed.
func dist#ft#FTchange()
let lnum = 1
while lnum <= 10
if getline(lnum)[0] == '@'
setf change
return
endif
if lnum == 1 && (getline(1)[0] == '#' || getline(1)[0] == '!')
setf ch
return
endif
if getline(lnum) =~ "MODULE"
setf chill
return
endif
if getline(lnum) =~ 'main\s*(\|#\s*include\|//'
setf ch
return
endif
let lnum = lnum + 1
endwhile
setf chill
endfunc
func dist#ft#FTent()
" This function checks for valid cl syntax in the first five lines.
" Look for either an opening comment, '#', or a block start, '{".
" If not found, assume SGML.
let lnum = 1
while lnum < 6
let line = getline(lnum)
if line =~ '^\s*[#{]'
setf cl
return
elseif line !~ '^\s*$'
" Not a blank line, not a comment, and not a block start,
" so doesn't look like valid cl code.
break
endif
let lnum = lnum + 1
endw
setf dtd
endfunc
func dist#ft#EuphoriaCheck()
if exists('g:filetype_euphoria')
exe 'setf ' . g:filetype_euphoria
else
setf euphoria3
endif
endfunc
func dist#ft#DtraceCheck()
let lines = getline(1, min([line("$"), 100]))
if match(lines, '^module\>\|^import\>') > -1
" D files often start with a module and/or import statement.
setf d
elseif match(lines, '^#!\S\+dtrace\|#pragma\s\+D\s\+option\|:\S\{-}:\S\{-}:') > -1
setf dtrace
else
setf d
endif
endfunc
func dist#ft#FTe()
if exists('g:filetype_euphoria')
exe 'setf ' . g:filetype_euphoria
else
let n = 1
while n < 100 && n < line("$")
if getline(n) =~ "^\\s*\\(<'\\|'>\\)\\s*$"
setf specman
return
endif
let n = n + 1
endwhile
setf eiffel
endif
endfunc
" Distinguish between HTML, XHTML and Django
func dist#ft#FThtml()
let n = 1
while n < 10 && n < line("$")
if getline(n) =~ '\<DTD\s\+XHTML\s'
setf xhtml
return
endif
if getline(n) =~ '{%\s*\(extends\|block\|load\)\>\|{#\s\+'
setf htmldjango
return
endif
let n = n + 1
endwhile
setf html
endfunc
" Distinguish between standard IDL and MS-IDL
func dist#ft#FTidl()
let n = 1
while n < 50 && n < line("$")
if getline(n) =~ '^\s*import\s\+"\(unknwn\|objidl\)\.idl"'
setf msidl
return
endif
let n = n + 1
endwhile
setf idl
endfunc
" Distinguish between "default" and Cproto prototype file. */
func dist#ft#ProtoCheck(default)
" Cproto files have a comment in the first line and a function prototype in
" the second line, it always ends in ";". Indent files may also have
" comments, thus we can't match comments to see the difference.
" IDL files can have a single ';' in the second line, require at least one
" chacter before the ';'.
if getline(2) =~ '.;$'
setf cpp
else
exe 'setf ' . a:default
endif
endfunc
func dist#ft#FTm()
let n = 1
let saw_comment = 0 " Whether we've seen a multiline comment leader.
while n < 100
let line = getline(n)
if line =~ '^\s*/\*'
" /* ... */ is a comment in Objective C and Murphi, so we can't conclude
" it's either of them yet, but track this as a hint in case we don't see
" anything more definitive.
let saw_comment = 1
endif
if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|//\)'
setf objc
return
endif
if line =~ '^\s*%'
setf matlab
return
endif
if line =~ '^\s*(\*'
setf mma
return
endif
if line =~ '^\c\s*\(\(type\|var\)\>\|--\)'
setf murphi
return
endif
let n = n + 1
endwhile
if saw_comment
" We didn't see anything definitive, but this looks like either Objective C
" or Murphi based on the comment leader. Assume the former as it is more
" common.
setf objc
elseif exists("g:filetype_m")
" Use user specified default filetype for .m
exe "setf " . g:filetype_m
else
" Default is matlab
setf matlab
endif
endfunc
func dist#ft#FTmms()
let n = 1
while n < 10
let line = getline(n)
if line =~ '^\s*\(%\|//\)' || line =~ '^\*'
setf mmix
return
endif
if line =~ '^\s*#'
setf make
return
endif
let n = n + 1
endwhile
setf mmix
endfunc
" This function checks if one of the first five lines start with a dot. In
" that case it is probably an nroff file: 'filetype' is set and 1 is returned.
func dist#ft#FTnroff()
if getline(1)[0] . getline(2)[0] . getline(3)[0] . getline(4)[0] . getline(5)[0] =~ '\.'
setf nroff
return 1
endif
return 0
endfunc
func dist#ft#FTmm()
let n = 1
while n < 10
let line = getline(n)
if line =~ '^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)'
setf objcpp
return
endif
let n = n + 1
endwhile
setf nroff
endfunc
func dist#ft#FTpl()
if exists("g:filetype_pl")
exe "setf " . g:filetype_pl
else
" recognize Prolog by specific text in the first non-empty line
" require a blank after the '%' because Perl uses "%list" and "%translate"
let l = getline(nextnonblank(1))
if l =~ '\<prolog\>' || l =~ '^\s*\(%\+\(\s\|$\)\|/\*\)' || l =~ ':-'
setf prolog
else
setf perl
endif
endif
endfunc
func dist#ft#FTinc()
if exists("g:filetype_inc")
exe "setf " . g:filetype_inc
else
let lines = getline(1).getline(2).getline(3)
if lines =~? "perlscript"
setf aspperl
elseif lines =~ "<%"
setf aspvbs
elseif lines =~ "<?"
setf php
else
call dist#ft#FTasmsyntax()
if exists("b:asmsyntax")
exe "setf " . fnameescape(b:asmsyntax)
else
setf pov
endif
endif
endif
endfunc
func dist#ft#FTprogress_cweb()
if exists("g:filetype_w")
exe "setf " . g:filetype_w
return
endif
if getline(1) =~ '&ANALYZE' || getline(3) =~ '&GLOBAL-DEFINE'
setf progress
else
setf cweb
endif
endfunc
func dist#ft#FTprogress_asm()
if exists("g:filetype_i")
exe "setf " . g:filetype_i
return
endif
" This function checks for an assembly comment the first ten lines.
" If not found, assume Progress.
let lnum = 1
while lnum <= 10 && lnum < line('$')
let line = getline(lnum)
if line =~ '^\s*;' || line =~ '^\*'
call dist#ft#FTasm()
return
elseif line !~ '^\s*$' || line =~ '^/\*'
" Not an empty line: Doesn't look like valid assembly code.
" Or it looks like a Progress /* comment
break
endif
let lnum = lnum + 1
endw
setf progress
endfunc
func dist#ft#FTprogress_pascal()
if exists("g:filetype_p")
exe "setf " . g:filetype_p
return
endif
" This function checks for valid Pascal syntax in the first ten lines.
" Look for either an opening comment or a program start.
" If not found, assume Progress.
let lnum = 1
while lnum <= 10 && lnum < line('$')
let line = getline(lnum)
if line =~ '^\s*\(program\|unit\|procedure\|function\|const\|type\|var\)\>'
\ || line =~ '^\s*{' || line =~ '^\s*(\*'
setf pascal
return
elseif line !~ '^\s*$' || line =~ '^/\*'
" Not an empty line: Doesn't look like valid Pascal code.
" Or it looks like a Progress /* comment
break
endif
let lnum = lnum + 1
endw
setf progress
endfunc
func dist#ft#FTr()
let max = line("$") > 50 ? 50 : line("$")
for n in range(1, max)
" Rebol is easy to recognize, check for that first
if getline(n) =~? '\<REBOL\>'
setf rebol
return
endif
endfor
for n in range(1, max)
" R has # comments
if getline(n) =~ '^\s*#'
setf r
return
endif
" Rexx has /* comments */
if getline(n) =~ '^\s*/\*'
setf rexx
return
endif
endfor
" Nothing recognized, use user default or assume Rexx
if exists("g:filetype_r")
exe "setf " . g:filetype_r
else
" Rexx used to be the default, but R appears to be much more popular.
setf r
endif
endfunc
func dist#ft#McSetf()
" Rely on the file to start with a comment.
" MS message text files use ';', Sendmail files use '#' or 'dnl'
for lnum in range(1, min([line("$"), 20]))
let line = getline(lnum)
if line =~ '^\s*\(#\|dnl\)'
setf m4 " Sendmail .mc file
return
elseif line =~ '^\s*;'
setf msmessages " MS Message text file
return
endif
endfor
setf m4 " Default: Sendmail .mc file
endfunc
" Called from filetype.vim and scripts.vim.
func dist#ft#SetFileTypeSH(name)
if expand("<amatch>") =~ g:ft_ignore_pat
return
endif
if a:name =~ '\<csh\>'
" Some .sh scripts contain #!/bin/csh.
call dist#ft#SetFileTypeShell("csh")
return
elseif a:name =~ '\<tcsh\>'
" Some .sh scripts contain #!/bin/tcsh.
call dist#ft#SetFileTypeShell("tcsh")
return
elseif a:name =~ '\<zsh\>'
" Some .sh scripts contain #!/bin/zsh.
call dist#ft#SetFileTypeShell("zsh")
return
elseif a:name =~ '\<ksh\>'
let b:is_kornshell = 1
if exists("b:is_bash")
unlet b:is_bash
endif
if exists("b:is_sh")
unlet b:is_sh
endif
elseif exists("g:bash_is_sh") || a:name =~ '\<bash\>' || a:name =~ '\<bash2\>'
let b:is_bash = 1
if exists("b:is_kornshell")
unlet b:is_kornshell
endif
if exists("b:is_sh")
unlet b:is_sh
endif
elseif a:name =~ '\<sh\>'
let b:is_sh = 1
if exists("b:is_kornshell")
unlet b:is_kornshell
endif
if exists("b:is_bash")
unlet b:is_bash
endif
endif
call dist#ft#SetFileTypeShell("sh")
endfunc
" For shell-like file types, check for an "exec" command hidden in a comment,
" as used for Tcl.
" Also called from scripts.vim, thus can't be local to this script.
func dist#ft#SetFileTypeShell(name)
if expand("<amatch>") =~ g:ft_ignore_pat
return
endif
let l = 2
while l < 20 && l < line("$") && getline(l) =~ '^\s*\(#\|$\)'
" Skip empty and comment lines.
let l = l + 1
endwhile
if l < line("$") && getline(l) =~ '\s*exec\s' && getline(l - 1) =~ '^\s*#.*\\$'
" Found an "exec" line after a comment with continuation
let n = substitute(getline(l),'\s*exec\s\+\([^ ]*/\)\=', '', '')
if n =~ '\<tclsh\|\<wish'
setf tcl
return
endif
endif
exe "setf " . a:name
endfunc
func dist#ft#CSH()
if exists("g:filetype_csh")
call dist#ft#SetFileTypeShell(g:filetype_csh)
elseif &shell =~ "tcsh"
call dist#ft#SetFileTypeShell("tcsh")
else
call dist#ft#SetFileTypeShell("csh")
endif
endfunc
let s:ft_rules_udev_rules_pattern = '^\s*\cudev_rules\s*=\s*"\([^"]\{-1,}\)/*".*'
func dist#ft#FTRules()
let path = expand('<amatch>:p')
if path =~ '^/\(etc/udev/\%(rules\.d/\)\=.*\.rules\|lib/udev/\%(rules\.d/\)\=.*\.rules\)$'
setf udevrules
return
endif
if path =~ '^/etc/ufw/'
setf conf " Better than hog
return
endif
if path =~ '^/\(etc\|usr/share\)/polkit-1/rules\.d'
setf javascript
return
endif
try
let config_lines = readfile('/etc/udev/udev.conf')
catch /^Vim\%((\a\+)\)\=:E484/
setf hog
return
endtry
let dir = expand('<amatch>:p:h')
for line in config_lines
if line =~ s:ft_rules_udev_rules_pattern
let udev_rules = substitute(line, s:ft_rules_udev_rules_pattern, '\1', "")
if dir == udev_rules
setf udevrules
endif
break
endif
endfor
setf hog
endfunc
func dist#ft#SQL()
if exists("g:filetype_sql")
exe "setf " . g:filetype_sql
else
setf sql
endif
endfunc
" If the file has an extension of 't' and is in a directory 't' or 'xt' then
" it is almost certainly a Perl test file.
" If the first line starts with '#' and contains 'perl' it's probably a Perl
" file.
" (Slow test) If a file contains a 'use' statement then it is almost certainly
" a Perl file.
func dist#ft#FTperl()
let dirname = expand("%:p:h:t")
if expand("%:e") == 't' && (dirname == 't' || dirname == 'xt')
setf perl
return 1
endif
if getline(1)[0] == '#' && getline(1) =~ 'perl'
setf perl
return 1
endif
if search('^use\s\s*\k', 'nc', 30)
setf perl
return 1
endif
return 0
endfunc
" Choose context, plaintex, or tex (LaTeX) based on these rules:
" 1. Check the first line of the file for "%&<format>".
" 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
" 3. Default to "latex" or to g:tex_flavor, can be set in user's vimrc.
func dist#ft#FTtex()
let firstline = getline(1)
if firstline =~ '^%&\s*\a\+'
let format = tolower(matchstr(firstline, '\a\+'))
let format = substitute(format, 'pdf', '', '')
if format == 'tex'
let format = 'latex'
elseif format == 'plaintex'
let format = 'plain'
endif
elseif expand('%') =~ 'tex/context/.*/.*.tex'
let format = 'context'
else
" Default value, may be changed later:
let format = exists("g:tex_flavor") ? g:tex_flavor : 'plain'
" Save position, go to the top of the file, find first non-comment line.
let save_cursor = getpos('.')
call cursor(1,1)
let firstNC = search('^\s*[^[:space:]%]', 'c', 1000)
if firstNC " Check the next thousand lines for a LaTeX or ConTeXt keyword.
let lpat = 'documentclass\>\|usepackage\>\|begin{\|newcommand\>\|renewcommand\>'
let cpat = 'start\a\+\|setup\a\+\|usemodule\|enablemode\|enableregime\|setvariables\|useencoding\|usesymbols\|stelle\a\+\|verwende\a\+\|stel\a\+\|gebruik\a\+\|usa\a\+\|imposta\a\+\|regle\a\+\|utilisemodule\>'
let kwline = search('^\s*\\\%(' . lpat . '\)\|^\s*\\\(' . cpat . '\)',
\ 'cnp', firstNC + 1000)
if kwline == 1 " lpat matched
let format = 'latex'
elseif kwline == 2 " cpat matched
let format = 'context'
endif " If neither matched, keep default set above.
" let lline = search('^\s*\\\%(' . lpat . '\)', 'cn', firstNC + 1000)
" let cline = search('^\s*\\\%(' . cpat . '\)', 'cn', firstNC + 1000)
" if cline > 0
" let format = 'context'
" endif
" if lline > 0 && (cline == 0 || cline > lline)
" let format = 'tex'
" endif
endif " firstNC
call setpos('.', save_cursor)
endif " firstline =~ '^%&\s*\a\+'
" Translation from formats to file types. TODO: add AMSTeX, RevTex, others?
if format == 'plain'
setf plaintex
elseif format == 'context'
setf context
else " probably LaTeX
setf tex
endif
return
endfunc
func dist#ft#FTxml()
let n = 1
while n < 100 && n < line("$")
let line = getline(n)
" DocBook 4 or DocBook 5.
let is_docbook4 = line =~ '<!DOCTYPE.*DocBook'
let is_docbook5 = line =~ ' xmlns="http://docbook.org/ns/docbook"'
if is_docbook4 || is_docbook5
let b:docbk_type = "xml"
if is_docbook5
let b:docbk_ver = 5
else
let b:docbk_ver = 4
endif
setf docbk
return
endif
if line =~ 'xmlns:xbl="http://www.mozilla.org/xbl"'
setf xbl
return
endif
let n += 1
endwhile
setf xml
endfunc
func dist#ft#FTy()
let n = 1
while n < 100 && n < line("$")
let line = getline(n)
if line =~ '^\s*%'
setf yacc
return
endif
if getline(n) =~ '^\s*\(#\|class\>\)' && getline(n) !~ '^\s*#\s*include'
setf racc
return
endif
let n = n + 1
endwhile
setf yacc
endfunc
func dist#ft#Redif()
let lnum = 1
while lnum <= 5 && lnum < line('$')
if getline(lnum) =~ "^\ctemplate-type:"
setf redif
return
endif
let lnum = lnum + 1
endwhile
endfunc
" Restore 'cpoptions'
let &cpo = s:cpo_save
unlet s:cpo_save

View File

@@ -93,27 +93,27 @@ function! s:help_to_link(s) abort
return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n ]+)', ':help |\1|', 'g') return substitute(a:s, '\v:h%[elp] ([^|][^"\r\n ]+)', ':help |\1|', 'g')
endfunction endfunction
" Format a message for a specific report item " Format a message for a specific report item.
" a:1: Optional advice (string or list)
function! s:format_report_message(status, msg, ...) abort " {{{ function! s:format_report_message(status, msg, ...) abort " {{{
let output = ' - ' . a:status . ': ' . s:indent_after_line1(a:msg, 4) let output = ' - ' . a:status . ': ' . s:indent_after_line1(a:msg, 4)
let advice = []
" Optional parameters " Optional parameters
if a:0 > 0 if a:0 > 0
let advice = type(a:1) == type("") ? [a:1] : a:1 let advice = type(a:1) == type('') ? [a:1] : a:1
if type(advice) != type([]) if type(advice) != type([])
throw "Expected String or List" throw 'a:1: expected String or List'
endif
" Report each suggestion
if !empty(advice)
let output .= "\n - ADVICE:"
for suggestion in advice
let output .= "\n - " . s:indent_after_line1(suggestion, 10)
endfor
endif endif
endif endif
" Report each suggestion
if len(advice) > 0
let output .= "\n - ADVICE:"
endif
for suggestion in advice
let output .= "\n - " . s:indent_after_line1(suggestion, 10)
endfor
return s:help_to_link(output) return s:help_to_link(output)
endfunction " }}} endfunction " }}}
@@ -128,6 +128,7 @@ function! health#report_ok(msg) abort " {{{
endfunction " }}} endfunction " }}}
" Reports a health warning. " Reports a health warning.
" a:1: Optional advice (string or list)
function! health#report_warn(msg, ...) abort " {{{ function! health#report_warn(msg, ...) abort " {{{
if a:0 > 0 if a:0 > 0
echo s:format_report_message('WARNING', a:msg, a:1) echo s:format_report_message('WARNING', a:msg, a:1)
@@ -137,6 +138,7 @@ function! health#report_warn(msg, ...) abort " {{{
endfunction " }}} endfunction " }}}
" Reports a failed healthcheck. " Reports a failed healthcheck.
" a:1: Optional advice (string or list)
function! health#report_error(msg, ...) abort " {{{ function! health#report_error(msg, ...) abort " {{{
if a:0 > 0 if a:0 > 0
echo s:format_report_message('ERROR', a:msg, a:1) echo s:format_report_message('ERROR', a:msg, a:1)

View File

@@ -7,12 +7,12 @@ function! s:check_config() abort
" If $VIM is empty we don't care. Else make sure it is valid. " If $VIM is empty we don't care. Else make sure it is valid.
if !empty($VIM) && !filereadable($VIM.'/runtime/doc/nvim.txt') if !empty($VIM) && !filereadable($VIM.'/runtime/doc/nvim.txt')
let ok = v:false let ok = v:false
call health#report_error("$VIM is invalid: ".$VIM) call health#report_error('$VIM is invalid: '.$VIM)
endif endif
if exists('$NVIM_TUI_ENABLE_CURSOR_SHAPE') if exists('$NVIM_TUI_ENABLE_CURSOR_SHAPE')
let ok = v:false let ok = v:false
call health#report_warn("$NVIM_TUI_ENABLE_CURSOR_SHAPE is ignored in Nvim 0.2+", call health#report_warn('$NVIM_TUI_ENABLE_CURSOR_SHAPE is ignored in Nvim 0.2+',
\ [ "Use the 'guicursor' option to configure cursor shape. :help 'guicursor'", \ [ "Use the 'guicursor' option to configure cursor shape. :help 'guicursor'",
\ 'https://github.com/neovim/neovim/wiki/Following-HEAD#20170402' ]) \ 'https://github.com/neovim/neovim/wiki/Following-HEAD#20170402' ])
endif endif
@@ -100,8 +100,8 @@ function! s:check_performance() abort
else else
call health#report_info(buildtype) call health#report_info(buildtype)
call health#report_warn( call health#report_warn(
\ "Non-optimized build-type. Nvim will be slower.", \ 'Non-optimized build-type. Nvim will be slower.',
\ ["Install a different Nvim package, or rebuild with `CMAKE_BUILD_TYPE=RelWithDebInfo`.", \ ['Install a different Nvim package, or rebuild with `CMAKE_BUILD_TYPE=RelWithDebInfo`.',
\ s:suggest_faq]) \ s:suggest_faq])
endif endif
endfunction endfunction
@@ -174,7 +174,7 @@ function! s:check_terminal() abort
\ .(empty(kbs_entry) ? '? (not found)' : kdch1_entry)) \ .(empty(kbs_entry) ? '? (not found)' : kdch1_entry))
endif endif
for env_var in ['XTERM_VERSION', 'VTE_VERSION', 'TERM_PROGRAM', 'COLORTERM', 'SSH_TTY'] for env_var in ['XTERM_VERSION', 'VTE_VERSION', 'TERM_PROGRAM', 'COLORTERM', 'SSH_TTY']
if !exists('$'.env_var) if exists('$'.env_var)
call health#report_info(printf("$%s='%s'", env_var, eval('$'.env_var))) call health#report_info(printf("$%s='%s'", env_var, eval('$'.env_var)))
endif endif
endfor endfor

View File

@@ -13,6 +13,12 @@ function! s:normalize_path(s) abort
return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g') return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g')
endfunction endfunction
" Returns TRUE if `cmd` exits with success, else FALSE.
function! s:cmd_ok(cmd) abort
call system(a:cmd)
return v:shell_error == 0
endfunction
" Simple version comparison. " Simple version comparison.
function! s:version_cmp(a, b) abort function! s:version_cmp(a, b) abort
let a = split(a:a, '\.', 0) let a = split(a:a, '\.', 0)
@@ -120,6 +126,13 @@ endfunction
function! s:check_clipboard() abort function! s:check_clipboard() abort
call health#report_start('Clipboard (optional)') call health#report_start('Clipboard (optional)')
if !empty($TMUX) && executable('tmux') && executable('pbpaste') && !s:cmd_ok('pbpaste')
let tmux_version = matchstr(system('tmux -V'), '\d\+\.\d\+')
call health#report_error('pbcopy does not work with tmux version: '.tmux_version,
\ ['Install tmux 2.6+. https://superuser.com/q/231130',
\ 'or use tmux with reattach-to-user-namespace. https://superuser.com/a/413233'])
endif
let clipboard_tool = provider#clipboard#Executable() let clipboard_tool = provider#clipboard#Executable()
if exists('g:clipboard') && empty(clipboard_tool) if exists('g:clipboard') && empty(clipboard_tool)
call health#report_error( call health#report_error(
@@ -247,20 +260,23 @@ function! s:check_python(version) abort
let python_multiple = [] let python_multiple = []
if exists(loaded_var) && !exists('*provider#'.pyname.'#Call') if exists(loaded_var) && !exists('*provider#'.pyname.'#Call')
call health#report_info('Disabled. '.loaded_var.'='.eval(loaded_var)) call health#report_info('Disabled ('.loaded_var.'='.eval(loaded_var).'). This might be due to some previous error.')
return
endif endif
if !empty(pyenv) if !empty(pyenv)
if empty(pyenv_root) if empty(pyenv_root)
call health#report_warn( call health#report_info(
\ 'pyenv was found, but $PYENV_ROOT is not set.', \ 'pyenv was found, but $PYENV_ROOT is not set. `pyenv root` will be used.'
\ ['Did you follow the final install instructions?', \ .' If you run into problems, try setting $PYENV_ROOT explicitly.'
\ 'If you use a shell "framework" like Prezto or Oh My Zsh, try without.',
\ 'Try a different shell (bash).']
\ ) \ )
let pyenv_root = s:trim(s:system([pyenv, 'root']))
endif
if !isdirectory(pyenv_root)
call health#report_error('Invalid pyenv root: '.pyenv_root)
else else
call health#report_ok(printf('pyenv found: "%s"', pyenv)) call health#report_info(printf('pyenv: %s', pyenv))
call health#report_info(printf('pyenv root: %s', pyenv_root))
endif endif
endif endif
@@ -272,9 +288,6 @@ function! s:check_python(version) abort
if empty(pyname) if empty(pyname)
call health#report_warn('No Python interpreter was found with the neovim ' call health#report_warn('No Python interpreter was found with the neovim '
\ . 'module. Using the first available for diagnostics.') \ . 'module. Using the first available for diagnostics.')
if !empty(pythonx_errs)
call health#report_warn(pythonx_errs)
endif
endif endif
if !empty(pyname) if !empty(pyname)
@@ -332,8 +345,8 @@ function! s:check_python(version) abort
endif endif
endif endif
if !empty(python_bin) if !empty(python_bin) && !exists('g:'.host_prog_var)
if empty(venv) && !empty(pyenv) && !exists('g:'.host_prog_var) if empty(venv) && !empty(pyenv)
\ && !empty(pyenv_root) && resolve(python_bin) !~# '^'.pyenv_root.'/' \ && !empty(pyenv_root) && resolve(python_bin) !~# '^'.pyenv_root.'/'
call health#report_warn('pyenv is not set up optimally.', [ call health#report_warn('pyenv is not set up optimally.', [
\ printf('Create a virtualenv specifically ' \ printf('Create a virtualenv specifically '
@@ -341,7 +354,7 @@ function! s:check_python(version) abort
\ . 'the need to install the Neovim Python module in each ' \ . 'the need to install the Neovim Python module in each '
\ . 'version/virtualenv.', host_prog_var) \ . 'version/virtualenv.', host_prog_var)
\ ]) \ ])
elseif !empty(venv) && exists('g:'.host_prog_var) elseif !empty(venv)
if !empty(pyenv_root) if !empty(pyenv_root)
let venv_root = pyenv_root let venv_root = pyenv_root
else else
@@ -366,27 +379,16 @@ function! s:check_python(version) abort
let python_bin = '' let python_bin = ''
endif endif
" Check if $VIRTUAL_ENV is active " Check if $VIRTUAL_ENV is valid.
let virtualenv_inactive = 0
if exists('$VIRTUAL_ENV') if exists('$VIRTUAL_ENV')
if !empty(pyenv) if !empty(pyname) && $VIRTUAL_ENV !=# matchstr(exepath(pyname), '^\V'.$VIRTUAL_ENV)
let pyenv_prefix = resolve(s:trim(s:system([pyenv, 'prefix']))) call health#report_warn(
if $VIRTUAL_ENV != pyenv_prefix \ '$VIRTUAL_ENV exists but appears to be inactive. '
let virtualenv_inactive = 1 \ . 'This could lead to unexpected results.',
endif \ [ 'If you are using Zsh, see: http://vi.stackexchange.com/a/7654' ])
elseif !empty(pyname) && exepath(pyname) !~# '^'.$VIRTUAL_ENV.'/'
let virtualenv_inactive = 1
endif endif
endif endif
if virtualenv_inactive
call health#report_warn(
\ '$VIRTUAL_ENV exists but appears to be inactive. '
\ . 'This could lead to unexpected results.',
\ [ 'If you are using Zsh, see: http://vi.stackexchange.com/a/7654/5229' ])
endif
" Diagnostic output " Diagnostic output
call health#report_info('Executable: ' . (empty(python_bin) ? 'Not found' : python_bin)) call health#report_info('Executable: ' . (empty(python_bin) ? 'Not found' : python_bin))
if len(python_multiple) if len(python_multiple)
@@ -451,10 +453,11 @@ function! s:check_ruby() abort
let host = provider#ruby#Detect() let host = provider#ruby#Detect()
if empty(host) if empty(host)
call health#report_warn('Missing "neovim" gem.', call health#report_warn('`neovim-ruby-host` not found.',
\ ['Run in shell: gem install neovim', \ ['Run `gem install neovim` to ensure the neovim RubyGem is installed.',
\ 'Is the gem bin directory in $PATH? Check `gem environment`.', \ 'Run `gem environment` to ensure the gem bin directory is in $PATH.',
\ 'If you are using rvm/rbenv/chruby, try "rehashing".']) \ 'If you are using rvm/rbenv/chruby, try "rehashing".',
\ 'See :help g:ruby_host_prog for non-standard gem installations.'])
return return
endif endif
call health#report_info('Host: '. host) call health#report_info('Host: '. host)
@@ -488,7 +491,7 @@ function! s:check_ruby() abort
endfunction endfunction
function! s:check_node() abort function! s:check_node() abort
call health#report_start('Node provider (optional)') call health#report_start('Node.js provider (optional)')
let loaded_var = 'g:loaded_node_provider' let loaded_var = 'g:loaded_node_provider'
if exists(loaded_var) && !exists('*provider#node#Call') if exists(loaded_var) && !exists('*provider#node#Call')
@@ -502,7 +505,16 @@ function! s:check_node() abort
\ ['Install Node.js and verify that `node` and `npm` commands work.']) \ ['Install Node.js and verify that `node` and `npm` commands work.'])
return return
endif endif
call health#report_info('Node: '. s:system('node -v')) let node_v = get(split(s:system('node -v'), "\n"), 0, '')
call health#report_info('Node.js: '. node_v)
if !s:shell_error && s:version_cmp(node_v[1:], '6.0.0') < 0
call health#report_warn('Neovim node.js host does not support '.node_v)
" Skip further checks, they are nonsense if nodejs is too old.
return
endif
if !provider#node#can_inspect()
call health#report_warn('node.js on this system does not support --inspect-brk so $NVIM_NODE_HOST_DEBUG is ignored.')
endif
let host = provider#node#Detect() let host = provider#node#Detect()
if empty(host) if empty(host)
@@ -511,7 +523,7 @@ function! s:check_node() abort
\ 'Is the npm bin directory in $PATH?']) \ 'Is the npm bin directory in $PATH?'])
return return
endif endif
call health#report_info('Host: '. host) call health#report_info('Neovim node.js host: '. host)
let latest_npm_cmd = has('win32') ? 'cmd /c npm info neovim --json' : 'npm info neovim --json' let latest_npm_cmd = has('win32') ? 'cmd /c npm info neovim --json' : 'npm info neovim --json'
let latest_npm = s:system(split(latest_npm_cmd)) let latest_npm = s:system(split(latest_npm_cmd))
@@ -530,11 +542,11 @@ function! s:check_node() abort
let latest_npm = get(get(pkg_data, 'dist-tags', {}), 'latest', 'unable to parse') let latest_npm = get(get(pkg_data, 'dist-tags', {}), 'latest', 'unable to parse')
endif endif
let current_npm_cmd = host .' --version' let current_npm_cmd = ['node', host, '--version']
let current_npm = s:system(current_npm_cmd) let current_npm = s:system(current_npm_cmd)
if s:shell_error if s:shell_error
call health#report_error('Failed to run: '. current_npm_cmd, call health#report_error('Failed to run: '. string(current_npm_cmd),
\ ['Report this issue with the output of: ', current_npm_cmd]) \ ['Report this issue with the output of: ', string(current_npm_cmd)])
return return
endif endif
@@ -544,7 +556,7 @@ function! s:check_node() abort
\ current_npm, latest_npm), \ current_npm, latest_npm),
\ ['Run in shell: npm update neovim']) \ ['Run in shell: npm update neovim'])
else else
call health#report_ok('Latest "neovim" npm is installed: '. current_npm) call health#report_ok('Latest "neovim" npm package is installed: '. current_npm)
endif endif
endfunction endfunction

View File

@@ -65,9 +65,9 @@ function! man#open_page(count, count1, mods, ...) abort
try try
set eventignore+=BufReadCmd set eventignore+=BufReadCmd
if a:mods !~# 'tab' && s:find_man() if a:mods !~# 'tab' && s:find_man()
execute 'silent edit' fnameescape(bufname) execute 'silent keepalt edit' fnameescape(bufname)
else else
execute 'silent' a:mods 'split' fnameescape(bufname) execute 'silent keepalt' a:mods 'split' fnameescape(bufname)
endif endif
finally finally
set eventignore-=BufReadCmd set eventignore-=BufReadCmd
@@ -148,7 +148,8 @@ function! s:get_page(path) abort
let manwidth = empty($MANWIDTH) ? winwidth(0) : $MANWIDTH let manwidth = 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
let cmd = ['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'man'] " Set MAN_KEEP_FORMATTING so Debian man doesn't discard backspaces.
let cmd = ['env', 'MANPAGER=cat', 'MANWIDTH='.manwidth, 'MAN_KEEP_FORMATTING=1', 'man']
return s:system(cmd + (s:localfile_arg ? ['-l', a:path] : [a:path])) return s:system(cmd + (s:localfile_arg ? ['-l', a:path] : [a:path]))
endfunction endfunction
@@ -157,11 +158,10 @@ function! s:put_page(page) abort
setlocal noreadonly setlocal noreadonly
silent keepjumps %delete _ silent keepjumps %delete _
silent put =a:page silent put =a:page
" Remove all backspaced/escape characters.
execute 'silent keeppatterns keepjumps %substitute,.\b\|\e\[\d\+m,,e'.(&gdefault?'':'g')
while getline(1) =~# '^\s*$' while getline(1) =~# '^\s*$'
silent keepjumps 1delete _ silent keepjumps 1delete _
endwhile endwhile
lua require("man").highlight_man_page()
setlocal filetype=man setlocal filetype=man
endfunction endfunction
@@ -299,6 +299,12 @@ endfunction
" see man#extract_sect_and_name_ref on why tolower(sect) " see man#extract_sect_and_name_ref on why tolower(sect)
function! man#complete(arg_lead, cmd_line, cursor_pos) abort function! man#complete(arg_lead, cmd_line, cursor_pos) abort
let args = split(a:cmd_line) let args = split(a:cmd_line)
let cmd_offset = index(args, 'Man')
if cmd_offset > 0
" Prune all arguments up to :Man itself. Otherwise modifier commands like
" :tab, :vertical, etc. would lead to a wrong length.
let args = args[cmd_offset:]
endif
let l = len(args) let l = len(args)
if l > 3 if l > 3
return return
@@ -370,13 +376,12 @@ function! s:format_candidate(path, psect) abort
endfunction endfunction
function! man#init_pager() abort function! man#init_pager() abort
" Remove all backspaced/escape characters.
execute 'silent keeppatterns keepjumps %substitute,.\b\|\e\[\d\+m,,e'.(&gdefault?'':'g')
if getline(1) =~# '^\s*$' if getline(1) =~# '^\s*$'
silent keepjumps 1delete _ silent keepjumps 1delete _
else else
keepjumps 1 keepjumps 1
endif endif
lua require("man").highlight_man_page()
" This is not perfect. See `man glDrawArraysInstanced`. Since the title is " This is not perfect. See `man glDrawArraysInstanced`. Since the title is
" all caps it is impossible to tell what the original capitilization was. " all caps it is impossible to tell what the original capitilization was.
let ref = substitute(matchstr(getline(1), '^[^)]\+)'), ' ', '_', 'g') let ref = substitute(matchstr(getline(1), '^[^)]\+)'), ' ', '_', 'g')

View File

@@ -1,20 +1,21 @@
" Common functionality for providers " Common functions for providers
let s:stderr = {} " Start the provider and perform a 'poll' request
"
function! provider#stderr_collector(chan_id, data, event) " Returns a valid channel on success
let stderr = get(s:stderr, a:chan_id, ['']) function! provider#Poll(argv, orig_name, log_env) abort
let stderr[-1] .= a:data[0] let job = {'rpc': v:true, 'stderr_buffered': v:true}
call extend(stderr, a:data[1:]) try
let s:stderr[a:chan_id] = stderr let channel_id = jobstart(a:argv, job)
endfunction if channel_id > 0 && rpcrequest(channel_id, 'poll') ==# 'ok'
return channel_id
function! provider#clear_stderr(chan_id) endif
if has_key(s:stderr, a:chan_id) catch
call remove(s:stderr, a:chan_id) echomsg v:throwpoint
endif echomsg v:exception
endfunction for row in get(job, 'stderr', [])
echomsg row
function! provider#get_stderr(chan_id) endfor
return get(s:stderr, a:chan_id, []) endtry
throw remote#host#LoadErrorForHost(a:orig_name, a:log_env)
endfunction endfunction

View File

@@ -7,7 +7,7 @@ let s:clipboard = {}
" When caching is enabled, store the jobid of the xclip/xsel process keeping " When caching is enabled, store the jobid of the xclip/xsel process keeping
" ownership of the selection, so we know how long the cache is valid. " ownership of the selection, so we know how long the cache is valid.
let s:selection = { 'owner': 0, 'data': [], 'on_stderr': function('provider#stderr_collector') } let s:selection = { 'owner': 0, 'data': [], 'stderr_buffered': v:true }
function! s:selection.on_exit(jobid, data, event) abort function! s:selection.on_exit(jobid, data, event) abort
" At this point this nvim instance might already have launched " At this point this nvim instance might already have launched
@@ -16,19 +16,17 @@ function! s:selection.on_exit(jobid, data, event) abort
let self.owner = 0 let self.owner = 0
endif endif
if a:data != 0 if a:data != 0
let stderr = provider#get_stderr(a:jobid)
echohl WarningMsg echohl WarningMsg
echomsg 'clipboard: error invoking '.get(self.argv, 0, '?').': '.join(stderr) echomsg 'clipboard: error invoking '.get(self.argv, 0, '?').': '.join(self.stderr)
echohl None echohl None
endif endif
call provider#clear_stderr(a:jobid)
endfunction endfunction
let s:selections = { '*': s:selection, '+': copy(s:selection) } let s:selections = { '*': s:selection, '+': copy(s:selection) }
function! s:try_cmd(cmd, ...) abort function! s:try_cmd(cmd, ...) abort
let argv = split(a:cmd, " ") let argv = split(a:cmd, " ")
let out = a:0 ? systemlist(argv, a:1, 1) : systemlist(argv, [''], 1) let out = systemlist(argv, (a:0 ? a:1 : ['']), 1)
if v:shell_error if v:shell_error
if !exists('s:did_error_try_cmd') if !exists('s:did_error_try_cmd')
echohl WarningMsg echohl WarningMsg
@@ -66,7 +64,7 @@ function! provider#clipboard#Executable() abort
let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null }) let s:paste = get(g:clipboard, 'paste', { '+': v:null, '*': v:null })
let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0) let s:cache_enabled = get(g:clipboard, 'cache_enabled', 0)
return get(g:clipboard, 'name', 'g:clipboard') return get(g:clipboard, 'name', 'g:clipboard')
elseif has('mac') && executable('pbcopy') elseif has('mac') && executable('pbpaste') && s:cmd_ok('pbpaste')
let s:copy['+'] = 'pbcopy' let s:copy['+'] = 'pbcopy'
let s:paste['+'] = 'pbpaste' let s:paste['+'] = 'pbpaste'
let s:copy['*'] = s:copy['+'] let s:copy['*'] = s:copy['+']
@@ -142,12 +140,13 @@ function! s:clipboard.set(lines, regtype, reg) abort
return 0 return 0
end end
let selection = s:selections[a:reg] if s:selections[a:reg].owner > 0
if selection.owner > 0
" The previous provider instance should exit when the new one takes " The previous provider instance should exit when the new one takes
" ownership, but kill it to be sure we don't fill up the job table. " ownership, but kill it to be sure we don't fill up the job table.
call jobstop(selection.owner) call jobstop(s:selections[a:reg].owner)
end end
let s:selections[a:reg] = copy(s:selection)
let selection = s:selections[a:reg]
let selection.data = [a:lines, a:regtype] let selection.data = [a:lines, a:regtype]
let argv = split(s:copy[a:reg], " ") let argv = split(s:copy[a:reg], " ")
let selection.argv = argv let selection.argv = argv

View File

@@ -3,13 +3,59 @@ if exists('g:loaded_node_provider')
endif endif
let g:loaded_node_provider = 1 let g:loaded_node_provider = 1
let s:job_opts = {'rpc': v:true, 'on_stderr': function('provider#stderr_collector')} function! s:is_minimum_version(version, min_major, min_minor) abort
if empty(a:version)
function! provider#node#Detect() abort let nodejs_version = get(split(system(['node', '-v']), "\n"), 0, '')
return has('win32') ? exepath('neovim-node-host.cmd') : exepath('neovim-node-host') if v:shell_error || nodejs_version[0] !=# 'v'
return 0
endif
else
let nodejs_version = a:version
endif
" Remove surrounding junk. Example: 'v4.12.0' => '4.12.0'
let nodejs_version = matchstr(nodejs_version, '\(\d\.\?\)\+')
" [major, minor, patch]
let v_list = split(nodejs_version, '\.')
return len(v_list) == 3
\ && ((str2nr(v_list[0]) > str2nr(a:min_major))
\ || (str2nr(v_list[0]) == str2nr(a:min_major)
\ && str2nr(v_list[1]) >= str2nr(a:min_minor)))
endfunction endfunction
function! provider#node#Prog() " Support for --inspect-brk requires node 6.12+ or 7.6+ or 8+
" Return 1 if it is supported
" Return 0 otherwise
function! provider#node#can_inspect() abort
if !executable('node')
return 0
endif
let ver = get(split(system(['node', '-v']), "\n"), 0, '')
if v:shell_error || ver[0] !=# 'v'
return 0
endif
return (ver[1] ==# '6' && s:is_minimum_version(ver, 6, 12))
\ || s:is_minimum_version(ver, 7, 6)
endfunction
function! provider#node#Detect() abort
if exists('g:node_host_prog')
return g:node_host_prog
endif
let global_modules = get(split(system('npm root -g'), "\n"), 0, '')
if v:shell_error || !isdirectory(global_modules)
return ''
endif
if !s:is_minimum_version(v:null, 6, 0)
return ''
endif
let entry_point = glob(global_modules . '/neovim/bin/cli.js')
if !filereadable(entry_point)
return ''
endif
return entry_point
endfunction
function! provider#node#Prog() abort
return s:prog return s:prog
endfunction endfunction
@@ -19,37 +65,18 @@ function! provider#node#Require(host) abort
return return
endif endif
if has('win32') let args = ['node']
let args = provider#node#Prog()
else
let args = ['node']
if !empty($NVIM_NODE_HOST_DEBUG) if !empty($NVIM_NODE_HOST_DEBUG) && provider#node#can_inspect()
call add(args, '--inspect-brk') call add(args, '--inspect-brk')
endif
call add(args , provider#node#Prog())
endif endif
try call add(args, provider#node#Prog())
let channel_id = jobstart(args, s:job_opts)
if rpcrequest(channel_id, 'poll') ==# 'ok' return provider#Poll(args, a:host.orig_name, '$NVIM_NODE_LOG_FILE')
return channel_id
endif
catch
echomsg v:throwpoint
echomsg v:exception
for row in provider#get_stderr(channel_id)
echomsg row
endfor
endtry
finally
call provider#clear_stderr(channel_id)
endtry
throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_NODE_LOG_FILE')
endfunction endfunction
function! provider#node#Call(method, args) function! provider#node#Call(method, args) abort
if s:err != '' if s:err != ''
echoerr s:err echoerr s:err
return return
@@ -74,7 +101,7 @@ let s:err = ''
let s:prog = provider#node#Detect() let s:prog = provider#node#Detect()
if empty(s:prog) if empty(s:prog)
let s:err = 'Cannot find the "neovim" node package. Try :CheckHealth' let s:err = 'Cannot find the "neovim" node package. Try :checkhealth'
endif endif
call remote#host#RegisterPlugin('node-provider', 'node', []) call remote#host#RegisterPlugin('node-provider', 'node', [])

View File

@@ -11,11 +11,11 @@ let g:loaded_python_provider = 1
let [s:prog, s:err] = provider#pythonx#Detect(2) let [s:prog, s:err] = provider#pythonx#Detect(2)
function! provider#python#Prog() function! provider#python#Prog() abort
return s:prog return s:prog
endfunction endfunction
function! provider#python#Error() function! provider#python#Error() abort
return s:err return s:err
endfunction endfunction
@@ -29,7 +29,7 @@ endif
call remote#host#RegisterClone('legacy-python-provider', 'python') call remote#host#RegisterClone('legacy-python-provider', 'python')
call remote#host#RegisterPlugin('legacy-python-provider', 'script_host.py', []) call remote#host#RegisterPlugin('legacy-python-provider', 'script_host.py', [])
function! provider#python#Call(method, args) function! provider#python#Call(method, args) abort
if s:err != '' if s:err != ''
return return
endif endif

View File

@@ -11,11 +11,11 @@ let g:loaded_python3_provider = 1
let [s:prog, s:err] = provider#pythonx#Detect(3) let [s:prog, s:err] = provider#pythonx#Detect(3)
function! provider#python3#Prog() function! provider#python3#Prog() abort
return s:prog return s:prog
endfunction endfunction
function! provider#python3#Error() function! provider#python3#Error() abort
return s:err return s:err
endfunction endfunction
@@ -29,7 +29,7 @@ endif
call remote#host#RegisterClone('legacy-python3-provider', 'python3') call remote#host#RegisterClone('legacy-python3-provider', 'python3')
call remote#host#RegisterPlugin('legacy-python3-provider', 'script_host.py', []) call remote#host#RegisterPlugin('legacy-python3-provider', 'script_host.py', [])
function! provider#python3#Call(method, args) function! provider#python3#Call(method, args) abort
if s:err != '' if s:err != ''
return return
endif endif

View File

@@ -5,8 +5,6 @@ endif
let s:loaded_pythonx_provider = 1 let s:loaded_pythonx_provider = 1
let s:job_opts = {'rpc': v:true, 'on_stderr': function('provider#stderr_collector')}
function! provider#pythonx#Require(host) abort function! provider#pythonx#Require(host) abort
let ver = (a:host.orig_name ==# 'python') ? 2 : 3 let ver = (a:host.orig_name ==# 'python') ? 2 : 3
@@ -20,22 +18,7 @@ function! provider#pythonx#Require(host) abort
call add(args, plugin.path) call add(args, plugin.path)
endfor endfor
try return provider#Poll(args, a:host.orig_name, '$NVIM_PYTHON_LOG_FILE')
let channel_id = jobstart(args, s:job_opts)
if rpcrequest(channel_id, 'poll') ==# 'ok'
return channel_id
endif
catch
echomsg v:throwpoint
echomsg v:exception
for row in provider#get_stderr(channel_id)
echomsg row
endfor
finally
call provider#clear_stderr(channel_id)
endtry
throw remote#host#LoadErrorForHost(a:host.orig_name,
\ '$NVIM_PYTHON_LOG_FILE')
endfunction endfunction
function! provider#pythonx#Detect(major_ver) abort function! provider#pythonx#Detect(major_ver) abort

View File

@@ -4,17 +4,6 @@ if exists('g:loaded_ruby_provider')
endif endif
let g:loaded_ruby_provider = 1 let g:loaded_ruby_provider = 1
let s:stderr = {}
let s:job_opts = {'rpc': v:true}
function! s:job_opts.on_stderr(chan_id, data, event)
let stderr = get(s:stderr, a:chan_id, [''])
let last = remove(stderr, -1)
let a:data[0] = last.a:data[0]
call extend(stderr, a:data)
let s:stderr[a:chan_id] = stderr
endfunction
function! provider#ruby#Detect() abort function! provider#ruby#Detect() abort
if exists("g:ruby_host_prog") if exists("g:ruby_host_prog")
return g:ruby_host_prog return g:ruby_host_prog
@@ -23,7 +12,7 @@ function! provider#ruby#Detect() abort
end end
endfunction endfunction
function! provider#ruby#Prog() function! provider#ruby#Prog() abort
return s:prog return s:prog
endfunction endfunction
@@ -35,22 +24,10 @@ function! provider#ruby#Require(host) abort
let prog .= " " . shellescape(plugin.path) let prog .= " " . shellescape(plugin.path)
endfor endfor
try return provider#Poll(prog, a:host.orig_name, '$NVIM_RUBY_LOG_FILE')
let channel_id = jobstart(prog, s:job_opts)
if rpcrequest(channel_id, 'poll') ==# 'ok'
return channel_id
endif
catch
echomsg v:throwpoint
echomsg v:exception
for row in get(s:stderr, channel_id, [])
echomsg row
endfor
endtry
throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_RUBY_LOG_FILE')
endfunction endfunction
function! provider#ruby#Call(method, args) function! provider#ruby#Call(method, args) abort
if s:err != '' if s:err != ''
echoerr s:err echoerr s:err
return return

View File

@@ -2,9 +2,6 @@
" Setup: {{{1 " Setup: {{{1
function! tutor#SetupVim() function! tutor#SetupVim()
if &columns < 90
set columns=90
endif
if !exists('g:did_load_ftplugin') || g:did_load_ftplugin != 1 if !exists('g:did_load_ftplugin') || g:did_load_ftplugin != 1
filetype plugin on filetype plugin on
endif endif

View File

@@ -49,6 +49,7 @@ version.api_prerelease Declares the current API level as unstable >
(version.api_prerelease && fn.since == version.api_level) (version.api_prerelease && fn.since == version.api_level)
functions API function signatures functions API function signatures
ui_events UI event signatures |ui| ui_events UI event signatures |ui|
ui_options Supported |ui-options|
{fn}.since API level where function {fn} was introduced {fn}.since API level where function {fn} was introduced
{fn}.deprecated_since API level where function {fn} was deprecated {fn}.deprecated_since API level where function {fn} was deprecated
types Custom handle types defined by Nvim types Custom handle types defined by Nvim
@@ -60,8 +61,7 @@ External programs ("clients") can use the metadata to discover the |rpc-api|.
API contract *api-contract* API contract *api-contract*
The API is made of functions and events. Clients call functions like those The API is made of functions and events. Clients call functions like those
described at |api-global|, and may "attach" in order to receive rich events, described at |api-global|, and may "attach" to receive rich |ui-events|.
described at |rpc-remote-ui|.
As Nvim develops, its API may change only according the following "contract": As Nvim develops, its API may change only according the following "contract":
@@ -446,7 +446,11 @@ nvim_get_keymap({mode}) *nvim_get_keymap()*
Array of maparg()-like dictionaries describing mappings Array of maparg()-like dictionaries describing mappings
nvim_get_api_info() *nvim_get_api_info()* nvim_get_api_info() *nvim_get_api_info()*
TODO: Documentation Returns a 2-tuple (Array), where item 0 is the current channel
id and item 1 is the |api-metadata| map (Dictionary).
Return:~
2-tuple [{channel-id}, {api-metadata}]
Attributes:~ Attributes:~
{async} {async}
@@ -477,6 +481,84 @@ nvim_call_atomic({calls}) *nvim_call_atomic()*
error ocurred, the values from all preceding calls will error ocurred, the values from all preceding calls will
still be returned. still be returned.
*nvim_parse_expression()*
nvim_parse_expression({expr}, {flags}, {highlight})
Parse a VimL expression
Attributes:~
{async}
Parameters:~
{expr} Expression to parse. Is always treated as a
single line.
{flags} Flags: - "m" if multiple expressions in a
row are allowed (only the first one will be
parsed), - "E" if EOC tokens are not allowed
(determines whether they will stop parsing
process or be recognized as an
operator/space, though also yielding an
error). - "l" when needing to start parsing
with lvalues for ":let" or ":for". Common
flag sets: - "m" to parse like for ":echo". -
"E" to parse like for "<C-r>=". - empty
string for ":call". - "lm" to parse for
":let".
{highlight} If true, return value will also include
"highlight" key containing array of 4-tuples
(arrays) (Integer, Integer, Integer, String),
where first three numbers define the
highlighted region and represent line,
starting column and ending column (latter
exclusive: one should highlight region
[start_col, end_col)).
Return:~
AST: top-level dictionary with these keys: "error":
Dictionary with error, present only if parser saw some
error. Contains the following keys: "message": String,
error message in printf format, translated. Must contain
exactly one "%.*s". "arg": String, error message argument.
"len": Amount of bytes successfully parsed. With flags
equal to "" that should be equal to the length of expr
string. @note: “Sucessfully parsed” here means
“participated in AST creation”, not “till the first
error”. "ast": AST, either nil or a dictionary with these
keys: "type": node type, one of the value names from
ExprASTNodeType stringified without "kExprNode" prefix.
"start": a pair [line, column] describing where node is
“started” where "line" is always 0 (will not be 0 if you
will be using nvim_parse_viml() on e.g. ":let", but that
is not present yet). Both elements are Integers. "len":
“length” of the node. This and "start" are there for
debugging purposes primary (debugging parser and providing
debug information). "children": a list of nodes described
in top/"ast". There always is zero, one or two children,
key will not be present if node has no children. Maximum
number of children may be found in node_maxchildren array.
Local values (present only for certain nodes): "scope": a
single Integer, specifies scope for "Option" and
"PlainIdentifier" nodes. For "Option" it is one of
ExprOptScope values, for "PlainIdentifier" it is one of
ExprVarScope values. "ident": identifier (without scope,
if any), present for "Option", "PlainIdentifier",
"PlainKey" and "Environment" nodes. "name": Integer,
register name (one character) or -1. Only present for
"Register" nodes. "cmp_type": String, comparison type, one
of the value names from ExprComparisonType, stringified
without "kExprCmp" prefix. Only present for "Comparison"
nodes. "ccs_strategy": String, case comparison strategy,
one of the value names from ExprCaseCompareStrategy,
stringified without "kCCStrategy" prefix. Only present for
"Comparison" nodes. "augmentation": String, augmentation
type for "Assignment" nodes. Is either an empty string,
"Add", "Subtract" or "Concat" for "=", "+=", "-=" or ".="
respectively. "invert": Boolean, true if result of
comparison needs to be inverted. Only present for
"Comparison" nodes. "ivalue": Integer, integer value for
"Integer" nodes. "fvalue": Float, floating-point value for
"Float" nodes. "svalue": String, value for
"SingleQuotedString" and "DoubleQuotedString" nodes.
nvim__id({obj}) *nvim__id()* nvim__id({obj}) *nvim__id()*
Returns object given as argument Returns object given as argument
@@ -717,9 +799,10 @@ nvim_buf_add_highlight({buffer}, {src_id}, {hl_group}, {line},
or -1 for ungrouped highlight or -1 for ungrouped highlight
{hl_group} Name of the highlight group to use {hl_group} Name of the highlight group to use
{line} Line to highlight (zero-indexed) {line} Line to highlight (zero-indexed)
{col_start} Start of range of columns to highlight {col_start} Start of (byte-indexed) column range to
{col_end} End of range of columns to highlight, or -1 highlight
to highlight to end of line {col_end} End of (byte-indexed) column range to
highlight, or -1 to highlight to end of line
Return:~ Return:~
The src_id that was used The src_id that was used
@@ -953,9 +1036,6 @@ nvim_tabpage_is_valid({tabpage}) *nvim_tabpage_is_valid()*
============================================================================== ==============================================================================
UI Functions *api-ui* UI Functions *api-ui*
remote_ui_disconnect() *remote_ui_disconnect()*
TODO: Documentation
nvim_ui_attach({width}, {height}, {options}) *nvim_ui_attach()* nvim_ui_attach({width}, {height}, {options}) *nvim_ui_attach()*
TODO: Documentation TODO: Documentation
@@ -968,4 +1048,4 @@ nvim_ui_try_resize({width}, {height}) *nvim_ui_try_resize()*
nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()* nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()*
TODO: Documentation TODO: Documentation
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:norl:

View File

@@ -259,13 +259,12 @@ Name triggered by ~
|BufNew| just after creating a new buffer |BufNew| just after creating a new buffer
|SwapExists| detected an existing swap file |SwapExists| detected an existing swap file
|TermOpen| when a terminal buffer is starting |TermOpen| when a terminal job starts
|TermClose| when a terminal buffer ends |TermClose| when a terminal job ends
Options Options
|FileType| when the 'filetype' option has been set |FileType| when the 'filetype' option has been set
|Syntax| when the 'syntax' option has been set |Syntax| when the 'syntax' option has been set
|TermChanged| after the value of 'term' has changed
|OptionSet| after setting any option |OptionSet| after setting any option
Startup and exit Startup and exit
@@ -933,26 +932,20 @@ TabEnter Just after entering a tab page. |tab-page|
TabLeave Just before leaving a tab page. |tab-page| TabLeave Just before leaving a tab page. |tab-page|
A WinLeave event will have been triggered A WinLeave event will have been triggered
first. first.
{Nvim} *TabNew* *TabNew*
TabNew When creating a new tab page. |tab-page| TabNew When creating a new tab page. |tab-page|
After WinEnter and before TabEnter. After WinEnter and before TabEnter.
{Nvim} *TabNewEntered* *TabNewEntered*
TabNewEntered After entering a new tab page. |tab-page| TabNewEntered After entering a new tab page. |tab-page|
After BufEnter. After BufEnter.
{Nvim} *TabClosed* *TabClosed*
TabClosed After closing a tab page. <afile> can be used TabClosed After closing a tab page. <afile> can be used
for the tab page number. for the tab page number.
*TermChanged* *TermClose*
TermChanged After the value of 'term' has changed. Useful TermClose When a |terminal| job ends.
for re-loading the syntax file to update the *TermOpen*
colors, fonts and other terminal-dependent TermOpen When a |terminal| job is starting. Can be
settings. Executed for all loaded buffers. used to configure the terminal buffer.
{Nvim} *TermClose*
TermClose When a terminal buffer ends.
{Nvim} *TermOpen*
TermOpen When a terminal buffer is starting. This can
be used to configure the terminal emulator by
setting buffer variables. |terminal|
*TermResponse* *TermResponse*
TermResponse After the response to |t_RV| is received from TermResponse After the response to |t_RV| is received from
the terminal. The value of |v:termresponse| the terminal. The value of |v:termresponse|

View File

@@ -4,9 +4,9 @@
NVIM REFERENCE MANUAL by Thiago de Arruda NVIM REFERENCE MANUAL by Thiago de Arruda
Nvim's facilities for async io *channel* Nvim asynchronous IO *channel*
Type <M-]> to see the table of contents. Type |gO| to see the table of contents.
============================================================================== ==============================================================================
1. Introduction *channel-intro* 1. Introduction *channel-intro*
@@ -43,7 +43,7 @@ bytes. Additionally, for a job channel using rpc, bytes can still be
read over its stderr. Similarily, only bytes can be written to nvim's own stderr. read over its stderr. Similarily, only bytes can be written to nvim's own stderr.
*channel-callback* *buffered* *channel-callback* *buffered*
*on_stdout* *on_stderr* *on_stdin* *on_data* *E5210* *on_stdout* *on_stderr* *on_stdin* *on_data*
A callback function `on_{stream}` will be invoked with data read from the A callback function `on_{stream}` will be invoked with data read from the
channel. By default, the callback will be invoked immediately when data is channel. By default, the callback will be invoked immediately when data is
available, to facilitate interactive communication. The same callback will available, to facilitate interactive communication. The same callback will
@@ -52,7 +52,11 @@ Alternatively the `{stream}_buffered` option can be set to invoke the callback
only when the underlying stream reaches EOF, and will then be passed in only when the underlying stream reaches EOF, and will then be passed in
complete output. This is helpful when only the complete output is useful, and complete output. This is helpful when only the complete output is useful, and
not partial data. Futhermore if `{stream}_buffered` is set but not a callback, not partial data. Futhermore if `{stream}_buffered` is set but not a callback,
the data is saved in the options dict, with the stream name as key. the data is saved in the options dict, with the stream name as key. For this
to work a new options dict must be used for each opened channel. If a script
uses a global `s:job_opts` dict, it can be copied with |copy()| before supplying
it to |jobstart()|. If a dict is reused, so that the dict key already is
occupied, error `E5210` will be raised.
- The arguments passed to the callback function are: - The arguments passed to the callback function are:

View File

@@ -22,6 +22,10 @@ Commands ~
*:wv* *:wv*
*:wviminfo* Deprecated alias to |:wshada| command. *:wviminfo* Deprecated alias to |:wshada| command.
Environment Variables ~
*$NVIM_LISTEN_ADDRESS* Deprecated in favor of |--listen|. If both are given,
$NVIM_LISTEN_ADDRESS is ignored.
Events ~ Events ~
*EncodingChanged* Never fired; 'encoding' is always "utf-8". *EncodingChanged* Never fired; 'encoding' is always "utf-8".
*FileEncoding* Never fired; equivalent to |EncodingChanged|. *FileEncoding* Never fired; equivalent to |EncodingChanged|.
@@ -37,8 +41,8 @@ Functions ~
*file_readable()* Obsolete name for |filereadable()|. *file_readable()* Obsolete name for |filereadable()|.
*highlight_exists()* Obsolete name for |hlexists()|. *highlight_exists()* Obsolete name for |hlexists()|.
*highlightID()* Obsolete name for |hlID()|. *highlightID()* Obsolete name for |hlID()|.
*jobclose()* Obsolete name for |chanclose()| *jobclose()* Obsolete name for |chanclose()|
*jobsend()* Obsolete name for |chansend()| *jobsend()* Obsolete name for |chansend()|
*last_buffer_nr()* Obsolete name for bufnr("$"). *last_buffer_nr()* Obsolete name for bufnr("$").
Modifiers ~ Modifiers ~
@@ -48,8 +52,11 @@ Modifiers ~
*:map-special* <> notation is always enabled. |cpo-<| *:map-special* <> notation is always enabled. |cpo-<|
Options ~ Options ~
*'cscopeverbose'* Enabled by default. Use |:silent| instead.
'gd'
'gdefault' Enables the |:substitute| flag 'g' by default.
*'fe'* 'fenc'+'enc' before Vim 6.0; no longer used. *'fe'* 'fenc'+'enc' before Vim 6.0; no longer used.
*'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed. *'highlight'* *'hl'* Names of builtin |highlight-groups| cannot be changed.
*'langnoremap'* Deprecated alias to 'nolangremap'. *'langnoremap'* Deprecated alias to 'nolangremap'.
*'vi'* *'vi'*
*'viminfo'* Deprecated alias to 'shada' option. *'viminfo'* Deprecated alias to 'shada' option.

View File

@@ -270,9 +270,9 @@ External UIs are expected to implement these common features:
- Send the "super" key (Windows key, Apple key) as a |<D-| chord. - Send the "super" key (Windows key, Apple key) as a |<D-| chord.
Implementation ~ Implementation ~
- Options can be monitored for changes by the |OptionSet| autocmd. E.g. if the - UI-related options ('guifont', 'ambiwidth', …) are published in the
user sets the 'guifont' option, this autocmd notifies channel 42: > "option_set" |ui-global| event. The event is triggered when the UI first
autocmd OptionSet guifont call rpcnotify(42, 'option-changed', 'guifont', &guifont) connects to Nvim and whenever an option is changed by the user or a plugin.
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:norl:

View File

@@ -562,16 +562,16 @@ list of the current window.
buffer. buffer.
Also see |++opt| and |+cmd|. Also see |++opt| and |+cmd|.
:[count]arge[dit][!] [++opt] [+cmd] {name} *:arge* *:argedit* :[count]arge[dit][!] [++opt] [+cmd] {name} .. *:arge* *:argedit*
Add {name} to the argument list and edit it. Add {name}s to the argument list and edit it.
When {name} already exists in the argument list, this When {name} already exists in the argument list, this
entry is edited. entry is edited.
This is like using |:argadd| and then |:edit|. This is like using |:argadd| and then |:edit|.
Note that only one file name is allowed, and spaces Spaces in filenames have to be escaped with "\".
inside the file name are allowed, like with |:edit|.
[count] is used like with |:argadd|. [count] is used like with |:argadd|.
[!] is required if the current file cannot be If the current file cannot be |abandon|ed {name}s will
|abandon|ed. still be added to the argument list, but won't be
edited. No check for duplicates is done.
Also see |++opt| and |+cmd|. Also see |++opt| and |+cmd|.
:[count]arga[dd] {name} .. *:arga* *:argadd* *E479* :[count]arga[dd] {name} .. *:arga* *:argadd* *E479*

View File

@@ -1559,10 +1559,10 @@ v:exception The value of the exception most recently caught and not
< Output: "caught oops". < Output: "caught oops".
*v:false* *false-variable* *v:false* *false-variable*
v:false Special value used to put "false" in JSON and msgpack. See v:false Special value used to put "false" in JSON and msgpack. See
|json_encode()|. This value is converted to "v:false" when used |json_encode()|. This value is converted to "v:false" when used
as a String (e.g. in |expr5| with string concatenation as a String (e.g. in |expr5| with string concatenation
operator) and to zero when used as a Number (e.g. in |expr5| operator) and to zero when used as a Number (e.g. in |expr5|
or |expr7| when used with numeric operators). Read-only. or |expr7| when used with numeric operators). Read-only.
*v:fcs_reason* *fcs_reason-variable* *v:fcs_reason* *fcs_reason-variable*
@@ -1703,16 +1703,16 @@ v:mouse_col Column number for a mouse click obtained with |getchar()|.
value is zero when there was no mouse button click. value is zero when there was no mouse button click.
*v:msgpack_types* *msgpack_types-variable* *v:msgpack_types* *msgpack_types-variable*
v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()| v:msgpack_types Dictionary containing msgpack types used by |msgpackparse()|
and |msgpackdump()|. All types inside dictionary are fixed and |msgpackdump()|. All types inside dictionary are fixed
(not editable) empty lists. To check whether some list is one (not editable) empty lists. To check whether some list is one
of msgpack types, use |is| operator. of msgpack types, use |is| operator.
*v:null* *null-variable* *v:null* *null-variable*
v:null Special value used to put "null" in JSON and NIL in msgpack. v:null Special value used to put "null" in JSON and NIL in msgpack.
See |json_encode()|. This value is converted to "v:null" when See |json_encode()|. This value is converted to "v:null" when
used as a String (e.g. in |expr5| with string concatenation used as a String (e.g. in |expr5| with string concatenation
operator) and to zero when used as a Number (e.g. in |expr5| operator) and to zero when used as a Number (e.g. in |expr5|
or |expr7| when used with numeric operators). Read-only. or |expr7| when used with numeric operators). Read-only.
*v:oldfiles* *oldfiles-variable* *v:oldfiles* *oldfiles-variable*
@@ -1788,9 +1788,9 @@ v:scrollstart String describing the script or function that caused the
hit-enter prompt. hit-enter prompt.
*v:servername* *servername-variable* *v:servername* *servername-variable*
*$NVIM_LISTEN_ADDRESS* v:servername Primary listen-address of the current Nvim instance, the first
v:servername Default Nvim server address. Equivalent to item returned by |serverlist()|. Can be set by |--listen| or
|$NVIM_LISTEN_ADDRESS| on startup. |serverstop()| |$NVIM_LISTEN_ADDRESS| at startup. |serverstart()| |serverstop()|
Read-only. Read-only.
@@ -1903,10 +1903,10 @@ v:throwpoint The point where the exception most recently caught and not
< Output: "Exception from test.vim, line 2" < Output: "Exception from test.vim, line 2"
*v:true* *true-variable* *v:true* *true-variable*
v:true Special value used to put "true" in JSON and msgpack. See v:true Special value used to put "true" in JSON and msgpack. See
|json_encode()|. This value is converted to "v:true" when used |json_encode()|. This value is converted to "v:true" when used
as a String (e.g. in |expr5| with string concatenation as a String (e.g. in |expr5| with string concatenation
operator) and to one when used as a Number (e.g. in |expr5| or operator) and to one when used as a Number (e.g. in |expr5| or
|expr7| when used with numeric operators). Read-only. |expr7| when used with numeric operators). Read-only.
*v:val* *val-variable* *v:val* *val-variable*
@@ -2492,7 +2492,7 @@ assert_fails({cmd} [, {error}]) *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()|.
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
"Expected False but got {actual}" is produced. "Expected False but got {actual}" is produced.
@@ -3182,7 +3182,7 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
empty({expr}) *empty()* empty({expr}) *empty()*
Return the Number 1 if {expr} is empty, zero otherwise. Return the Number 1 if {expr} is empty, zero otherwise.
A |List| or |Dictionary| is empty when it does not have any A |List| or |Dictionary| is empty when it does not have any
items. A Number is empty when its value is zero. Special items. A Number is empty when its value is zero. Special
variable is empty when it is |v:false| or |v:null|. variable is empty when it is |v:false| or |v:null|.
escape({string}, {chars}) *escape()* escape({string}, {chars}) *escape()*
@@ -4327,17 +4327,25 @@ getqflist([{what}]) *getqflist()*
If the optional {what} dictionary argument is supplied, then If the optional {what} dictionary argument is supplied, then
returns only the items listed in {what} as a dictionary. The returns only the items listed in {what} as a dictionary. The
following string items are supported in {what}: following string items are supported in {what}:
context get the context stored with |setqflist()|
items quickfix list entries
nr get information for this quickfix list; zero nr get information for this quickfix list; zero
means the current quickfix list means the current quickfix list and '$' means
the last quickfix list
title get the list title title get the list title
winid get the |window-ID| (if opened) winid get the |window-ID| (if opened)
all all of the above quickfix properties all all of the above quickfix properties
Non-string items in {what} are ignored. Non-string items in {what} are ignored.
If "nr" is not present then the current quickfix list is used. If "nr" is not present then the current quickfix list is used.
To get the number of lists in the quickfix stack, set 'nr' to
'$' in {what}. The 'nr' value in the returned dictionary
contains the quickfix stack size.
In case of error processing {what}, an empty dictionary is In case of error processing {what}, an empty dictionary is
returned. returned.
The returned dictionary contains the following entries: The returned dictionary contains the following entries:
context context information stored with |setqflist()|
items quickfix list entries
nr quickfix list number nr quickfix list number
title quickfix list title text title quickfix list title text
winid quickfix |window-ID| (if opened) winid quickfix |window-ID| (if opened)
@@ -4749,7 +4757,7 @@ input({opts})
string, or a blank string (for no prompt). A '\n' can be used string, or a blank string (for no prompt). A '\n' can be used
in the prompt to start a new line. in the prompt to start a new line.
In the second form it accepts a single dictionary with the In the second form it accepts a single dictionary with the
following keys, any of which may be omitted: following keys, any of which may be omitted:
Key Default Description ~ Key Default Description ~
@@ -4757,7 +4765,7 @@ input({opts})
default "" Same as {text} in the first form. default "" Same as {text} in the first form.
completion nothing Same as {completion} in the first form. completion nothing Same as {completion} in the first form.
cancelreturn "" Same as {cancelreturn} from cancelreturn "" Same as {cancelreturn} from
|inputdialog()|. Also works with |inputdialog()|. Also works with
input(). input().
highlight nothing Highlight handler: |Funcref|. highlight nothing Highlight handler: |Funcref|.
@@ -4833,8 +4841,8 @@ input({opts})
modifier. If the function causes any errors, it will be modifier. If the function causes any errors, it will be
skipped for the duration of the current input() call. skipped for the duration of the current input() call.
Currently coloring is disabled when command-line contains Highlighting is disabled if command-line contains arabic
arabic characters. characters.
NOTE: This function must not be used in a startup file, for NOTE: This function must not be used in a startup file, for
the versions that only run in GUI mode (e.g., the Win32 GUI). the versions that only run in GUI mode (e.g., the Win32 GUI).
@@ -4948,19 +4956,19 @@ islocked({expr}) *islocked()* *E786*
message. Use |exists()| to check for existence. message. Use |exists()| to check for existence.
id({expr}) *id()* id({expr}) *id()*
Returns a |String| which is a unique identifier of the Returns a |String| which is a unique identifier of the
container type (|List|, |Dict| and |Partial|). It is container type (|List|, |Dict| and |Partial|). It is
guaranteed that for the mentioned types `id(v1) ==# id(v2)` guaranteed that for the mentioned types `id(v1) ==# id(v2)`
returns true iff `type(v1) == type(v2) && v1 is v2` (note: returns true iff `type(v1) == type(v2) && v1 is v2` (note:
|v:_null_list| and |v:_null_dict| have the same `id()` with |v:_null_list| and |v:_null_dict| have the same `id()` with
different types because they are internally represented as different types because they are internally represented as
a NULL pointers). Currently `id()` returns a hexadecimal a NULL pointers). Currently `id()` returns a hexadecimal
representanion of the pointers to the containers (i.e. like representanion of the pointers to the containers (i.e. like
`0x994a40`), same as `printf("%p", {expr})`, but it is advised `0x994a40`), same as `printf("%p", {expr})`, but it is advised
against counting on exact format of return value. against counting on exact format of return value.
It is not guaranteed that `id(no_longer_existing_container)` It is not guaranteed that `id(no_longer_existing_container)`
will not be equal to some other `id()`: new containers may will not be equal to some other `id()`: new containers may
reuse identifiers of the garbage-collected ones. reuse identifiers of the garbage-collected ones.
items({dict}) *items()* items({dict}) *items()*
@@ -5071,14 +5079,14 @@ join({list} [, {sep}]) *join()*
The opposite function is |split()|. The opposite function is |split()|.
json_decode({expr}) *json_decode()* json_decode({expr}) *json_decode()*
Convert {expr} from JSON object. Accepts |readfile()|-style Convert {expr} from JSON object. Accepts |readfile()|-style
list as the input, as well as regular string. May output any list as the input, as well as regular string. May output any
Vim value. In the following cases it will output Vim value. In the following cases it will output
|msgpack-special-dict|: |msgpack-special-dict|:
1. Dictionary contains duplicate key. 1. Dictionary contains duplicate key.
2. Dictionary contains empty key. 2. Dictionary contains empty key.
3. String contains NUL byte. Two special dictionaries: for 3. String contains NUL byte. Two special dictionaries: for
dictionary and for string will be emitted in case string dictionary and for string will be emitted in case string
with NUL byte was a dictionary key. with NUL byte was a dictionary key.
Note: function treats its input as UTF-8 always. The JSON Note: function treats its input as UTF-8 always. The JSON
@@ -5087,14 +5095,14 @@ json_decode({expr}) *json_decode()*
Non-UTF-8 characters are an error. Non-UTF-8 characters are an error.
json_encode({expr}) *json_encode()* json_encode({expr}) *json_encode()*
Convert {expr} into a JSON string. Accepts Convert {expr} into a JSON string. Accepts
|msgpack-special-dict| as the input. Will not convert |msgpack-special-dict| as the input. Will not convert
|Funcref|s, mappings with non-string keys (can be created as |Funcref|s, mappings with non-string keys (can be created as
|msgpack-special-dict|), values with self-referencing |msgpack-special-dict|), values with self-referencing
containers, strings which contain non-UTF-8 characters, containers, strings which contain non-UTF-8 characters,
pseudo-UTF-8 strings which contain codepoints reserved for pseudo-UTF-8 strings which contain codepoints reserved for
surrogate pairs (such strings are not valid UTF-8 strings). surrogate pairs (such strings are not valid UTF-8 strings).
Non-printable characters are converted into "\u1234" escapes Non-printable characters are converted into "\u1234" escapes
or special escapes like "\t", other are dumped as-is. or special escapes like "\t", other are dumped as-is.
keys({dict}) *keys()* keys({dict}) *keys()*
@@ -5193,7 +5201,7 @@ line({expr}) The result is a Number, which is the line number of the file
This autocommand jumps to the last known position in a file This autocommand jumps to the last known position in a file
just after opening it, if the '" mark is set: > just after opening it, if the '" mark is set: >
:au BufReadPost * :au BufReadPost *
\ if line("'\"") > 1 && line("'\"") <= line("$") && &ft !~# 'commit' \ if line("'\"") > 1 && line("'\"") <= line("$") && &ft !~# 'commit'
\ | exe "normal! g`\"" \ | exe "normal! g`\""
\ | endif \ | endif
@@ -5244,7 +5252,7 @@ log10({expr}) *log10()*
< -2.0 < -2.0
luaeval({expr}[, {expr}]) luaeval({expr}[, {expr}])
Evaluate Lua expression {expr} and return its result converted Evaluate Lua expression {expr} and return its result converted
to Vim data structures. See |lua-luaeval| for more details. to Vim data structures. See |lua-luaeval| for more details.
map({expr1}, {expr2}) *map()* map({expr1}, {expr2}) *map()*
@@ -5493,7 +5501,7 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])
sets buffer line boundaries to redraw screen. It is supposed sets buffer line boundaries to redraw screen. It is supposed
to be used when fast match additions and deletions are to be used when fast match additions and deletions are
required, for example to highlight matching parentheses. required, for example to highlight matching parentheses.
*E5030* *E5031*
The list {pos} can contain one of these items: The list {pos} can contain one of these items:
- A number. This whole line will be highlighted. The first - A number. This whole line will be highlighted. The first
line has number 1. line has number 1.
@@ -5507,6 +5515,10 @@ matchaddpos({group}, {pos} [, {priority} [, {id} [, {dict}]]])
- A list with three numbers, e.g., [23, 11, 3]. As above, but - A list with three numbers, e.g., [23, 11, 3]. As above, but
the third number gives the length of the highlight in bytes. the third number gives the length of the highlight in bytes.
Entries with zero and negative line numbers are silently
ignored, as well as entries with negative column numbers and
lengths.
The maximum number of positions is 8. The maximum number of positions is 8.
Example: > Example: >
@@ -5675,7 +5687,7 @@ mkdir({name} [, {path} [, {prot}]])
:call mkdir($HOME . "/tmp/foo/bar", "p", 0700) :call mkdir($HOME . "/tmp/foo/bar", "p", 0700)
< This function is not available in the |sandbox|. < This function is not available in the |sandbox|.
If you try to create an existing directory with {path} set to If you try to create an existing directory with {path} set to
"p" mkdir() will silently exit. "p" mkdir() will silently exit.
*mode()* *mode()*
@@ -5728,78 +5740,76 @@ msgpackdump({list}) {Nvim} *msgpackdump()*
5. Points 3. and 4. do not apply to |msgpack-special-dict|s. 5. Points 3. and 4. do not apply to |msgpack-special-dict|s.
msgpackparse({list}) {Nvim} *msgpackparse()* msgpackparse({list}) {Nvim} *msgpackparse()*
Convert a |readfile()|-style list to a list of VimL objects. Convert a |readfile()|-style list to a list of VimL objects.
Example: > Example: >
let fname = expand('~/.config/nvim/shada/main.shada') let fname = expand('~/.config/nvim/shada/main.shada')
let mpack = readfile(fname, 'b') let mpack = readfile(fname, 'b')
let shada_objects = msgpackparse(mpack) let shada_objects = msgpackparse(mpack)
< This will read ~/.config/nvim/shada/main.shada file to < This will read ~/.config/nvim/shada/main.shada file to
`shada_objects` list. `shada_objects` list.
Limitations: Limitations:
1. Mapping ordering is not preserved unless messagepack 1. Mapping ordering is not preserved unless messagepack
mapping is dumped using generic mapping mapping is dumped using generic mapping
(|msgpack-special-map|). (|msgpack-special-map|).
2. Since the parser aims to preserve all data untouched 2. Since the parser aims to preserve all data untouched
(except for 1.) some strings are parsed to (except for 1.) some strings are parsed to
|msgpack-special-dict| format which is not convenient to |msgpack-special-dict| format which is not convenient to
use. use.
*msgpack-special-dict* *msgpack-special-dict*
Some messagepack strings may be parsed to special Some messagepack strings may be parsed to special
dictionaries. Special dictionaries are dictionaries which dictionaries. Special dictionaries are dictionaries which
1. Contain exactly two keys: `_TYPE` and `_VAL`. 1. Contain exactly two keys: `_TYPE` and `_VAL`.
2. `_TYPE` key is one of the types found in |v:msgpack_types| 2. `_TYPE` key is one of the types found in |v:msgpack_types|
variable. variable.
3. Value for `_VAL` has the following format (Key column 3. Value for `_VAL` has the following format (Key column
contains name of the key from |v:msgpack_types|): contains name of the key from |v:msgpack_types|):
Key Value ~ Key Value ~
nil Zero, ignored when dumping. This value cannot nil Zero, ignored when dumping. Not returned by
possibly appear in |msgpackparse()| output in Neovim |msgpackparse()| since |v:null| was introduced.
versions which have |v:null|. boolean One or zero. When dumping it is only checked that
boolean One or zero. When dumping it is only checked that value is a |Number|. Not returned by |msgpackparse()|
value is a |Number|. This value cannot possibly since |v:true| and |v:false| were introduced.
appear in |msgpackparse()| output in Neovim versions integer |List| with four numbers: sign (-1 or 1), highest two
which have |v:true| and |v:false|. bits, number with bits from 62nd to 31st, lowest 31
integer |List| with four numbers: sign (-1 or 1), highest two bits. I.e. to get actual number one will need to use
bits, number with bits from 62nd to 31st, lowest 31
bits. I.e. to get actual number one will need to use
code like > code like >
_VAL[0] * ((_VAL[1] << 62) _VAL[0] * ((_VAL[1] << 62)
& (_VAL[2] << 31) & (_VAL[2] << 31)
& _VAL[3]) & _VAL[3])
< Special dictionary with this type will appear in < Special dictionary with this type will appear in
|msgpackparse()| output under one of the following |msgpackparse()| output under one of the following
circumstances: circumstances:
1. |Number| is 32-bit and value is either above 1. |Number| is 32-bit and value is either above
INT32_MAX or below INT32_MIN. INT32_MAX or below INT32_MIN.
2. |Number| is 64-bit and value is above INT64_MAX. It 2. |Number| is 64-bit and value is above INT64_MAX. It
cannot possibly be below INT64_MIN because msgpack cannot possibly be below INT64_MIN because msgpack
C parser does not support such values. C parser does not support such values.
float |Float|. This value cannot possibly appear in float |Float|. This value cannot possibly appear in
|msgpackparse()| output. |msgpackparse()| output.
string |readfile()|-style list of strings. This value will string |readfile()|-style list of strings. This value will
appear in |msgpackparse()| output if string contains appear in |msgpackparse()| output if string contains
zero byte or if string is a mapping key and mapping is zero byte or if string is a mapping key and mapping is
being represented as special dictionary for other being represented as special dictionary for other
reasons. reasons.
binary |readfile()|-style list of strings. This value will binary |readfile()|-style list of strings. This value will
appear in |msgpackparse()| output if binary string appear in |msgpackparse()| output if binary string
contains zero byte. contains zero byte.
array |List|. This value cannot appear in |msgpackparse()| array |List|. This value cannot appear in |msgpackparse()|
output. output.
*msgpack-special-map* *msgpack-special-map*
map |List| of |List|s with two items (key and value) each. map |List| of |List|s with two items (key and value) each.
This value will appear in |msgpackparse()| output if This value will appear in |msgpackparse()| output if
parsed mapping contains one of the following keys: parsed mapping contains one of the following keys:
1. Any key that is not a string (including keys which 1. Any key that is not a string (including keys which
are binary strings). are binary strings).
2. String with NUL byte inside. 2. String with NUL byte inside.
3. Duplicate key. 3. Duplicate key.
4. Empty key. 4. Empty key.
ext |List| with two values: first is a signed integer ext |List| with two values: first is a signed integer
representing extension type. Second is representing extension type. Second is
|readfile()|-style list of strings. |readfile()|-style list of strings.
nextnonblank({lnum}) *nextnonblank()* nextnonblank({lnum}) *nextnonblank()*
@@ -6073,11 +6083,11 @@ pumvisible() *pumvisible()*
py3eval({expr}) *py3eval()* py3eval({expr}) *py3eval()*
Evaluate Python expression {expr} and return its result Evaluate Python expression {expr} and return its result
converted to Vim data structures. converted to Vim data structures.
Numbers and strings are returned as they are (strings are Numbers and strings are returned as they are (strings are
copied though, Unicode strings are additionally converted to copied though, Unicode strings are additionally converted to
UTF-8). UTF-8).
Lists are represented as Vim |List| type. Lists are represented as Vim |List| type.
Dictionaries are represented as Vim |Dictionary| type with Dictionaries are represented as Vim |Dictionary| type with
keys converted to strings. keys converted to strings.
{only available when compiled with the |+python3| feature} {only available when compiled with the |+python3| feature}
@@ -6145,7 +6155,7 @@ readfile({fname} [, {binary} [, {max}]])
reltime([{start} [, {end}]]) *reltime()* reltime([{start} [, {end}]]) *reltime()*
Return an item that represents a time value. The format of Return an item that represents a time value. The format of
the item depends on the system. It can be passed to the item depends on the system. It can be passed to
|reltimestr()| to convert it to a string or |reltimefloat()| |reltimestr()| to convert it to a string or |reltimefloat()|
to convert to a float. to convert to a float.
Without an argument it returns the current "relative time", an Without an argument it returns the current "relative time", an
@@ -6628,15 +6638,11 @@ server2client({clientid}, {string}) *server2client()*
:echo server2client(expand("<client>"), "HELLO") :echo server2client(expand("<client>"), "HELLO")
< <
serverlist() *serverlist()* serverlist() *serverlist()*
Returns a list of available server names in a list. Returns a list of server addresses, or empty if all servers
When there are no servers an empty string is returned. were stopped. |serverstart()| |serverstop()|
Example: > Example: >
:echo serverlist() :echo serverlist()
< {Nvim} *--serverlist*
The Vim command-line option `--serverlist` was removed from
Nvim, but it can be imitated: >
nvim --cmd "echo serverlist()" --cmd "q"
<
serverstart([{address}]) *serverstart()* serverstart([{address}]) *serverstart()*
Opens a socket or named pipe at {address} and listens for Opens a socket or named pipe at {address} and listens for
|RPC| messages. Clients can send |API| commands to the address |RPC| messages. Clients can send |API| commands to the address
@@ -6664,13 +6670,9 @@ serverstart([{address}]) *serverstart()*
< |$NVIM_LISTEN_ADDRESS| is set to {address} if not already set. < |$NVIM_LISTEN_ADDRESS| is set to {address} if not already set.
*--servername*
The Vim command-line option `--servername` can be imitated: >
nvim --cmd "let g:server_addr = serverstart('foo')"
<
serverstop({address}) *serverstop()* serverstop({address}) *serverstop()*
Closes the pipe or socket at {address}. Does nothing if Closes the pipe or socket at {address}.
{address} is empty or invalid. Returns TRUE if {address} is valid, else FALSE.
If |$NVIM_LISTEN_ADDRESS| is stopped it is unset. If |$NVIM_LISTEN_ADDRESS| is stopped it is unset.
If |v:servername| is stopped it is set to the next available If |v:servername| is stopped it is set to the next available
address returned by |serverlist()|. address returned by |serverlist()|.
@@ -6843,6 +6845,7 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
nr error number nr error number
text description of the error text description of the error
type single-character error type, 'E', 'W', etc. type single-character error type, 'E', 'W', etc.
valid recognized error message
The "col", "vcol", "nr", "type" and "text" entries are The "col", "vcol", "nr", "type" and "text" entries are
optional. Either "lnum" or "pattern" entry can be used to optional. Either "lnum" or "pattern" entry can be used to
@@ -6852,21 +6855,26 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
item will not be handled as an error line. item will not be handled as an error line.
If both "pattern" and "lnum" are present then "pattern" will If both "pattern" and "lnum" are present then "pattern" will
be used. be used.
If the "valid" entry is not supplied, then the valid flag is
set when "bufnr" is a valid buffer or "filename" exists.
If you supply an empty {list}, the quickfix list will be If you supply an empty {list}, the quickfix list will be
cleared. cleared.
Note that the list is not exactly the same as what Note that the list is not exactly the same as what
|getqflist()| returns. |getqflist()| returns.
*E927* {action} values: *E927*
If {action} is set to 'a', then the items from {list} are 'a' The items from {list} are added to the existing
added to the existing quickfix list. If there is no existing quickfix list. If there is no existing list, then a
list, then a new list is created. new list is created.
If {action} is set to 'r', then the items from the current 'r' The items from the current quickfix list are replaced
quickfix list are replaced with the items from {list}. This with the items from {list}. This can also be used to
can also be used to clear the list: > clear the list: >
:call setqflist([], 'r') :call setqflist([], 'r')
< <
'f' All the quickfix lists in the quickfix stack are
freed.
If {action} is not present or is set to ' ', then a new list If {action} is not present or is set to ' ', then a new list
is created. is created.
@@ -6877,7 +6885,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
only the items listed in {what} are set. The first {list} only the items listed in {what} are set. The first {list}
argument is ignored. The following items can be specified in argument is ignored. The following items can be specified in
{what}: {what}:
nr list number in the quickfix stack context any Vim type can be stored as a context
items list of quickfix entries. Same as the {list}
argument.
nr list number in the quickfix stack; zero
means the current quickfix list and '$' means
the last quickfix list
title quickfix list title text title quickfix list title text
Unsupported keys in {what} are ignored. Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list If the "nr" item is not present, then the current quickfix list
@@ -6929,9 +6942,9 @@ setreg({regname}, {value} [, {options}])
:call setreg('a', "1\n2\n3", 'b5') :call setreg('a', "1\n2\n3", 'b5')
< This example shows using the functions to save and restore a < This example shows using the functions to save and restore a
register (note: you may not reliably restore register value register (note: you may not reliably restore register value
without using the third argument to |getreg()| as without it without using the third argument to |getreg()| as without it
newlines are represented as newlines AND Nul bytes are newlines are represented as newlines AND Nul bytes are
represented as newlines as well, see |NL-used-for-Nul|). > represented as newlines as well, see |NL-used-for-Nul|). >
:let var_a = getreg('a', 1, 1) :let var_a = getreg('a', 1, 1)
:let var_amode = getregtype('a') :let var_amode = getregtype('a')
@@ -6982,18 +6995,22 @@ shellescape({string} [, {special}]) *shellescape()*
quotes within {string}. quotes within {string}.
Otherwise, it will enclose {string} in single quotes and Otherwise, it will enclose {string} in single quotes and
replace all "'" with "'\''". replace all "'" with "'\''".
When the {special} argument is present and it's a non-zero When the {special} argument is present and it's a non-zero
Number or a non-empty String (|non-zero-arg|), then special Number or a non-empty String (|non-zero-arg|), then special
items such as "!", "%", "#" and "<cword>" will be preceded by items such as "!", "%", "#" and "<cword>" will be preceded by
a backslash. This backslash will be removed again by the |:!| a backslash. This backslash will be removed again by the |:!|
command. command.
The "!" character will be escaped (again with a |non-zero-arg| The "!" character will be escaped (again with a |non-zero-arg|
{special}) when 'shell' contains "csh" in the tail. That is {special}) when 'shell' contains "csh" in the tail. That is
because for csh and tcsh "!" is used for history replacement because for csh and tcsh "!" is used for history replacement
even when inside single quotes. even when inside single quotes.
The <NL> character is also escaped. With a |non-zero-arg|
{special} and 'shell' containing "csh" in the tail it's With a |non-zero-arg| {special} the <NL> character is also
escaped. When 'shell' containing "csh" in the tail it's
escaped a second time. escaped a second time.
Example of use with a |:!| command: > Example of use with a |:!| command: >
:exe '!dir ' . shellescape(expand('<cfile>'), 1) :exe '!dir ' . shellescape(expand('<cfile>'), 1)
< This results in a directory listing for the file under the < This results in a directory listing for the file under the
@@ -7369,20 +7386,20 @@ string({expr}) Return {expr} converted to a String. If {expr} is a Number,
{expr} type result ~ {expr} type result ~
String 'string' String 'string'
Number 123 Number 123
Float 123.123456 or 1.123456e8 or Float 123.123456 or 1.123456e8 or
`str2float('inf')` `str2float('inf')`
Funcref `function('name')` Funcref `function('name')`
List [item, item] List [item, item]
Dictionary {key: value, key: value} Dictionary {key: value, key: value}
Note that in String values the ' character is doubled. Note that in String values the ' character is doubled.
Also see |strtrans()|. Also see |strtrans()|.
Note 2: Output format is mostly compatible with YAML, except Note 2: Output format is mostly compatible with YAML, except
for infinite and NaN floating-point values representations for infinite and NaN floating-point values representations
which use |str2float()|. Strings are also dumped literally, which use |str2float()|. Strings are also dumped literally,
only single quote is escaped, which does not allow using YAML only single quote is escaped, which does not allow using YAML
for parsing back binary strings. |eval()| should always work for for parsing back binary strings. |eval()| should always work for
strings and floats though and this is the only official strings and floats though and this is the only official
method, use |msgpackdump()| or |json_encode()| if you need to method, use |msgpackdump()| or |json_encode()| if you need to
share data with other application. share data with other application.
*strlen()* *strlen()*
@@ -7577,17 +7594,29 @@ synIDtrans({synID}) *synIDtrans()*
":highlight link" are followed. ":highlight link" are followed.
synconcealed({lnum}, {col}) *synconcealed()* synconcealed({lnum}, {col}) *synconcealed()*
The result is a List. The first item in the list is 0 if the The result is a List with currently three items:
character at the position {lnum} and {col} is not part of a 1. The first item in the list is 0 if the character at the
concealable region, 1 if it is. The second item in the list is position {lnum} and {col} is not part of a concealable
a string. If the first item is 1, the second item contains the region, 1 if it is.
text which will be displayed in place of the concealed text, 2. The second item in the list is a string. If the first item
depending on the current setting of 'conceallevel'. The third is 1, the second item contains the text which will be
and final item in the list is a unique number representing the displayed in place of the concealed text, depending on the
specific syntax region matched. This allows detection of the current setting of 'conceallevel' and 'listchars'.
beginning of a new concealable region if there are two 3. The third and final item in the list is a number
consecutive regions with the same replacement character. representing the specific syntax region matched in the
For an example use see $VIMRUNTIME/syntax/2html.vim . line. When the character is not concealed the value is
zero. This allows detection of the beginning of a new
concealable region if there are two consecutive regions
with the same replacement character. For an example, if
the text is "123456" and both "23" and "45" are concealed
and replace by the character "X", then:
call returns ~
synconcealed(lnum, 1) [0, '', 0]
synconcealed(lnum, 2) [1, 'X', 1]
synconcealed(lnum, 3) [1, 'X', 1]
synconcealed(lnum, 4) [1, 'X', 2]
synconcealed(lnum, 5) [1, 'X', 2]
synconcealed(lnum, 6) [0, '', 0]
synstack({lnum}, {col}) *synstack()* synstack({lnum}, {col}) *synstack()*
@@ -7620,6 +7649,9 @@ system({cmd} [, {input}]) *system()* *E677*
|writefile()| does with {binary} set to "b" (i.e. with |writefile()| does with {binary} set to "b" (i.e. with
a newline between each list item, and newlines inside list a newline between each list item, and newlines inside list
items converted to NULs). items converted to NULs).
When {input} is given and is a valid buffer id, the content of
the buffer is written to the file line by line, each line
terminated by a NL (and NUL where the text has NL).
*E5677* *E5677*
Note: system() cannot write to or read from backgrounded ("&") Note: system() cannot write to or read from backgrounded ("&")
shell commands, e.g.: > shell commands, e.g.: >
@@ -7630,10 +7662,10 @@ system({cmd} [, {input}]) *system()* *E677*
redirection syntax) before input can reach it. Use redirection syntax) before input can reach it. Use
|jobstart()| instead. |jobstart()| instead.
Note: Use |shellescape()| or |::S| with |expand()| or Note: Use |shellescape()| or |::S| with |expand()| or
|fnamemodify()| to escape special characters in a command |fnamemodify()| to escape special characters in a command
argument. Newlines in {cmd} may cause the command to fail. argument. Newlines in {cmd} may cause the command to fail.
The characters in 'shellquote' and 'shellxquote' may also The characters in 'shellquote' and 'shellxquote' may also
cause trouble. cause trouble.
The result is a String. Example: > The result is a String. Example: >
@@ -7660,9 +7692,9 @@ system({cmd} [, {input}]) *system()* *E677*
systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()* systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()*
Same as |system()|, but returns a |List| with lines (parts of Same as |system()|, but returns a |List| with lines (parts of
output separated by NL) with NULs transformed into NLs. Output output separated by NL) with NULs transformed into NLs. Output
is the same as |readfile()| will output with {binary} argument is the same as |readfile()| will output with {binary} argument
set to "b", except that a final newline is not preserved, set to "b", except that a final newline is not preserved,
unless {keepempty} is non-zero. unless {keepempty} is non-zero.
Note that on MS-Windows you may get trailing CR characters. Note that on MS-Windows you may get trailing CR characters.
@@ -7926,7 +7958,7 @@ type({expr}) *type()*
:if type(myvar) == type({}) :if type(myvar) == type({})
:if type(myvar) == type(0.0) :if type(myvar) == type(0.0)
:if type(myvar) == type(v:true) :if type(myvar) == type(v:true)
< In place of checking for |v:null| type it is better to check < In place of checking for |v:null| type it is better to check
for |v:null| directly as it is the only value of this type: > for |v:null| directly as it is the only value of this type: >
:if myvar is v:null :if myvar is v:null
< To check if the v:t_ variables exist use this: > < To check if the v:t_ variables exist use this: >
@@ -8243,10 +8275,10 @@ writefile({list}, {fname} [, {flags}])
:call writefile(["foo"], "event.log", "a") :call writefile(["foo"], "event.log", "a")
:call writefile(["bar"], "event.log", "a") :call writefile(["bar"], "event.log", "a")
< <
When {flags} contains "S" fsync() call is not used, with "s" When {flags} contains "S" fsync() call is not used, with "s"
it is used, 'fsync' option applies by default. No fsync() it is used, 'fsync' option applies by default. No fsync()
means that writefile() will finish faster, but writes may be means that writefile() will finish faster, but writes may be
left in OS buffers and not yet written to disk. Such changes left in OS buffers and not yet written to disk. Such changes
will disappear if system crashes before OS does writing. will disappear if system crashes before OS does writing.
All NL characters are replaced with a NUL character. All NL characters are replaced with a NUL character.
@@ -8414,6 +8446,7 @@ win32 Windows version of Vim (32 or 64 bit).
winaltkeys Compiled with 'winaltkeys' option. winaltkeys Compiled with 'winaltkeys' option.
windows Compiled with support for more than one window. windows Compiled with support for more than one window.
writebackup Compiled with 'writebackup' default on. writebackup Compiled with 'writebackup' default on.
wsl WSL (Windows Subsystem for Linux) version of Vim.
*string-match* *string-match*
Matching a pattern in a String Matching a pattern in a String
@@ -8728,7 +8761,7 @@ like this: >
When such a function is called, and it is not defined yet, Vim will search the When such a function is called, and it is not defined yet, Vim will search the
"autoload" directories in 'runtimepath' for a script file called "autoload" directories in 'runtimepath' for a script file called
"filename.vim". For example "~/.config/nvim/autoload/filename.vim". That "filename.vim". For example "~/.config/nvim/autoload/filename.vim". That
file should then define the function like this: > file should then define the function like this: >
function filename#funcname() function filename#funcname()
@@ -8889,11 +8922,6 @@ This does NOT work: >
value and the global value are changed. value and the global value are changed.
Example: > Example: >
:let &path = &path . ',/usr/local/include' :let &path = &path . ',/usr/local/include'
< This also works for terminal codes in the form t_xx.
But only for alphanumerical names. Example: >
:let &t_k1 = "\<Esc>[234;"
< When the code does not exist yet it will be created as
a terminal key code, there is no error.
:let &{option-name} .= {expr1} :let &{option-name} .= {expr1}
For a string option: Append {expr1} to the value. For a string option: Append {expr1} to the value.
@@ -9004,8 +9032,8 @@ This does NOT work: >
< *E741* *E940* < *E741* *E940*
If you try to change a locked variable you get an If you try to change a locked variable you get an
error message: "E741: Value is locked: {name}". error message: "E741: Value is locked: {name}".
If you try to lock or unlock a built-in variable you If you try to lock or unlock a built-in variable you
will get an error message "E940: Cannot lock or unlock will get an error message "E940: Cannot lock or unlock
variable {name}". variable {name}".
[depth] is relevant when locking a |List| or [depth] is relevant when locking a |List| or
@@ -9264,17 +9292,17 @@ This does NOT work: >
with the |:redraw| command. Example: > with the |:redraw| command. Example: >
:new | redraw | echo "there is a new window" :new | redraw | echo "there is a new window"
< *:echo-self-refer* < *:echo-self-refer*
When printing nested containers echo prints second When printing nested containers echo prints second
occurrence of the self-referencing container using occurrence of the self-referencing container using
"[...@level]" (self-referencing |List|) or "[...@level]" (self-referencing |List|) or
"{...@level}" (self-referencing |Dict|): > "{...@level}" (self-referencing |Dict|): >
:let l = [] :let l = []
:call add(l, l) :call add(l, l)
:let l2 = [] :let l2 = []
:call add(l2, [l2]) :call add(l2, [l2])
:echo l l2 :echo l l2
< echoes "[[...@0]] [[[...@0]]]". Echoing "[l]" will < echoes "[[...@0]] [[[...@0]]]". Echoing "[l]" will
echo "[[[...@1]]]" because l first occurs at second echo "[[[...@1]]]" because l first occurs at second
level. level.
*:echon* *:echon*
@@ -10505,18 +10533,19 @@ missing: >
To execute a command only when the |+eval| feature is disabled requires a trick, To execute a command only when the |+eval| feature is disabled requires a trick,
as this example shows: > as this example shows: >
if 1
nnoremap : :" silent! while 0
endif set history=111
normal :set history=111<CR> silent! endwhile
if 1
nunmap : When the |+eval| feature is available the command is skipped because of the
endif "while 0". Without the |+eval| feature the "while 0" is an error, which is
silently ignored, and the command is executed.
The "<CR>" here is a real CR character, type CTRL-V Enter to get it. The "<CR>" here is a real CR character, type CTRL-V Enter to get it.
When the |+eval| feature is available the ":" is remapped to add a double When the |+eval| feature is available the ":" is remapped to add a double
quote, which has the effect of commenting-out the command. without the quote, which has the effect of commenting-out the command. Without the
|+eval| feature the nnoremap command is skipped and the command is executed. |+eval| feature the nnoremap command is skipped and the command is executed.
============================================================================== ==============================================================================
@@ -10563,7 +10592,7 @@ option will still be marked as it was set in the sandbox.
In a few situations it is not allowed to change the text in the buffer, jump In a few situations it is not allowed to change the text in the buffer, jump
to another window and some other things that might confuse or break what Vim to another window and some other things that might confuse or break what Vim
is currently doing. This mostly applies to things that happen when Vim is is currently doing. This mostly applies to things that happen when Vim is
actually doing something else. For example, evaluating the 'balloonexpr' may actually doing something else. For example, evaluating the 'balloonexpr' may
happen any moment the mouse cursor is resting at some position. happen any moment the mouse cursor is resting at some position.
This is not allowed when the textlock is active: This is not allowed when the textlock is active:
@@ -10573,5 +10602,123 @@ This is not allowed when the textlock is active:
- closing a window or quitting Vim - closing a window or quitting Vim
- etc. - etc.
==============================================================================
13. Command-line expressions highlighting *expr-highlight*
Expressions entered by the user in |i_CTRL-R_=|, |c_CTRL-\_e|, |quote=| are
highlighted by the built-in expressions parser. It uses highlight groups
described in the table below, which may be overriden by colorschemes.
*hl-NvimInvalid*
Besides the "Nvim"-prefixed highlight groups described below, there are
"NvimInvalid"-prefixed highlight groups which have the same meaning but
indicate that the token contains an error or that an error occurred just
before it. They have mostly the same hierarchy, except that (by default) in
place of any non-Nvim-prefixed group NvimInvalid linking to `Error` is used
and some other intermediate groups are present.
Group Default link Colored expression ~
*hl-NvimInternalError* None, red/red Parser bug
*hl-NvimAssignment* Operator Generic assignment
*hl-NvimPlainAssignment* NvimAssignment `=` in |:let|
*hl-NvimAugmentedAssignment* NvimAssignment Generic, `+=`/`-=`/`.=`
*hl-NvimAssignmentWithAddition* NvimAugmentedAssignment `+=` in |:let+=|
*hl-NvimAssignmentWithSubtraction* NvimAugmentedAssignment `-=` in |:let-=|
*hl-NvimAssignmentWithConcatenation* NvimAugmentedAssignment `.=` in |:let.=|
*hl-NvimOperator* Operator Generic operator
*hl-NvimUnaryOperator* NvimOperator Generic unary op
*hl-NvimUnaryPlus* NvimUnaryOperator |expr-unary-+|
*hl-NvimUnaryMinus* NvimUnaryOperator |expr-unary--|
*hl-NvimNot* NvimUnaryOperator |expr-!|
*hl-NvimBinaryOperator* NvimOperator Generic binary op
*hl-NvimComparison* NvimBinaryOperator Any |expr4| operator
*hl-NvimComparisonModifier* NvimComparison `#`/`?` near |expr4| op
*hl-NvimBinaryPlus* NvimBinaryOperator |expr-+|
*hl-NvimBinaryMinus* NvimBinaryOperator |expr--|
*hl-NvimConcat* NvimBinaryOperator |expr-.|
*hl-NvimConcatOrSubscript* NvimConcat |expr-.| or |expr-entry|
*hl-NvimOr* NvimBinaryOperator |expr-barbar|
*hl-NvimAnd* NvimBinaryOperator |expr-&&|
*hl-NvimMultiplication* NvimBinaryOperator |expr-star|
*hl-NvimDivision* NvimBinaryOperator |expr-/|
*hl-NvimMod* NvimBinaryOperator |expr-%|
*hl-NvimTernary* NvimOperator `?` in |expr1|
*hl-NvimTernaryColon* NvimTernary `:` in |expr1|
*hl-NvimParenthesis* Delimiter Generic bracket
*hl-NvimLambda* NvimParenthesis `{`/`}` in |lambda|
*hl-NvimNestingParenthesis* NvimParenthesis `(`/`)` in |expr-nesting|
*hl-NvimCallingParenthesis* NvimParenthesis `(`/`)` in |expr-function|
*hl-NvimSubscript* NvimParenthesis Generic subscript
*hl-NvimSubscriptBracket* NvimSubscript `[`/`]` in |expr-[]|
*hl-NvimSubscriptColon* NvimSubscript `:` in |expr-[:]|
*hl-NvimCurly* NvimSubscript `{`/`}` in
|curly-braces-names|
*hl-NvimContainer* NvimParenthesis Generic container
*hl-NvimDict* NvimContainer `{`/`}` in |dict| literal
*hl-NvimList* NvimContainer `[`/`]` in |list| literal
*hl-NvimIdentifier* Identifier Generic identifier
*hl-NvimIdentifierScope* NvimIdentifier Namespace: letter
before `:` in
|internal-variables|
*hl-NvimIdentifierScopeDelimiter* NvimIdentifier `:` after namespace
letter
*hl-NvimIdentifierName* NvimIdentifier Rest of the ident
*hl-NvimIdentifierKey* NvimIdentifier Identifier after
|expr-entry|
*hl-NvimColon* Delimiter `:` in |dict| literal
*hl-NvimComma* Delimiter `,` in |dict|/|list|
literal or
|expr-function|
*hl-NvimArrow* Delimiter `->` in |lambda|
*hl-NvimRegister* SpecialChar |expr-register|
*hl-NvimNumber* Number Non-prefix digits
in integer
|expr-number|
*hl-NvimNumberPrefix* Type `0` for |octal-number|
`0x` for |hex-number|
`0b` for |binary-number|
*hl-NvimFloat* NvimNumber Floating-point
number
*hl-NvimOptionSigil* Type `&` in |expr-option|
*hl-NvimOptionScope* NvimIdentifierScope Option scope if any
*hl-NvimOptionScopeDelimiter* NvimIdentifierScopeDelimiter
`:` after option scope
*hl-NvimOptionName* NvimIdentifier Option name
*hl-NvimEnvironmentSigil* NvimOptionSigil `$` in |expr-env|
*hl-NvimEnvironmentName* NvimIdentifier Env variable name
*hl-NvimString* String Generic string
*hl-NvimStringBody* NvimString Generic string
literal body
*hl-NvimStringQuote* NvimString Generic string quote
*hl-NvimStringSpecial* SpecialChar Generic string
non-literal body
*hl-NvimSingleQuote* NvimStringQuote `'` in |expr-'|
*hl-NvimSingleQuotedBody* NvimStringBody Literal part of
|expr-'| string body
*hl-NvimSingleQuotedQuote* NvimStringSpecial `''` inside |expr-'|
string body
*hl-NvimDoubleQuote* NvimStringQuote `"` in |expr-quote|
*hl-NvimDoubleQuotedBody* NvimStringBody Literal part of
|expr-quote| body
*hl-NvimDoubleQuotedEscape* NvimStringSpecial Valid |expr-quote|
escape sequence
*hl-NvimDoubleQuotedUnknownEscape* NvimInvalidValue Unrecognized
|expr-quote| escape
sequence
vim:tw=78:ts=8:noet:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@@ -24,10 +24,8 @@ Each time a new or existing file is edited, Vim will try to recognize the type
of the file and set the 'filetype' option. This will trigger the FileType of the file and set the 'filetype' option. This will trigger the FileType
event, which can be used to set the syntax highlighting, set options, etc. event, which can be used to set the syntax highlighting, set options, etc.
Detail: The ":filetype on" command will load one of these files: Detail: The ":filetype on" command will load this file:
Mac $VIMRUNTIME/filetype.vim $VIMRUNTIME/filetype.vim
MS-DOS $VIMRUNTIME\filetype.vim
Unix $VIMRUNTIME/filetype.vim
This file is a Vim script that defines autocommands for the This file is a Vim script that defines autocommands for the
BufNewFile and BufRead events. If the file type is not found by the BufNewFile and BufRead events. If the file type is not found by the
name, the file $VIMRUNTIME/scripts.vim is used to detect it from the name, the file $VIMRUNTIME/scripts.vim is used to detect it from the

View File

@@ -4,42 +4,19 @@
VIM REFERENCE MANUAL by Andy Kahn VIM REFERENCE MANUAL by Andy Kahn
*cscope* *Cscope* *cscope* *Cscope*
This document explains how to use Vim's cscope interface. Cscope is a "code intelligence" tool that helps you navigate C programs. It
can also perform some refactoring tasks, such as renaming a global variable in
all source files. Think of it as "ctags on steroids".
Cscope is a tool like ctags, but think of it as ctags on steroids since it See |cscope-usage| for a quickstart.
does a lot more than what ctags provides. In Vim, jumping to a result from
a cscope query is just like jumping to any tag; it is saved on the tag stack
so that with the right keyboard mappings, you can jump back and forth between
functions as you normally would with |tags|.
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
============================================================================== ==============================================================================
1. Cscope introduction *cscope-intro* Cscope introduction *cscope-intro*
The following text is taken from a version of the cscope man page:
----- Cscope is designed to answer questions like:
Cscope is an interactive screen-oriented tool that helps you:
Learn how a C program works without endless flipping through a thick
listing.
Locate the section of code to change to fix a bug without having to
learn the entire program.
Examine the effect of a proposed change such as adding a value to an
enum variable.
Verify that a change has been made in all source files such as adding
an argument to an existing function.
Rename a global variable in all source files.
Change a constant to a preprocessor symbol in selected lines of files.
It is designed to answer questions like:
Where is this symbol used? Where is this symbol used?
Where is it defined? Where is it defined?
Where did this variable get its value? Where did this variable get its value?
@@ -51,35 +28,17 @@ The following text is taken from a version of the cscope man page:
Where is this source file in the directory structure? Where is this source file in the directory structure?
What files include this header file? What files include this header file?
Cscope answers these questions from a symbol database that it builds the Cscope answers these questions from a symbol database that it builds the first
first time it is used on the source files. On a subsequent call, cscope time it is used on the source files. On a subsequent call, cscope rebuilds
rebuilds the database only if a source file has changed or the list of the database only if a source file has changed or the list of source files is
source files is different. When the database is rebuilt the data for the different. When the database is rebuilt the data for the unchanged files is
unchanged files is copied from the old database, which makes rebuilding copied from the old database, which makes rebuilding much faster than the
much faster than the initial build. initial build.
-----
When cscope is normally invoked, you will get a full-screen selection
screen allowing you to make a query for one of the above questions.
However, once a match is found to your query and you have entered your
text editor to edit the source file containing match, you cannot simply
jump from tag to tag as you normally would with vi's Ctrl-] or :tag
command.
Vim's cscope interface is done by invoking cscope with its line-oriented
interface, and then parsing the output returned from a query. The end
result is that cscope query results become just like regular tags, so
you can jump to them just like you do with normal tags (Ctrl-] or :tag)
and then go back by popping off the tagstack with Ctrl-T. (Please note
however, that you don't actually jump to a cscope tag simply by doing
Ctrl-] or :tag without remapping these commands or setting an option.
See the remaining sections on how the cscope interface works and for
suggested use.)
See |cscope-usage| to get started.
============================================================================== ==============================================================================
2. Cscope related commands *cscope-commands* Cscope commands *cscope-commands*
*:cscope* *:cs* *:scs* *:scscope* *E259* *E262* *E561* *E560* *:cscope* *:cs* *:scs* *:scscope* *E259* *E262* *E561* *E560*
All cscope commands are accessed through suboptions to the cscope commands. All cscope commands are accessed through suboptions to the cscope commands.
@@ -232,7 +191,7 @@ through your tags file(s).
============================================================================== ==============================================================================
3. Cscope options *cscope-options* Cscope options *cscope-options*
Use the |:set| command to set all cscope options. Ideally, you would do Use the |:set| command to set all cscope options. Ideally, you would do
this in one of your startup files (e.g., vimrc). Some cscope related this in one of your startup files (e.g., vimrc). Some cscope related
@@ -245,7 +204,6 @@ started will have no effect!
:set csprg=/usr/local/bin/cscope :set csprg=/usr/local/bin/cscope
< <
*cscopequickfix* *csqf* *E469* *cscopequickfix* *csqf* *E469*
{not available when compiled without the |+quickfix| feature}
'cscopequickfix' specifies whether to use quickfix window to show cscope 'cscopequickfix' specifies whether to use quickfix window to show cscope
results. This is a list of comma-separated values. Each item consists of results. This is a list of comma-separated values. Each item consists of
|cscope-find| command (s, g, d, c, t, e, f, i or a) and flag (+, - or 0). |cscope-find| command (s, g, d, c, t, e, f, i or a) and flag (+, - or 0).
@@ -260,81 +218,56 @@ seems to be useful: >
If 'cscopetag' is set, the commands ":tag" and CTRL-] as well as "vim -t" If 'cscopetag' is set, the commands ":tag" and CTRL-] as well as "vim -t"
will always use |:cstag| instead of the default :tag behavior. Effectively, will always use |:cstag| instead of the default :tag behavior. Effectively,
by setting 'cst', you will always search your cscope databases as well as by setting 'cst', you will always search your cscope databases as well as
your tag files. The default is off. Examples: > your tag files. The default is off.
:set cst
:set nocst
<
*cscoperelative* *csre* *cscoperelative* *csre*
If 'cscoperelative' is set, then in absence of a prefix given to cscope If 'cscoperelative' is set, then in absence of a prefix given to cscope
(prefix is the argument of -P option of cscope), basename of cscope.out (prefix is the argument of -P option of cscope), basename of cscope.out
location (usually the project root directory) will be used as the prefix location (usually the project root directory) will be used as the prefix
to construct an absolute path. The default is off. Note: This option is to construct an absolute path. The default is off. Note: This option is
only effective when cscope (cscopeprg) is initialized without a prefix only effective when cscope (cscopeprg) is initialized without a prefix
path (-P). Examples: > path (-P).
:set csre
:set nocsre
<
*cscopetagorder* *csto* *cscopetagorder* *csto*
The value of 'csto' determines the order in which |:cstag| performs a search. The value of 'csto' determines the order in which |:cstag| performs a search.
If 'csto' is set to zero, cscope database(s) are searched first, followed If 'csto' is set to zero, cscope database(s) are searched first, followed
by tag file(s) if cscope did not return any matches. If 'csto' is set to by tag file(s) if cscope did not return any matches. If 'csto' is set to
one, tag file(s) are searched before cscope database(s). The default is zero. one, tag file(s) are searched before cscope database(s). The default is zero.
Examples: >
:set csto=0
:set csto=1
<
*cscopeverbose* *csverb*
If 'cscopeverbose' is not set (the default), messages will not be printed
indicating success or failure when adding a cscope database. Ideally, you
should reset this option in your |init.vim| before adding any cscope
databases, and after adding them, set it. From then on, when you add more
databases within Vim, you will get a (hopefully) useful message should the
database fail to be added. Examples: >
:set csverb
:set nocsverb
<
*cscopepathcomp* *cspc* *cscopepathcomp* *cspc*
The value of 'cspc' determines how many components of a file's path to 'cscopepathcomp' determines how many components of a file's path to display.
display. With the default value of zero the entire path will be displayed. With the default value of zero the entire path will be displayed.
The value one will display only the filename with no path. Other values The value one will display only the filename with no path. Other values
display that many components. For example: > display that many components. For example: >
:set cspc=3 :set cscopepathcomp=3
will display the last 3 components of the file's path, including the file will display the last 3 components of the file's path, including the file
name itself. name itself.
============================================================================== ==============================================================================
4. How to use cscope in Vim *cscope-howtouse* Using cscope in Nvim *cscope-usage* *cscope-howtouse*
The first thing you need to do is to build a cscope database for your To get started, build the cscope database in your project root directory: >
source files. For the most basic case, simply do "cscope -b". Please cscope -bcqR
refer to the cscope man page for more details.
Assuming you have a cscope database, you need to "add" the database to Vim. See the cscope manpage for details: >
This establishes a cscope "connection" and makes it available for Vim to use. :Man cscope
You can do this in your vimrc file, or you can do it manually after starting
vim. For example, to add the cscope database "cscope.out", you would do:
:cs add cscope.out By default the cscope database file is named "cscope.out". After building the
database, connect to it from Nvim: >
:cscope add cscope.out
You can double-check the result of this by executing ":cs show". This will That establishes a cscope connection for Nvim to use. You can check the
produce output which looks like this: result with ":cs show". It will show something like:
# pid database name prepend path # pid database name prepend path
0 28806 cscope.out <none> 0 28806 cscope.out <none>
Note:
Because of the Microsoft RTL limitations, Win32 version shows 0 instead
of the real pid.
Once a cscope connection is established, you can make queries to cscope and Once a cscope connection is established, you can make queries to cscope and
the results will be printed to you. Queries are made using the command the results will be printed. Queries are made using the command ":cs find".
":cs find". For example: For example: >
:cs find g ALIGN_SIZE :cs find g ALIGN_SIZE
This can get a little cumbersome since one ends up doing a significant To make this easier you can configure mappings, see |cscope-suggestions|.
amount of typing. Fortunately, there are ways around this by mapping
shortcut keys. See |cscope-suggestions| for suggested usage.
If the results return only one match, you will automatically be taken to it. If the results return only one match, you will automatically be taken to it.
If there is more than one match, you will be given a selection screen to pick If there is more than one match, you will be given a selection screen to pick
@@ -343,39 +276,28 @@ simply hit Ctrl-T to get back to the previous one.
============================================================================== ==============================================================================
5. Limitations *cscope-limitations* Limitations *cscope-limitations*
Cscope support for Vim is only available on systems that support these four
system calls: fork(), pipe(), execl(), waitpid(). This means it is mostly
limited to Unix systems.
Additionally Cscope support works for Win32. For more information and a
cscope version for Win32 see:
http://iamphet.nm.ru/cscope/index.html
Hard-coded limitation: doing a |:tjump| when |:cstag| searches the tag files Hard-coded limitation: doing a |:tjump| when |:cstag| searches the tag files
is not configurable (e.g., you can't do a tselect instead). is not configurable (e.g., you can't do a tselect instead).
==============================================================================
6. Suggested usage *cscope-suggestions*
Put these entries in your vimrc (adjust the pathname accordingly to your ==============================================================================
setup): > Sample config *cscope-suggestions*
Copy this into your init.vim (adjust paths for your system): >
if has("cscope") if has("cscope")
set csprg=/usr/local/bin/cscope set csprg=/usr/local/bin/cscope
set csto=0 set csto=0
set cst set cst
set nocsverb
" add any database in current directory " add any database in current directory
if filereadable("cscope.out") if filereadable("cscope.out")
cs add cscope.out silent cs add cscope.out
" else add database pointed to by environment " else add database pointed to by environment
elseif $CSCOPE_DB != "" elseif $CSCOPE_DB != ""
cs add $CSCOPE_DB silent cs add $CSCOPE_DB
endif endif
set csverb
endif endif
By setting 'cscopetag', we have effectively replaced all instances of the :tag By setting 'cscopetag', we have effectively replaced all instances of the :tag
@@ -447,47 +369,6 @@ Cscope Home Page (http://cscope.sourceforge.net/): >
\:vert scs find d <C-R>=expand("<cword>")<CR><CR> \:vert scs find d <C-R>=expand("<cword>")<CR><CR>
nmap <C-Space><C-Space>a nmap <C-Space><C-Space>a
\:vert scs find a <C-R>=expand("<cword>")<CR><CR> \:vert scs find a <C-R>=expand("<cword>")<CR><CR>
<
==============================================================================
7. Cscope availability and information *cscope-info*
If you do not already have cscope (it did not come with your compiler
license or OS distribution), then you can download it for free from:
http://cscope.sourceforge.net/
This is released by SCO under the BSD license.
If you want a newer version of cscope, you will probably have to buy it.
According to the (old) nvi documentation:
You can buy version 13.3 source with an unrestricted license
for $400 from AT&T Software Solutions by calling +1-800-462-8146.
Also you can download cscope 13.x and mlcscope 14.x (multi-lingual cscope
which supports C, C++, Java, lex, yacc, breakpoint listing, Ingres, and SDL)
from World-Wide Exptools Open Source packages page:
http://www.bell-labs.com/project/wwexptools/packages.html
In Solaris 2.x, if you have the C compiler license, you will also have
cscope. Both are usually located under /opt/SUNWspro/bin
SGI developers can also get it. Search for Cscope on this page:
http://freeware.sgi.com/index-by-alpha.html
https://toolbox.sgi.com/toolbox/utilities/cscope/
The second one is for those who have a password for the SGI toolbox.
There is source to an older version of a cscope clone (called "cs") available
on the net. Due to various reasons, this is not supported with Vim.
The cscope interface/support for Vim was originally written by
Andy Kahn <ackahn@netapp.com>. The original structure (as well as a tiny
bit of code) was adapted from the cscope interface in nvi. Please report
any problems, suggestions, patches, et al., you have for the usage of
cscope within Vim to him.
*cscope-win32*
For a cscope version for Win32 see:
http://code.google.com/p/cscope-win32/
Win32 support was added by Sergey Khorev <sergey.khorev@gmail.com>. Contact
him if you have Win32-specific issues.
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:norl:

View File

@@ -320,6 +320,21 @@ The examples below assume a 'shiftwidth' of 4.
{ { { {
void function(); void function(); void function(); void function();
} } } }
<
*cino-E*
EN Indent inside C++ linkage specifications (extern "C" or
extern "C++") N characters extra compared to a normal block.
(default 0).
cino= cino=E-s >
extern "C" { extern "C" {
void function(); void function();
} }
extern "C" extern "C"
{ {
void function(); void function();
} }
< <
*cino-p* *cino-p*
pN Parameter declarations for K&R-style function declarations will pN Parameter declarations for K&R-style function declarations will
@@ -550,7 +565,7 @@ The examples below assume a 'shiftwidth' of 4.
The defaults, spelled out in full, are: The defaults, spelled out in full, are:
cinoptions=>s,e0,n0,f0,{0,}0,^0,L-1,:s,=s,l0,b0,gs,hs,N0,ps,ts,is,+s, cinoptions=>s,e0,n0,f0,{0,}0,^0,L-1,:s,=s,l0,b0,gs,hs,N0,E0,ps,ts,is,+s,
c3,C0,/0,(2s,us,U0,w0,W0,k0,m0,j0,J0,)20,*70,#0 c3,C0,/0,(2s,us,U0,w0,W0,k0,m0,j0,J0,)20,*70,#0
Vim puts a line in column 1 if: Vim puts a line in column 1 if:

View File

@@ -40,10 +40,11 @@ char action ~
*i_CTRL-[* *i_<Esc>* *i_CTRL-[* *i_<Esc>*
<Esc> or CTRL-[ End insert or Replace mode, go back to Normal mode. Finish <Esc> or CTRL-[ End insert or Replace mode, go back to Normal mode. Finish
abbreviation. abbreviation.
Note: If your <Esc> key is hard to hit on your keyboard, train Note: If your <Esc> key is hard to hit, try CTRL-[ instead.
yourself to use CTRL-[. *i_META* *i_ALT*
If Esc doesn't work and you are using a Mac, try CTRL-Esc. |ALT| (|META|) acts like <Esc> if the chord is not mapped.
Or disable Listening under Accessibility preferences. For example <A-x> acts like <Esc>x if <A-x> does not have an
insert-mode mapping.
*i_CTRL-C* *i_CTRL-C*
CTRL-C Quit insert mode, go back to Normal mode. Do not check for CTRL-C Quit insert mode, go back to Normal mode. Do not check for
abbreviations. Does not trigger the |InsertLeave| autocommand abbreviations. Does not trigger the |InsertLeave| autocommand
@@ -1077,6 +1078,8 @@ items:
item with the same word is already present. item with the same word is already present.
empty when non-zero this match will be added even when it is empty when non-zero this match will be added even when it is
an empty string an empty string
user_data custom data which is associated with the item and
available in |v:completed_item|
All of these except "icase", "dup" and "empty" must be a string. If an item All of these except "icase", "dup" and "empty" must be a string. If an item
does not meet these requirements then an error message is given and further does not meet these requirements then an error message is given and further
@@ -1170,6 +1173,8 @@ The menu is used when:
The 'pumheight' option can be used to set a maximum height. The default is to The 'pumheight' option can be used to set a maximum height. The default is to
use all space available. use all space available.
The 'pumwidth' option can be used to set a minimum width. The default is 15
characters.
There are three states: There are three states:
1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P. 1. A complete match has been inserted, e.g., after using CTRL-N or CTRL-P.

View File

@@ -58,7 +58,7 @@ Description of what happens:
- The first shell is idle, waiting to read commands from its stdin. - The first shell is idle, waiting to read commands from its stdin.
- The second shell is started with -c which executes the command (a for-loop - The second shell is started with -c which executes the command (a for-loop
printing 0 through 9) and then exits. printing 0 through 9) and then exits.
- `JobHandler()` callback is passed to |jobstart()| to handle various job - `OnEvent()` callback is passed to |jobstart()| to handle various job
events. It displays stdout/stderr data received from the shells. events. It displays stdout/stderr data received from the shells.
For |on_stdout| and |on_stderr| see |channel-callback|. For |on_stdout| and |on_stderr| see |channel-callback|.

View File

@@ -232,8 +232,10 @@ For this reason the following is blocked:
- Editing another buffer. - Editing another buffer.
- The |:normal| command. - The |:normal| command.
- Moving the cursor is allowed, but it is restored afterwards. - Moving the cursor is allowed, but it is restored afterwards.
- If the cmdline is changed, the old text and cursor position are restored.
If you want the mapping to do any of these let the returned characters do If you want the mapping to do any of these let the returned characters do
that. that. Alternatively use a |<Cmd>| mapping which doesn't have these
restrictions.
You can use getchar(), it consumes typeahead if there is any. E.g., if you You can use getchar(), it consumes typeahead if there is any. E.g., if you
have these mappings: > have these mappings: >
@@ -272,6 +274,29 @@ again for using <expr>. This does work: >
Using 0x80 as a single byte before other text does not work, it will be seen Using 0x80 as a single byte before other text does not work, it will be seen
as a special key. as a special key.
*<Cmd>* *:map-command*
A command mapping is a mapping that directly executes a command. Command
mappings are written by placing a command in between <Cmd> and <CR> in the
rhs of a mapping (in any mode): >
noremap <f3> <Cmd>echo mode(1)<cr>
<
*E5520*
The command must be complete and ended with a <CR>. If the command is
incomplete, an error is raised. |Command-line| mode is never entered.
This is more flexible than using `:<c-u>` in visual and operator pending
mode, or `<c-o>:` in insert mode, as the commands are exectued directly in the
mode, and not normal mode. Also visual mode is not aborted. Commands can be
invoked directly in cmdline mode, which is not simple otherwise (a timer has
to be used). Unlike <expr> mappings, there are not any specific restrictions
what the command can do, except for what is normally possible to do in every
specific mode. The command should be executed the same way as if an
(unrestricted) |autocmd| was invoked or an async event event was processed.
Note: In select mode, |:map| or |:vmap| command mappings will be executed in
visual mode. If a mapping is intended to work in select mode, it is
recomendend to map it using |:smap|, possibly in addition to the same mapping
with |:map| or |:xmap|.
1.3 MAPPING AND MODES *:map-modes* 1.3 MAPPING AND MODES *:map-modes*
*mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* *mapmode-t* *mapmode-nvo* *mapmode-n* *mapmode-v* *mapmode-o* *mapmode-t*

View File

@@ -70,9 +70,8 @@ An rpc socket is automatically created with each instance. The socket
location is stored in |v:servername|. By default this is a named pipe location is stored in |v:servername|. By default this is a named pipe
with an automatically generated address. See |XXX|. with an automatically generated address. See |XXX|.
To make Nvim listen on a TCP/IP socket instead, set the To make Nvim listen on a TCP/IP socket instead, specify |--listen|: >
|$NVIM_LISTEN_ADDRESS| environment variable before starting Nvim: > nvim --listen 127.0.0.1:6666
NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim
<Also, more sockets and named pipes can be listened on using |serverstart()|. <Also, more sockets and named pipes can be listened on using |serverstart()|.
Note that localhost TCP sockets are generally less secure than named pipes, Note that localhost TCP sockets are generally less secure than named pipes,
@@ -242,4 +241,4 @@ Even for statically compiled clients it is good practice to avoid hardcoding
the type codes, because a client may be built against one Nvim version but the type codes, because a client may be built against one Nvim version but
connect to another with different type codes. connect to another with different type codes.
vim:tw=78:ts=8:ft=help:norl:

View File

@@ -1807,12 +1807,6 @@ A jump table for the options with a short description can be found at |Q_op|.
Determines the order in which ":cstag" performs a search. See Determines the order in which ":cstag" performs a search. See
|cscopetagorder|. |cscopetagorder|.
*'cscopeverbose'* *'csverb'*
*'nocscopeverbose'* *'nocsverb'*
'cscopeverbose' 'csverb' boolean (default off)
global
Give messages when adding a cscope database. See |cscopeverbose|.
*'cursorbind'* *'crb'* *'nocursorbind'* *'nocrb'* *'cursorbind'* *'crb'* *'nocursorbind'* *'nocrb'*
'cursorbind' 'crb' boolean (default off) 'cursorbind' 'crb' boolean (default off)
local to window local to window
@@ -2042,6 +2036,11 @@ A jump table for the options with a short description can be found at |Q_op|.
column of the last screen line. Overrules "lastline". column of the last screen line. Overrules "lastline".
uhex Show unprintable characters hexadecimal as <xx> uhex Show unprintable characters hexadecimal as <xx>
instead of using ^C and ~C. instead of using ^C and ~C.
msgsep When showing messages longer than 'cmdheight' lines,
only scroll the message lines and not the entire
screen. This also shows a separator line filled with
chars determined by 'fillchars' option, and
highlighted with the |MsgSeparator| group.
When neither "lastline" nor "truncate" is included, a last line that When neither "lastline" nor "truncate" is included, a last line that
doesn't fit is replaced with "@" lines. doesn't fit is replaced with "@" lines.
@@ -2383,7 +2382,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Only normal file name characters can be used, "/\*?[|<>" are illegal. Only normal file name characters can be used, "/\*?[|<>" are illegal.
*'fillchars'* *'fcs'* *'fillchars'* *'fcs'*
'fillchars' 'fcs' string (default "vert:|,fold:-") 'fillchars' 'fcs' string (default "")
global global
{not available when compiled without the |+windows| {not available when compiled without the |+windows|
and |+folding| features} and |+folding| features}
@@ -2393,16 +2392,20 @@ A jump table for the options with a short description can be found at |Q_op|.
item default Used for ~ item default Used for ~
stl:c ' ' or '^' statusline of the current window stl:c ' ' or '^' statusline of the current window
stlnc:c ' ' or '=' statusline of the non-current windows stlnc:c ' ' or '=' statusline of the non-current windows
vert:c '|' vertical separators |:vsplit| vert:c '│' or '|' vertical separators |:vsplit|
fold:c '-' filling 'foldtext' fold:c '·' or '-' filling 'foldtext'
diff:c '-' deleted lines of the 'diff' option diff:c '-' deleted lines of the 'diff' option
msgsep:c ' ' message separator 'display'
Any one that is omitted will fall back to the default. For "stl" and Any one that is omitted will fall back to the default. For "stl" and
"stlnc" the space will be used when there is highlighting, '^' or '=' "stlnc" the space will be used when there is highlighting, '^' or '='
otherwise. otherwise.
If 'ambiwidth' is "double" then "vert" and "fold" default to
single-byte alternatives.
Example: > Example: >
:set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:- :set fillchars=stl:^,stlnc:=,vert:,fold:·,diff:-
< This is similar to the default, except that these characters will also < This is similar to the default, except that these characters will also
be used when there is highlighting. be used when there is highlighting.
@@ -2712,6 +2715,10 @@ A jump table for the options with a short description can be found at |Q_op|.
:s///g subst. one subst. all :s///g subst. one subst. all
:s///gg subst. all subst. one :s///gg subst. all subst. one
DEPRECATED: Setting this option may break plugins that are not aware
of this option. Also, many users get confused that adding the /g flag
has the opposite effect of that it normally does.
*'grepformat'* *'gfm'* *'grepformat'* *'gfm'*
'grepformat' 'gfm' string (default "%f:%l:%m,%f:%l%m,%f %l%m") 'grepformat' 'gfm' string (default "%f:%l:%m,%f:%l%m,%f %l%m")
global global
@@ -3301,7 +3308,17 @@ A jump table for the options with a short description can be found at |Q_op|.
pattern and/or a lot of text the match may not be found. This is to pattern and/or a lot of text the match may not be found. This is to
avoid that Vim hangs while you are typing the pattern. avoid that Vim hangs while you are typing the pattern.
The |hl-IncSearch| highlight group determines the highlighting. The |hl-IncSearch| highlight group determines the highlighting.
See also: 'hlsearch'. When 'hlsearch' is on, all matched strings are highlighted too while typing
a search command. See also: 'hlsearch'.
If you don't want turn 'hlsearch' on, but want to highlight all matches
while searching, you can turn on and off 'hlsearch' with autocmd.
Example: >
augroup vimrc-incsearch-highlight
autocmd!
autocmd CmdlineEnter /,\? :set hlsearch
autocmd CmdlineLeave /,\? :set nohlsearch
augroup END
<
CTRL-L can be used to add one character from after the current match CTRL-L can be used to add one character from after the current match
to the command line. If 'ignorecase' and 'smartcase' are set and the to the command line. If 'ignorecase' and 'smartcase' are set and the
command line has no uppercase characters, the added character is command line has no uppercase characters, the added character is
@@ -3672,7 +3689,7 @@ A jump table for the options with a short description can be found at |Q_op|.
< Minimum value is 2, maximum value is 1000. < Minimum value is 2, maximum value is 1000.
*'linespace'* *'lsp'* *'linespace'* *'lsp'*
'linespace' 'lsp' number (default 0, 1 for Win32 GUI) 'linespace' 'lsp' number (default 0)
global global
{only in the GUI} {only in the GUI}
Number of pixel lines inserted between characters. Useful if the font Number of pixel lines inserted between characters. Useful if the font
@@ -3809,6 +3826,23 @@ A jump table for the options with a short description can be found at |Q_op|.
This option cannot be set from a |modeline| or in the |sandbox|, for This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons. security reasons.
*'makeencoding'* *'menc'*
'makeencoding' 'menc' string (default "")
global or local to buffer |global-local|
{only available when compiled with the |+multi_byte|
feature}
{not in Vi}
Encoding used for reading the output of external commands. When empty,
encoding is not converted.
This is used for `:make`, `:lmake`, `:grep`, `:lgrep`, `:grepadd`,
`:lgrepadd`, `:cfile`, `:cgetfile`, `:caddfile`, `:lfile`, `:lgetfile`,
and `:laddfile`.
This would be mostly useful when you use MS-Windows. If |+iconv| is
enabled and GNU libiconv is used, setting 'makeencoding' to "char" has
the same effect as setting to the system locale encoding. Example: >
:set makeencoding=char " system locale is used
<
*'makeprg'* *'mp'* *'makeprg'* *'mp'*
'makeprg' 'mp' string (default "make") 'makeprg' 'mp' string (default "make")
global or local to buffer |global-local| global or local to buffer |global-local|
@@ -5132,10 +5166,10 @@ A jump table for the options with a short description can be found at |Q_op|.
security reasons. security reasons.
*'shellcmdflag'* *'shcf'* *'shellcmdflag'* *'shcf'*
'shellcmdflag' 'shcf' string (default: "-c"; Windows: "/c") 'shellcmdflag' 'shcf' string (default: "-c"; Windows: "/s /c")
global global
Flag passed to the shell to execute "!" and ":!" commands; e.g., Flag passed to the shell to execute "!" and ":!" commands; e.g.,
"bash.exe -c ls" or "cmd.exe /c dir". For Windows `bash.exe -c ls` or `cmd.exe /s /c "dir"`. For Windows
systems, the default is set according to the value of 'shell', to systems, the default is set according to the value of 'shell', to
reduce the need to set this option by the user. reduce the need to set this option by the user.
On Unix it can have more than one flag. Each white space separated On Unix it can have more than one flag. Each white space separated
@@ -5256,7 +5290,7 @@ A jump table for the options with a short description can be found at |Q_op|.
to execute most external commands with cmd.exe. to execute most external commands with cmd.exe.
*'shellxquote'* *'sxq'* *'shellxquote'* *'sxq'*
'shellxquote' 'sxq' string (default: "") 'shellxquote' 'sxq' string (default: "", Windows: "\"")
global global
Quoting character(s), put around the command passed to the shell, for Quoting character(s), put around the command passed to the shell, for
the "!" and ":!" commands. Includes the redirection. See the "!" and ":!" commands. Includes the redirection. See
@@ -5420,14 +5454,13 @@ A jump table for the options with a short description can be found at |Q_op|.
See |tab-page| for more information about tab pages. See |tab-page| for more information about tab pages.
*'sidescroll'* *'ss'* *'sidescroll'* *'ss'*
'sidescroll' 'ss' number (default 0) 'sidescroll' 'ss' number (default 1)
global global
The minimal number of columns to scroll horizontally. Used only when The minimal number of columns to scroll horizontally. Used only when
the 'wrap' option is off and the cursor is moved off of the screen. the 'wrap' option is off and the cursor is moved off of the screen.
When it is zero the cursor will be put in the middle of the screen. When it is zero the cursor will be put in the middle of the screen.
When using a slow terminal set it to a large number or 0. When using When using a slow terminal set it to a large number or 0. Not used
a fast terminal use a small number or 1. Not used for "zh" and "zl" for "zh" and "zl" commands.
commands.
*'sidescrolloff'* *'siso'* *'sidescrolloff'* *'siso'*
'sidescrolloff' 'siso' number (default 0) 'sidescrolloff' 'siso' number (default 0)
@@ -6192,7 +6225,6 @@ A jump table for the options with a short description can be found at |Q_op|.
When on, uses |highlight-guifg| and |highlight-guibg| attributes in When on, uses |highlight-guifg| and |highlight-guibg| attributes in
the terminal (thus using 24-bit color). Requires a ISO-8613-3 the terminal (thus using 24-bit color). Requires a ISO-8613-3
compatible terminal. compatible terminal.
Must be set at startup (in your |init.vim| or |--cmd|).
*'terse'* *'noterse'* *'terse'* *'noterse'*
'terse' boolean (default off) 'terse' boolean (default off)
@@ -6258,15 +6290,14 @@ A jump table for the options with a short description can be found at |Q_op|.
*'timeoutlen'* *'tm'* *'timeoutlen'* *'tm'*
'timeoutlen' 'tm' number (default 1000) 'timeoutlen' 'tm' number (default 1000)
global global
The time in milliseconds that is waited for a mapped sequence to Time in milliseconds to wait for a mapped sequence to complete.
complete.
*'ttimeoutlen'* *'ttm'* *'ttimeoutlen'* *'ttm'*
'ttimeoutlen' 'ttm' number (default 50) 'ttimeoutlen' 'ttm' number (default 50)
global global
The time in milliseconds that is waited for a key code Time in milliseconds to wait for a key code sequence to complete. Also
sequence to complete. Also used for CTRL-\ CTRL-N and CTRL-\ CTRL-G used for CTRL-\ CTRL-N and CTRL-\ CTRL-G when part of a command has
when part of a command has been typed. been typed.
*'title'* *'notitle'* *'title'* *'notitle'*
'title' boolean (default off) 'title' boolean (default off)
@@ -6424,6 +6455,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Currently, these messages are given: Currently, these messages are given:
>= 1 When the shada file is read or written. >= 1 When the shada file is read or written.
>= 2 When a file is ":source"'ed. >= 2 When a file is ":source"'ed.
>= 3 UI info, terminal capabilities
>= 5 Every searched tags file and include file. >= 5 Every searched tags file and include file.
>= 8 Files for which a group of autocommands is executed. >= 8 Files for which a group of autocommands is executed.
>= 9 Every executed autocommand. >= 9 Every executed autocommand.
@@ -6895,7 +6927,8 @@ A jump table for the options with a short description can be found at |Q_op|.
'writedelay' 'wd' number (default 0) 'writedelay' 'wd' number (default 0)
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 non-zero, characters are sent to the terminal one by screen. When positive, characters are sent to the UI one by one.
one. For debugging purposes. When negative, all redrawn characters cause a delay, even if the
character already was displayed by the UI. For debugging purposes.
vim:tw=78:ts=8:ft=help:noet:norl: vim:tw=78:ts=8:ft=help:noet:norl:

View File

@@ -33,20 +33,20 @@ To use Vim Python 2/3 plugins with Nvim:
- For Python 2 plugins, make sure an interpreter for Python 2.6 or 2.7 is - For Python 2 plugins, make sure an interpreter for Python 2.6 or 2.7 is
available in your `$PATH`, then install the `neovim` Python package systemwide: > available in your `$PATH`, then install the `neovim` Python package systemwide: >
$ sudo pip2 install --upgrade neovim sudo pip2 install --upgrade neovim
< <
or for the current user: > or for the current user: >
$ pip2 install --user --upgrade neovim pip2 install --user --upgrade neovim
< <
- For Python 3 plugins, make sure an interpreter for Python 3.3 or above is - For Python 3 plugins, make sure an interpreter for Python 3.3 or above is
available in your `$PATH`, then install the `neovim` Python package systemwide: > available in your `$PATH`, then install the `neovim` Python package systemwide: >
$ sudo pip3 install --upgrade neovim sudo pip3 install --upgrade neovim
< <
or for the current user: > or for the current user: >
$ pip3 install --user --upgrade neovim pip3 install --user --upgrade neovim
< <
Note: The `--upgrade` flag ensures you have the latest version even if Note: The `--upgrade` flag ensures you have the latest version even if
a previous version was already installed. a previous version was already installed.
PYTHON PROVIDER CONFIGURATION ~ PYTHON PROVIDER CONFIGURATION ~
*g:python_host_prog* *g:python_host_prog*
@@ -93,7 +93,7 @@ Run |:checkhealth| to see if your system is up-to-date.
RUBY QUICKSTART ~ RUBY QUICKSTART ~
To use Vim Ruby plugins with Nvim, just install the latest `neovim` RubyGem: > To use Vim Ruby plugins with Nvim, just install the latest `neovim` RubyGem: >
$ gem install neovim gem install neovim
RUBY PROVIDER CONFIGURATION ~ RUBY PROVIDER CONFIGURATION ~
*g:loaded_ruby_provider* *g:loaded_ruby_provider*
@@ -112,7 +112,30 @@ To use an absolute path (e.g. to an rbenv installation): >
To use the RVM "system" Ruby installation: > To use the RVM "system" Ruby installation: >
let g:ruby_host_prog = 'rvm system do neovim-ruby-host' let g:ruby_host_prog = 'rvm system do neovim-ruby-host'
< <
==============================================================================
Node.js integration *provider-nodejs*
Nvim supports Node.js |remote-plugin|s.
https://github.com/neovim/node-client/
https://nodejs.org/
NODEJS QUICKSTART~
To use javascript remote-plugins with Nvim, install the `neovim` npm package: >
npm install -g neovim
<
NODEJS PROVIDER CONFIGURATION~
*g:loaded_node_provider*
To disable Node support: >
:let g:loaded_node_provider = 1
<
*g:node_host_prog*
Command to start the Node host. Setting this makes startup faster.
By default, Nvim searches for `neovim-node-host` using "npm root -g", which
can be slow. To avoid this, set g:node_host_prog to an absolute path: >
let g:node_host_prog = '/usr/local/bin/neovim-node-host'
<
============================================================================== ==============================================================================
Clipboard integration *provider-clipboard* *clipboard* Clipboard integration *provider-clipboard* *clipboard*

View File

@@ -165,6 +165,9 @@ processing a quickfix or location list command, it will be aborted.
keep Vim running while compiling. If you give the keep Vim running while compiling. If you give the
name of the errorfile, the 'errorfile' option will name of the errorfile, the 'errorfile' option will
be set to [errorfile]. See |:cc| for [!]. be set to [errorfile]. See |:cc| for [!].
If the encoding of the error file differs from the
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
*:lf* *:lfile* *:lf* *:lfile*
:lf[ile][!] [errorfile] Same as ":cfile", except the location list for the :lf[ile][!] [errorfile] Same as ":cfile", except the location list for the
@@ -176,6 +179,9 @@ processing a quickfix or location list command, it will be aborted.
:cg[etfile] [errorfile] *:cg* *:cgetfile* :cg[etfile] [errorfile] *:cg* *:cgetfile*
Read the error file. Just like ":cfile" but don't Read the error file. Just like ":cfile" but don't
jump to the first error. jump to the first error.
If the encoding of the error file differs from the
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
:lg[etfile] [errorfile] *:lg* *:lgetfile* :lg[etfile] [errorfile] *:lg* *:lgetfile*
@@ -186,6 +192,9 @@ processing a quickfix or location list command, it will be aborted.
:caddf[ile] [errorfile] Read the error file and add the errors from the :caddf[ile] [errorfile] Read the error file and add the errors from the
errorfile to the current quickfix list. If a quickfix errorfile to the current quickfix list. If a quickfix
list is not present, then a new list is created. list is not present, then a new list is created.
If the encoding of the error file differs from the
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
*:laddf* *:laddfile* *:laddf* *:laddfile*
:laddf[ile] [errorfile] Same as ":caddfile", except the location list for the :laddf[ile] [errorfile] Same as ":caddfile", except the location list for the
@@ -322,6 +331,7 @@ use this code: >
endfunction endfunction
au QuickfixCmdPost make call QfMakeConv() au QuickfixCmdPost make call QfMakeConv()
Another option is using 'makeencoding'.
EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST: EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
*:cdo* *:cdo*
@@ -460,7 +470,11 @@ keep its height, ignoring 'winheight' and 'equalalways'. You can change the
height manually (e.g., by dragging the status line above it with the mouse). height manually (e.g., by dragging the status line above it with the mouse).
In the quickfix window, each line is one error. The line number is equal to In the quickfix window, each line is one error. The line number is equal to
the error number. You can use ":.cc" to jump to the error under the cursor. the error number. The current entry is highlighted with the QuickFixLine
highlighting. You can change it to your liking, e.g.: >
:hi QuickFixLine ctermbg=Yellow guibg=Yellow
You can use ":.cc" to jump to the error under the cursor.
Hitting the <Enter> key or double-clicking the mouse on a line has the same Hitting the <Enter> key or double-clicking the mouse on a line has the same
effect. The file containing the error is opened in the window above the effect. The file containing the error is opened in the window above the
quickfix window. If there already is a window for that file, it is used quickfix window. If there already is a window for that file, it is used
@@ -586,6 +600,9 @@ lists, use ":cnewer 99" first.
like |:cnext| and |:cprevious|, see above. like |:cnext| and |:cprevious|, see above.
This command does not accept a comment, any " This command does not accept a comment, any "
characters are considered part of the arguments. characters are considered part of the arguments.
If the encoding of the program output differs from the
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
*:lmak* *:lmake* *:lmak* *:lmake*
:lmak[e][!] [arguments] :lmak[e][!] [arguments]
@@ -645,6 +662,7 @@ read the error messages: >
au QuickfixCmdPost make call QfMakeConv() au QuickfixCmdPost make call QfMakeConv()
(Example by Faque Cheng) (Example by Faque Cheng)
Another option is using 'makeencoding'.
============================================================================== ==============================================================================
5. Using :vimgrep and :grep *grep* *lid* 5. Using :vimgrep and :grep *grep* *lid*
@@ -759,6 +777,9 @@ id-utils) in a similar way to its compiler integration (see |:make| above).
When 'grepprg' is "internal" this works like When 'grepprg' is "internal" this works like
|:vimgrep|. Note that the pattern needs to be |:vimgrep|. Note that the pattern needs to be
enclosed in separator characters then. enclosed in separator characters then.
If the encoding of the program output differs from the
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
*:lgr* *:lgrep* *:lgr* *:lgrep*
:lgr[ep][!] [arguments] Same as ":grep", except the location list for the :lgr[ep][!] [arguments] Same as ":grep", except the location list for the
@@ -783,6 +804,10 @@ id-utils) in a similar way to its compiler integration (see |:make| above).
\ | catch /E480:/ \ | catch /E480:/
\ | endtry" \ | endtry"
< <
If the encoding of the program output differs from the
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
*:lgrepa* *:lgrepadd* *:lgrepa* *:lgrepadd*
:lgrepa[dd][!] [arguments] :lgrepa[dd][!] [arguments]
Same as ":grepadd", except the location list for the Same as ":grepadd", except the location list for the

View File

@@ -655,7 +655,6 @@ Short explanation of each option: *option-list*
'cscoperelative' 'csre' Use cscope.out path basename as prefix 'cscoperelative' 'csre' Use cscope.out path basename as prefix
'cscopetag' 'cst' use cscope for tag commands 'cscopetag' 'cst' use cscope for tag commands
'cscopetagorder' 'csto' determines ":cstag" search order 'cscopetagorder' 'csto' determines ":cstag" search order
'cscopeverbose' 'csverb' give messages when adding a cscope database
'cursorbind' 'crb' move cursor in window as it moves in other windows 'cursorbind' 'crb' move cursor in window as it moves in other windows
'cursorcolumn' 'cuc' highlight the screen column of the cursor 'cursorcolumn' 'cuc' highlight the screen column of the cursor
'cursorline' 'cul' highlight the screen line of the cursor 'cursorline' 'cul' highlight the screen line of the cursor
@@ -762,6 +761,7 @@ Short explanation of each option: *option-list*
'loadplugins' 'lpl' load plugin scripts when starting up 'loadplugins' 'lpl' load plugin scripts when starting up
'magic' changes special characters in search patterns 'magic' changes special characters in search patterns
'makeef' 'mef' name of the errorfile for ":make" 'makeef' 'mef' name of the errorfile for ":make"
'makeencoding' 'menc' encoding of external make/grep commands
'makeprg' 'mp' program to use for the ":make" command 'makeprg' 'mp' program to use for the ":make" command
'matchpairs' 'mps' pairs of characters that "%" can match 'matchpairs' 'mps' pairs of characters that "%" can match
'matchtime' 'mat' tenths of a second to show matching paren 'matchtime' 'mat' tenths of a second to show matching paren

View File

@@ -249,14 +249,14 @@ argument.
for reading or writing a ShaDa file. Can be used to find for reading or writing a ShaDa file. Can be used to find
out what is happening upon startup and exit. out what is happening upon startup and exit.
Example: > Example: >
vim -V8 foobar nvim -V8
-V[N]{filename} -V[N]{filename}
Like -V and set 'verbosefile' to {filename}. The result is Like -V and set 'verbosefile' to {filename}. Messages are not
that messages are not displayed but written to the file displayed; instead they are written to the file {filename}.
{filename}. {filename} must not start with a digit. {filename} must not start with a digit.
Example: > Example: >
vim -V20vimlog foobar nvim -V20vimlog
< <
*-D* *-D*
-D Debugging. Go to debugging mode when executing the first -D Debugging. Go to debugging mode when executing the first
@@ -355,6 +355,10 @@ argument.
instead. instead.
See also |silent-mode|, which does start a (limited) UI. See also |silent-mode|, which does start a (limited) UI.
--listen {addr} *--listen*
Start |RPC| server on pipe or TCP address {addr}. Sets the
primary listen address |v:servername| to {addr}. |serverstart()|
============================================================================== ==============================================================================
2. Initialization *initialization* *startup* 2. Initialization *initialization* *startup*
@@ -439,15 +443,14 @@ accordingly. Vim proceeds in this order:
:runtime! filetype.vim :runtime! filetype.vim
:runtime! ftplugin.vim :runtime! ftplugin.vim
:runtime! indent.vim :runtime! indent.vim
< This step is skipped if ":filetype ..." was called before now or if < Skipped if ":filetype … off" was called or if the "-u NONE" command
the "-u NONE" command line argument was given. line argument was given.
5. Enable syntax highlighting. 5. Enable syntax highlighting.
This does the same as the command: > This does the same as the command: >
:runtime! syntax/syntax.vim :runtime! syntax/syntax.vim
< Note: This enables filetype detection even if ":filetype off" was < Skipped if ":syntax off" was called or if the "-u NONE" command
called before now. line argument was given.
This step is skipped if the "-u NONE" command line argument was given.
6. Load the plugin scripts. *load-plugins* 6. Load the plugin scripts. *load-plugins*
This does the same as the command: > This does the same as the command: >
@@ -1392,4 +1395,4 @@ RPC clients for debugging. $NVIM_LOG_FILE contains the log file path: >
Usually the file is ~/.local/share/nvim/log unless that path is inaccessible Usually the file is ~/.local/share/nvim/log unless that path is inaccessible
or if $NVIM_LOG_FILE was set before |startup|. or if $NVIM_LOG_FILE was set before |startup|.
vim:tw=78:ts=8:ft=help:norl: vim:noet:tw=78:ts=8:ft=help:norl:

View File

@@ -4709,17 +4709,7 @@ ctermbg={color-nr} *highlight-ctermbg*
"cterm". For example, on some systems "cterm=bold ctermfg=3" gives "cterm". For example, on some systems "cterm=bold ctermfg=3" gives
another color, on others you just get color 3. another color, on others you just get color 3.
For an xterm this depends on your resources, and is a bit The following names are recognized, with the color number used:
unpredictable. See your xterm documentation for the defaults. The
colors for a color-xterm can be changed from the .Xdefaults file.
Unfortunately this means that it's not possible to get the same colors
for each user.
The MSDOS standard colors are fixed (in a console window), so these
have been used for the names. But the meaning of color names in X11
are fixed, so these color settings have been used, to make the
highlighting settings portable (complicated, isn't it?). The
following names are recognized, with the color number used:
*cterm-colors* *cterm-colors*
NR-16 NR-8 COLOR NAME ~ NR-16 NR-8 COLOR NAME ~
@@ -4919,6 +4909,8 @@ MatchParen The character under the cursor or just before it, if it
*hl-ModeMsg* *hl-ModeMsg*
ModeMsg 'showmode' message (e.g., "-- INSERT --") ModeMsg 'showmode' message (e.g., "-- INSERT --")
*hl-MsgSeparator*
MsgSeparator Separator for scrolled messages, `msgsep` flag of 'display'
*hl-MoreMsg* *hl-MoreMsg*
MoreMsg |more-prompt| MoreMsg |more-prompt|
*hl-NonText* *hl-NonText*

View File

@@ -38,13 +38,13 @@ Otherwise Nvim cannot know what sequences your terminal expects, and weird
or sub-optimal behavior will result (scrolling quirks, wrong colors, etc.). or sub-optimal behavior will result (scrolling quirks, wrong colors, etc.).
$TERM is also important because it is mirrored by SSH to the remote session, $TERM is also important because it is mirrored by SSH to the remote session,
unlike other common client-end environment variables ($COLORTERM, unlike most other environment variables.
$XTERM_VERSION, $VTE_VERSION, $KONSOLE_PROFILE_NAME, $TERM_PROGRAM, ...).
For this terminal Set $TERM to |builtin-terms| For this terminal Set $TERM to |builtin-terms|
------------------------------------------------------------------------- -------------------------------------------------------------------------
iTerm (original) iterm, iTerm.app N iTerm (original) iterm, iTerm.app N
iTerm2 (new capabilities) iterm2, iTerm2.app Y iTerm2 (new capabilities) iterm2, iTerm2.app Y
Konsole konsole-256color N
anything libvte-based vte, vte-256color Y anything libvte-based vte, vte-256color Y
(e.g. GNOME Terminal) (aliases: gnome, gnome-256color) (e.g. GNOME Terminal) (aliases: gnome, gnome-256color)
tmux tmux, tmux-256color Y tmux tmux, tmux-256color Y
@@ -232,11 +232,6 @@ correct values. See |:mode|.
Slow and fast terminals *slow-fast-terminal* Slow and fast terminals *slow-fast-terminal*
*slow-terminal* *slow-terminal*
If you have a fast terminal you may like to set the 'ruler' option. The
cursor position is shown in the status line. If you are using horizontal
scrolling ('wrap' option off) consider setting 'sidescroll' to a small
number.
If you have a slow terminal you may want to reset the 'showcmd' and 'ruler' If you have a slow terminal you may want to reset the 'showcmd' and 'ruler'
options. The command characters and cursor positions will not be shown in the options. The command characters and cursor positions will not be shown in the
status line (which involves a lot of cursor motions and attribute changes for status line (which involves a lot of cursor motions and attribute changes for

View File

@@ -9,7 +9,7 @@ Nvim UI protocol *ui*
Type |gO| to see the table of contents. Type |gO| to see the table of contents.
============================================================================== ==============================================================================
Introduction *ui-intro* UI Events *ui-events*
GUIs can be implemented as external processes communicating with Nvim over the GUIs can be implemented as external processes communicating with Nvim over the
RPC API. The UI model consists of a terminal-like grid with a single, RPC API. The UI model consists of a terminal-like grid with a single,
@@ -30,10 +30,22 @@ a dictionary with these (optional) keys:
`ext_cmdline` Externalize the cmdline. |ui-cmdline| `ext_cmdline` Externalize the cmdline. |ui-cmdline|
`ext_wildmenu` Externalize the wildmenu. |ui-ext-wildmenu| `ext_wildmenu` Externalize the wildmenu. |ui-ext-wildmenu|
Nvim will then send msgpack-rpc notifications, with the method name "redraw" Specifying a non-existent option is an error. To facilitate an ui that
and a single argument, an array of screen update events. supports different versions of Nvim, the |api-metadata| key `ui_options`
Update events are tuples whose first element is the event name and remaining contains the list of supported options. Additionally Nvim currently requires
elements the event parameters. that all connected UIs use the same set of widgets. Therefore the active
widgets will be the intersection of the requested widget sets of all connected
UIs. The "option_set" event will be used to specify which widgets actually are
active.
After attaching, Nvim will send msgpack-rpc notifications, with the method
name "redraw" and a single argument, an array of screen update events. Update
events are arrays whose first element is the event name and remaining elements
are each tuples of event parameters. This allows multiple events of the same
kind to be sent in a row without the event name being repeated. This batching
is mostly used for "put", as each "put" event just puts contents in one screen
cell, but clients must be prepared for multiple argument sets being batched
for all event kinds.
Events must be handled in order. The user should only see the updated screen Events must be handled in order. The user should only see the updated screen
state after all events in the same "redraw" batch are processed (not any state after all events in the same "redraw" batch are processed (not any
@@ -80,6 +92,29 @@ Global Events *ui-global*
Some keys are missing in some modes. Some keys are missing in some modes.
["option_set", name, value]
The value of ui related option `name` changed. The sent options are
listed below:
'arabicshape'
'ambiwith'
'emoji'
'guifont'
'guifontset'
'guifontwide'
'linespace'
'showtabline'
'termguicolors'
`ext_*` (all |ui-ext-options|)
Options are not added to the list if their effects are already taken
care of. For instance, instead of forwarding the raw 'mouse' option
value, `mouse_on` and `mouse_off` directly indicate if mouse support
is active right now. Some options like 'ambiwith' have already taken
effect on the grid, where appropriate empty cells are added, however
an ui might still use these options when rendering raw text sent from
Nvim, like the text of the cmdline when |ui-ext-cmdline| is set.
["mode_change", mode, mode_idx] ["mode_change", mode, mode_idx]
The mode changed. The first parameter `mode` is a string representing The mode changed. The first parameter `mode` 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 received in

View File

@@ -207,21 +207,18 @@ g8 Print the hex values of the bytes used in the
:sh[ell] Removed. |vim-differences| {Nvim} :sh[ell] Removed. |vim-differences| {Nvim}
*:terminal* *:te* *:terminal* *:te*
:te[rminal][!] [{cmd}] Execute {cmd} with 'shell' in a new |terminal| buffer. :te[rminal][!] [{cmd}] Execute {cmd} with 'shell' in a new |terminal-emulator|
Equivalent to: > buffer. Without {cmd}, start an interactive 'shell'.
:enew
:call termopen('{cmd}')
<
See |termopen()|.
Without {cmd}, start an interactive shell. Type |i| to enter |Terminal-mode|, then keys are sent to
the job running in the terminal. Type <C-\><C-N> to
leave Terminal-mode. |CTRL-\_CTRL-N|
Creating the terminal buffer fails when changes have been Fails if changes have been made to the current buffer,
made to the current buffer, unless 'hidden' is set. unless 'hidden' is set.
To enter |Terminal-mode| automatically: > To enter |Terminal-mode| automatically: >
autocmd BufEnter term://* startinsert autocmd TermOpen * startinsert
autocmd BufLeave term://* stopinsert
< <
*:!cmd* *:!* *E34* *:!cmd* *:!* *E34*
:!{cmd} Execute {cmd} with 'shell'. See also |:terminal|. :!{cmd} Execute {cmd} with 'shell'. See also |:terminal|.

View File

@@ -32,8 +32,10 @@ a complete and centralized reference of those differences.
- 'backupdir' defaults to .,~/.local/share/nvim/backup (|xdg|) - 'backupdir' defaults to .,~/.local/share/nvim/backup (|xdg|)
- 'belloff' defaults to "all" - 'belloff' defaults to "all"
- 'complete' doesn't include "i" - 'complete' doesn't include "i"
- 'cscopeverbose' is enabled
- 'directory' defaults to ~/.local/share/nvim/swap// (|xdg|), auto-created - 'directory' defaults to ~/.local/share/nvim/swap// (|xdg|), auto-created
- 'display' defaults to "lastline" - 'display' defaults to "lastline,msgsep"
- 'fillchars' defaults (in effect) to "vert:│,fold:·"
- 'formatoptions' defaults to "tcqj" - 'formatoptions' defaults to "tcqj"
- 'history' defaults to 10000 (the maximum) - 'history' defaults to 10000 (the maximum)
- 'hlsearch' is set by default - 'hlsearch' is set by default
@@ -47,6 +49,7 @@ a complete and centralized reference of those differences.
- 'ruler' is set by default - 'ruler' is set by default
- 'sessionoptions' doesn't include "options" - 'sessionoptions' doesn't include "options"
- 'showcmd' is set by default - 'showcmd' is set by default
- 'sidescroll' defaults to 1
- 'smarttab' is set by default - 'smarttab' is set by default
- 'tabpagemax' defaults to 50 - 'tabpagemax' defaults to 50
- 'tags' defaults to "./tags;,tags" - 'tags' defaults to "./tags;,tags"
@@ -70,6 +73,7 @@ Providers
Ruby plugins |provider-ruby| Ruby plugins |provider-ruby|
Shared data |shada| Shared data |shada|
Embedded terminal |terminal| Embedded terminal |terminal|
VimL parser |nvim_parse_expression()|
XDG base directories |xdg| XDG base directories |xdg|
USER EXPERIENCE ~ USER EXPERIENCE ~
@@ -126,7 +130,9 @@ Some `CTRL-SHIFT-...` key chords are distinguished from `CTRL-...` variants
Options: Options:
'cpoptions' flags: |cpo-_| 'cpoptions' flags: |cpo-_|
'display' flag `msgsep` to minimize scrolling when showing messages
'guicursor' works in the terminal 'guicursor' works in the terminal
'fillchars' flag `msgsep` (see 'display' above)
'inccommand' shows interactive results for |:substitute|-like commands 'inccommand' shows interactive results for |:substitute|-like commands
'scrollback' 'scrollback'
'statusline' supports unlimited alignment sections 'statusline' supports unlimited alignment sections
@@ -160,19 +166,23 @@ Events:
Highlight groups: Highlight groups:
|hl-NormalNC| highlights non-current windows |hl-NormalNC| highlights non-current windows
|hl-MsgSeparator| highlights separator for scrolled messages
|hl-QuickFixLine| |hl-QuickFixLine|
|hl-Substitute| |hl-Substitute|
|hl-TermCursor| |hl-TermCursor|
|hl-TermCursorNC| |hl-TermCursorNC|
|hl-Whitespace| highlights 'listchars' whitespace |hl-Whitespace| highlights 'listchars' whitespace
|expr-highlight| highlight groups (prefixed with "Nvim")
UI: Command-line highlighting:
*E5408* *E5409* *g:Nvim_color_expr* *g:Nvim_color_cmdline* The expression prompt (|@=|, |c_CTRL-R_=|, |i_CTRL-R_=|) is highlighted
Command-line coloring is supported. Only |input()| and |inputdialog()| may using a built-in VimL expression parser. |expr-highlight|
be colored. For testing purposes expressions (e.g. |i_CTRL-R_=|) and regular *E5408* *E5409*
command-line (|:|) are colored by callbacks defined in `g:Nvim_color_expr` |input()|, |inputdialog()| support custom highlighting. |input()-highlight|
and `g:Nvim_color_cmdline` respectively (these callbacks are for testing *g:Nvim_color_cmdline*
only, and will be removed in a future version). (Experimental) Command-line (|:|) is colored by callback defined in
`g:Nvim_color_cmdline` (this callback is for testing only, and will be
removed in the future).
============================================================================== ==============================================================================
4. Changed features *nvim-features-changed* 4. Changed features *nvim-features-changed*
@@ -299,7 +309,8 @@ Highlight groups:
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other |hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
groups groups
The variable name "count" is no fallback for |v:count| anymore. VimL (Vim script) compatibility:
`count` does not alias to |v:count|
============================================================================== ==============================================================================
5. Missing legacy features *nvim-features-missing* 5. Missing legacy features *nvim-features-missing*
@@ -327,22 +338,26 @@ Ed-compatible mode:
":set noedcompatible" is ignored ":set noedcompatible" is ignored
":set edcompatible" is an error ":set edcompatible" is an error
*t_xx* *:set-termcap* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI* *t_xx* *termcap-options* *t_AB* *t_Sb* *t_vb* *t_SI*
Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure Nvim does not have special `t_XX` options nor <t_XX> keycodes to configure
terminal capabilities. Instead Nvim treats the terminal as any other UI. For terminal capabilities. Instead Nvim treats the terminal as any other UI. For
example, 'guicursor' sets the terminal cursor style if possible. example, 'guicursor' sets the terminal cursor style if possible.
*'term'* *E529* *E530* *E531* *:set-termcap*
Start Nvim with 'verbose' level 3 to see the terminal capabilities. >
nvim -V3
<
*'term'* *E529* *E530* *E531*
'term' reflects the terminal type derived from |$TERM| and other environment 'term' reflects the terminal type derived from |$TERM| and other environment
checks. For debugging only; not reliable during startup. > checks. For debugging only; not reliable during startup. >
:echo &term :echo &term
"builtin_x" means one of the |builtin-terms| was chosen, because the expected "builtin_x" means one of the |builtin-terms| was chosen, because the expected
terminfo file was not found on the system. terminfo file was not found on the system.
*termcap* *termcap*
Nvim never uses the termcap database, only |terminfo| and |builtin-terms|. Nvim never uses the termcap database, only |terminfo| and |builtin-terms|.
*xterm-8bit* *xterm-8-bit* *xterm-8bit* *xterm-8-bit*
Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this Xterm can be run in a mode where it uses true 8-bit CSI. Supporting this
requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8 requires autodetection of whether the terminal is in UTF-8 mode or non-UTF-8
mode, as the 8-bit CSI character has to be written differently in each case. mode, as the 8-bit CSI character has to be written differently in each case.
@@ -365,7 +380,6 @@ MS-DOS support:
Test functions: Test functions:
test_alloc_fail() test_alloc_fail()
test_autochdir() test_autochdir()
test_disable_char_avail()
test_garbagecollect_now() test_garbagecollect_now()
test_null_channel() test_null_channel()
test_null_dict() test_null_dict()
@@ -373,6 +387,7 @@ Test functions:
test_null_list() test_null_list()
test_null_partial() test_null_partial()
test_null_string() test_null_string()
test_override()
test_settime() test_settime()
Other options: Other options:

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ if exists('b:did_ftplugin') || &filetype !=# 'man'
endif endif
let b:did_ftplugin = 1 let b:did_ftplugin = 1
let s:pager = !exists('b:man_sect') let s:pager = get(s:, 'pager', 0) || !exists('b:man_sect')
if s:pager if s:pager
call man#init_pager() call man#init_pager()
@@ -35,7 +35,7 @@ if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
nnoremap <silent> <buffer> <C-]> :Man<CR> nnoremap <silent> <buffer> <C-]> :Man<CR>
nnoremap <silent> <buffer> K :Man<CR> nnoremap <silent> <buffer> K :Man<CR>
nnoremap <silent> <buffer> <C-T> :call man#pop_tag()<CR> nnoremap <silent> <buffer> <C-T> :call man#pop_tag()<CR>
if 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
nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c

168
runtime/lua/man.lua Normal file
View File

@@ -0,0 +1,168 @@
local buf_hls = {}
local function highlight_line(line, linenr)
local chars = {}
local prev_char = ''
local overstrike, escape = false, false
local hls = {} -- Store highlight groups as { attr, start, final }
local NONE, BOLD, UNDERLINE, ITALIC = 0, 1, 2, 3
local hl_groups = {[BOLD]="manBold", [UNDERLINE]="manUnderline", [ITALIC]="manItalic"}
local attr = NONE
local byte = 0 -- byte offset
local function end_attr_hl(attr)
for i, hl in ipairs(hls) do
if hl.attr == attr and hl.final == -1 then
hl.final = byte
hls[i] = hl
end
end
end
local function add_attr_hl(code)
local continue_hl = true
if code == 0 then
attr = NONE
continue_hl = false
elseif code == 1 then
attr = BOLD
elseif code == 22 then
attr = BOLD
continue_hl = false
elseif code == 3 then
attr = ITALIC
elseif code == 23 then
attr = ITALIC
continue_hl = false
elseif code == 4 then
attr = UNDERLINE
elseif code == 24 then
attr = UNDERLINE
continue_hl = false
else
attr = NONE
return
end
if continue_hl then
hls[#hls + 1] = {attr=attr, start=byte, final=-1}
else
if attr == NONE then
for a, _ in pairs(hl_groups) do
end_attr_hl(a)
end
else
end_attr_hl(attr)
end
end
end
-- Break input into UTF8 code points. ASCII code points (from 0x00 to 0x7f)
-- can be represented in one byte. Any code point above that is represented by
-- a leading byte (0xc0 and above) and continuation bytes (0x80 to 0xbf, or
-- decimal 128 to 191).
for char in line:gmatch("[^\128-\191][\128-\191]*") do
if overstrike then
local last_hl = hls[#hls]
if char == prev_char then
if char == '_' and attr == UNDERLINE and last_hl and last_hl.final == byte then
-- This underscore is in the middle of an underlined word
attr = UNDERLINE
else
attr = BOLD
end
elseif prev_char == '_' then
-- char is underlined
attr = UNDERLINE
elseif prev_char == '+' and char == 'o' then
-- bullet (overstrike text '+^Ho')
attr = BOLD
char = '·'
elseif prev_char == '·' and char == 'o' then
-- bullet (additional handling for '+^H+^Ho^Ho')
attr = BOLD
char = '·'
else
-- use plain char
attr = NONE
end
-- Grow the previous highlight group if possible
if last_hl and last_hl.attr == attr and last_hl.final == byte then
last_hl.final = byte + #char
else
hls[#hls + 1] = {attr=attr, start=byte, final=byte + #char}
end
overstrike = false
prev_char = ''
byte = byte + #char
chars[#chars + 1] = char
elseif escape then
-- Use prev_char to store the escape sequence
prev_char = prev_char .. char
-- We only want to match against SGR sequences, which consist of ESC
-- followed by '[', then a series of parameter and intermediate bytes in
-- the range 0x20 - 0x3f, then 'm'. (See ECMA-48, sections 5.4 & 8.3.117)
local sgr = prev_char:match("^%[([\032-\063]*)m$")
if sgr then
local match = ''
while sgr and #sgr > 0 do
-- Match against SGR parameters, which may be separated by ';'
match, sgr = sgr:match("^(%d*);?(.*)")
add_attr_hl(match + 0) -- coerce to number
end
escape = false
elseif not prev_char:match("^%[[\032-\063]*$") then
-- Stop looking if this isn't a partial CSI sequence
escape = false
end
elseif char == "\027" then
escape = true
prev_char = ''
elseif char == "\b" then
overstrike = true
prev_char = chars[#chars]
byte = byte - #prev_char
chars[#chars] = nil
else
byte = byte + #char
chars[#chars + 1] = char
end
end
for _, hl in ipairs(hls) do
if hl.attr ~= NONE then
buf_hls[#buf_hls + 1] = {
0,
-1,
hl_groups[hl.attr],
linenr - 1,
hl.start,
hl.final
}
end
end
return table.concat(chars, '')
end
local function highlight_man_page()
local mod = vim.api.nvim_buf_get_option(0, "modifiable")
vim.api.nvim_buf_set_option(0, "modifiable", true)
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
for i, line in ipairs(lines) do
lines[i] = highlight_line(line, i)
end
vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
for _, args in ipairs(buf_hls) do
vim.api.nvim_buf_add_highlight(unpack(args))
end
buf_hls = {}
vim.api.nvim_buf_set_option(0, "modifiable", mod)
end
return { highlight_man_page = highlight_man_page }

View File

@@ -1087,6 +1087,9 @@ if has("quickfix")
call <SID>OptionG("gp", &gp) call <SID>OptionG("gp", &gp)
call append("$", "grepformat\tlist of formats for output of 'grepprg'") call append("$", "grepformat\tlist of formats for output of 'grepprg'")
call <SID>OptionG("gfm", &gfm) call <SID>OptionG("gfm", &gfm)
call append("$", "makeencoding\tencoding of the \":make\" and \":grep\" output")
call append("$", "\t(global or local to buffer)")
call <SID>OptionG("menc", &menc)
endif endif

View File

@@ -1,8 +1 @@
function! s:complete(lead, _line, _pos) abort autocmd CmdUndefined CheckHealth checkhealth
return sort(filter(map(globpath(&runtimepath, 'autoload/health/*', 1, 1),
\ 'fnamemodify(v:val, ":t:r")'),
\ 'empty(a:lead) || v:val[:strlen(a:lead)-1] ==# a:lead'))
endfunction
command! -nargs=* -complete=customlist,s:complete CheckHealth
\ call health#check([<f-args>])

View File

@@ -56,6 +56,6 @@ function! s:LoadRemotePlugins() abort
endif endif
endfunction endfunction
command! UpdateRemotePlugins call remote#host#UpdateRemotePlugins() command! -bar UpdateRemotePlugins call remote#host#UpdateRemotePlugins()
call s:LoadRemotePlugins() call s:LoadRemotePlugins()

View File

@@ -1,11 +1,15 @@
" Vim support file to detect file types in scripts " Vim support file to detect file types in scripts
" "
" Maintainer: Bram Moolenaar <Bram@vim.org> " Maintainer: Bram Moolenaar <Bram@vim.org>
" Last change: 2017 Aug 27 " Last change: 2017 Nov 11
" This file is called by an autocommand for every file that has just been " This file is called by an autocommand for every file that has just been
" loaded into a buffer. It checks if the type of file can be recognized by " loaded into a buffer. It checks if the type of file can be recognized by
" the file contents. The autocommand is in $VIMRUNTIME/filetype.vim. " the file contents. The autocommand is in $VIMRUNTIME/filetype.vim.
"
" Note that the pattern matches are done with =~# to avoid the value of the
" 'ignorecase' option making a difference. Where case is to be ignored use
" =~? instead. Do not use =~ anywhere.
" Only do the rest when the FileType autocommand has not been triggered yet. " Only do the rest when the FileType autocommand has not been triggered yet.
@@ -28,12 +32,12 @@ set cpo&vim
let s:line1 = getline(1) let s:line1 = getline(1)
if s:line1 =~ "^#!" if s:line1 =~# "^#!"
" A script that starts with "#!". " A script that starts with "#!".
" Check for a line like "#!/usr/bin/env VAR=val bash". Turn it into " Check for a line like "#!/usr/bin/env VAR=val bash". Turn it into
" "#!/usr/bin/bash" to make matching easier. " "#!/usr/bin/bash" to make matching easier.
if s:line1 =~ '^#!\s*\S*\<env\s' if s:line1 =~# '^#!\s*\S*\<env\s'
let s:line1 = substitute(s:line1, '\S\+=\S\+', '', 'g') let s:line1 = substitute(s:line1, '\S\+=\S\+', '', 'g')
let s:line1 = substitute(s:line1, '\<env\s\+', '', '') let s:line1 = substitute(s:line1, '\<env\s\+', '', '')
endif endif
@@ -44,11 +48,11 @@ if s:line1 =~ "^#!"
" "#!/usr/bin/env perl [path/args]" " "#!/usr/bin/env perl [path/args]"
" If there is no path use the first word: "#!perl [path/args]". " If there is no path use the first word: "#!perl [path/args]".
" Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]". " Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]".
if s:line1 =~ '^#!\s*\a:[/\\]' if s:line1 =~# '^#!\s*\a:[/\\]'
let s:name = substitute(s:line1, '^#!.*[/\\]\(\i\+\).*', '\1', '') let s:name = substitute(s:line1, '^#!.*[/\\]\(\i\+\).*', '\1', '')
elseif s:line1 =~ '^#!.*\<env\>' elseif s:line1 =~# '^#!.*\<env\>'
let s:name = substitute(s:line1, '^#!.*\<env\>\s\+\(\i\+\).*', '\1', '') let s:name = substitute(s:line1, '^#!.*\<env\>\s\+\(\i\+\).*', '\1', '')
elseif s:line1 =~ '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)' elseif s:line1 =~# '^#!\s*[^/\\ ]*\>\([^/\\]\|$\)'
let s:name = substitute(s:line1, '^#!\s*\([^/\\ ]*\>\).*', '\1', '') let s:name = substitute(s:line1, '^#!\s*\([^/\\ ]*\>\).*', '\1', '')
else else
let s:name = substitute(s:line1, '^#!\s*\S*[/\\]\(\i\+\).*', '\1', '') let s:name = substitute(s:line1, '^#!\s*\S*[/\\]\(\i\+\).*', '\1', '')
@@ -56,116 +60,116 @@ if s:line1 =~ "^#!"
" tcl scripts may have #!/bin/sh in the first line and "exec wish" in the " tcl scripts may have #!/bin/sh in the first line and "exec wish" in the
" third line. Suggested by Steven Atkinson. " third line. Suggested by Steven Atkinson.
if getline(3) =~ '^exec wish' if getline(3) =~# '^exec wish'
let s:name = 'wish' let s:name = 'wish'
endif endif
" Bourne-like shell scripts: bash bash2 ksh ksh93 sh " Bourne-like shell scripts: bash bash2 ksh ksh93 sh
if s:name =~ '^\(bash\d*\|\|ksh\d*\|sh\)\>' if s:name =~# '^\(bash\d*\|\|ksh\d*\|sh\)\>'
call SetFileTypeSH(s:line1) " defined in filetype.vim call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
" csh scripts " csh scripts
elseif s:name =~ '^csh\>' elseif s:name =~# '^csh\>'
if exists("g:filetype_csh") if exists("g:filetype_csh")
call SetFileTypeShell(g:filetype_csh) call dist#ft#SetFileTypeShell(g:filetype_csh)
else else
call SetFileTypeShell("csh") call dist#ft#SetFileTypeShell("csh")
endif endif
" tcsh scripts " tcsh scripts
elseif s:name =~ '^tcsh\>' elseif s:name =~# '^tcsh\>'
call SetFileTypeShell("tcsh") call dist#ft#SetFileTypeShell("tcsh")
" Z shell scripts " Z shell scripts
elseif s:name =~ '^zsh\>' elseif s:name =~# '^zsh\>'
set ft=zsh set ft=zsh
" TCL scripts " TCL scripts
elseif s:name =~ '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>' elseif s:name =~# '^\(tclsh\|wish\|expectk\|itclsh\|itkwish\)\>'
set ft=tcl set ft=tcl
" Expect scripts " Expect scripts
elseif s:name =~ '^expect\>' elseif s:name =~# '^expect\>'
set ft=expect set ft=expect
" Gnuplot scripts " Gnuplot scripts
elseif s:name =~ '^gnuplot\>' elseif s:name =~# '^gnuplot\>'
set ft=gnuplot set ft=gnuplot
" Makefiles " Makefiles
elseif s:name =~ 'make\>' elseif s:name =~# 'make\>'
set ft=make set ft=make
" Lua " Lua
elseif s:name =~ 'lua' elseif s:name =~# 'lua'
set ft=lua set ft=lua
" Perl 6 " Perl 6
elseif s:name =~ 'perl6' elseif s:name =~# 'perl6'
set ft=perl6 set ft=perl6
" Perl " Perl
elseif s:name =~ 'perl' elseif s:name =~# 'perl'
set ft=perl set ft=perl
" PHP " PHP
elseif s:name =~ 'php' elseif s:name =~# 'php'
set ft=php set ft=php
" Python " Python
elseif s:name =~ 'python' elseif s:name =~# 'python'
set ft=python set ft=python
" Groovy " Groovy
elseif s:name =~ '^groovy\>' elseif s:name =~# '^groovy\>'
set ft=groovy set ft=groovy
" Ruby " Ruby
elseif s:name =~ 'ruby' elseif s:name =~# 'ruby'
set ft=ruby set ft=ruby
" JavaScript " JavaScript
elseif s:name =~ 'node\(js\)\=\>' || s:name =~ 'rhino\>' elseif s:name =~# 'node\(js\)\=\>' || s:name =~# 'rhino\>'
set ft=javascript set ft=javascript
" BC calculator " BC calculator
elseif s:name =~ '^bc\>' elseif s:name =~# '^bc\>'
set ft=bc set ft=bc
" sed " sed
elseif s:name =~ 'sed\>' elseif s:name =~# 'sed\>'
set ft=sed set ft=sed
" OCaml-scripts " OCaml-scripts
elseif s:name =~ 'ocaml' elseif s:name =~# 'ocaml'
set ft=ocaml set ft=ocaml
" Awk scripts " Awk scripts
elseif s:name =~ 'awk\>' elseif s:name =~# 'awk\>'
set ft=awk set ft=awk
" Website MetaLanguage " Website MetaLanguage
elseif s:name =~ 'wml' elseif s:name =~# 'wml'
set ft=wml set ft=wml
" Scheme scripts " Scheme scripts
elseif s:name =~ 'scheme' elseif s:name =~# 'scheme'
set ft=scheme set ft=scheme
" CFEngine scripts " CFEngine scripts
elseif s:name =~ 'cfengine' elseif s:name =~# 'cfengine'
set ft=cfengine set ft=cfengine
" Erlang scripts " Erlang scripts
elseif s:name =~ 'escript' elseif s:name =~# 'escript'
set ft=erlang set ft=erlang
" Haskell " Haskell
elseif s:name =~ 'haskell' elseif s:name =~# 'haskell'
set ft=haskell set ft=haskell
" Scala " Scala
elseif s:name =~ 'scala\>' elseif s:name =~# 'scala\>'
set ft=scala set ft=scala
endif endif
@@ -180,28 +184,28 @@ else
let s:line5 = getline(5) let s:line5 = getline(5)
" Bourne-like shell scripts: sh ksh bash bash2 " Bourne-like shell scripts: sh ksh bash bash2
if s:line1 =~ '^:$' if s:line1 =~# '^:$'
call SetFileTypeSH(s:line1) " defined in filetype.vim call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
" Z shell scripts " Z shell scripts
elseif s:line1 =~ '^#compdef\>' || s:line1 =~ '^#autoload\>' || elseif s:line1 =~# '^#compdef\>' || s:line1 =~# '^#autoload\>' ||
\ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~ '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>' \ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~# '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
set ft=zsh set ft=zsh
" ELM Mail files " ELM Mail files
elseif s:line1 =~ '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$' elseif s:line1 =~# '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
set ft=mail set ft=mail
" Mason " Mason
elseif s:line1 =~ '^<[%&].*>' elseif s:line1 =~# '^<[%&].*>'
set ft=mason set ft=mason
" Vim scripts (must have '" vim' as the first line to trigger this) " Vim scripts (must have '" vim' as the first line to trigger this)
elseif s:line1 =~ '^" *[vV]im$' elseif s:line1 =~# '^" *[vV]im$'
set ft=vim set ft=vim
" MOO " MOO
elseif s:line1 =~ '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$' elseif s:line1 =~# '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
set ft=moo set ft=moo
" Diff file: " Diff file:
@@ -215,40 +219,45 @@ else
" - "=== ", "--- ", "+++ " (bzr diff, common case) " - "=== ", "--- ", "+++ " (bzr diff, common case)
" - "=== (removed|added|renamed|modified)" (bzr diff, alternative) " - "=== (removed|added|renamed|modified)" (bzr diff, alternative)
" - "# HG changeset patch" in first line (Mercurial export format) " - "# HG changeset patch" in first line (Mercurial export format)
elseif s:line1 =~ '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)' elseif s:line1 =~# '^\(diff\>\|Only in \|\d\+\(,\d\+\)\=[cda]\d\+\>\|# It was generated by makepatch \|Index:\s\+\f\+\r\=$\|===== \f\+ \d\+\.\d\+ vs edited\|==== //\f\+#\d\+\|# HG changeset patch\)'
\ || (s:line1 =~ '^--- ' && s:line2 =~ '^+++ ') \ || (s:line1 =~# '^--- ' && s:line2 =~# '^+++ ')
\ || (s:line1 =~ '^\* looking for ' && s:line2 =~ '^\* comparing to ') \ || (s:line1 =~# '^\* looking for ' && s:line2 =~# '^\* comparing to ')
\ || (s:line1 =~ '^\*\*\* ' && s:line2 =~ '^--- ') \ || (s:line1 =~# '^\*\*\* ' && s:line2 =~# '^--- ')
\ || (s:line1 =~ '^=== ' && ((s:line2 =~ '^=\{66\}' && s:line3 =~ '^--- ' && s:line4 =~ '^+++') || (s:line2 =~ '^--- ' && s:line3 =~ '^+++ '))) \ || (s:line1 =~# '^=== ' && ((s:line2 =~# '^=\{66\}' && s:line3 =~# '^--- ' && s:line4 =~# '^+++') || (s:line2 =~# '^--- ' && s:line3 =~# '^+++ ')))
\ || (s:line1 =~ '^=== \(removed\|added\|renamed\|modified\)') \ || (s:line1 =~# '^=== \(removed\|added\|renamed\|modified\)')
set ft=diff set ft=diff
" PostScript Files (must have %!PS as the first line, like a2ps output) " PostScript Files (must have %!PS as the first line, like a2ps output)
elseif s:line1 =~ '^%![ \t]*PS' elseif s:line1 =~# '^%![ \t]*PS'
set ft=postscr set ft=postscr
" M4 scripts: Guess there is a line that starts with "dnl". " M4 scripts: Guess there is a line that starts with "dnl".
elseif s:line1 =~ '^\s*dnl\>' elseif s:line1 =~# '^\s*dnl\>'
\ || s:line2 =~ '^\s*dnl\>' \ || s:line2 =~# '^\s*dnl\>'
\ || s:line3 =~ '^\s*dnl\>' \ || s:line3 =~# '^\s*dnl\>'
\ || s:line4 =~ '^\s*dnl\>' \ || s:line4 =~# '^\s*dnl\>'
\ || s:line5 =~ '^\s*dnl\>' \ || s:line5 =~# '^\s*dnl\>'
set ft=m4 set ft=m4
" AmigaDos scripts
elseif $TERM == "amiga"
\ && (s:line1 =~# "^;" || s:line1 =~? '^\.bra')
set ft=amiga
" SiCAD scripts (must have procn or procd as the first line to trigger this) " SiCAD scripts (must have procn or procd as the first line to trigger this)
elseif s:line1 =~? '^ *proc[nd] *$' elseif s:line1 =~? '^ *proc[nd] *$'
set ft=sicad set ft=sicad
" Purify log files start with "**** Purify" " Purify log files start with "**** Purify"
elseif s:line1 =~ '^\*\*\*\* Purify' elseif s:line1 =~# '^\*\*\*\* Purify'
set ft=purifylog set ft=purifylog
" XML " XML
elseif s:line1 =~ '<?\s*xml.*?>' elseif s:line1 =~# '<?\s*xml.*?>'
set ft=xml set ft=xml
" XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN") " XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN")
elseif s:line1 =~ '\<DTD\s\+XHTML\s' elseif s:line1 =~# '\<DTD\s\+XHTML\s'
set ft=xhtml set ft=xhtml
" HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN") " HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN")
@@ -257,43 +266,43 @@ else
set ft=html set ft=html
" PDF " PDF
elseif s:line1 =~ '^%PDF-' elseif s:line1 =~# '^%PDF-'
set ft=pdf set ft=pdf
" XXD output " XXD output
elseif s:line1 =~ '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} ' elseif s:line1 =~# '^\x\{7}: \x\{2} \=\x\{2} \=\x\{2} \=\x\{2} '
set ft=xxd set ft=xxd
" RCS/CVS log output " RCS/CVS log output
elseif s:line1 =~ '^RCS file:' || s:line2 =~ '^RCS file:' elseif s:line1 =~# '^RCS file:' || s:line2 =~# '^RCS file:'
set ft=rcslog set ft=rcslog
" CVS commit " CVS commit
elseif s:line2 =~ '^CVS:' || getline("$") =~ '^CVS: ' elseif s:line2 =~# '^CVS:' || getline("$") =~# '^CVS: '
set ft=cvs set ft=cvs
" Prescribe " Prescribe
elseif s:line1 =~ '^!R!' elseif s:line1 =~# '^!R!'
set ft=prescribe set ft=prescribe
" Send-pr " Send-pr
elseif s:line1 =~ '^SEND-PR:' elseif s:line1 =~# '^SEND-PR:'
set ft=sendpr set ft=sendpr
" SNNS files " SNNS files
elseif s:line1 =~ '^SNNS network definition file' elseif s:line1 =~# '^SNNS network definition file'
set ft=snnsnet set ft=snnsnet
elseif s:line1 =~ '^SNNS pattern definition file' elseif s:line1 =~# '^SNNS pattern definition file'
set ft=snnspat set ft=snnspat
elseif s:line1 =~ '^SNNS result file' elseif s:line1 =~# '^SNNS result file'
set ft=snnsres set ft=snnsres
" Virata " Virata
elseif s:line1 =~ '^%.\{-}[Vv]irata' elseif s:line1 =~# '^%.\{-}[Vv]irata'
\ || s:line2 =~ '^%.\{-}[Vv]irata' \ || s:line2 =~# '^%.\{-}[Vv]irata'
\ || s:line3 =~ '^%.\{-}[Vv]irata' \ || s:line3 =~# '^%.\{-}[Vv]irata'
\ || s:line4 =~ '^%.\{-}[Vv]irata' \ || s:line4 =~# '^%.\{-}[Vv]irata'
\ || s:line5 =~ '^%.\{-}[Vv]irata' \ || s:line5 =~# '^%.\{-}[Vv]irata'
set ft=virata set ft=virata
" Strace " Strace
@@ -301,17 +310,17 @@ else
set ft=strace set ft=strace
" VSE JCL " VSE JCL
elseif s:line1 =~ '^\* $$ JOB\>' || s:line1 =~ '^// *JOB\>' elseif s:line1 =~# '^\* $$ JOB\>' || s:line1 =~# '^// *JOB\>'
set ft=vsejcl set ft=vsejcl
" TAK and SINDA " TAK and SINDA
elseif s:line4 =~ 'K & K Associates' || s:line2 =~ 'TAK 2000' elseif s:line4 =~# 'K & K Associates' || s:line2 =~# 'TAK 2000'
set ft=takout set ft=takout
elseif s:line3 =~ 'S Y S T E M S I M P R O V E D ' elseif s:line3 =~# 'S Y S T E M S I M P R O V E D '
set ft=sindaout set ft=sindaout
elseif getline(6) =~ 'Run Date: ' elseif getline(6) =~# 'Run Date: '
set ft=takcmp set ft=takcmp
elseif getline(9) =~ 'Node File 1' elseif getline(9) =~# 'Node File 1'
set ft=sindacmp set ft=sindacmp
" DNS zone files " DNS zone files
@@ -319,34 +328,34 @@ else
set ft=bindzone set ft=bindzone
" BAAN " BAAN
elseif s:line1 =~ '|\*\{1,80}' && s:line2 =~ 'VRC ' elseif s:line1 =~# '|\*\{1,80}' && s:line2 =~# 'VRC '
\ || s:line2 =~ '|\*\{1,80}' && s:line3 =~ 'VRC ' \ || s:line2 =~# '|\*\{1,80}' && s:line3 =~# 'VRC '
set ft=baan set ft=baan
" Valgrind " Valgrind
elseif s:line1 =~ '^==\d\+== valgrind' || s:line3 =~ '^==\d\+== Using valgrind' elseif s:line1 =~# '^==\d\+== valgrind' || s:line3 =~# '^==\d\+== Using valgrind'
set ft=valgrind set ft=valgrind
" Go docs " Go docs
elseif s:line1 =~ '^PACKAGE DOCUMENTATION$' elseif s:line1 =~# '^PACKAGE DOCUMENTATION$'
set ft=godoc set ft=godoc
" Renderman Interface Bytestream " Renderman Interface Bytestream
elseif s:line1 =~ '^##RenderMan' elseif s:line1 =~# '^##RenderMan'
set ft=rib set ft=rib
" Scheme scripts " Scheme scripts
elseif s:line1 =~ 'exec\s\+\S*scheme' || s:line2 =~ 'exec\s\+\S*scheme' elseif s:line1 =~# 'exec\s\+\S*scheme' || s:line2 =~# 'exec\s\+\S*scheme'
set ft=scheme set ft=scheme
" Git output " Git output
elseif s:line1 =~ '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$' elseif s:line1 =~# '^\(commit\|tree\|object\) \x\{40\}\>\|^tag \S\+$'
set ft=git set ft=git
" Gprof (gnu profiler) " Gprof (gnu profiler)
elseif s:line1 == 'Flat profile:' elseif s:line1 == 'Flat profile:'
\ && s:line2 == '' \ && s:line2 == ''
\ && s:line3 =~ '^Each sample counts as .* seconds.$' \ && s:line3 =~# '^Each sample counts as .* seconds.$'
set ft=gprof set ft=gprof
" Erlang terms " Erlang terms
@@ -357,18 +366,18 @@ else
" CVS diff " CVS diff
else else
let s:lnum = 1 let s:lnum = 1
while getline(s:lnum) =~ "^? " && s:lnum < line("$") while getline(s:lnum) =~# "^? " && s:lnum < line("$")
let s:lnum += 1 let s:lnum += 1
endwhile endwhile
if getline(s:lnum) =~ '^Index:\s\+\f\+$' if getline(s:lnum) =~# '^Index:\s\+\f\+$'
set ft=diff set ft=diff
" locale input files: Formal Definitions of Cultural Conventions " locale input files: Formal Definitions of Cultural Conventions
" filename must be like en_US, fr_FR@euro or en_US.UTF-8 " filename must be like en_US, fr_FR@euro or en_US.UTF-8
elseif expand("%") =~ '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_' elseif expand("%") =~# '\a\a_\a\a\($\|[.@]\)\|i18n$\|POSIX$\|translit_'
let s:lnum = 1 let s:lnum = 1
while s:lnum < 100 && s:lnum < line("$") while s:lnum < 100 && s:lnum < line("$")
if getline(s:lnum) =~ '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$' if getline(s:lnum) =~# '^LC_\(IDENTIFICATION\|CTYPE\|COLLATE\|MONETARY\|NUMERIC\|TIME\|MESSAGES\|PAPER\|TELEPHONE\|MEASUREMENT\|NAME\|ADDRESS\)$'
setf fdcc setf fdcc
break break
endif endif

BIN
runtime/spell/en.utf-8.spl Normal file

Binary file not shown.

View File

@@ -32,7 +32,7 @@ syntax match dircolorsEscape '\\[abefnrtv?_\\^#]'
syntax match dircolorsEscape '\\[0-9]\{3}' syntax match dircolorsEscape '\\[0-9]\{3}'
syntax match dircolorsEscape '\\x[0-9a-f]\{3}' syntax match dircolorsEscape '\\x[0-9a-f]\{3}'
if !has('gui_running') && &t_Co == '' if !(has('gui_running') || &termguicolors) && &t_Co == ''
syntax match dircolorsNumber '\<\d\+\>' syntax match dircolorsNumber '\<\d\+\>'
highlight default link dircolorsNumber Number highlight default link dircolorsNumber Number
endif endif
@@ -84,7 +84,7 @@ endfunction
function! s:get_hi_str(color, place) abort function! s:get_hi_str(color, place) abort
if a:color >= 0 && a:color <= 255 if a:color >= 0 && a:color <= 255
if has('gui_running') if has('gui_running') || &termguicolors
return ' gui' . a:place . '=' . s:termguicolors[a:color] return ' gui' . a:place . '=' . s:termguicolors[a:color]
elseif a:color <= 7 || &t_Co == 256 || &t_Co == 88 elseif a:color <= 7 || &t_Co == 256 || &t_Co == 88
return ' cterm' . a:place . '=' . a:color return ' cterm' . a:place . '=' . a:color
@@ -169,7 +169,7 @@ function! s:preview_color(linenr) abort
\ ' "\_s\zs' . colordef . '\ze\_s"' \ ' "\_s\zs' . colordef . '\ze\_s"'
let hi_attrs_str = '' let hi_attrs_str = ''
if !empty(hi_attrs) if !empty(hi_attrs)
if has('gui_running') if has('gui_running') || &termguicolors
let hi_attrs_str = ' gui=' . join(hi_attrs, ',') let hi_attrs_str = ' gui=' . join(hi_attrs, ',')
else else
let hi_attrs_str = ' cterm=' . join(hi_attrs, ',') let hi_attrs_str = ' cterm=' . join(hi_attrs, ',')
@@ -199,11 +199,11 @@ endfunction
let b:dc_next_index = 0 let b:dc_next_index = 0
if has('gui_running') if has('gui_running') || &termguicolors
call s:set_guicolors() call s:set_guicolors()
endif endif
if has('gui_running') || &t_Co != '' if has('gui_running') || &termguicolors || &t_Co != ''
call s:reset_colors() call s:reset_colors()
autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.') autocmd CursorMoved,CursorMovedI <buffer> call s:preview_color('.')

View File

@@ -18,6 +18,10 @@ highlight default link manOptionDesc Constant
highlight default link manReference PreProc highlight default link manReference PreProc
highlight default link manSubHeading Function highlight default link manSubHeading Function
highlight default manUnderline cterm=underline gui=underline
highlight default manBold cterm=bold gui=bold
highlight default manItalic cterm=italic gui=italic
if &filetype != 'man' if &filetype != 'man'
" May have been included by some other filetype. " May have been included by some other filetype.
finish finish

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +1,43 @@
{ {
"expect": { "expect": {
"24": -1, "24": -1,
"102": "The cow jumped over the moon.", "103": "The cow jumped over the moon.",
"122": "There is some text missing from this line.", "124": "There is some text missing from this line.",
"123": "There is some text missing from this line.", "125": "There is some text missing from this line.",
"141": "There is some text missing from this line.", "144": "There is some text missing from this line.",
"142": "There is some text missing from this line.", "145": "There is some text missing from this line.",
"143": "There is also some text missing here.", "146": "There is also some text missing here.",
"144": "There is also some text missing here.", "147": "There is also some text missing here.",
"215": "There are some words that don't belong in this sentence.", "220": "There are some words that don't belong in this sentence.",
"231": "Somebody typed the end of this line twice.", "236": "Somebody typed the end of this line twice.",
"271": -1, "276": -1,
"290": "This line of words is cleaned up.", "295": "This line of words is cleaned up.",
"304": -1,
"305": -1,
"306": -1,
"307": -1,
"308": -1,
"309": -1, "309": -1,
"310": -1, "310": -1,
"325": "Fix the errors on this line and replace them with undo.", "311": -1,
"365": -1, "312": -1,
"366": -1, "313": -1,
"367": -1, "314": -1,
"368": -1, "315": -1,
"382": "When this line was typed in, someone pressed some wrong keys!", "332": "Fix the errors on this line and replace them with undo.",
"383": "When this line was typed in, someone pressed some wrong keys!", "372": -1,
"403": "This line has a few words that need changing using the change operator.", "373": -1,
"404": "This line has a few words that need changing using the change operator.", "374": -1,
"424": "The end of this line needs to be corrected using the c$ command.", "375": -1,
"425": "The end of this line needs to be corrected using the c$ command.", "389": "When this line was typed in, someone pressed some wrong keys!",
"487": -1, "390": "When this line was typed in, someone pressed some wrong keys!",
"506": -1, "411": "This line has a few words that need changing using the change operator.",
"531": "Usually the best time to see the flowers is in the spring.", "412": "This line has a few words that need changing using the change operator.",
"722": -1, "432": "The end of this line needs to be corrected using the c$ command.",
"727": -1, "433": "The end of this line needs to be corrected using the c$ command.",
"744": "This line will allow you to practice appending text to a line.", "497": -1,
"745": "This line will allow you to practice appending text to a line.", "516": -1,
"765": "Adding 123 to 456 gives you 579.", "541": "Usually the best time to see the flowers is in the spring.",
"766": "Adding 123 to 456 gives you 579.", "759": "This line will allow you to practice appending text to a line.",
"790": "a) This is the first item.", "760": "This line will allow you to practice appending text to a line.",
"791": " b) This is the second item." "780": "Adding 123 to 456 gives you 579.",
"781": "Adding 123 to 456 gives you 579.",
"807": "a) This is the first item.",
"808": " b) This is the second item."
} }
} }

View File

@@ -45,6 +45,8 @@ if sys.version_info[0] < 3:
doc_filename = 'api.txt' doc_filename = 'api.txt'
# String used to find the start of the generated part of the doc. # String used to find the start of the generated part of the doc.
section_start_token = '*api-global*' section_start_token = '*api-global*'
# Required prefix for API function names.
api_func_name_prefix = 'nvim_'
# Section name overrides. # Section name overrides.
section_name = { section_name = {
@@ -260,11 +262,11 @@ def parse_parblock(parent, width=62):
def parse_source_xml(filename): def parse_source_xml(filename):
"""Collects API functions. """Collects API functions.
This returns two strings: Returns two strings:
1. The API functions 1. API functions
2. The deprecated API functions 2. Deprecated API functions
The caller decides what to do with the deprecated documentation. Caller decides what to do with the deprecated documentation.
""" """
global xrefs global xrefs
xrefs = set() xrefs = set()
@@ -294,9 +296,8 @@ def parse_source_xml(filename):
annotations = get_text(get_child(member, 'argsstring')) annotations = get_text(get_child(member, 'argsstring'))
if annotations and ')' in annotations: if annotations and ')' in annotations:
annotations = annotations.rsplit(')', 1)[-1].strip() annotations = annotations.rsplit(')', 1)[-1].strip()
# XXX: (doxygen 1.8.11) 'argsstring' only includes FUNC_ATTR_* # XXX: (doxygen 1.8.11) 'argsstring' only includes attributes of
# attributes if the function signature is non-void. # non-void functions. Special-case void functions here.
# Force attributes here for such functions.
if name == 'nvim_get_mode' and len(annotations) == 0: if name == 'nvim_get_mode' and len(annotations) == 0:
annotations += 'FUNC_API_ASYNC' annotations += 'FUNC_API_ASYNC'
annotations = filter(None, map(lambda x: annotation_map.get(x), annotations = filter(None, map(lambda x: annotation_map.get(x),
@@ -379,7 +380,7 @@ def parse_source_xml(filename):
if 'Deprecated' in xrefs: if 'Deprecated' in xrefs:
deprecated_functions.append(func_doc) deprecated_functions.append(func_doc)
else: elif name.startswith(api_func_name_prefix):
functions.append(func_doc) functions.append(func_doc)
xrefs.clear() xrefs.clear()
@@ -477,7 +478,7 @@ def gen_docs(config):
docs += '\n\n\n' docs += '\n\n\n'
docs = docs.rstrip() + '\n\n' docs = docs.rstrip() + '\n\n'
docs += ' vim:tw=78:ts=8:ft=help:norl:' docs += ' vim:tw=78:ts=8:ft=help:norl:\n'
doc_file = os.path.join(base_dir, 'runtime/doc', doc_filename) doc_file = os.path.join(base_dir, 'runtime/doc', doc_filename)
delete_lines_below(doc_file, section_start_token) delete_lines_below(doc_file, section_start_token)

View File

@@ -11,6 +11,8 @@ if [ -z "$ARCH" ]; then
export ARCH="$(arch)" export ARCH="$(arch)"
fi fi
TAG=$1
# App name, used by generate_appimage. # App name, used by generate_appimage.
APP=nvim APP=nvim
@@ -35,7 +37,7 @@ VERSION=$("$ROOT_DIR"/build/bin/nvim --version | head -n 1 | grep -o 'v.*')
cd "$APP_BUILD_DIR" cd "$APP_BUILD_DIR"
curl -Lo "$APP_BUILD_DIR"/appimage_functions.sh https://github.com/probonopd/AppImages/raw/master/functions.sh curl -Lo "$APP_BUILD_DIR"/appimage_functions.sh https://github.com/AppImage/AppImages/raw/master/functions.sh
. ./appimage_functions.sh . ./appimage_functions.sh
# Copy desktop and icon file to AppDir for AppRun to pick them up. # Copy desktop and icon file to AppDir for AppRun to pick them up.
@@ -53,7 +55,7 @@ move_lib
# Delete stuff that should not go into the AppImage. # Delete stuff that should not go into the AppImage.
# Delete dangerous libraries; see # Delete dangerous libraries; see
# https://github.com/probonopd/AppImages/blob/master/excludelist # https://github.com/AppImage/AppImages/blob/master/excludelist
delete_blacklisted delete_blacklisted
######################################################################## ########################################################################
@@ -69,14 +71,16 @@ cd "$APP_BUILD_DIR" # Get out of AppImage directory.
# - Expects: $ARCH, $APP, $VERSION env vars # - Expects: $ARCH, $APP, $VERSION env vars
# - Expects: ./$APP.AppDir/ directory # - Expects: ./$APP.AppDir/ directory
# - Produces: ../out/$APP-$VERSION.glibc$GLIBC_NEEDED-$ARCH.AppImage # - Produces: ../out/$APP-$VERSION.glibc$GLIBC_NEEDED-$ARCH.AppImage
generate_appimage if [ -n "$TAG" ]; then
generate_type2_appimage -u "gh-releases-zsync|neovim|neovim|$TAG|nvim.appimage.zsync"
else
generate_type2_appimage
fi
# NOTE: There is currently a bug in the `generate_appimage` function (see # Moving the final executable to a different folder so it isn't in the
# https://github.com/probonopd/AppImages/issues/228) that causes repeated builds # way for a subsequent build.
# that result in the same name to fail.
# Moving the final executable to a different folder gets around this issue.
mv "$ROOT_DIR"/out/*.AppImage "$ROOT_DIR"/build/bin mv "$ROOT_DIR"/out/*.AppImage* "$ROOT_DIR"/build/bin
# Remove the (now empty) folder the AppImage was built in # Remove the (now empty) folder the AppImage was built in
rmdir "$ROOT_DIR"/out rmdir "$ROOT_DIR"/out

View File

@@ -343,13 +343,15 @@ run_analysis() {(
cd "$tgt" cd "$tgt"
# pvs-studio-analyzer exits with a non-zero exit code when there are detected
# errors, so ignore its return
pvs-studio-analyzer \ pvs-studio-analyzer \
analyze \ analyze \
--threads "$(get_jobs_num)" \ --threads "$(get_jobs_num)" \
--output-file PVS-studio.log \ --output-file PVS-studio.log \
--verbose \ --verbose \
--file build/compile_commands.json \ --file build/compile_commands.json \
--sourcetree-root . --sourcetree-root . || true
plog-converter -t xml -o PVS-studio.xml PVS-studio.log plog-converter -t xml -o PVS-studio.xml PVS-studio.log
plog-converter -t errorfile -o PVS-studio.err PVS-studio.log plog-converter -t errorfile -o PVS-studio.err PVS-studio.log

View File

@@ -1,50 +0,0 @@
#!/usr/bin/env expect
if {$argc < 2} {
puts "Need commands for running the tests and for starting nvim"
exit 1
}
set timeout 60
set run_tests [split [lindex $argv 0] " "]
set run_nvim [split [lindex $argv 1] " "]
# don't echo to stdout
log_user 0
# set NVIM_LISTEN_ADDRESS, so nvim will listen on a known socket
set env(NVIM_LISTEN_ADDRESS) "/tmp/nvim-[exec date +%s%N].sock"
# start nvim
spawn {*}$run_nvim
# save the job descriptor
set nvim_id $spawn_id
# Reset function that can be invoked by test runners to put nvim in a cleaner
# state
send {
:echo "read"."y"
}
# wait until nvim is ready
expect "ready"
# run tests
spawn {*}$run_tests
set tests_id $spawn_id
set status 1
# listen for test output in the background
expect_background {
* {
# show test output to the user
send_user -- $expect_out(buffer)
}
eof {
# collect the exit status code
set spawn_id $tests_id
catch wait result
set status [lindex $result 3]
set spawn_id $nvim_id
# quit nvim
send ":qa!\r"
}
}
# switch back nvim and wait until it exits
set spawn_id $nvim_id
expect eof
exit $status

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3.4 #!/usr/bin/env python3
import os import os
import sys import sys

View File

@@ -14,26 +14,34 @@ readonly BRANCH_PREFIX="vim-"
CREATED_FILES=() CREATED_FILES=()
usage() { usage() {
echo "Helper script for porting Vim patches. For more information, see" echo "Port Vim patches to Neovim"
echo "https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim" echo "https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim"
echo echo
echo "Usage: ${BASENAME} [-h | -l | -p vim-revision | -r pr-number]" echo "Usage: ${BASENAME} [-h | -l | -p vim-revision | -r pr-number]"
echo echo
echo "Options:" echo "Options:"
echo " -h Show this message and exit." echo " -h Show this message and exit."
echo " -l Show list of Vim patches missing from Neovim." echo " -l List missing Vim patches."
echo " -p {vim-revision} Download and generate the specified Vim patch." echo " -L List missing Vim patches (for scripts)."
echo " vim-revision can be a version number '8.0.xxx'" echo " -M List all merged patch-numbers (at current v:version)."
echo " or a valid Git ref (hash, tag, etc.)." echo " -p {vim-revision} Download and generate a Vim patch. vim-revision"
echo " -P {vim-revision} Download, generate and apply the Vim patch." echo " can be a Vim version (8.0.xxx) or a Git hash."
echo " -g {vim-revision} Download the Vim patch vim-revision." echo " -P {vim-revision} Download, generate and apply a Vim patch."
echo " vim-revision can be a version number of the " echo " -g {vim-revision} Download a Vim patch."
echo " format '7.4.xxx' or a Git commit hash." echo " -s Create a vim-patch pull request."
echo " -s Submit a vim-patch pull request to Neovim." echo " -r {pr-number} Review a vim-patch pull request."
echo " -r {pr-number} Review a vim-patch pull request to Neovim." echo ' -V Clone the Vim source code to $VIM_SOURCE_DIR.'
echo echo
echo "Set VIM_SOURCE_DIR to change where Vim's sources are stored." echo ' $VIM_SOURCE_DIR controls where Vim sources are found'
echo "Default is '${VIM_SOURCE_DIR_DEFAULT}'." echo " (default: '${VIM_SOURCE_DIR_DEFAULT}')"
}
msg_ok() {
printf "\e[32m✔\e[0m $@\n"
}
msg_err() {
printf "\e[31m✘\e[0m $@\n"
} }
# Checks if a program is in the user's PATH, and is executable. # Checks if a program is in the user's PATH, and is executable.
@@ -73,26 +81,29 @@ get_vim_sources() {
require_executable git require_executable git
if [[ ! -d ${VIM_SOURCE_DIR} ]]; then if [[ ! -d ${VIM_SOURCE_DIR} ]]; then
echo "Cloning Vim sources into '${VIM_SOURCE_DIR}'." echo "Cloning Vim into: ${VIM_SOURCE_DIR}"
git clone https://github.com/vim/vim.git "${VIM_SOURCE_DIR}" git clone https://github.com/vim/vim.git "${VIM_SOURCE_DIR}"
cd "${VIM_SOURCE_DIR}" cd "${VIM_SOURCE_DIR}"
else else
if [[ ! -d "${VIM_SOURCE_DIR}/.git" ]]; then if [[ ! -d "${VIM_SOURCE_DIR}/.git" ]]; then
echo "${VIM_SOURCE_DIR} does not appear to be a git repository." msg_err "${VIM_SOURCE_DIR} does not appear to be a git repository."
echo " Please remove it and try again." echo " Please remove it and try again."
exit 1 exit 1
fi fi
cd "${VIM_SOURCE_DIR}" cd "${VIM_SOURCE_DIR}"
echo "Updating Vim sources in '${VIM_SOURCE_DIR}'." echo "Updating Vim sources: ${VIM_SOURCE_DIR}"
git pull && git pull &&
echo "Updated Vim sources." || msg_ok "Updated Vim sources." ||
echo "Could not update Vim sources; ignoring error." msg_err "Could not update Vim sources; ignoring error."
fi fi
} }
commit_message() { commit_message() {
printf 'vim-patch:%s\n\n%s\n\n%s' "${vim_version}" \ if [[ -n "$vim_tag" ]]; then
"${vim_message}" "${vim_commit_url}" printf '%s\n%s' "${vim_message}" "${vim_commit_url}"
else
printf 'vim-patch:%s\n\n%s\n%s' "$vim_version" "$vim_message" "$vim_commit_url"
fi
} }
find_git_remote() { find_git_remote() {
@@ -107,22 +118,23 @@ assign_commit_details() {
vim_tag="v${1}" vim_tag="v${1}"
vim_commit=$(cd "${VIM_SOURCE_DIR}" \ vim_commit=$(cd "${VIM_SOURCE_DIR}" \
&& git log -1 --format="%H" "${vim_tag}") && git log -1 --format="%H" "${vim_tag}")
local strip_commit_line=true local munge_commit_line=true
else else
# Interpret parameter as commit hash. # Interpret parameter as commit hash.
vim_version="${1:0:12}" vim_version="${1:0:12}"
vim_tag=
vim_commit=$(cd "${VIM_SOURCE_DIR}" \ vim_commit=$(cd "${VIM_SOURCE_DIR}" \
&& git log -1 --format="%H" "${vim_version}") && git log -1 --format="%H" "${vim_version}")
local strip_commit_line=false local munge_commit_line=false
fi fi
vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}" vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}"
vim_message="$(cd "${VIM_SOURCE_DIR}" \ vim_message="$(cd "${VIM_SOURCE_DIR}" \
&& git log -1 --pretty='format:%B' "${vim_commit}" \ && git log -1 --pretty='format:%B' "${vim_commit}" \
| sed -e 's/\(#[0-9]*\)/vim\/vim\1/g')" | sed -e 's/\(#[0-9]*\)/vim\/vim\1/g')"
if [[ ${strip_commit_line} == "true" ]]; then if [[ ${munge_commit_line} == "true" ]]; then
# Remove first line of commit message. # Remove first line of commit message.
vim_message="$(echo "${vim_message}" | sed -e '1d')" vim_message="$(echo "${vim_message}" | sed -e '1s/^patch /vim-patch:/')"
fi fi
patch_file="vim-${vim_version}.patch" patch_file="vim-${vim_version}.patch"
} }
@@ -147,6 +159,10 @@ preprocess_patch() {
# Remove some testdir/Make_*.mak files # Remove some testdir/Make_*.mak files
local na_src_testdir='Make_amiga.mak\|Make_dos.mak\|Make_ming.mak\|Make_vms.mms' local na_src_testdir='Make_amiga.mak\|Make_dos.mak\|Make_ming.mak\|Make_vms.mms'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/testdir/\<\%('${na_src_testdir}'\)\>@norm! d/\v(^diff)|%$
' +w +q "$file"
# Remove version.c #7555
local na_po='version.c' local na_po='version.c'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\<\%('${na_po}'\)\>@norm! d/\v(^diff)|%$ 2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\<\%('${na_po}'\)\>@norm! d/\v(^diff)|%$
' +w +q "$file" ' +w +q "$file"
@@ -164,16 +180,16 @@ preprocess_patch() {
# Rename src/ paths to src/nvim/ # Rename src/ paths to src/nvim/
LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g' \ LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file" "$file" > "$file".tmp && mv "$file".tmp "$file"
# Rename path to matchit plugin.
# Rename path to matchit plugin. # Rename path to matchit plugin.
LC_ALL=C sed -e 's@\( [ab]/runtime\)/pack/dist/opt/matchit/\(plugin/matchit.vim\)@\1/\2@g' \ LC_ALL=C sed -e 's@\( [ab]/runtime\)/pack/dist/opt/matchit/\(plugin/matchit.vim\)@\1/\2@g' \
"$file" > "$file".tmp && mv "$file".tmp "$file" "$file" > "$file".tmp && mv "$file".tmp "$file"
} }
get_vim_sources get_vimpatch() {
get_vim_sources get_vim_sources
assign_commit_details "${1}"
git log -1 "${vim_commit}" -- >/dev/null 2>&1 || { git log -1 "${vim_commit}" -- >/dev/null 2>&1 || {
>&2 msg_err "Couldn't find Vim revision '${vim_commit}'." >&2 msg_err "Couldn't find Vim revision '${vim_commit}'."
@@ -186,11 +202,11 @@ get_vim_patch() {
cd "${NVIM_SOURCE_DIR}" cd "${NVIM_SOURCE_DIR}"
echo "$patch_content" > "${NVIM_SOURCE_DIR}/${patch_file}" printf "Creating patch...\n"
echo "$patch_content" > "${NVIM_SOURCE_DIR}/${patch_file}" echo "$patch_content" > "${NVIM_SOURCE_DIR}/${patch_file}"
printf "Pre-processing patch...\n" printf "Pre-processing patch...\n"
preprocess_patch "${NVIM_SOURCE_DIR}/${patch_file}"
msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'.\n" msg_ok "Saved patch to '${NVIM_SOURCE_DIR}/${patch_file}'.\n"
} }
@@ -199,34 +215,36 @@ stage_patch() {
get_vimpatch "$1" get_vimpatch "$1"
local try_apply="${2:-}" local try_apply="${2:-}"
git_remote="$(find_git_remote)" local git_remote
git_remote="$(find_git_remote)" git_remote="$(find_git_remote)"
local checked_out_branch local checked_out_branch
checked_out_branch="$(git rev-parse --abbrev-ref HEAD)" checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
echo "✔ Current branch '${checked_out_branch}' seems to be a vim-patch" if [[ "${checked_out_branch}" == ${BRANCH_PREFIX}* ]]; then
echo " branch; not creating a new branch." msg_ok "Current branch '${checked_out_branch}' seems to be a vim-patch"
echo " branch; not creating a new branch." echo " branch; not creating a new branch."
else else
printf "\nFetching '${git_remote}/master'.\n" printf "\nFetching '${git_remote}/master'.\n"
output="$(git fetch "${git_remote}" master 2>&1)" && output="$(git fetch "${git_remote}" master 2>&1)" &&
msg_ok "${output}" || msg_ok "${output}" ||
(msg_err "${output}"; false) (msg_err "${output}"; false)
local nvim_branch="${BRANCH_PREFIX}${vim_version}"
echo local nvim_branch="${BRANCH_PREFIX}${vim_version}"
echo echo
echo "Creating new branch '${nvim_branch}' based on '${git_remote}/master'." echo "Creating new branch '${nvim_branch}' based on '${git_remote}/master'."
cd "${NVIM_SOURCE_DIR}" cd "${NVIM_SOURCE_DIR}"
output="$(git checkout -b "${nvim_branch}" "${git_remote}/master" 2>&1)" && output="$(git checkout -b "${nvim_branch}" "${git_remote}/master" 2>&1)" &&
(echo "${output}"; false) msg_ok "${output}" ||
fi (msg_err "${output}"; false)
fi fi
printf "\nCreating empty commit with correct commit message.\n" printf "\nCreating empty commit with correct commit message.\n"
echo "${output}" || output="$(commit_message | git commit --allow-empty --file 2>&1 -)" &&
msg_ok "${output}" ||
(msg_err "${output}"; false) (msg_err "${output}"; false)
if test -n "$try_apply" ; then if test -n "$try_apply" ; then
if ! check_executable patch; then
printf "\n" printf "\n"
msg_err "'patch' command not found\n" msg_err "'patch' command not found\n"
else else
@@ -274,16 +292,17 @@ submit_pr() {
else else
>&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable." >&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable."
exit 1 exit 1
fi
cd "${NVIM_SOURCE_DIR}" cd "${NVIM_SOURCE_DIR}"
local checked_out_branch local checked_out_branch
checked_out_branch="$(git rev-parse --abbrev-ref HEAD)" checked_out_branch="$(git rev-parse --abbrev-ref HEAD)"
if [[ "${checked_out_branch}" != ${BRANCH_PREFIX}* ]]; then if [[ "${checked_out_branch}" != ${BRANCH_PREFIX}* ]]; then
msg_err "Current branch '${checked_out_branch}' doesn't seem to be a vim-patch branch." msg_err "Current branch '${checked_out_branch}' doesn't seem to be a vim-patch branch."
fi exit 1
fi fi
local git_remote
local git_remote
git_remote="$(find_git_remote)" git_remote="$(find_git_remote)"
local pr_body local pr_body
pr_body="$(git log --grep=vim-patch --reverse --format='#### %s%n%n%b%n' "${git_remote}"/master..HEAD)" pr_body="$(git log --grep=vim-patch --reverse --format='#### %s%n%n%b%n' "${git_remote}"/master..HEAD)"
@@ -294,16 +313,16 @@ submit_pr() {
local pr_title="${patches[*]}" # Create space-separated string from array. local pr_title="${patches[*]}" # Create space-separated string from array.
pr_title="${pr_title// /,}" # Replace spaces with commas. pr_title="${pr_title// /,}" # Replace spaces with commas.
pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")" local pr_message
pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")"
if [[ $push_first -ne 0 ]]; then if [[ $push_first -ne 0 ]]; then
echo "Pushing to 'origin/${checked_out_branch}'." echo "Pushing to 'origin/${checked_out_branch}'."
output="$(git push origin "${checked_out_branch}" 2>&1)" && output="$(git push origin "${checked_out_branch}" 2>&1)" &&
msg_ok "${output}" || msg_ok "${output}" ||
(msg_err "${output}"; false) (msg_err "${output}"; false)
echo
fi echo
fi fi
echo "Creating pull request." echo "Creating pull request."
@@ -314,43 +333,74 @@ submit_pr() {
echo echo
echo "Cleaning up files." echo "Cleaning up files."
local patch_file local patch_file
patch_file="vim-${patch_file}.patch" for patch_file in "${patches[@]}"; do
patch_file="vim-${patch_file}.patch" patch_file="vim-${patch_file}.patch"
if [[ ! -f "${NVIM_SOURCE_DIR}/${patch_file}" ]]; then if [[ ! -f "${NVIM_SOURCE_DIR}/${patch_file}" ]]; then
continue continue
rm -- "${NVIM_SOURCE_DIR}/${patch_file}" fi
echo "✔ Removed '${NVIM_SOURCE_DIR}/${patch_file}'." rm -- "${NVIM_SOURCE_DIR}/${patch_file}"
msg_ok "Removed '${NVIM_SOURCE_DIR}/${patch_file}'."
done
} }
}
# Gets all Vim commits since the "start" commit.
list_vim_commits() { (
cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD
) }
# Prints all (sorted) "vim-patch:xxx" tokens found in the Nvim git log.
list_vimpatch_tokens() {
local tokens
# Find all "vim-patch:xxx" tokens in the Nvim git log.
tokens="$(cd "${NVIM_SOURCE_DIR}" && git log -E --grep='vim-patch:[^ ]+' | grep 'vim-patch')"
echo "$tokens" | grep -E 'vim-patch:[^ ,{]{7,}' \
| sed 's/.*\(vim-patch:[.0-9a-z]\+\).*/\1/' \
| sort \
| uniq
}
# Prints all patch-numbers (for the current v:version) for which there is
# a "vim-patch:xxx" token in the Nvim git log.
list_vimpatch_numbers() {
# Transform "vim-patch:X.Y.ZZZZ" to "ZZZZ".
list_vimpatch_tokens | while read vimpatch_token; do
echo "$vimpatch_token" | grep '8\.0\.' | sed 's/.*vim-patch:8\.0\.\([0-9a-z]\+\).*/\1/'
done
}
# Prints a newline-delimited list of Vim commits, for use by scripts. # Prints a newline-delimited list of Vim commits, for use by scripts.
list_missing_vimpatches() { list_missing_vimpatches() {
get_vim_sources local tokens vim_commit vim_commits is_missing vim_tag patch_number
printf "\nVim patches missing from Neovim:\n"
local vim_commits # Find all "vim-patch:xxx" tokens in the Nvim git log.
vim_commits="$(cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD)" tokens="$(list_vimpatch_tokens)"
local vim_commit # Get missing Vim commits
for vim_commit in ${vim_commits}; do vim_commits="$(list_vim_commits)"
local is_missing for vim_commit in ${vim_commits}; do
local vim_tag # Check for vim-patch:<commit_hash> (usually runtime updates).
# This fails for untagged commits (e.g., runtime file updates) so mask the return status is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${vim_commit:0:7}" && echo false || echo true)"
vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" || true
if [[ -n "${vim_tag}" ]]; then if ! [ "$is_missing" = "false" ] \
&& vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" && vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)"
patch_number="$(echo ${patch_number} | sed 's/^0*//g')" # Remove prefix "0"
# Tagged Vim patch, check version.c:
is_missing="$(sed -n '/static const int included_patches/,/}/p' "${NVIM_SOURCE_DIR}/src/nvim/version.c" |
grep -x -e "[[:space:]]*//[[:space:]]${patch_number} NA.*" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")"
vim_commit="${vim_tag#v}"
if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then
vim_commit="${vim_commit} (+runtime)"
then then
# Vim version number (not commit hash). # Vim version number (not commit hash).
# Untagged Vim patch (e.g. runtime updates), check the Neovim git log: # Check for vim-patch:<tag> (not commit hash).
is_missing="$(cd "${NVIM_SOURCE_DIR}" && patch_number="${vim_tag:1}" # "v7.4.0001" => "7.4.0001"
is_missing="$(echo "$tokens" | >/dev/null 2>&1 grep "vim\-patch:${patch_number}" && echo false || echo true)"
vim_commit="${vim_tag#v}"
fi
if ! [ "$is_missing" = "false" ]; then
echo "${vim_commit}"
fi
done
}
# Prints a human-formatted list of Vim commits, with instructional messages.
show_vimpatches() {
get_vim_sources
printf "\nVim patches missing from Neovim:\n"
list_missing_vimpatches | while read vim_commit; do list_missing_vimpatches | while read vim_commit; do
if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then
@@ -380,9 +430,9 @@ review_commit() {
local git_patch_prefix='Subject: \[PATCH\] ' local git_patch_prefix='Subject: \[PATCH\] '
local nvim_patch local nvim_patch
local vim_version nvim_patch="$(curl -Ssf "${nvim_patch_url}")"
local vim_version local vim_version
vim_version="$(head -n 4 <<< "${nvim_patch}" | sed -n "s/${git_patch_prefix}vim-patch:\([a-z0-9.]*\)$/\1/p")"
echo echo
if [[ -n "${vim_version}" ]]; then if [[ -n "${vim_version}" ]]; then
@@ -405,9 +455,9 @@ review_commit() {
assign_commit_details "${vim_version}" assign_commit_details "${vim_version}"
local expected_commit_message local expected_commit_message
local message_length expected_commit_message="$(commit_message)"
local message_length local message_length
local commit_message message_length="$(wc -l <<< "${expected_commit_message}")"
local commit_message local commit_message
commit_message="$(tail -n +4 <<< "${nvim_patch}" | head -n "${message_length}")" commit_message="$(tail -n +4 <<< "${nvim_patch}" | head -n "${message_length}")"
if [[ "${commit_message#${git_patch_prefix}}" == "${expected_commit_message}" ]]; then if [[ "${commit_message#${git_patch_prefix}}" == "${expected_commit_message}" ]]; then
@@ -417,10 +467,10 @@ review_commit() {
echo " Expected:" echo " Expected:"
echo "${expected_commit_message}" echo "${expected_commit_message}"
echo " Actual:" echo " Actual:"
fi echo "${commit_message#${git_patch_prefix}}"
fi fi
echo "Creating files." echo
echo "Creating files." echo "Creating files."
echo "${nvim_patch}" > "${NVIM_SOURCE_DIR}/n${patch_file}" echo "${nvim_patch}" > "${NVIM_SOURCE_DIR}/n${patch_file}"
msg_ok "Saved pull request diff to '${NVIM_SOURCE_DIR}/n${patch_file}'." msg_ok "Saved pull request diff to '${NVIM_SOURCE_DIR}/n${patch_file}'."
@@ -461,14 +511,22 @@ review_pr() {
if [[ "${reply}" == n ]]; then if [[ "${reply}" == n ]]; then
break break
fi fi
done fi
done done
clean_files clean_files
} }
while getopts "hlLMVp:P:g:r:s" opt; do while getopts "hlLMVp:P:g:r:s" opt; do
h) case ${opt} in
h)
usage
exit 0
;;
l)
show_vimpatches
exit 0
;;
L) L)
list_missing_vimpatches list_missing_vimpatches
exit 0 exit 0
@@ -480,7 +538,7 @@ while getopts "hlp:P:g:r:s" opt; do
p) p)
stage_patch "${OPTARG}" stage_patch "${OPTARG}"
exit 0 exit 0
P) ;;
P) P)
stage_patch "${OPTARG}" TRY_APPLY stage_patch "${OPTARG}" TRY_APPLY
exit 0 exit 0
@@ -491,6 +549,10 @@ while getopts "hlp:P:g:r:s" opt; do
;; ;;
r) r)
review_pr "${OPTARG}" review_pr "${OPTARG}"
exit 0
;;
s)
submit_pr
exit 0 exit 0
;; ;;
V) V)

67
scripts/vimpatch.lua Executable file
View File

@@ -0,0 +1,67 @@
-- Updates version.c list of applied Vim patches.
--
-- Usage:
-- VIM_SOURCE_DIR=~/neovim/.vim-src/ nvim -i NONE -u NONE --headless +'luafile ./scripts/vimpatch.lua' +q
local nvim = vim.api
local function pprint(o)
print(nvim.nvim_call_function('string', { o }))
end
local function systemlist(...)
local rv = nvim.nvim_call_function('systemlist', ...)
local err = nvim.nvim_get_vvar('shell_error')
local args_str = nvim.nvim_call_function('string', ...)
if 0 ~= err then
error('command failed: '..args_str)
end
return rv
end
local function vimpatch_sh_list_numbers()
return systemlist( { { 'bash', '-c', 'scripts/vim-patch.sh -M', } } )
end
-- Generates the lines to be inserted into the src/version.c
-- `included_patches[]` definition.
local function gen_version_c_lines()
-- Set of merged Vim 8.0.zzzz patch numbers.
local merged_patch_numbers = {}
local highest = 0
for _, n in ipairs(vimpatch_sh_list_numbers()) do
if n then
merged_patch_numbers[tonumber(n)] = true
highest = math.max(highest, n)
end
end
local lines = {}
for i = highest, 0, -1 do
local is_merged = (nil ~= merged_patch_numbers[i])
if is_merged then
table.insert(lines, string.format(' %s,', i))
else
table.insert(lines, string.format(' // %s,', i))
end
end
return lines
end
local function patch_version_c()
local lines = gen_version_c_lines()
nvim.nvim_command('silent noswapfile noautocmd edit src/nvim/version.c')
nvim.nvim_command('/static const int included_patches')
-- Delete the existing lines.
nvim.nvim_command('silent normal! j0d/};\rk')
-- Insert the lines.
nvim.nvim_call_function('append', {
nvim.nvim_eval('line(".")'),
lines,
})
nvim.nvim_command('silent write')
end
patch_version_c()

41
snap/snapcraft.yaml Normal file
View File

@@ -0,0 +1,41 @@
name: neovim
version: git
summary: Vim-fork focused on extensibility and agility.
description: |
Neovim is a project that seeks to aggressively refactor Vim in order to:
Simplify maintenance and encourage contributions
Split the work between multiple developers
Enable the implementation of new/modern user interfaces without any modifications to the core source
Improve extensibility with a new plugin architecture
For lots more details, see the wiki!
confinement: classic
apps:
neovim:
command: usr/local/bin/nvim
plugs: [network, network-bind, x11]
environment:
HOME: /home/$USER
VIM: $SNAP/usr/local/share/nvim/runtime
parts:
neovim:
source: .
plugin: make
make-parameters:
- CMAKE_BUILD_TYPE=Release
build-packages:
- ninja-build
- libtool
- libtool-bin
- autoconf
- automake
- cmake
- g++
- pkg-config
- unzip
snap:
- usr/local/bin
- usr/local/share/nvim
- -usr/local/share/man

View File

@@ -1,3 +1,7 @@
# multiqueue.h pointer arithmetic is not accepted by asan # multiqueue.h pointer arithmetic is not accepted by asan
fun:multiqueue_node_data fun:multiqueue_node_data
fun:tv_dict_watcher_node_data fun:tv_dict_watcher_node_data
# Allocation in loop_schedule_deferred() is freed by loop_deferred_event(), but
# this sometimes does not happen during teardown.
func:loop_schedule_deferred

View File

@@ -201,6 +201,7 @@ _ERROR_CATEGORIES = [
'runtime/printf', 'runtime/printf',
'runtime/printf_format', 'runtime/printf_format',
'runtime/threadsafe_fn', 'runtime/threadsafe_fn',
'runtime/deprecated',
'syntax/parenthesis', 'syntax/parenthesis',
'whitespace/alignment', 'whitespace/alignment',
'whitespace/blank_line', 'whitespace/blank_line',
@@ -2123,8 +2124,10 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
+ (level_starts[depth][2] == '{')): + (level_starts[depth][2] == '{')):
if depth not in ignore_error_levels: if depth not in ignore_error_levels:
error(filename, linenum, 'whitespace/alignment', 2, error(filename, linenum, 'whitespace/alignment', 2,
'Inner expression should be aligned ' ('Inner expression should be aligned '
'as opening brace + 1 (+ 2 in case of {)') 'as opening brace + 1 (+ 2 in case of {{). '
'Relevant opening is on line {0!r}').format(
level_starts[depth][3]))
prev_line_start = pos prev_line_start = pos
elif brace == 'e': elif brace == 'e':
pass pass
@@ -2141,7 +2144,8 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
ignore_error_levels.add(depth) ignore_error_levels.add(depth)
line_ended_with_opening = ( line_ended_with_opening = (
pos == len(line) - 2 * (line.endswith(' \\')) - 1) pos == len(line) - 2 * (line.endswith(' \\')) - 1)
level_starts[depth] = (pos, line_ended_with_opening, brace) level_starts[depth] = (pos, line_ended_with_opening, brace,
linenum)
if line_ended_with_opening: if line_ended_with_opening:
depth_line_starts[depth] = (prev_line_start, brace) depth_line_starts[depth] = (prev_line_start, brace)
else: else:
@@ -3200,6 +3204,14 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
if match: if match:
error(filename, linenum, 'runtime/printf', 4, error(filename, linenum, 'runtime/printf', 4,
'Use xstrlcat or snprintf instead of %s' % match.group(1)) 'Use xstrlcat or snprintf instead of %s' % match.group(1))
if not Search(r'eval/typval\.[ch]$', filename):
match = Search(r'(?:\.|->)'
r'(?:lv_(?:first|last|refcount|len|watch|idx(?:_item)?'
r'|copylist|lock)'
r'|li_(?:next|prev|tv))\b', line)
if match:
error(filename, linenum, 'runtime/deprecated', 4,
'Accessing list_T internals directly is prohibited')
# Check for suspicious usage of "if" like # Check for suspicious usage of "if" like
# } if (a == b) { # } if (a == b) {

View File

@@ -13,6 +13,9 @@ endif()
if(WIN32) if(WIN32)
# tell MinGW compiler to enable wmain # tell MinGW compiler to enable wmain
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -municode")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreFoundation")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -framework CoreFoundation")
endif() endif()
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
@@ -86,6 +89,8 @@ foreach(subdir
event event
eval eval
lua lua
viml
viml/parser
) )
if(${subdir} MATCHES "tui" AND NOT FEAT_TUI) if(${subdir} MATCHES "tui" AND NOT FEAT_TUI)
continue() continue()
@@ -170,7 +175,7 @@ endif()
get_directory_property(gen_cdefs COMPILE_DEFINITIONS) get_directory_property(gen_cdefs COMPILE_DEFINITIONS)
foreach(gen_cdef ${gen_cdefs} DO_NOT_DEFINE_EMPTY_ATTRIBUTES) foreach(gen_cdef ${gen_cdefs} DO_NOT_DEFINE_EMPTY_ATTRIBUTES)
if(NOT "${gen_cdef}" MATCHES "INCLUDE_GENERATED_DECLARATIONS") if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS")
list(APPEND gen_cflags "-D${gen_cdef}") list(APPEND gen_cflags "-D${gen_cdef}")
endif() endif()
endforeach() endforeach()
@@ -182,6 +187,10 @@ get_directory_property(gen_includes INCLUDE_DIRECTORIES)
foreach(gen_include ${gen_includes} ${LUA_PREFERRED_INCLUDE_DIRS}) foreach(gen_include ${gen_includes} ${LUA_PREFERRED_INCLUDE_DIRS})
list(APPEND gen_cflags "-I${gen_include}") list(APPEND gen_cflags "-I${gen_include}")
endforeach() endforeach()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT)
list(APPEND gen_cflags "-isysroot")
list(APPEND gen_cflags "${CMAKE_OSX_SYSROOT}")
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
separate_arguments(C_FLAGS_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS}) separate_arguments(C_FLAGS_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS})
separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}}) separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}})
@@ -350,6 +359,10 @@ endforeach()
# Our dependencies come first. # Our dependencies come first.
if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
list(APPEND NVIM_LINK_LIBRARIES pthread c++abi)
endif()
if (LibIntl_FOUND) if (LibIntl_FOUND)
list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY}) list(APPEND NVIM_LINK_LIBRARIES ${LibIntl_LIBRARY})
endif() endif()
@@ -428,6 +441,7 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/tidy.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/tidy.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/win32yank.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/win32yank.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/winpty-agent.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/winpty-agent.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/xxd.exe" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/D3Dcompiler_47.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/D3Dcompiler_47.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/libEGL.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/libEGL.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/
@@ -446,6 +460,8 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/platforms/qwindows.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/platforms/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/platforms/qwindows.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/platforms/
) )
add_dependencies(nvim_runtime_deps external_blobs) add_dependencies(nvim_runtime_deps external_blobs)
else()
add_custom_target(nvim_runtime_deps) # Stub target to avoid CMP0046.
endif() endif()
add_library( add_library(

View File

@@ -1,10 +1,22 @@
Nvim core source Nvim core
================ =========
Module-specific details are documented at the top of each module (`terminal.c`, Module-specific details are documented at the top of each module (`terminal.c`,
`screen.c`, ...). `screen.c`, ).
See `:help development` for more guidelines. See `:help dev` for guidelines.
Filename conventions
--------------------
The source files use extensions to hint about their purpose.
- `*.c`, `*.generated.c` - full C files, with all includes, etc.
- `*.c.h` - parametrized C files, contain all necessary includes, but require
defining macros before actually using. Example: `typval_encode.c.h`
- `*.h` - full headers, with all includes. Does *not* apply to `*.generated.h`.
- `*.h.generated.h` - exported functions declarations.
- `*.c.generated.h` - static functions declarations.
Logs Logs
---- ----
@@ -20,17 +32,75 @@ UI events are logged at level 0 (`DEBUG_LOG_LEVEL`).
rm -rf build/ rm -rf build/
make CMAKE_EXTRA_FLAGS="-DMIN_LOG_LEVEL=0" make CMAKE_EXTRA_FLAGS="-DMIN_LOG_LEVEL=0"
Filename conventions Build with ASAN
-------------------- ---------------
The source files use extensions to hint about their purpose. Building Nvim with Clang sanitizers (Address Sanitizer: ASan, Undefined
Behavior Sanitizer: UBSan, Memory Sanitizer: MSan, Thread Sanitizer: TSan) is
a good way to catch undefined behavior, leaks and other errors as soon as they
happen. It's significantly faster than Valgrind.
- `*.c`, `*.generated.c` - full C files, with all includes, etc. Requires clang 3.4 or later:
- `*.c.h` - parametrized C files, contain all necessary includes, but require
defining macros before actually using. Example: `typval_encode.c.h` clang --version
- `*.h` - full headers, with all includes. Does *not* apply to `*.generated.h`.
- `*.h.generated.h` - exported functions declarations. Build Nvim with sanitizer instrumentation:
- `*.c.generated.h` - static functions declarations.
CC=clang make CMAKE_EXTRA_FLAGS="-DCLANG_ASAN_UBSAN=ON"
Create a directory to store logs:
mkdir -p "$HOME/logs"
Enable the sanitizer(s) via these environment variables:
# Change to detect_leaks=1 to detect memory leaks (slower).
export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer
export MSAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer
export TSAN_OPTIONS="external_symbolizer_path=/usr/lib/llvm-5.0/bin/llvm-symbolizer log_path=${HOME}/logs/tsan"
Logs will be written to `${HOME}/logs/*san.PID`.
TUI debugging
-------------
### TUI troubleshoot
Nvim logs its internal terminfo state at 'verbose' level 3. This makes it
possible to see exactly what terminfo values Nvim is using on any system.
nvim -V3log
### TUI trace
The ancient `script` command is still the "state of the art" for tracing
terminal behavior. The libvterm `vterm-dump` utility formats the result for
human-readability.
Record a Nvim terminal session and format it with `vterm-dump`:
script foo
./build/bin/nvim -u NONE
# Exit the script session with CTRL-d
# Use `vterm-dump` utility to format the result.
./.deps/usr/bin/vterm-dump foo > bar
Then you can compare `bar` with another session, to debug TUI behavior.
### TUI redraw
Set the 'writedelay' option to see where and when the UI is painted.
:set writedelay=1
### Terminal reference
- `man terminfo`
- http://bazaar.launchpad.net/~libvterm/libvterm/trunk/view/head:/doc/seqs.txt
- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
Nvim lifecycle Nvim lifecycle
-------------- --------------
@@ -39,7 +109,7 @@ Following describes how Nvim processes input.
Consider a typical Vim-like editing session: Consider a typical Vim-like editing session:
01. Vim dispays the welcome screen 01. Vim displays the welcome screen
02. User types: `:` 02. User types: `:`
03. Vim enters command-line mode 03. Vim enters command-line mode
04. User types: `edit README.txt<CR>` 04. User types: `edit README.txt<CR>`

View File

@@ -399,7 +399,11 @@ void nvim_buf_set_lines(uint64_t channel_id,
// Only adjust marks if we managed to switch to a window that holds // Only adjust marks if we managed to switch to a window that holds
// the buffer, otherwise line numbers will be invalid. // the buffer, otherwise line numbers will be invalid.
if (save_curbuf.br_buf == NULL) { if (save_curbuf.br_buf == NULL) {
mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra, false); mark_adjust((linenr_T)start,
(linenr_T)(end - 1),
MAXLNUM,
(long)extra,
false);
} }
changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra); changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra);
@@ -763,8 +767,8 @@ ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
/// or -1 for ungrouped highlight /// or -1 for ungrouped highlight
/// @param hl_group Name of the highlight group to use /// @param hl_group Name of the highlight group to use
/// @param line Line to highlight (zero-indexed) /// @param line Line to highlight (zero-indexed)
/// @param col_start Start of range of columns to highlight /// @param col_start Start of (byte-indexed) column range to highlight
/// @param col_end End of range of columns to highlight, /// @param col_end End of (byte-indexed) column range to highlight,
/// or -1 to highlight to end of line /// or -1 to highlight to end of line
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return The src_id that was used /// @return The src_id that was used
@@ -806,7 +810,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
/// Clears highlights from a given source group and a range of lines /// Clears highlights from a given source group and a range of lines
/// ///
/// To clear a source group in the entire buffer, pass in 1 and -1 to /// To clear a source group in the entire buffer, pass in 0 and -1 to
/// line_start and line_end respectively. /// line_start and line_end respectively.
/// ///
/// @param buffer Buffer handle /// @param buffer Buffer handle

View File

@@ -47,7 +47,7 @@ typedef enum {
/// Internal call from lua code /// Internal call from lua code
#define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1) #define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1)
static inline bool is_internal_call(uint64_t channel_id) static inline bool is_internal_call(const uint64_t channel_id)
REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST; REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
/// Check whether call is internal /// Check whether call is internal

View File

@@ -26,6 +26,7 @@
#include "nvim/version.h" #include "nvim/version.h"
#include "nvim/lib/kvec.h" #include "nvim/lib/kvec.h"
#include "nvim/getchar.h" #include "nvim/getchar.h"
#include "nvim/ui.h"
/// Helper structure for vim_to_object /// Helper structure for vim_to_object
typedef struct { typedef struct {
@@ -46,13 +47,15 @@ typedef struct {
/// @param[out] tstate Location where try state should be saved. /// @param[out] tstate Location where try state should be saved.
void try_enter(TryState *const tstate) void try_enter(TryState *const tstate)
{ {
// TODO(ZyX-I): Check whether try_enter()/try_leave() may use
// enter_cleanup()/leave_cleanup(). Or
// save_dbg_stuff()/restore_dbg_stuff().
*tstate = (TryState) { *tstate = (TryState) {
.current_exception = current_exception, .current_exception = current_exception,
.msg_list = (const struct msglist *const *)msg_list, .msg_list = (const struct msglist *const *)msg_list,
.private_msg_list = NULL, .private_msg_list = NULL,
.trylevel = trylevel, .trylevel = trylevel,
.got_int = got_int, .got_int = got_int,
.did_throw = did_throw,
.need_rethrow = need_rethrow, .need_rethrow = need_rethrow,
.did_emsg = did_emsg, .did_emsg = did_emsg,
}; };
@@ -60,7 +63,6 @@ void try_enter(TryState *const tstate)
current_exception = NULL; current_exception = NULL;
trylevel = 1; trylevel = 1;
got_int = false; got_int = false;
did_throw = false;
need_rethrow = false; need_rethrow = false;
did_emsg = false; did_emsg = false;
} }
@@ -81,7 +83,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
assert(trylevel == 0); assert(trylevel == 0);
assert(!need_rethrow); assert(!need_rethrow);
assert(!got_int); assert(!got_int);
assert(!did_throw);
assert(!did_emsg); assert(!did_emsg);
assert(msg_list == &tstate->private_msg_list); assert(msg_list == &tstate->private_msg_list);
assert(*msg_list == NULL); assert(*msg_list == NULL);
@@ -90,7 +91,6 @@ bool try_leave(const TryState *const tstate, Error *const err)
current_exception = tstate->current_exception; current_exception = tstate->current_exception;
trylevel = tstate->trylevel; trylevel = tstate->trylevel;
got_int = tstate->got_int; got_int = tstate->got_int;
did_throw = tstate->did_throw;
need_rethrow = tstate->need_rethrow; need_rethrow = tstate->need_rethrow;
did_emsg = tstate->did_emsg; did_emsg = tstate->did_emsg;
return ret; return ret;
@@ -126,7 +126,7 @@ bool try_end(Error *err)
did_emsg = false; did_emsg = false;
if (got_int) { if (got_int) {
if (did_throw) { if (current_exception) {
// If we got an interrupt, discard the current exception // If we got an interrupt, discard the current exception
discard_current_exception(); discard_current_exception();
} }
@@ -145,7 +145,7 @@ bool try_end(Error *err)
if (should_free) { if (should_free) {
xfree(msg); xfree(msg);
} }
} else if (did_throw) { } else if (current_exception) {
api_set_error(err, kErrorTypeException, "%s", current_exception->value); api_set_error(err, kErrorTypeException, "%s", current_exception->value);
discard_current_exception(); discard_current_exception();
} }
@@ -566,7 +566,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
typval_encode_dict_end(edata) typval_encode_dict_end(edata)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
TYPVAL_ENCODE_CONV_NIL() TYPVAL_ENCODE_CONV_NIL(val)
#define TYPVAL_ENCODE_SCOPE static #define TYPVAL_ENCODE_SCOPE static
#define TYPVAL_ENCODE_NAME object #define TYPVAL_ENCODE_NAME object
@@ -783,22 +783,20 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
break; break;
case kObjectTypeArray: { case kObjectTypeArray: {
list_T *const list = tv_list_alloc(); list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size);
for (uint32_t i = 0; i < obj.data.array.size; i++) { for (uint32_t i = 0; i < obj.data.array.size; i++) {
Object item = obj.data.array.items[i]; Object item = obj.data.array.items[i];
listitem_T *li = tv_list_item_alloc(); typval_T li_tv;
if (!object_to_vim(item, &li->li_tv, err)) { if (!object_to_vim(item, &li_tv, err)) {
// cleanup
tv_list_item_free(li);
tv_list_free(list); tv_list_free(list);
return false; return false;
} }
tv_list_append(list, li); tv_list_append_owned_tv(list, li_tv);
} }
list->lv_refcount++; tv_list_ref(list);
tv->v_type = VAR_LIST; tv->v_type = VAR_LIST;
tv->vval.v_list = list; tv->vval.v_list = list;
@@ -957,6 +955,12 @@ static void init_ui_event_metadata(Dictionary *metadata)
msgpack_rpc_to_object(&unpacked.data, &ui_events); msgpack_rpc_to_object(&unpacked.data, &ui_events);
msgpack_unpacked_destroy(&unpacked); msgpack_unpacked_destroy(&unpacked);
PUT(*metadata, "ui_events", ui_events); PUT(*metadata, "ui_events", ui_events);
Array ui_options = ARRAY_DICT_INIT;
ADD(ui_options, STRING_OBJ(cstr_to_string("rgb")));
for (UIExtension i = 0; i < kUIExtCount; i++) {
ADD(ui_options, STRING_OBJ(cstr_to_string(ui_ext_names[i])));
}
PUT(*metadata, "ui_options", ARRAY_OBJ(ui_options));
} }
static void init_error_type_metadata(Dictionary *metadata) static void init_error_type_metadata(Dictionary *metadata)

View File

@@ -93,7 +93,6 @@ typedef struct {
const struct msglist *const *msg_list; const struct msglist *const *msg_list;
int trylevel; int trylevel;
int got_int; int got_int;
int did_throw;
int need_rethrow; int need_rethrow;
int did_emsg; int did_emsg;
} TryState; } TryState;

View File

@@ -43,10 +43,10 @@ void remote_ui_disconnect(uint64_t channel_id)
return; return;
} }
UIData *data = ui->data; UIData *data = ui->data;
// destroy pending screen updates api_free_array(data->buffer); // Destroy pending screen updates.
api_free_array(data->buffer);
pmap_del(uint64_t)(connected_uis, channel_id); pmap_del(uint64_t)(connected_uis, channel_id);
xfree(ui->data); xfree(ui->data);
ui->data = NULL; // Flag UI as "stopped".
ui_detach_impl(ui); ui_detach_impl(ui);
xfree(ui); xfree(ui);
} }
@@ -56,7 +56,8 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{ {
if (pmap_has(uint64_t)(connected_uis, channel_id)) { if (pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException, "UI already attached for channel"); api_set_error(err, kErrorTypeException,
"UI already attached to channel: %" PRId64, channel_id);
return; return;
} }
@@ -86,6 +87,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->put = remote_ui_put; ui->put = remote_ui_put;
ui->bell = remote_ui_bell; ui->bell = remote_ui_bell;
ui->visual_bell = remote_ui_visual_bell; ui->visual_bell = remote_ui_visual_bell;
ui->default_colors_set = remote_ui_default_colors_set;
ui->update_fg = remote_ui_update_fg; ui->update_fg = remote_ui_update_fg;
ui->update_bg = remote_ui_update_bg; ui->update_bg = remote_ui_update_bg;
ui->update_sp = remote_ui_update_sp; ui->update_sp = remote_ui_update_sp;
@@ -93,6 +95,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->suspend = remote_ui_suspend; ui->suspend = remote_ui_suspend;
ui->set_title = remote_ui_set_title; ui->set_title = remote_ui_set_title;
ui->set_icon = remote_ui_set_icon; ui->set_icon = remote_ui_set_icon;
ui->option_set = remote_ui_option_set;
ui->event = remote_ui_event; ui->event = remote_ui_event;
memset(ui->ui_ext, 0, sizeof(ui->ui_ext)); memset(ui->ui_ext, 0, sizeof(ui->ui_ext));
@@ -128,7 +131,8 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{ {
if (!pmap_has(uint64_t)(connected_uis, channel_id)) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException, "UI is not attached for channel"); api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return; return;
} }
remote_ui_disconnect(channel_id); remote_ui_disconnect(channel_id);
@@ -140,7 +144,8 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width,
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{ {
if (!pmap_has(uint64_t)(connected_uis, channel_id)) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException, "UI is not attached for channel"); api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return; return;
} }
@@ -161,7 +166,8 @@ void nvim_ui_set_option(uint64_t channel_id, String name,
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{ {
if (!pmap_has(uint64_t)(connected_uis, channel_id)) { if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(error, kErrorTypeException, "UI is not attached for channel"); api_set_error(error, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return; return;
} }
UI *ui = pmap_get(uint64_t)(connected_uis, channel_id); UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
@@ -174,18 +180,6 @@ void nvim_ui_set_option(uint64_t channel_id, String name,
static void ui_set_option(UI *ui, String name, Object value, Error *error) static void ui_set_option(UI *ui, String name, Object value, Error *error)
{ {
#define UI_EXT_OPTION(o, e) \
do { \
if (strequal(name.data, #o)) { \
if (value.type != kObjectTypeBoolean) { \
api_set_error(error, kErrorTypeValidation, #o " must be a Boolean"); \
return; \
} \
ui->ui_ext[(e)] = value.data.boolean; \
return; \
} \
} while (0)
if (strequal(name.data, "rgb")) { if (strequal(name.data, "rgb")) {
if (value.type != kObjectTypeBoolean) { if (value.type != kObjectTypeBoolean) {
api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean"); api_set_error(error, kErrorTypeValidation, "rgb must be a Boolean");
@@ -195,13 +189,21 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
return; return;
} }
UI_EXT_OPTION(ext_cmdline, kUICmdline); for (UIExtension i = 0; i < kUIExtCount; i++) {
UI_EXT_OPTION(ext_popupmenu, kUIPopupmenu); if (strequal(name.data, ui_ext_names[i])) {
UI_EXT_OPTION(ext_tabline, kUITabline); if (value.type != kObjectTypeBoolean) {
UI_EXT_OPTION(ext_wildmenu, kUIWildmenu); snprintf((char *)IObuff, IOSIZE, "%s must be a Boolean",
ui_ext_names[i]);
api_set_error(error, kErrorTypeValidation, (char *)IObuff);
return;
}
ui->ui_ext[i] = value.data.boolean;
return;
}
}
if (strequal(name.data, "popupmenu_external")) { if (strequal(name.data, "popupmenu_external")) {
// LEGACY: Deprecated option, use `ui_ext` instead. // LEGACY: Deprecated option, use `ext_cmdline` instead.
if (value.type != kObjectTypeBoolean) { if (value.type != kObjectTypeBoolean) {
api_set_error(error, kErrorTypeValidation, api_set_error(error, kErrorTypeValidation,
"popupmenu_external must be a Boolean"); "popupmenu_external must be a Boolean");
@@ -211,7 +213,8 @@ static void ui_set_option(UI *ui, String name, Object value, Error *error)
return; return;
} }
api_set_error(error, kErrorTypeValidation, "No such ui option"); api_set_error(error, kErrorTypeValidation, "No such UI option: %s",
name.data);
#undef UI_EXT_OPTION #undef UI_EXT_OPTION
} }
@@ -242,7 +245,7 @@ static void push_call(UI *ui, char *name, Array args)
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{ {
Array args = ARRAY_DICT_INIT; Array args = ARRAY_DICT_INIT;
Dictionary hl = hlattrs2dict(attrs); Dictionary hl = hlattrs2dict(&attrs, ui->rgb);
ADD(args, DICTIONARY_OBJ(hl)); ADD(args, DICTIONARY_OBJ(hl));
push_call(ui, "highlight_set", args); push_call(ui, "highlight_set", args);

View File

@@ -47,17 +47,22 @@ void visual_bell(void)
void flush(void) void flush(void)
FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL; FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
void update_fg(Integer fg) void update_fg(Integer fg)
FUNC_API_SINCE(3); FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void update_bg(Integer bg) void update_bg(Integer bg)
FUNC_API_SINCE(3); FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void update_sp(Integer sp) void update_sp(Integer sp)
FUNC_API_SINCE(3); FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
Integer cterm_fg, Integer cterm_bg)
FUNC_API_SINCE(4);
void suspend(void) void suspend(void)
FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL; FUNC_API_SINCE(3) FUNC_API_BRIDGE_IMPL;
void set_title(String title) void set_title(String title)
FUNC_API_SINCE(3); FUNC_API_SINCE(3);
void set_icon(String icon) void set_icon(String icon)
FUNC_API_SINCE(3); FUNC_API_SINCE(3);
void option_set(String name, Object value)
FUNC_API_SINCE(4);
void popupmenu_show(Array items, Integer selected, Integer row, Integer col) void popupmenu_show(Array items, Integer selected, Integer row, Integer col)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;

View File

@@ -33,6 +33,10 @@
#include "nvim/syntax.h" #include "nvim/syntax.h"
#include "nvim/getchar.h" #include "nvim/getchar.h"
#include "nvim/os/input.h" #include "nvim/os/input.h"
#include "nvim/os/process.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
#include "nvim/ui.h"
#define LINE_BUFFER_SIZE 4096 #define LINE_BUFFER_SIZE 4096
@@ -41,14 +45,15 @@
#endif #endif
/// Executes an ex-command. /// Executes an ex-command.
/// On VimL error: Returns the VimL error; v:errmsg is not updated. ///
/// On parse error: forwards the Vim error; does not update v:errmsg.
/// On runtime error: forwards the Vim error; does not update v:errmsg.
/// ///
/// @param command Ex-command string /// @param command Ex-command string
/// @param[out] err Error details (including actual VimL error), if any /// @param[out] err Error details (Vim error), if any
void nvim_command(String command, Error *err) void nvim_command(String command, Error *err)
FUNC_API_SINCE(1) FUNC_API_SINCE(1)
{ {
// Run the command
try_start(); try_start();
do_cmdline_cmd(command.data); do_cmdline_cmd(command.data);
update_screen(VALID); update_screen(VALID);
@@ -205,18 +210,51 @@ String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
return cstr_as_string(ptr); return cstr_as_string(ptr);
} }
String nvim_command_output(String str, Error *err) /// Executes an ex-command and returns its (non-error) output.
/// Shell |:!| output is not captured.
///
/// On parse error: forwards the Vim error; does not update v:errmsg.
/// On runtime error: forwards the Vim error; does not update v:errmsg.
///
/// @param command Ex-command string
/// @param[out] err Error details (Vim error), if any
String nvim_command_output(String command, Error *err)
FUNC_API_SINCE(1) FUNC_API_SINCE(1)
{ {
do_cmdline_cmd("redir => v:command_output"); const int save_msg_silent = msg_silent;
nvim_command(str, err); garray_T *const save_capture_ga = capture_ga;
do_cmdline_cmd("redir END"); garray_T capture_local;
ga_init(&capture_local, 1, 80);
try_start();
msg_silent++;
capture_ga = &capture_local;
do_cmdline_cmd(command.data);
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
try_end(err);
if (ERROR_SET(err)) { if (ERROR_SET(err)) {
return (String)STRING_INIT; goto theend;
} }
return cstr_to_string((char *)get_vim_var_str(VV_COMMAND_OUTPUT)); if (capture_local.ga_len > 1) {
String s = (String){
.data = capture_local.ga_data,
.size = (size_t)capture_local.ga_len,
};
// redir usually (except :echon) prepends a newline.
if (s.data[0] == '\n') {
memmove(s.data, s.data + 1, s.size);
s.data[s.size - 1] = '\0';
s.size = s.size - 1;
}
return s; // Caller will free the memory.
}
theend:
ga_clear(&capture_local);
return (String)STRING_INIT;
} }
/// Evaluates a VimL expression (:help expression). /// Evaluates a VimL expression (:help expression).
@@ -787,6 +825,10 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode)
return keymap_array(mode, NULL); return keymap_array(mode, NULL);
} }
/// Returns a 2-tuple (Array), where item 0 is the current channel id and item
/// 1 is the |api-metadata| map (Dictionary).
///
/// @returns 2-tuple [{channel-id}, {api-metadata}]
Array nvim_get_api_info(uint64_t channel_id) Array nvim_get_api_info(uint64_t channel_id)
FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY
{ {
@@ -889,6 +931,460 @@ theend:
return rv; return rv;
} }
typedef struct {
ExprASTNode **node_p;
Object *ret_node_p;
} ExprASTConvStackItem;
/// @cond DOXYGEN_NOT_A_FUNCTION
typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// @endcond
/// Parse a VimL expression
///
/// @param[in] expr Expression to parse. Is always treated as a single line.
/// @param[in] flags Flags:
///
/// - "m" if multiple expressions in a row are allowed (only
/// the first one will be parsed),
/// - "E" if EOC tokens are not allowed (determines whether
/// they will stop parsing process or be recognized as an
/// operator/space, though also yielding an error).
/// - "l" when needing to start parsing with lvalues for
/// ":let" or ":for".
///
/// Common flag sets:
/// - "m" to parse like for ":echo".
/// - "E" to parse like for "<C-r>=".
/// - empty string for ":call".
/// - "lm" to parse for ":let".
/// @param[in] highlight If true, return value will also include "highlight"
/// key containing array of 4-tuples (arrays) (Integer,
/// Integer, Integer, String), where first three numbers
/// define the highlighted region and represent line,
/// starting column and ending column (latter exclusive:
/// one should highlight region [start_col, end_col)).
///
/// @return AST: top-level dictionary with these keys:
///
/// "error": Dictionary with error, present only if parser saw some
/// error. Contains the following keys:
///
/// "message": String, error message in printf format, translated.
/// Must contain exactly one "%.*s".
/// "arg": String, error message argument.
///
/// "len": Amount of bytes successfully parsed. With flags equal to ""
/// that should be equal to the length of expr string.
///
/// @note: “Sucessfully parsed” here means “participated in AST
/// creation”, not “till the first error”.
///
/// "ast": AST, either nil or a dictionary with these keys:
///
/// "type": node type, one of the value names from ExprASTNodeType
/// stringified without "kExprNode" prefix.
/// "start": a pair [line, column] describing where node is “started”
/// where "line" is always 0 (will not be 0 if you will be
/// using nvim_parse_viml() on e.g. ":let", but that is not
/// present yet). Both elements are Integers.
/// "len": “length” of the node. This and "start" are there for
/// debugging purposes primary (debugging parser and providing
/// debug information).
/// "children": a list of nodes described in top/"ast". There always
/// is zero, one or two children, key will not be present
/// if node has no children. Maximum number of children
/// may be found in node_maxchildren array.
///
/// Local values (present only for certain nodes):
///
/// "scope": a single Integer, specifies scope for "Option" and
/// "PlainIdentifier" nodes. For "Option" it is one of
/// ExprOptScope values, for "PlainIdentifier" it is one of
/// ExprVarScope values.
/// "ident": identifier (without scope, if any), present for "Option",
/// "PlainIdentifier", "PlainKey" and "Environment" nodes.
/// "name": Integer, register name (one character) or -1. Only present
/// for "Register" nodes.
/// "cmp_type": String, comparison type, one of the value names from
/// ExprComparisonType, stringified without "kExprCmp"
/// prefix. Only present for "Comparison" nodes.
/// "ccs_strategy": String, case comparison strategy, one of the
/// value names from ExprCaseCompareStrategy,
/// stringified without "kCCStrategy" prefix. Only
/// present for "Comparison" nodes.
/// "augmentation": String, augmentation type for "Assignment" nodes.
/// Is either an empty string, "Add", "Subtract" or
/// "Concat" for "=", "+=", "-=" or ".=" respectively.
/// "invert": Boolean, true if result of comparison needs to be
/// inverted. Only present for "Comparison" nodes.
/// "ivalue": Integer, integer value for "Integer" nodes.
/// "fvalue": Float, floating-point value for "Float" nodes.
/// "svalue": String, value for "SingleQuotedString" and
/// "DoubleQuotedString" nodes.
Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
Error *err)
FUNC_API_SINCE(4) FUNC_API_ASYNC
{
int pflags = 0;
for (size_t i = 0 ; i < flags.size ; i++) {
switch (flags.data[i]) {
case 'm': { pflags |= kExprFlagsMulti; break; }
case 'E': { pflags |= kExprFlagsDisallowEOC; break; }
case 'l': { pflags |= kExprFlagsParseLet; break; }
case NUL: {
api_set_error(err, kErrorTypeValidation, "Invalid flag: '\\0' (%u)",
(unsigned)flags.data[i]);
return (Dictionary)ARRAY_DICT_INIT;
}
default: {
api_set_error(err, kErrorTypeValidation, "Invalid flag: '%c' (%u)",
flags.data[i], (unsigned)flags.data[i]);
return (Dictionary)ARRAY_DICT_INIT;
}
}
}
ParserLine plines[] = {
{
.data = expr.data,
.size = expr.size,
.allocated = false,
},
{ NULL, 0, false },
};
ParserLine *plines_p = plines;
ParserHighlight colors;
kvi_init(colors);
ParserHighlight *const colors_p = (highlight ? &colors : NULL);
ParserState pstate;
viml_parser_init(
&pstate, parser_simple_get_line, &plines_p, colors_p);
ExprAST east = viml_pexpr_parse(&pstate, pflags);
const size_t ret_size = (
2 // "ast", "len"
+ (size_t)(east.err.msg != NULL) // "error"
+ (size_t)highlight // "highlight"
+ 0);
Dictionary ret = {
.items = xmalloc(ret_size * sizeof(ret.items[0])),
.size = 0,
.capacity = ret_size,
};
ret.items[ret.size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ast"),
.value = NIL,
};
ret.items[ret.size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("len"),
.value = INTEGER_OBJ((Integer)(pstate.pos.line == 1
? plines[0].size
: pstate.pos.col)),
};
if (east.err.msg != NULL) {
Dictionary err_dict = {
.items = xmalloc(2 * sizeof(err_dict.items[0])),
.size = 2,
.capacity = 2,
};
err_dict.items[0] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("message"),
.value = STRING_OBJ(cstr_to_string(east.err.msg)),
};
if (east.err.arg == NULL) {
err_dict.items[1] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("arg"),
.value = STRING_OBJ(STRING_INIT),
};
} else {
err_dict.items[1] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("arg"),
.value = STRING_OBJ(((String) {
.data = xmemdupz(east.err.arg, (size_t)east.err.arg_len),
.size = (size_t)east.err.arg_len,
})),
};
}
ret.items[ret.size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("error"),
.value = DICTIONARY_OBJ(err_dict),
};
}
if (highlight) {
Array hl = (Array) {
.items = xmalloc(kv_size(colors) * sizeof(hl.items[0])),
.capacity = kv_size(colors),
.size = kv_size(colors),
};
for (size_t i = 0 ; i < kv_size(colors) ; i++) {
const ParserHighlightChunk chunk = kv_A(colors, i);
Array chunk_arr = (Array) {
.items = xmalloc(4 * sizeof(chunk_arr.items[0])),
.capacity = 4,
.size = 4,
};
chunk_arr.items[0] = INTEGER_OBJ((Integer)chunk.start.line);
chunk_arr.items[1] = INTEGER_OBJ((Integer)chunk.start.col);
chunk_arr.items[2] = INTEGER_OBJ((Integer)chunk.end_col);
chunk_arr.items[3] = STRING_OBJ(cstr_to_string(chunk.group));
hl.items[i] = ARRAY_OBJ(chunk_arr);
}
ret.items[ret.size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("highlight"),
.value = ARRAY_OBJ(hl),
};
}
kvi_destroy(colors);
// Walk over the AST, freeing nodes in process.
ExprASTConvStack ast_conv_stack;
kvi_init(ast_conv_stack);
kvi_push(ast_conv_stack, ((ExprASTConvStackItem) {
.node_p = &east.root,
.ret_node_p = &ret.items[0].value,
}));
while (kv_size(ast_conv_stack)) {
ExprASTConvStackItem cur_item = kv_last(ast_conv_stack);
ExprASTNode *const node = *cur_item.node_p;
if (node == NULL) {
assert(kv_size(ast_conv_stack) == 1);
kv_drop(ast_conv_stack, 1);
} else {
if (cur_item.ret_node_p->type == kObjectTypeNil) {
const size_t ret_node_items_size = (size_t)(
3 // "type", "start" and "len"
+ (node->children != NULL) // "children"
+ (node->type == kExprNodeOption
|| node->type == kExprNodePlainIdentifier) // "scope"
+ (node->type == kExprNodeOption
|| node->type == kExprNodePlainIdentifier
|| node->type == kExprNodePlainKey
|| node->type == kExprNodeEnvironment) // "ident"
+ (node->type == kExprNodeRegister) // "name"
+ (3 // "cmp_type", "ccs_strategy", "invert"
* (node->type == kExprNodeComparison))
+ (node->type == kExprNodeInteger) // "ivalue"
+ (node->type == kExprNodeFloat) // "fvalue"
+ (node->type == kExprNodeDoubleQuotedString
|| node->type == kExprNodeSingleQuotedString) // "svalue"
+ (node->type == kExprNodeAssignment) // "augmentation"
+ 0);
Dictionary ret_node = {
.items = xmalloc(ret_node_items_size * sizeof(ret_node.items[0])),
.capacity = ret_node_items_size,
.size = 0,
};
*cur_item.ret_node_p = DICTIONARY_OBJ(ret_node);
}
Dictionary *ret_node = &cur_item.ret_node_p->data.dictionary;
if (node->children != NULL) {
const size_t num_children = 1 + (node->children->next != NULL);
Array children_array = {
.items = xmalloc(num_children * sizeof(children_array.items[0])),
.capacity = num_children,
.size = num_children,
};
for (size_t i = 0; i < num_children; i++) {
children_array.items[i] = NIL;
}
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("children"),
.value = ARRAY_OBJ(children_array),
};
kvi_push(ast_conv_stack, ((ExprASTConvStackItem) {
.node_p = &node->children,
.ret_node_p = &children_array.items[0],
}));
} else if (node->next != NULL) {
kvi_push(ast_conv_stack, ((ExprASTConvStackItem) {
.node_p = &node->next,
.ret_node_p = cur_item.ret_node_p + 1,
}));
} else if (node != NULL) {
kv_drop(ast_conv_stack, 1);
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("type"),
.value = STRING_OBJ(cstr_to_string(east_node_type_tab[node->type])),
};
Array start_array = {
.items = xmalloc(2 * sizeof(start_array.items[0])),
.capacity = 2,
.size = 2,
};
start_array.items[0] = INTEGER_OBJ((Integer)node->start.line);
start_array.items[1] = INTEGER_OBJ((Integer)node->start.col);
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("start"),
.value = ARRAY_OBJ(start_array),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("len"),
.value = INTEGER_OBJ((Integer)node->len),
};
switch (node->type) {
case kExprNodeDoubleQuotedString:
case kExprNodeSingleQuotedString: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("svalue"),
.value = STRING_OBJ(((String) {
.data = node->data.str.value,
.size = node->data.str.size,
})),
};
break;
}
case kExprNodeOption: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("scope"),
.value = INTEGER_OBJ(node->data.opt.scope),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ident"),
.value = STRING_OBJ(((String) {
.data = xmemdupz(node->data.opt.ident,
node->data.opt.ident_len),
.size = node->data.opt.ident_len,
})),
};
break;
}
case kExprNodePlainIdentifier: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("scope"),
.value = INTEGER_OBJ(node->data.var.scope),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ident"),
.value = STRING_OBJ(((String) {
.data = xmemdupz(node->data.var.ident,
node->data.var.ident_len),
.size = node->data.var.ident_len,
})),
};
break;
}
case kExprNodePlainKey: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ident"),
.value = STRING_OBJ(((String) {
.data = xmemdupz(node->data.var.ident,
node->data.var.ident_len),
.size = node->data.var.ident_len,
})),
};
break;
}
case kExprNodeEnvironment: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ident"),
.value = STRING_OBJ(((String) {
.data = xmemdupz(node->data.env.ident,
node->data.env.ident_len),
.size = node->data.env.ident_len,
})),
};
break;
}
case kExprNodeRegister: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("name"),
.value = INTEGER_OBJ(node->data.reg.name),
};
break;
}
case kExprNodeComparison: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("cmp_type"),
.value = STRING_OBJ(cstr_to_string(
eltkn_cmp_type_tab[node->data.cmp.type])),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ccs_strategy"),
.value = STRING_OBJ(cstr_to_string(
ccs_tab[node->data.cmp.ccs])),
};
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("invert"),
.value = BOOLEAN_OBJ(node->data.cmp.inv),
};
break;
}
case kExprNodeFloat: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("fvalue"),
.value = FLOAT_OBJ(node->data.flt.value),
};
break;
}
case kExprNodeInteger: {
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("ivalue"),
.value = INTEGER_OBJ((Integer)(
node->data.num.value > API_INTEGER_MAX
? API_INTEGER_MAX
: (Integer)node->data.num.value)),
};
break;
}
case kExprNodeAssignment: {
const ExprAssignmentType asgn_type = node->data.ass.type;
ret_node->items[ret_node->size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("augmentation"),
.value = STRING_OBJ(
asgn_type == kExprAsgnPlain
? (String)STRING_INIT
: cstr_to_string(expr_asgn_type_tab[asgn_type])),
};
break;
}
case kExprNodeMissing:
case kExprNodeOpMissing:
case kExprNodeTernary:
case kExprNodeTernaryValue:
case kExprNodeSubscript:
case kExprNodeListLiteral:
case kExprNodeUnaryPlus:
case kExprNodeBinaryPlus:
case kExprNodeNested:
case kExprNodeCall:
case kExprNodeComplexIdentifier:
case kExprNodeUnknownFigure:
case kExprNodeLambda:
case kExprNodeDictLiteral:
case kExprNodeCurlyBracesIdentifier:
case kExprNodeComma:
case kExprNodeColon:
case kExprNodeArrow:
case kExprNodeConcat:
case kExprNodeConcatOrSubscript:
case kExprNodeOr:
case kExprNodeAnd:
case kExprNodeUnaryMinus:
case kExprNodeBinaryMinus:
case kExprNodeNot:
case kExprNodeMultiplication:
case kExprNodeDivision:
case kExprNodeMod: {
break;
}
}
assert(cur_item.ret_node_p->data.dictionary.size
== cur_item.ret_node_p->data.dictionary.capacity);
xfree(*cur_item.node_p);
*cur_item.node_p = NULL;
}
}
}
kvi_destroy(ast_conv_stack);
assert(ret.size == ret.capacity);
// Should be a no-op actually, leaving it in case non-nodes will need to be
// freed later.
viml_pexpr_free_ast(east);
viml_parser_destroy(&pstate);
return ret;
}
/// Writes a message to vim output or error buffer. The string is split /// Writes a message to vim output or error buffer. The string is split
/// and flushed after each newline. Incomplete lines are kept for writing /// and flushed after each newline. Incomplete lines are kept for writing
@@ -976,3 +1472,95 @@ Float nvim__id_float(Float flt)
{ {
return flt; return flt;
} }
/// Gets a list of dictionaries representing attached UIs.
///
/// @return Array of UI dictionaries
Array nvim_list_uis(void)
FUNC_API_SINCE(4)
{
return ui_array();
}
/// Gets the immediate children of process `pid`.
///
/// @return Array of child process ids, empty if process not found.
Array nvim_get_proc_children(Integer pid, Error *err)
FUNC_API_SINCE(4)
{
Array rvobj = ARRAY_DICT_INIT;
int *proc_list = NULL;
if (pid <= 0 || pid > INT_MAX) {
api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid);
goto end;
}
size_t proc_count;
int rv = os_proc_children((int)pid, &proc_list, &proc_count);
if (rv != 0) {
// syscall failed (possibly because of kernel options), try shelling out.
DLOG("fallback to vim._os_proc_children()");
Array a = ARRAY_DICT_INIT;
ADD(a, INTEGER_OBJ(pid));
String s = cstr_to_string("return vim._os_proc_children(select(1, ...))");
Object o = nvim_execute_lua(s, a, err);
api_free_string(s);
api_free_array(a);
if (o.type == kObjectTypeArray) {
rvobj = o.data.array;
} else if (!ERROR_SET(err)) {
api_set_error(err, kErrorTypeException,
"Failed to get process children. pid=%" PRId64 " error=%d",
pid, rv);
}
goto end;
}
for (size_t i = 0; i < proc_count; i++) {
ADD(rvobj, INTEGER_OBJ(proc_list[i]));
}
end:
xfree(proc_list);
return rvobj;
}
/// Gets info describing process `pid`.
///
/// @return Map of process properties, or NIL if process not found.
Object nvim_get_proc(Integer pid, Error *err)
FUNC_API_SINCE(4)
{
Object rvobj = OBJECT_INIT;
rvobj.data.dictionary = (Dictionary)ARRAY_DICT_INIT;
rvobj.type = kObjectTypeDictionary;
if (pid <= 0 || pid > INT_MAX) {
api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid);
return NIL;
}
#ifdef WIN32
rvobj.data.dictionary = os_proc_info((int)pid);
if (rvobj.data.dictionary.size == 0) { // Process not found.
return NIL;
}
#else
// Cross-platform process info APIs are miserable, so use `ps` instead.
Array a = ARRAY_DICT_INIT;
ADD(a, INTEGER_OBJ(pid));
String s = cstr_to_string("return vim._os_proc_info(select(1, ...))");
Object o = nvim_execute_lua(s, a, err);
api_free_string(s);
api_free_array(a);
if (o.type == kObjectTypeArray && o.data.array.size == 0) {
return NIL; // Process not found.
} else if (o.type == kObjectTypeDictionary) {
rvobj.data.dictionary = o.data.dictionary;
} else if (!ERROR_SET(err)) {
api_set_error(err, kErrorTypeException,
"Failed to get process info. pid=%" PRId64, pid);
}
#endif
return rvobj;
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "nvim/macros.h"
#include "nvim/func_attr.h" #include "nvim/func_attr.h"
#include "nvim/os/os_defs.h" #include "nvim/os/os_defs.h"
@@ -98,6 +99,10 @@ static inline bool ascii_isxdigit(int)
REAL_FATTR_CONST REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE; REAL_FATTR_ALWAYS_INLINE;
static inline bool ascii_isident(int)
REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE;
static inline bool ascii_isbdigit(int) static inline bool ascii_isbdigit(int)
REAL_FATTR_CONST REAL_FATTR_CONST
REAL_FATTR_ALWAYS_INLINE; REAL_FATTR_ALWAYS_INLINE;
@@ -138,6 +143,14 @@ static inline bool ascii_isxdigit(int c)
|| (c >= 'A' && c <= 'F'); || (c >= 'A' && c <= 'F');
} }
/// Checks if `c` is an “identifier” character
///
/// That is, whether it is alphanumeric character or underscore.
static inline bool ascii_isident(int c)
{
return ASCII_ISALNUM(c) || c == '_';
}
/// Checks if `c` is a binary digit, that is, 0-1. /// Checks if `c` is a binary digit, that is, 0-1.
/// ///
/// @see {ascii_isdigit} /// @see {ascii_isdigit}

View File

@@ -129,7 +129,7 @@ read_buffer(
if (read_stdin) { if (read_stdin) {
// Set or reset 'modified' before executing autocommands, so that // Set or reset 'modified' before executing autocommands, so that
// it can be changed there. // it can be changed there.
if (!readonlymode && !bufempty()) { if (!readonlymode && !BUFEMPTY()) {
changed(); changed();
} else if (retval != FAIL) { } else if (retval != FAIL) {
unchanged(curbuf, false); unchanged(curbuf, false);
@@ -1387,31 +1387,40 @@ void set_curbuf(buf_T *buf, int action)
/* Don't restart Select mode after switching to another buffer. */ /* Don't restart Select mode after switching to another buffer. */
VIsual_reselect = FALSE; VIsual_reselect = FALSE;
/* close_windows() or apply_autocmds() may change curbuf */ // close_windows() or apply_autocmds() may change curbuf and wipe out "buf"
prevbuf = curbuf; prevbuf = curbuf;
bufref_T bufref; bufref_T newbufref;
set_bufref(&bufref, prevbuf); bufref_T prevbufref;
set_bufref(&prevbufref, prevbuf);
set_bufref(&newbufref, buf);
// Autocommands may delete the curren buffer and/or the buffer we wan to go
// to. In those cases don't close the buffer.
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf) if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf)
|| (bufref_valid(&bufref) && !aborting())) { || (bufref_valid(&prevbufref) && bufref_valid(&newbufref)
&& !aborting())) {
if (prevbuf == curwin->w_buffer) { if (prevbuf == curwin->w_buffer) {
reset_synblock(curwin); reset_synblock(curwin);
} }
if (unload) { if (unload) {
close_windows(prevbuf, false); close_windows(prevbuf, false);
} }
if (bufref_valid(&bufref) && !aborting()) { if (bufref_valid(&prevbufref) && !aborting()) {
win_T *previouswin = curwin; win_T *previouswin = curwin;
if (prevbuf == curbuf) if (prevbuf == curbuf) {
u_sync(FALSE); u_sync(false);
close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL, prevbuf, }
unload ? action : (action == DOBUF_GOTO close_buffer(prevbuf == curwin->w_buffer ? curwin : NULL,
&& !P_HID(prevbuf) prevbuf,
&& !bufIsChanged( unload
prevbuf)) ? DOBUF_UNLOAD : 0, FALSE); ? action
if (curwin != previouswin && win_valid(previouswin)) : (action == DOBUF_GOTO && !buf_hide(prevbuf)
/* autocommands changed curwin, Grr! */ && !bufIsChanged(prevbuf)) ? DOBUF_UNLOAD : 0,
false);
if (curwin != previouswin && win_valid(previouswin)) {
// autocommands changed curwin, Grr!
curwin = previouswin; curwin = previouswin;
}
} }
} }
/* An autocommand may have deleted "buf", already entered it (e.g., when /* An autocommand may have deleted "buf", already entered it (e.g., when
@@ -1616,7 +1625,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
&& curbuf != NULL && curbuf != NULL
&& curbuf->b_ffname == NULL && curbuf->b_ffname == NULL
&& curbuf->b_nwindows <= 1 && curbuf->b_nwindows <= 1
&& (curbuf->b_ml.ml_mfp == NULL || bufempty())) { && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY())) {
buf = curbuf; buf = curbuf;
/* It's like this buffer is deleted. Watch out for autocommands that /* It's like this buffer is deleted. Watch out for autocommands that
* change curbuf! If that happens, allocate a new buffer anyway. */ * change curbuf! If that happens, allocate a new buffer anyway. */
@@ -1775,6 +1784,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
clear_string_option(&buf->b_p_flp); clear_string_option(&buf->b_p_flp);
clear_string_option(&buf->b_p_isk); clear_string_option(&buf->b_p_isk);
clear_string_option(&buf->b_p_keymap); clear_string_option(&buf->b_p_keymap);
keymap_ga_clear(&buf->b_kmap_ga);
ga_clear(&buf->b_kmap_ga); ga_clear(&buf->b_kmap_ga);
clear_string_option(&buf->b_p_com); clear_string_option(&buf->b_p_com);
clear_string_option(&buf->b_p_cms); clear_string_option(&buf->b_p_cms);
@@ -1808,6 +1818,7 @@ void free_buf_options(buf_T *buf, int free_p_ff)
buf->b_p_ul = NO_LOCAL_UNDOLEVEL; buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
clear_string_option(&buf->b_p_lw); clear_string_option(&buf->b_p_lw);
clear_string_option(&buf->b_p_bkc); clear_string_option(&buf->b_p_bkc);
clear_string_option(&buf->b_p_menc);
} }
@@ -1870,7 +1881,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
// If 'switchbuf' contains "split", "vsplit" or "newtab" and the // If 'switchbuf' contains "split", "vsplit" or "newtab" and the
// current buffer isn't empty: open new tab or window // current buffer isn't empty: open new tab or window
if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB)) if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB))
&& !bufempty()) { && !BUFEMPTY()) {
if (swb_flags & SWB_NEWTAB) { if (swb_flags & SWB_NEWTAB) {
tabpage_new(); tabpage_new();
} else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0) } else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0)
@@ -2672,7 +2683,7 @@ void buflist_altfpos(win_T *win)
} }
/// Check that "ffname" is not the same file as current file. /// Check that "ffname" is not the same file as current file.
/// Fname must have a full path (expanded by path_get_absolute_path()). /// Fname must have a full path (expanded by path_to_absolute()).
/// ///
/// @param ffname full path name to check /// @param ffname full path name to check
bool otherfile(char_u *ffname) bool otherfile(char_u *ffname)
@@ -2682,7 +2693,7 @@ bool otherfile(char_u *ffname)
} }
/// Check that "ffname" is not the same file as the file loaded in "buf". /// Check that "ffname" is not the same file as the file loaded in "buf".
/// Fname must have a full path (expanded by path_get_absolute_path()). /// Fname must have a full path (expanded by path_to_absolute()).
/// ///
/// @param buf buffer to check /// @param buf buffer to check
/// @param ffname full path name to check /// @param ffname full path name to check
@@ -4406,12 +4417,12 @@ do_arg_all (
} }
wp->w_arg_idx = i; wp->w_arg_idx = i;
if (i == opened_len && !keep_tabs) { /* close this window */ if (i == opened_len && !keep_tabs) { // close this window
if (P_HID(buf) || forceit || buf->b_nwindows > 1 if (buf_hide(buf) || forceit || buf->b_nwindows > 1
|| !bufIsChanged(buf)) { || !bufIsChanged(buf)) {
/* If the buffer was changed, and we would like to hide it, /* If the buffer was changed, and we would like to hide it,
* try autowriting. */ * try autowriting. */
if (!P_HID(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) { if (!buf_hide(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) {
bufref_T bufref; bufref_T bufref;
set_bufref(&bufref, buf); set_bufref(&bufref, buf);
(void)autowrite(buf, false); (void)autowrite(buf, false);
@@ -4426,7 +4437,7 @@ do_arg_all (
&& (first_tabpage->tp_next == NULL || !had_tab)) { && (first_tabpage->tp_next == NULL || !had_tab)) {
use_firstwin = true; use_firstwin = true;
} else { } else {
win_close(wp, !P_HID(buf) && !bufIsChanged(buf)); win_close(wp, !buf_hide(buf) && !bufIsChanged(buf));
// check if autocommands removed the next window // check if autocommands removed the next window
if (!win_valid(wpnext)) { if (!win_valid(wpnext)) {
// start all over... // start all over...
@@ -4460,11 +4471,12 @@ do_arg_all (
last_curwin = curwin; last_curwin = curwin;
last_curtab = curtab; last_curtab = curtab;
win_enter(lastwin, false); win_enter(lastwin, false);
/* ":drop all" should re-use an empty window to avoid "--remote-tab" // ":drop all" should re-use an empty window to avoid "--remote-tab"
* leaving an empty tab page when executed locally. */ // leaving an empty tab page when executed locally.
if (keep_tabs && bufempty() && curbuf->b_nwindows == 1 if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
&& curbuf->b_ffname == NULL && !curbuf->b_changed) && curbuf->b_ffname == NULL && !curbuf->b_changed) {
use_firstwin = TRUE; use_firstwin = true;
}
for (i = 0; i < count && i < opened_len && !got_int; ++i) { for (i = 0; i < count && i < opened_len && !got_int; ++i) {
if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
@@ -4503,14 +4515,15 @@ do_arg_all (
new_curwin = curwin; new_curwin = curwin;
new_curtab = curtab; new_curtab = curtab;
} }
(void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE,
ECMD_ONE, ((buf_hide(curwin->w_buffer)
((P_HID(curwin->w_buffer) || bufIsChanged(curwin->w_buffer))
|| bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) ? ECMD_HIDE : 0) + ECMD_OLDBUF,
+ ECMD_OLDBUF, curwin); curwin);
if (use_firstwin) if (use_firstwin) {
++autocmd_no_leave; autocmd_no_leave++;
use_firstwin = FALSE; }
use_firstwin = false;
} }
os_breakcheck(); os_breakcheck();
@@ -4697,14 +4710,14 @@ void ex_buffer_all(exarg_T *eap)
* Close superfluous windows. * Close superfluous windows.
*/ */
for (wp = lastwin; open_wins > count; ) { for (wp = lastwin; open_wins > count; ) {
r = (P_HID(wp->w_buffer) || !bufIsChanged(wp->w_buffer) r = (buf_hide(wp->w_buffer) || !bufIsChanged(wp->w_buffer)
|| autowrite(wp->w_buffer, FALSE) == OK); || autowrite(wp->w_buffer, false) == OK);
if (!win_valid(wp)) { if (!win_valid(wp)) {
/* BufWrite Autocommands made the window invalid, start over */ /* BufWrite Autocommands made the window invalid, start over */
wp = lastwin; wp = lastwin;
} else if (r) { } else if (r) {
win_close(wp, !P_HID(wp->w_buffer)); win_close(wp, !buf_hide(wp->w_buffer));
--open_wins; open_wins--;
wp = lastwin; wp = lastwin;
} else { } else {
wp = wp->w_prev; wp = wp->w_prev;

View File

@@ -637,6 +637,7 @@ struct file_buffer {
uint32_t b_p_fex_flags; ///< flags for 'formatexpr' uint32_t b_p_fex_flags; ///< flags for 'formatexpr'
char_u *b_p_kp; ///< 'keywordprg' char_u *b_p_kp; ///< 'keywordprg'
int b_p_lisp; ///< 'lisp' int b_p_lisp; ///< 'lisp'
char_u *b_p_menc; ///< 'makeencoding'
char_u *b_p_mps; ///< 'matchpairs' char_u *b_p_mps; ///< 'matchpairs'
int b_p_ml; ///< 'modeline' int b_p_ml; ///< 'modeline'
int b_p_ml_nobin; ///< b_p_ml saved for binary mode int b_p_ml_nobin; ///< b_p_ml saved for binary mode
@@ -717,6 +718,7 @@ struct file_buffer {
int b_ind_hash_comment; int b_ind_hash_comment;
int b_ind_cpp_namespace; int b_ind_cpp_namespace;
int b_ind_if_for_while; int b_ind_if_for_while;
int b_ind_cpp_extern_c;
linenr_T b_no_eol_lnum; /* non-zero lnum when last line of next binary linenr_T b_no_eol_lnum; /* non-zero lnum when last line of next binary
* write should not have an end-of-line */ * write should not have an end-of-line */

View File

@@ -4,6 +4,7 @@
#include "nvim/api/ui.h" #include "nvim/api/ui.h"
#include "nvim/channel.h" #include "nvim/channel.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/event/socket.h" #include "nvim/event/socket.h"
#include "nvim/msgpack_rpc/channel.h" #include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/server.h" #include "nvim/msgpack_rpc/server.h"
@@ -179,10 +180,12 @@ static Channel *channel_alloc(ChannelStreamType type)
} }
/// Not implemented, only logging for now /// Not implemented, only logging for now
void channel_create_event(Channel *chan, char *ext_source) void channel_create_event(Channel *chan, const char *ext_source)
{ {
#if MIN_LOG_LEVEL <= INFO_LOG_LEVEL #if MIN_LOG_LEVEL <= INFO_LOG_LEVEL
char *stream_desc, *mode_desc, *source; const char *stream_desc;
const char *mode_desc;
const char *source;
switch (chan->streamtype) { switch (chan->streamtype) {
case kChannelStreamProc: case kChannelStreamProc:
@@ -222,8 +225,8 @@ void channel_create_event(Channel *chan, char *ext_source)
// external events should be included. // external events should be included.
source = ext_source; source = ext_source;
} else { } else {
eval_format_source_name_line((char *)IObuff, sizeof(IObuff)); eval_fmt_source_name_line((char *)IObuff, sizeof(IObuff));
source = (char *)IObuff; source = (const char *)IObuff;
} }
ILOG("new channel %" PRIu64 " (%s%s): %s", chan->id, stream_desc, ILOG("new channel %" PRIu64 " (%s%s): %s", chan->id, stream_desc,
@@ -234,15 +237,16 @@ void channel_create_event(Channel *chan, char *ext_source)
#endif #endif
} }
void channel_incref(Channel *channel) void channel_incref(Channel *chan)
{ {
channel->refcount++; chan->refcount++;
} }
void channel_decref(Channel *channel) void channel_decref(Channel *chan)
{ {
if (!(--channel->refcount)) { if (!(--chan->refcount)) {
multiqueue_put(main_loop.fast_events, free_channel_event, 1, channel); // delay free, so that libuv is done with the handles
multiqueue_put(main_loop.events, free_channel_event, 1, chan);
} }
} }
@@ -264,18 +268,18 @@ void callback_reader_start(CallbackReader *reader)
static void free_channel_event(void **argv) static void free_channel_event(void **argv)
{ {
Channel *channel = argv[0]; Channel *chan = argv[0];
if (channel->is_rpc) { if (chan->is_rpc) {
rpc_free(channel); rpc_free(chan);
} }
callback_reader_free(&channel->on_stdout); callback_reader_free(&chan->on_stdout);
callback_reader_free(&channel->on_stderr); callback_reader_free(&chan->on_stderr);
callback_free(&channel->on_exit); callback_free(&chan->on_exit);
pmap_del(uint64_t)(channels, channel->id); pmap_del(uint64_t)(channels, chan->id);
multiqueue_free(channel->events); multiqueue_free(chan->events);
xfree(channel); xfree(chan);
} }
static void channel_destroy_early(Channel *chan) static void channel_destroy_early(Channel *chan)
@@ -283,12 +287,15 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) { if ((chan->id != --next_chan_id)) {
abort(); abort();
} }
pmap_del(uint64_t)(channels, chan->id);
chan->id = 0;
if ((--chan->refcount != 0)) { if ((--chan->refcount != 0)) {
abort(); abort();
} }
free_channel_event((void **)&chan); // uv will keep a reference to handles until next loop tick, so delay free
multiqueue_put(main_loop.events, free_channel_event, 1, chan);
} }
@@ -391,17 +398,22 @@ uint64_t channel_connect(bool tcp, const char *address,
bool rpc, CallbackReader on_output, bool rpc, CallbackReader on_output,
int timeout, const char **error) int timeout, const char **error)
{ {
Channel *channel;
if (!tcp && rpc) { if (!tcp && rpc) {
char *path = fix_fname(address); char *path = fix_fname(address);
if (server_owns_pipe_address(path)) { bool loopback = server_owns_pipe_address(path);
// avoid deadlock
xfree(path);
return channel_create_internal_rpc();
}
xfree(path); xfree(path);
if (loopback) {
// Create a loopback channel. This avoids deadlock if nvim connects to
// its own named pipe.
channel = channel_alloc(kChannelStreamInternal);
rpc_start(channel);
goto end;
}
} }
Channel *channel = channel_alloc(kChannelStreamSocket); channel = channel_alloc(kChannelStreamSocket);
if (!socket_connect(&main_loop, &channel->stream.socket, if (!socket_connect(&main_loop, &channel->stream.socket,
tcp, address, timeout, error)) { tcp, address, timeout, error)) {
channel_destroy_early(channel); channel_destroy_early(channel);
@@ -421,7 +433,8 @@ uint64_t channel_connect(bool tcp, const char *address,
rstream_start(&channel->stream.socket, on_socket_output, channel); rstream_start(&channel->stream.socket, on_socket_output, channel);
} }
channel_create_event(channel, NULL); end:
channel_create_event(channel, address);
return channel->id; return channel->id;
} }
@@ -440,15 +453,6 @@ void channel_from_connection(SocketWatcher *watcher)
channel_create_event(channel, watcher->addr); channel_create_event(channel, watcher->addr);
} }
/// Creates a loopback channel. This is used to avoid deadlock
/// when an instance connects to its own named pipe.
static uint64_t channel_create_internal_rpc(void)
{
Channel *channel = channel_alloc(kChannelStreamInternal);
rpc_start(channel);
return channel->id;
}
/// Creates an API channel from stdin/stdout. This is used when embedding /// Creates an API channel from stdin/stdout. This is used when embedding
/// Neovim /// Neovim
uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
@@ -522,32 +526,21 @@ err:
return 0; return 0;
} }
/// NB: mutates buf in place! /// Convert binary byte array to a readfile()-style list
static list_T *buffer_to_tv_list(char *buf, size_t count) ///
/// @param[in] buf Array to convert.
/// @param[in] len Array length.
///
/// @return [allocated] Converted list.
static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{ {
list_T *ret = tv_list_alloc(); list_T *const l = tv_list_alloc(kListLenMayKnow);
char *ptr = buf; // Empty buffer should be represented by [''], encode_list_write() thinks
size_t remaining = count; // empty list is fine for the case.
size_t off = 0; tv_list_append_string(l, "", 0);
encode_list_write(l, buf, len);
while (off < remaining) { return l;
// append the line
if (ptr[off] == NL) {
tv_list_append_string(ret, ptr, (ssize_t)off);
size_t skip = off + 1;
ptr += skip;
remaining -= skip;
off = 0;
continue;
}
if (ptr[off] == NUL) {
// Translate NUL to NL
ptr[off] = NL;
}
off++;
}
tv_list_append_string(ret, ptr, (ssize_t)off);
return ret;
} }
// vimscript job callbacks must be executed on Nvim main loop // vimscript job callbacks must be executed on Nvim main loop
@@ -599,6 +592,7 @@ static void on_stdio_input(Stream *stream, RBuffer *buf, size_t count,
on_channel_output(stream, chan, buf, count, eof, &chan->on_stdout, "stdin"); on_channel_output(stream, chan, buf, count, eof, &chan->on_stdout, "stdin");
} }
/// @param type must have static lifetime
static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
size_t count, bool eof, CallbackReader *reader, size_t count, bool eof, CallbackReader *reader,
const char *type) const char *type)
@@ -613,14 +607,20 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
if (reader->cb.type != kCallbackNone) { if (reader->cb.type != kCallbackNone) {
process_channel_event(chan, &reader->cb, type, reader->buffer.ga_data, process_channel_event(chan, &reader->cb, type, reader->buffer.ga_data,
(size_t)reader->buffer.ga_len, 0); (size_t)reader->buffer.ga_len, 0);
ga_clear(&reader->buffer);
} else if (reader->self) { } else if (reader->self) {
list_T *data = buffer_to_tv_list(reader->buffer.ga_data, if (tv_dict_find(reader->self, type, -1) == NULL) {
(size_t)reader->buffer.ga_len); list_T *data = buffer_to_tv_list(reader->buffer.ga_data,
tv_dict_add_list(reader->self, type, strlen(type), data); (size_t)reader->buffer.ga_len);
tv_dict_add_list(reader->self, type, strlen(type), data);
} else {
// can't display error message now, defer it.
channel_incref(chan);
multiqueue_put(chan->events, on_buffered_error, 2, chan, type);
}
} else { } else {
abort(); abort();
} }
ga_clear(&reader->buffer);
} else if (reader->cb.type != kCallbackNone) { } else if (reader->cb.type != kCallbackNone) {
process_channel_event(chan, &reader->cb, type, ptr, 0, 0); process_channel_event(chan, &reader->cb, type, ptr, 0, 0);
} }
@@ -641,6 +641,14 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
} }
} }
static void on_buffered_error(void **args)
{
Channel *chan = (Channel *)args[0];
const char *stream = (const char *)args[1];
EMSG3(_(e_streamkey), stream, chan->id);
channel_decref(chan);
}
static void channel_process_exit_cb(Process *proc, int status, void *data) static void channel_process_exit_cb(Process *proc, int status, void *data)
{ {
Channel *chan = data; Channel *chan = data;
@@ -673,7 +681,7 @@ static void on_channel_event(void **args)
argv[1].v_type = VAR_LIST; argv[1].v_type = VAR_LIST;
argv[1].v_lock = VAR_UNLOCKED; argv[1].v_lock = VAR_UNLOCKED;
argv[1].vval.v_list = ev->received; argv[1].vval.v_list = ev->received;
argv[1].vval.v_list->lv_refcount++; tv_list_ref(argv[1].vval.v_list);
} else { } else {
argv[1].v_type = VAR_NUMBER; argv[1].v_type = VAR_NUMBER;
argv[1].v_lock = VAR_UNLOCKED; argv[1].v_lock = VAR_UNLOCKED;

Some files were not shown because too many files have changed in this diff Show More