aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml11
-rwxr-xr-x.github/workflows/env.sh12
-rw-r--r--cmake.deps/cmake/BuildLibvterm.cmake31
-rw-r--r--cmake.deps/cmake/Libvterm-tbl2inc_c.cmake163
-rw-r--r--cmake.deps/cmake/LibvtermCMakeLists.txt58
-rw-r--r--cmake/FindLIBVTERM.cmake10
-rw-r--r--cmake/FindUNIBILIUM.cmake12
-rw-r--r--cmake/Findlibvterm.cmake20
-rw-r--r--cmake/Findunibilium.cmake27
-rw-r--r--runtime/doc/builtin.txt1
-rw-r--r--runtime/doc/repeat.txt4
-rw-r--r--runtime/lua/man.lua4
-rwxr-xr-xsrc/nvim/CMakeLists.txt28
-rw-r--r--src/nvim/cmdexpand.c19
-rw-r--r--src/nvim/eval/funcs.c52
-rw-r--r--src/nvim/eval/typval.c80
-rw-r--r--src/nvim/eval/userfunc.c9
-rw-r--r--src/nvim/fileio.c184
-rw-r--r--src/nvim/getchar.c10
-rw-r--r--src/nvim/option.c10
-rw-r--r--src/nvim/optionstr.c45
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/runtime.c244
-rw-r--r--src/nvim/tag.c228
-rwxr-xr-xsrc/nvim/testdir/runnvim.sh3
-rw-r--r--src/nvim/testdir/test_edit.vim15
-rw-r--r--src/nvim/testdir/test_fold.vim58
-rw-r--r--src/nvim/testdir/test_gf.vim25
-rw-r--r--src/nvim/testdir/test_normal.vim46
-rw-r--r--src/nvim/testdir/test_packadd.vim84
-rw-r--r--src/nvim/testdir/test_taglist.vim4
-rw-r--r--src/nvim/testing.c49
-rw-r--r--src/nvim/textformat.c32
-rw-r--r--src/nvim/undo.c8
-rw-r--r--src/nvim/usercmd.c1
-rw-r--r--src/nvim/version.c40
-rw-r--r--src/nvim/vim.h1
-rw-r--r--src/nvim/window.c30
-rw-r--r--test/functional/lua/runtime_spec.lua6
-rw-r--r--test/functional/vimscript/exepath_spec.lua43
40 files changed, 883 insertions, 826 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b158d966e1..83ee4f0358 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -128,7 +128,7 @@ jobs:
- uses: actions/checkout@v3
- name: Setup common environment variables
- run: ./.github/workflows/env.sh lint
+ run: ./.github/workflows/env.sh lintc
- name: Install apt packages
run: |
@@ -141,14 +141,17 @@ jobs:
libtree-sitter-dev \
libunibilium-dev \
libuv1-dev \
- libvterm-dev \
lua-busted \
lua-filesystem \
lua-inspect \
lua-lpeg \
- lua-luv-dev \
lua-nvim \
luajit
+ # libvterm-dev \
+ # lua-luv-dev
+
+ # Remove comments from packages once we start using these external
+ # dependencies. See env.sh for more context.
- uses: ./.github/actions/cache
@@ -156,7 +159,7 @@ jobs:
run: ./ci/before_script.sh
- name: Build nvim
- run: ./ci/run_tests.sh build_nvim
+ run: make
- if: "!cancelled()"
name: Determine if run should be aborted
diff --git a/.github/workflows/env.sh b/.github/workflows/env.sh
index d93552fed3..2c3fbf9ef2 100755
--- a/.github/workflows/env.sh
+++ b/.github/workflows/env.sh
@@ -44,13 +44,15 @@ EOF
BUILD_UCHAR=1
EOF
;;
- lint)
+ lintc)
# Re-enable once system deps are available
# BUILD_FLAGS="$BUILD_FLAGS -DLIBLUV_LIBRARY:FILEPATH=/usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/lua/5.1/luv.so -DLIBLUV_INCLUDE_DIR:PATH=/usr/include/lua5.1"
- DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUV=ON"
- cat <<EOF >> "$GITHUB_ENV"
-USE_BUNDLED=OFF
-EOF
+
+ # Ideally all dependencies should external for this job, but some
+ # dependencies don't have the required version available. We use the
+ # bundled versions for these with the hopes of being able to remove them
+ # later on.
+ DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED=OFF -DUSE_BUNDLED_LUV=ON -DUSE_BUNDLED_LIBVTERM=ON"
;;
functionaltest-lua)
BUILD_FLAGS="$BUILD_FLAGS -DPREFER_LUA=ON"
diff --git a/cmake.deps/cmake/BuildLibvterm.cmake b/cmake.deps/cmake/BuildLibvterm.cmake
index 1578d56fba..b75987eb24 100644
--- a/cmake.deps/cmake/BuildLibvterm.cmake
+++ b/cmake.deps/cmake/BuildLibvterm.cmake
@@ -1,27 +1,3 @@
-if(WIN32)
- set(LIBVTERM_CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibvtermCMakeLists.txt
- ${DEPS_BUILD_DIR}/src/libvterm/CMakeLists.txt
- COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Libvterm-tbl2inc_c.cmake
- ${DEPS_BUILD_DIR}/src/libvterm/tbl2inc_c.cmake
- COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/libvterm
- -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
- -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
- -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
- -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
- -DCMAKE_POSITION_INDEPENDENT_CODE=ON)
- set(LIBVTERM_BUILD_COMMAND ${CMAKE_COMMAND} --build . --config $<CONFIG>)
- set(LIBVTERM_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config $<CONFIG>)
-else()
- set(LIBVTERM_INSTALL_COMMAND ${MAKE_PRG} CC=${DEPS_C_COMPILER}
- PREFIX=${DEPS_INSTALL_DIR}
- CFLAGS=-fPIC
- LDFLAGS+=-static
- ${DEFAULT_MAKE_CFLAGS}
- install)
-endif()
-
if(USE_EXISTING_SRC_DIR)
unset(LIBVTERM_URL)
endif()
@@ -30,10 +6,9 @@ ExternalProject_Add(libvterm
URL_HASH SHA256=${LIBVTERM_SHA256}
DOWNLOAD_NO_PROGRESS TRUE
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/libvterm
- BUILD_IN_SOURCE 1
- CONFIGURE_COMMAND "${LIBVTERM_CONFIGURE_COMMAND}"
- BUILD_COMMAND "${LIBVTERM_BUILD_COMMAND}"
- INSTALL_COMMAND "${LIBVTERM_INSTALL_COMMAND}"
+ PATCH_COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibvtermCMakeLists.txt
+ ${DEPS_BUILD_DIR}/src/libvterm/CMakeLists.txt
CMAKE_ARGS ${DEPS_CMAKE_ARGS}
CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS})
diff --git a/cmake.deps/cmake/Libvterm-tbl2inc_c.cmake b/cmake.deps/cmake/Libvterm-tbl2inc_c.cmake
deleted file mode 100644
index 32d973680f..0000000000
--- a/cmake.deps/cmake/Libvterm-tbl2inc_c.cmake
+++ /dev/null
@@ -1,163 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-set(HEX_ALPHABET "0123456789abcdef")
-
-function(ConvertToHex dec hex)
- while(dec GREATER 0)
- math(EXPR _val "${dec} % 16")
- math(EXPR dec "${dec} / 16")
- string(SUBSTRING ${HEX_ALPHABET} ${_val} 1 _val)
- set(_res "${_val}${_res}")
- endwhile()
- # Pad the result with the number of zeros
- # specified by the optional third argument
- if(${ARGC} EQUAL 3)
- set(padding ${ARGV2})
- string(LENGTH ${_res} _resLen)
- if(_resLen LESS ${padding})
- math(EXPR _neededPadding "${padding} - ${_resLen}")
- foreach(i RANGE 1 ${_neededPadding})
- set(_res "0${_res}")
- endforeach()
- endif()
- endif()
- set(${hex} "0x${_res}" PARENT_SCOPE)
-endfunction()
-
-function(ConvertFromHex hex dec)
- string(TOLOWER ${hex} hex)
- string(LENGTH "${hex}" _strlen)
- set(_res 0)
- while(_strlen GREATER 0)
- math(EXPR _res "${_res} * 16")
- string(SUBSTRING "${hex}" 0 1 NIBBLE)
- string(SUBSTRING "${hex}" 1 -1 hex)
- string(FIND ${HEX_ALPHABET} ${NIBBLE} value)
- if(value EQUAL -1)
- message(FATAL_ERROR "Invalid hex character '${NIBBLE}'")
- endif()
- math(EXPR _res "${_res} + ${value}")
- string(LENGTH "${hex}" _strlen)
- endwhile()
- set(${dec} ${_res} PARENT_SCOPE)
-endfunction()
-
-# Based on http://www.json.org/JSON_checker/utf8_decode.c
-function(DecodeUtf8 hexBytes codePoint)
- string(SUBSTRING ${hexBytes} 0 2 hexByte1)
- ConvertFromHex(${hexByte1} byte1)
- # Zero continuations (0 to 127)
- math(EXPR out "${byte1} & 128")
- if(out EQUAL 0)
- set(${codePoint} ${byte1} PARENT_SCOPE)
- return()
- endif()
- # One continuation (128 to 2047)
- math(EXPR out "${byte1} & 224")
- if(out EQUAL 192)
- string(SUBSTRING ${hexBytes} 2 2 hexByte2)
- ConvertFromHex(${hexByte2} byte2)
- math(EXPR result "((${byte1} & 31) << 6) | ${byte2}")
- if(result GREATER 127)
- set(${codePoint} ${result} PARENT_SCOPE)
- return()
- endif()
- else()
- # Two continuations (2048 to 55295 and 57344 to 65535)
- math(EXPR result "${byte1} & 240")
- if(result EQUAL 224)
- string(SUBSTRING ${hexBytes} 2 2 hexByte2)
- string(SUBSTRING ${hexBytes} 4 2 hexByte3)
- ConvertFromHex(${hexByte2} byte2)
- ConvertFromHex(${hexByte3} byte3)
- math(EXPR result "${byte2} | ${byte3}")
- if(result GREATER -1)
- math(EXPR result "((${byte1} & 15) << 12) | (${byte2} << 6) | ${byte3}")
- if((result GREATER 2047) AND (result LESS 55296 OR result GREATER 57343))
- set(${codePoint} ${result} PARENT_SCOPE)
- return()
- endif()
- endif()
- else()
- # Three continuations (65536 to 1114111)
- math(EXPR result "${byte1} & 248")
- if(result EQUAL 224)
- string(SUBSTRING ${hexBytes} 2 2 hexByte2)
- string(SUBSTRING ${hexBytes} 4 2 hexByte3)
- string(SUBSTRING ${hexBytes} 6 2 hexByte4)
- ConvertFromHex(${hexByte2} byte2)
- ConvertFromHex(${hexByte3} byte3)
- ConvertFromHex(${hexByte4} byte4)
- math(EXPR result "${byte2} | ${byte3} | ${byte4}")
- if(result GREATER -1)
- math(EXPR result "((c & 7) << 18) | (c1 << 12) | (c2 << 6) | c3")
- if((result GREATER 65535) AND (result LESS 1114112))
- set(${codePoint} ${result} PARENT_SCOPE)
- return()
- endif()
- endif()
- endif()
- endif()
- endif()
- message(FATAL_ERROR "Invalid UTF-8 encoding")
-endfunction()
-
-set(inputFile ${CMAKE_ARGV3})
-set(outputFile ${CMAKE_ARGV4})
-# Get the file contents in text and hex-encoded format because
-# CMake doesn't provide functions for converting between the two
-file(READ "${inputFile}" contents)
-file(READ "${inputFile}" hexContents HEX)
-
-# Convert the text contents into a list of lines by escaping
-# the list separator ';' and then replacing new line characters
-# with the list separator
-string(REGEX REPLACE ";" "\\\\;" contents ${contents})
-string(REGEX REPLACE "\n" ";" contents ${contents})
-
-get_filename_component(encname ${inputFile} NAME_WE)
-set(output
- "static const struct StaticTableEncoding encoding_${encname} = {\n"
- " { .decode = &decode_table },\n"
- " {")
-set(hexIndex 0)
-foreach(line ${contents})
- string(LENGTH ${line} lineLength)
- # Convert "A" to 0x41
- string(FIND ${line} "\"" beginQuote)
- if(NOT ${beginQuote} EQUAL -1)
- string(FIND ${line} "\"" endQuote REVERSE)
- if(${beginQuote} EQUAL ${endQuote})
- message(FATAL_ERROR "Line contains only one quote")
- endif()
- math(EXPR beginHexQuote "${hexIndex} + (${beginQuote} + 1)*2")
- math(EXPR endHexQuote "${hexIndex} + (${endQuote} + 1)*2")
- math(EXPR quoteLen "${endHexQuote} - ${beginHexQuote} - 1")
- string(SUBSTRING ${hexContents} ${beginHexQuote} ${quoteLen} hexQuote)
- DecodeUtf8(${hexQuote} codePoint)
- ConvertToHex(${codePoint} hexCodePoint 4)
- STRING(REGEX REPLACE "\"(.+)\"" ${hexCodePoint} line ${line})
- endif()
- # Strip comment
- string(REGEX REPLACE "[ \t\n]*#.*" "" line ${line})
- # Convert 3/1 to [0x31]
- string(REGEX REPLACE "^([0-9]+)/([0-9]+).*" "\\1;\\2" numbers ${line})
- list(GET numbers 0 upperBits)
- list(GET numbers 1 lowerBits)
- math(EXPR res "${upperBits}*16 + ${lowerBits}")
- ConvertToHex(${res} hex 2)
- string(REGEX REPLACE "^([0-9]+)/([0-9]+)" "[${hex}]" line ${line})
- # Convert U+0041 to 0x0041
- string(REPLACE "U+" "0x" line ${line})
- # Indent and append a comma
- set(line " ${line},")
- set(output "${output}\n${line}")
- # Increment the index by the number of characters in the line,
- # plus one for the new line character then multiple by two for the hex digit index
- math(EXPR hexIndex "${hexIndex} + 2*(${lineLength} + 1)")
-endforeach()
-set(output "${output}\n"
- " }\n"
- "}\;\n")
-
-file(WRITE ${outputFile} ${output})
diff --git a/cmake.deps/cmake/LibvtermCMakeLists.txt b/cmake.deps/cmake/LibvtermCMakeLists.txt
index 079ad28ba0..777ce6c54c 100644
--- a/cmake.deps/cmake/LibvtermCMakeLists.txt
+++ b/cmake.deps/cmake/LibvtermCMakeLists.txt
@@ -2,43 +2,18 @@ cmake_minimum_required(VERSION 3.10)
project(libvterm LANGUAGES C)
include(GNUInstallDirs)
-find_package(Perl)
if(MSVC)
- add_compile_options(/W3)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
else()
- add_compile_options(-Wall -std=c99)
+ add_compile_options(-std=c99)
endif()
-# Generate includes from tables
-file(GLOB TBL_FILES ${CMAKE_SOURCE_DIR}/src/encoding/*.tbl)
-set(TBL_FILES_HEADERS)
-foreach(file ${TBL_FILES})
- get_filename_component(basename ${file} NAME_WE)
- set(tname encoding/${basename}.inc)
- add_custom_command(OUTPUT
- COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/encoding/
- COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/tbl2inc_c.cmake ${file} ${CMAKE_BINARY_DIR}/${tname}
- COMMENT "Generating ${tname}"
- OUTPUT ${CMAKE_BINARY_DIR}/${tname}
- )
- list(APPEND TBL_FILES_HEADERS ${tname})
- # Only used for verifying that the output of tbl2inc_c.cmake is correct
- set(tname encoding-test/${basename}.inc)
- add_custom_command(OUTPUT
- COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/encoding-test/
- COMMAND ${PERL_EXECUTABLE} -CSD ${CMAKE_SOURCE_DIR}/tbl2inc_c.pl ${file} > ${CMAKE_BINARY_DIR}/${tname}
- COMMENT "Generating ${tname}"
- OUTPUT ${CMAKE_BINARY_DIR}/${tname}
- )
-endforeach()
-
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_BINARY_DIR})
file(GLOB VTERM_SOURCES ${CMAKE_SOURCE_DIR}/src/*.c)
-add_library(vterm ${VTERM_SOURCES} ${TBL_FILES_HEADERS})
+add_library(vterm ${VTERM_SOURCES})
install(TARGETS vterm ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES include/vterm.h include/vterm_keycodes.h
@@ -54,33 +29,4 @@ if(NOT WIN32)
endforeach()
endif()
-# Tests
-add_executable(harness EXCLUDE_FROM_ALL t/harness.c)
-target_link_libraries(harness vterm)
-set_target_properties(harness PROPERTIES
- # run-test.pl expects to find the harness in t/.libs/
- RUNTIME_OUTPUT_DIRECTORY t/.libs)
-
-if(Perl_FOUND)
- file(GLOB TESTFILES ${CMAKE_SOURCE_DIR}/t/*.test)
- add_custom_target(check)
- foreach(testfile ${TESTFILES})
- get_filename_component(target_name ${testfile} NAME_WE)
- add_custom_target(${target_name}
- COMMAND ${PERL_EXECUTABLE} ${CMAKE_SOURCE_DIR}/t/run-test.pl ${testfile}
- COMMENT "**${target_name} **"
- DEPENDS harness)
- add_dependencies(check ${target_name})
- endforeach()
-
- foreach(header_path ${TBL_FILES_HEADERS})
- get_filename_component(header_name ${header_path} NAME)
- set(perl_header_path ${CMAKE_BINARY_DIR}/encoding-test/${header_name})
- add_custom_target(test-${header_name}
- COMMAND ${CMAKE_COMMAND} -E compare_files
- ${header_path} ${perl_header_path}
- DEPENDS ${header_path} ${perl_header_path})
- endforeach()
-endif()
-
# vim: set ft=cmake:
diff --git a/cmake/FindLIBVTERM.cmake b/cmake/FindLIBVTERM.cmake
deleted file mode 100644
index 469494ddfd..0000000000
--- a/cmake/FindLIBVTERM.cmake
+++ /dev/null
@@ -1,10 +0,0 @@
-# - Try to find libvterm
-# Once done this will define
-# LIBVTERM_FOUND - System has libvterm
-# LIBVTERM_INCLUDE_DIRS - The libvterm include directories
-# LIBVTERM_LIBRARIES - The libraries needed to use libvterm
-
-include(LibFindMacros)
-
-libfind_pkg_detect(LIBVTERM vterm FIND_PATH vterm.h FIND_LIBRARY vterm)
-libfind_process(LIBVTERM REQUIRED)
diff --git a/cmake/FindUNIBILIUM.cmake b/cmake/FindUNIBILIUM.cmake
deleted file mode 100644
index 0bf27b45e2..0000000000
--- a/cmake/FindUNIBILIUM.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-# - Try to find unibilium
-# Once done this will define
-# UNIBILIUM_FOUND - System has unibilium
-# UNIBILIUM_INCLUDE_DIRS - The unibilium include directories
-# UNIBILIUM_LIBRARIES - The libraries needed to use unibilium
-
-include(LibFindMacros)
-
-libfind_pkg_detect(UNIBILIUM unibilium
- FIND_PATH unibilium.h
- FIND_LIBRARY unibilium)
-libfind_process(UNIBILIUM)
diff --git a/cmake/Findlibvterm.cmake b/cmake/Findlibvterm.cmake
new file mode 100644
index 0000000000..e73775d973
--- /dev/null
+++ b/cmake/Findlibvterm.cmake
@@ -0,0 +1,20 @@
+find_path(LIBVTERM_INCLUDE_DIR vterm.h)
+find_library(LIBVTERM_LIBRARY vterm)
+
+if(LIBVTERM_INCLUDE_DIR AND EXISTS "${LIBVTERM_INCLUDE_DIR}/vterm.h")
+ file(STRINGS ${LIBVTERM_INCLUDE_DIR}/vterm.h VTERM_VERSION_MAJOR REGEX "#define VTERM_VERSION_MAJOR")
+ string(REGEX MATCH "[0-9]+" VTERM_VERSION_MAJOR ${VTERM_VERSION_MAJOR})
+
+ file(STRINGS ${LIBVTERM_INCLUDE_DIR}/vterm.h VTERM_VERSION_MINOR REGEX "#define VTERM_VERSION_MINOR")
+ string(REGEX MATCH "[0-9]+" VTERM_VERSION_MINOR ${VTERM_VERSION_MINOR})
+
+ set(VTERM_VERSION ${VTERM_VERSION_MAJOR}.${VTERM_VERSION_MINOR})
+endif()
+
+find_package_handle_standard_args(libvterm
+ REQUIRED_VARS LIBVTERM_INCLUDE_DIR LIBVTERM_LIBRARY
+ VERSION_VAR VTERM_VERSION)
+
+add_library(libvterm INTERFACE)
+target_include_directories(libvterm SYSTEM BEFORE INTERFACE INTERFACE ${LIBVTERM_INCLUDE_DIR})
+target_link_libraries(main_lib INTERFACE ${LIBVTERM_LIBRARY})
diff --git a/cmake/Findunibilium.cmake b/cmake/Findunibilium.cmake
new file mode 100644
index 0000000000..fd8eb0cd7f
--- /dev/null
+++ b/cmake/Findunibilium.cmake
@@ -0,0 +1,27 @@
+find_path(UNIBILIUM_INCLUDE_DIR unibilium.h)
+find_library(UNIBILIUM_LIBRARY unibilium)
+
+find_package_handle_standard_args(unibilium
+ REQUIRED_VARS UNIBILIUM_INCLUDE_DIR UNIBILIUM_LIBRARY)
+
+add_library(unibilium INTERFACE)
+target_include_directories(unibilium SYSTEM BEFORE INTERFACE ${UNIBILIUM_INCLUDE_DIR})
+target_link_libraries(unibilium INTERFACE ${UNIBILIUM_LIBRARY})
+
+list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIR}")
+list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARY}")
+check_c_source_compiles("
+#include <unibilium.h>
+
+int
+main(void)
+{
+ unibi_str_from_var(unibi_var_from_str(\"\"));
+ return unibi_num_from_var(unibi_var_from_num(0));
+}
+" UNIBI_HAS_VAR_FROM)
+list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIR}")
+list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARY}")
+if(UNIBI_HAS_VAR_FROM)
+ target_compile_definitions(main_lib INTERFACE NVIM_UNIBI_HAS_VAR_FROM)
+endif()
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 4d2c85b134..c8f5570bae 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -2991,6 +2991,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
messages |:messages| suboptions
option options
packadd optional package |pack-add| names
+ runtime |:runtime| completion
scriptnames sourced script names |:scriptnames|
shellcmd Shell command
sign |:sign| suboptions
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 1bbd20702b..bf77aacdc0 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -211,9 +211,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
When [!] is included, all found files are sourced.
Else only the first found file is sourced.
- When [where] is omitted, first 'runtimepath' is
- searched, then directories under "start" in 'packpath'
- are searched.
+ When [where] is omitted only 'runtimepath' is used.
Other values:
START search only under "start" in 'packpath'
OPT search only under "opt" in 'packpath'
diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua
index a644dd68b8..732a4ab92e 100644
--- a/runtime/lua/man.lua
+++ b/runtime/lua/man.lua
@@ -420,6 +420,10 @@ local function extract_sect_and_name_path(path)
end
local function find_man()
+ if vim.bo.filetype == 'man' then
+ return true
+ end
+
local win = 1
while win <= fn.winnr('$') do
local buf = fn.winbufnr(win)
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 2361210e59..77ed0490d8 100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -22,17 +22,15 @@ find_package(TreeSitter REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${TreeSitter_INCLUDE_DIRS})
target_link_libraries(main_lib INTERFACE ${TreeSitter_LIBRARIES})
-find_package(UNIBILIUM 2.0 REQUIRED)
-target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${UNIBILIUM_INCLUDE_DIRS})
-target_link_libraries(main_lib INTERFACE ${UNIBILIUM_LIBRARIES})
+find_package(unibilium 2.0 REQUIRED)
+target_link_libraries(main_lib INTERFACE unibilium)
find_package(LibTermkey 0.22 REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIRS})
target_link_libraries(main_lib INTERFACE ${LIBTERMKEY_LIBRARIES})
-find_package(LIBVTERM 0.3 REQUIRED)
-target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBVTERM_INCLUDE_DIRS})
-target_link_libraries(main_lib INTERFACE ${LIBVTERM_LIBRARIES})
+find_package(libvterm 0.3 REQUIRED)
+target_link_libraries(main_lib INTERFACE libvterm)
find_package(Iconv REQUIRED)
target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${Iconv_INCLUDE_DIRS})
@@ -175,24 +173,6 @@ if(CI_BUILD)
endif()
endif()
-list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
-list(APPEND CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
-check_c_source_compiles("
-#include <unibilium.h>
-
-int
-main(void)
-{
- unibi_str_from_var(unibi_var_from_str(\"\"));
- return unibi_num_from_var(unibi_var_from_num(0));
-}
-" UNIBI_HAS_VAR_FROM)
-list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
-list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
-if(UNIBI_HAS_VAR_FROM)
- target_compile_definitions(main_lib INTERFACE NVIM_UNIBI_HAS_VAR_FROM)
-endif()
-
list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}")
check_c_source_compiles("
#include <msgpack.h>
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index be815151ef..5e4b49db24 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -109,6 +109,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
&& xp->xp_context != EXPAND_OLD_SETTING
&& xp->xp_context != EXPAND_OWNSYNTAX
&& xp->xp_context != EXPAND_PACKADD
+ && xp->xp_context != EXPAND_RUNTIME
&& xp->xp_context != EXPAND_SHELLCMD
&& xp->xp_context != EXPAND_TAGS
&& xp->xp_context != EXPAND_TAGS_LISTFILES
@@ -1215,6 +1216,7 @@ char *addstar(char *fname, size_t len, int context)
|| context == EXPAND_OWNSYNTAX
|| context == EXPAND_FILETYPE
|| context == EXPAND_PACKADD
+ || context == EXPAND_RUNTIME
|| ((context == EXPAND_TAGS_LISTFILES || context == EXPAND_TAGS)
&& fname[0] == '/')) {
retval = xstrnsave(fname, len);
@@ -2092,6 +2094,10 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa
xp->xp_pattern = (char *)arg;
break;
+ case CMD_runtime:
+ set_context_in_runtime_cmd(xp, arg);
+ break;
+
#ifdef HAVE_WORKING_LIBINTL
case CMD_language:
return set_context_in_lang_cmd(xp, arg);
@@ -2733,6 +2739,9 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
if (xp->xp_context == EXPAND_PACKADD) {
return ExpandPackAddDir(pat, numMatches, matches);
}
+ if (xp->xp_context == EXPAND_RUNTIME) {
+ return expand_runtime_cmd(pat, numMatches, matches);
+ }
// When expanding a function name starting with s:, match the <SNR>nr_
// prefix.
@@ -3201,11 +3210,12 @@ static int ExpandUserLua(expand_T *xp, int *num_file, char ***file)
/// Expand `file` for all comma-separated directories in `path`.
/// Adds matches to `ga`.
-void globpath(char *path, char *file, garray_T *ga, int expand_options)
+/// If "dirs" is true only expand directory names.
+void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dirs)
{
expand_T xpc;
ExpandInit(&xpc);
- xpc.xp_context = EXPAND_FILES;
+ xpc.xp_context = dirs ? EXPAND_DIRECTORIES : EXPAND_FILES;
char *buf = xmalloc(MAXPATHL);
@@ -3524,11 +3534,14 @@ void f_getcompletion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
set_context_in_menu_cmd(&xpc, "menu", xpc.xp_pattern, false);
xpc.xp_pattern_len = strlen(xpc.xp_pattern);
}
-
if (xpc.xp_context == EXPAND_SIGN) {
set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
xpc.xp_pattern_len = strlen(xpc.xp_pattern);
}
+ if (xpc.xp_context == EXPAND_RUNTIME) {
+ set_context_in_runtime_cmd(&xpc, xpc.xp_pattern);
+ xpc.xp_pattern_len = strlen(xpc.xp_pattern);
+ }
theend:
if (cmdline_fuzzy_completion_supported(&xpc)) {
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 5a31288ecd..938fef9a52 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2983,7 +2983,7 @@ static void f_globpath(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (file != NULL && !error) {
garray_T ga;
ga_init(&ga, (int)sizeof(char *), 10);
- globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags);
+ globpath((char *)tv_get_string(&argvars[0]), (char *)file, &ga, flags, false);
if (rettv->v_type == VAR_STRING) {
rettv->vval.v_string = ga_concat_strings_sep(&ga, "\n");
@@ -7823,34 +7823,35 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
// MSVC returns NULL for an invalid value of seconds.
if (curtime_ptr == NULL) {
rettv->vval.v_string = xstrdup(_("(Invalid)"));
- } else {
- vimconv_T conv;
+ return;
+ }
- conv.vc_type = CONV_NONE;
- char *enc = enc_locale();
- convert_setup(&conv, p_enc, enc);
- if (conv.vc_type != CONV_NONE) {
- p = string_convert(&conv, p, NULL);
- }
- char result_buf[256];
- if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) {
- result_buf[0] = NUL;
- }
+ vimconv_T conv;
- if (conv.vc_type != CONV_NONE) {
- xfree(p);
- }
- convert_setup(&conv, enc, p_enc);
- if (conv.vc_type != CONV_NONE) {
- rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
- } else {
- rettv->vval.v_string = xstrdup(result_buf);
- }
+ conv.vc_type = CONV_NONE;
+ char *enc = enc_locale();
+ convert_setup(&conv, p_enc, enc);
+ if (conv.vc_type != CONV_NONE) {
+ p = string_convert(&conv, p, NULL);
+ }
+ char result_buf[256];
+ if (p == NULL || strftime(result_buf, sizeof(result_buf), p, curtime_ptr) == 0) {
+ result_buf[0] = NUL;
+ }
- // Release conversion descriptors.
- convert_setup(&conv, NULL, NULL);
- xfree(enc);
+ if (conv.vc_type != CONV_NONE) {
+ xfree(p);
}
+ convert_setup(&conv, enc, p_enc);
+ if (conv.vc_type != CONV_NONE) {
+ rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
+ } else {
+ rettv->vval.v_string = xstrdup(result_buf);
+ }
+
+ // Release conversion descriptors.
+ convert_setup(&conv, NULL, NULL);
+ xfree(enc);
}
/// "strgetchar()" function
@@ -8654,6 +8655,7 @@ static void f_timer_pause(typval_T *argvars, typval_T *unused, EvalFuncData fptr
emsg(_(e_number_exp));
return;
}
+
int paused = (bool)tv_get_number(&argvars[1]);
timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0]));
if (timer != NULL) {
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 05b4737206..c298064d86 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -3208,17 +3208,19 @@ static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dic
/// @param[in,out] tv Value to free.
void tv_clear(typval_T *const tv)
{
- if (tv != NULL && tv->v_type != VAR_UNKNOWN) {
- // WARNING: do not translate the string here, gettext is slow and function
- // is used *very* often. At the current state encode_vim_to_nothing() does
- // not error out and does not use the argument anywhere.
- //
- // If situation changes and this argument will be used, translate it in the
- // place where it is used.
- const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument");
- (void)evn_ret;
- assert(evn_ret == OK);
+ if (tv == NULL || tv->v_type == VAR_UNKNOWN) {
+ return;
}
+
+ // WARNING: do not translate the string here, gettext is slow and function
+ // is used *very* often. At the current state encode_vim_to_nothing() does
+ // not error out and does not use the argument anywhere.
+ //
+ // If situation changes and this argument will be used, translate it in the
+ // place where it is used.
+ const int evn_ret = encode_vim_to_nothing(NULL, tv, "tv_clear() argument");
+ (void)evn_ret;
+ assert(evn_ret == OK);
}
//{{{3 Free
@@ -3228,35 +3230,37 @@ void tv_clear(typval_T *const tv)
/// @param tv Object to free.
void tv_free(typval_T *tv)
{
- if (tv != NULL) {
- switch (tv->v_type) {
- case VAR_PARTIAL:
- partial_unref(tv->vval.v_partial);
- break;
- case VAR_FUNC:
- func_unref(tv->vval.v_string);
- FALLTHROUGH;
- case VAR_STRING:
- xfree(tv->vval.v_string);
- break;
- case VAR_BLOB:
- tv_blob_unref(tv->vval.v_blob);
- break;
- case VAR_LIST:
- tv_list_unref(tv->vval.v_list);
- break;
- case VAR_DICT:
- tv_dict_unref(tv->vval.v_dict);
- break;
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_UNKNOWN:
- break;
- }
- xfree(tv);
+ if (tv == NULL) {
+ return;
+ }
+
+ switch (tv->v_type) {
+ case VAR_PARTIAL:
+ partial_unref(tv->vval.v_partial);
+ break;
+ case VAR_FUNC:
+ func_unref(tv->vval.v_string);
+ FALLTHROUGH;
+ case VAR_STRING:
+ xfree(tv->vval.v_string);
+ break;
+ case VAR_BLOB:
+ tv_blob_unref(tv->vval.v_blob);
+ break;
+ case VAR_LIST:
+ tv_list_unref(tv->vval.v_list);
+ break;
+ case VAR_DICT:
+ tv_dict_unref(tv->vval.v_dict);
+ break;
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ break;
}
+ xfree(tv);
}
//{{{3 Copy
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 22c5b1954d..6c6dc3fa43 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -760,13 +760,12 @@ static void funccal_unref(funccall_T *fc, ufunc_T *fp, bool force)
static bool func_remove(ufunc_T *fp)
{
hashitem_T *hi = hash_find(&func_hashtab, (char *)UF2HIKEY(fp));
-
- if (!HASHITEM_EMPTY(hi)) {
- hash_remove(&func_hashtab, hi);
- return true;
+ if (HASHITEM_EMPTY(hi)) {
+ return false;
}
- return false;
+ hash_remove(&func_hashtab, hi);
+ return true;
}
static void func_clear_items(ufunc_T *fp)
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 9da9d6199e..6b3e7dddb5 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -968,13 +968,11 @@ retry:
if (read_buf_lnum > from) {
size = 0;
} else {
- int n, ni;
- long tlen;
-
- tlen = 0;
+ int ni;
+ long tlen = 0;
for (;;) {
p = (char_u *)ml_get(read_buf_lnum) + read_buf_col;
- n = (int)strlen((char *)p);
+ int n = (int)strlen((char *)p);
if ((int)tlen + n + 1 > size) {
// Filled up to "size", append partial line.
// Change NL to NUL to reverse the effect done
@@ -2126,7 +2124,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
bool errmsg_allocated = false;
char *buffer;
char smallbuf[SMBUFSIZE];
- char *backup_ext;
int bufsize;
long perm; // file permissions
int retval = OK;
@@ -2555,8 +2552,6 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
if ((bkc & BKC_YES) || append) { // "yes"
backup_copy = true;
} else if ((bkc & BKC_AUTO)) { // "auto"
- int i;
-
// Don't rename the file when:
// - it's a hard link
// - it's a symbolic link
@@ -2571,7 +2566,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
// First find a file name that doesn't exist yet (use some
// arbitrary numbers).
STRCPY(IObuff, fname);
- for (i = 4913;; i += 123) {
+ for (int i = 4913;; i += 123) {
char *tail = path_tail(IObuff);
size_t size = (size_t)(tail - IObuff);
snprintf(tail, IOSIZE - size, "%d", i);
@@ -2624,18 +2619,10 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
}
// make sure we have a valid backup extension to use
- if (*p_bex == NUL) {
- backup_ext = ".bak";
- } else {
- backup_ext = p_bex;
- }
+ char *backup_ext = *p_bex == NUL ? ".bak" : p_bex;
if (backup_copy) {
- char *wp;
int some_error = false;
- char *dirp;
- char *rootname;
- char *p;
// Try to make the backup in each directory in the 'bdir' option.
//
@@ -2647,11 +2634,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
//
// For these reasons, the existing writable file must be truncated
// and reused. Creation of a backup COPY will be attempted.
- dirp = p_bdir;
+ char *dirp = p_bdir;
while (*dirp) {
// Isolate one directory name, using an entry in 'bdir'.
size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
- p = IObuff + dir_len;
+ char *p = IObuff + dir_len;
bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2];
if (trailing_pathseps) {
IObuff[dir_len - 2] = NUL;
@@ -2674,7 +2661,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
}
}
- rootname = get_file_in_dir(fname, IObuff);
+ char *rootname = get_file_in_dir(fname, IObuff);
if (rootname == NULL) {
some_error = true; // out of memory
goto nobackup;
@@ -2710,7 +2697,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
// delete an existing one, and try to use another name instead.
// Change one character, just before the extension.
//
- wp = backup + strlen(backup) - 1 - strlen(backup_ext);
+ char *wp = backup + strlen(backup) - 1 - strlen(backup_ext);
if (wp < backup) { // empty file name ???
wp = backup;
}
@@ -2781,10 +2768,6 @@ nobackup:
}
SET_ERRMSG(NULL);
} else {
- char *dirp;
- char *p;
- char *rootname;
-
// Make a backup by renaming the original file.
// If 'cpoptions' includes the "W" flag, we don't want to
@@ -2798,11 +2781,11 @@ nobackup:
// Form the backup file name - change path/fo.o.h to
// path/fo.o.h.bak Try all directories in 'backupdir', first one
// that works is used.
- dirp = p_bdir;
+ char *dirp = p_bdir;
while (*dirp) {
// Isolate one directory name and make the backup file name.
size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
- p = IObuff + dir_len;
+ char *p = IObuff + dir_len;
bool trailing_pathseps = after_pathsep(IObuff, p) && p[-1] == p[-2];
if (trailing_pathseps) {
IObuff[dir_len - 2] = NUL;
@@ -2826,7 +2809,7 @@ nobackup:
}
if (backup == NULL) {
- rootname = get_file_in_dir(fname, IObuff);
+ char *rootname = get_file_in_dir(fname, IObuff);
if (rootname == NULL) {
backup = NULL;
} else {
@@ -3690,9 +3673,7 @@ static bool msg_add_fileformat(int eol_type)
/// Append line and character count to IObuff.
void msg_add_lines(int insert_space, long lnum, off_T nchars)
{
- char *p;
-
- p = IObuff + strlen(IObuff);
+ char *p = IObuff + strlen(IObuff);
if (insert_space) {
*p++ = ' ';
@@ -3758,46 +3739,35 @@ static bool time_differs(const FileInfo *file_info, long mtime, long mtime_ns) F
/// @return FAIL for failure, OK otherwise.
static int buf_write_bytes(struct bw_info *ip)
{
- int wlen;
- char *buf = ip->bw_buf; // data to write
- int len = ip->bw_len; // length of data
+ char *buf = ip->bw_buf; // data to write
+ int len = ip->bw_len; // length of data
#ifdef HAS_BW_FLAGS
- int flags = ip->bw_flags; // extra flags
+ int flags = ip->bw_flags; // extra flags
#endif
// Skip conversion when writing the BOM.
if (!(flags & FIO_NOCONVERT)) {
- char *p;
- unsigned c;
- int n;
-
if (flags & FIO_UTF8) {
// Convert latin1 in the buffer to UTF-8 in the file.
- p = ip->bw_conv_buf; // translate to buffer
- for (wlen = 0; wlen < len; wlen++) {
+ char *p = ip->bw_conv_buf; // translate to buffer
+ for (int wlen = 0; wlen < len; wlen++) {
p += utf_char2bytes((uint8_t)buf[wlen], p);
}
buf = ip->bw_conv_buf;
len = (int)(p - ip->bw_conv_buf);
} else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) {
+ unsigned c;
+ int n = 0;
// Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
// Latin1 chars in the file.
- if (flags & FIO_LATIN1) {
- p = buf; // translate in-place (can only get shorter)
- } else {
- p = ip->bw_conv_buf; // translate to buffer
- }
- for (wlen = 0; wlen < len; wlen += n) {
+ // translate in-place (can only get shorter) or to buffer
+ char *p = flags & FIO_LATIN1 ? buf : ip->bw_conv_buf;
+ for (int wlen = 0; wlen < len; wlen += n) {
if (wlen == 0 && ip->bw_restlen != 0) {
- int l;
-
// Use remainder of previous call. Append the start of
// buf[] to get a full sequence. Might still be too
// short!
- l = CONV_RESTLEN - ip->bw_restlen;
- if (l > len) {
- l = len;
- }
+ int l = MIN(len, CONV_RESTLEN - ip->bw_restlen);
memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
n = utf_ptr2len_len((char *)ip->bw_rest, ip->bw_restlen + l);
if (n > ip->bw_restlen + len) {
@@ -3864,18 +3834,15 @@ static int buf_write_bytes(struct bw_info *ip)
if (ip->bw_iconv_fd != (iconv_t)-1) {
const char *from;
size_t fromlen;
- char *to;
size_t tolen;
// Convert with iconv().
if (ip->bw_restlen > 0) {
- char *fp;
-
// Need to concatenate the remainder of the previous call and
// the bytes of the current call. Use the end of the
// conversion buffer for this.
fromlen = (size_t)len + (size_t)ip->bw_restlen;
- fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
+ char *fp = ip->bw_conv_buf + ip->bw_conv_buflen - fromlen;
memmove(fp, ip->bw_rest, (size_t)ip->bw_restlen);
memmove(fp + ip->bw_restlen, buf, (size_t)len);
from = fp;
@@ -3885,7 +3852,7 @@ static int buf_write_bytes(struct bw_info *ip)
fromlen = (size_t)len;
tolen = ip->bw_conv_buflen;
}
- to = ip->bw_conv_buf;
+ char *to = ip->bw_conv_buf;
if (ip->bw_first) {
size_t save_len = tolen;
@@ -3925,7 +3892,7 @@ static int buf_write_bytes(struct bw_info *ip)
// Only checking conversion, which is OK if we get here.
return OK;
}
- wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len);
+ int wlen = (int)write_eintr(ip->bw_fd, buf, (size_t)len);
return (wlen < len) ? FAIL : OK;
}
@@ -3940,7 +3907,6 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL
{
char_u *p = (char_u *)(*pp);
bool error = false;
- int cc;
if (flags & FIO_UCS4) {
if (flags & FIO_ENDIAN_L) {
@@ -3963,7 +3929,7 @@ static bool ucs2bytes(unsigned c, char **pp, int flags) FUNC_ATTR_NONNULL_ALL
if (c >= 0x100000) {
error = true;
}
- cc = (int)(((c >> 10) & 0x3ff) + 0xd800);
+ int cc = (int)(((c >> 10) & 0x3ff) + 0xd800);
if (flags & FIO_ENDIAN_L) {
*p++ = (uint8_t)cc;
*p++ = (uint8_t)(cc >> 8);
@@ -4006,7 +3972,6 @@ static bool need_conversion(const char *fenc)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int same_encoding;
- int enc_flags;
int fenc_flags;
if (*fenc == NUL || strcmp(p_enc, fenc) == 0) {
@@ -4015,7 +3980,7 @@ static bool need_conversion(const char *fenc)
} else {
// Ignore difference between "ansi" and "latin1", "ucs-4" and
// "ucs-4be", etc.
- enc_flags = get_fio_flags(p_enc);
+ int enc_flags = get_fio_flags(p_enc);
fenc_flags = get_fio_flags(fenc);
same_encoding = (enc_flags != 0 && fenc_flags == enc_flags);
}
@@ -4036,12 +4001,10 @@ static bool need_conversion(const char *fenc)
/// @param name string to check for encoding
static int get_fio_flags(const char *name)
{
- int prop;
-
if (*name == NUL) {
name = p_enc;
}
- prop = enc_canon_props(name);
+ int prop = enc_canon_props(name);
if (prop & ENC_UNICODE) {
if (prop & ENC_2BYTE) {
if (prop & ENC_ENDIAN_L) {
@@ -4121,10 +4084,7 @@ static char *check_for_bom(const char *p_in, long size, int *lenp, int flags)
/// @return the length of the BOM (zero when no BOM).
static int make_bom(char_u *buf, char *name)
{
- int flags;
- char *p;
-
- flags = get_fio_flags(name);
+ int flags = get_fio_flags(name);
// Can't put a BOM in a non-Unicode file.
if (flags == FIO_LATIN1 || flags == 0) {
@@ -4137,7 +4097,7 @@ static int make_bom(char_u *buf, char *name)
buf[2] = 0xbf;
return 3;
}
- p = (char *)buf;
+ char *p = (char *)buf;
(void)ucs2bytes(0xfeff, &p, flags);
return (int)((char_u *)p - buf);
}
@@ -4153,8 +4113,6 @@ static int make_bom(char_u *buf, char *name)
/// name.
void shorten_buf_fname(buf_T *buf, char *dirname, int force)
{
- char *p;
-
if (buf->b_fname != NULL
&& !bt_nofilename(buf)
&& !path_with_url(buf->b_fname)
@@ -4164,7 +4122,7 @@ void shorten_buf_fname(buf_T *buf, char *dirname, int force)
if (buf->b_sfname != buf->b_ffname) {
XFREE_CLEAR(buf->b_sfname);
}
- p = path_shorten_fname(buf->b_ffname, dirname);
+ char *p = path_shorten_fname(buf->b_ffname, dirname);
if (p != NULL) {
buf->b_sfname = xstrdup(p);
buf->b_fname = buf->b_sfname;
@@ -4461,10 +4419,7 @@ int vim_rename(const char *from, const char *to)
{
int fd_in;
int fd_out;
- int n;
char *errmsg = NULL;
- char *buffer;
- long perm;
#ifdef HAVE_ACL
vim_acl_T acl; // ACL from original file
#endif
@@ -4506,7 +4461,7 @@ int vim_rename(const char *from, const char *to)
return -1;
}
STRCPY(tempname, from);
- for (n = 123; n < 99999; n++) {
+ for (int n = 123; n < 99999; n++) {
char *tail = path_tail(tempname);
snprintf(tail, (size_t)((MAXPATHL + 1) - (tail - tempname - 1)), "%d", n);
@@ -4540,7 +4495,7 @@ int vim_rename(const char *from, const char *to)
}
// Rename() failed, try copying the file.
- perm = os_getperm(from);
+ long perm = os_getperm(from);
#ifdef HAVE_ACL
// For systems that support ACL: get the ACL from the original file.
acl = os_get_acl(from);
@@ -4566,7 +4521,7 @@ int vim_rename(const char *from, const char *to)
// Avoid xmalloc() here as vim_rename() is called by buf_write() when nvim
// is `preserve_exit()`ing.
- buffer = try_malloc(BUFSIZE);
+ char *buffer = try_malloc(BUFSIZE);
if (buffer == NULL) {
close(fd_out);
close(fd_in);
@@ -4576,6 +4531,7 @@ int vim_rename(const char *from, const char *to)
return -1;
}
+ int n;
while ((n = (int)read_eintr(fd_in, buffer, BUFSIZE)) > 0) {
if (write_eintr(fd_out, buffer, (size_t)n) != n) {
errmsg = _("E208: Error writing to \"%s\"");
@@ -4619,8 +4575,6 @@ static int already_warned = false;
/// @return true if some message was written (screen should be redrawn and cursor positioned).
int check_timestamps(int focus)
{
- int didit = 0;
-
// Don't check timestamps while system() or another low-level function may
// cause us to lose and gain focus.
if (no_check_timestamps > 0) {
@@ -4635,6 +4589,8 @@ int check_timestamps(int focus)
return false;
}
+ int didit = 0;
+
if (!stuff_empty() || global_busy || !typebuf_typed()
|| autocmd_busy || curbuf->b_ro_locked > 0
|| allbuf_lock > 0) {
@@ -4678,13 +4634,11 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
{
buf_T *tbuf = curbuf;
int retval = OK;
- linenr_T lnum;
- char *p;
// Copy the lines in "frombuf" to "tobuf".
curbuf = tobuf;
- for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) {
- p = xstrdup(ml_get_buf(frombuf, lnum, false));
+ for (linenr_T lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) {
+ char *p = xstrdup(ml_get_buf(frombuf, lnum, false));
if (ml_append(lnum - 1, p, 0, false) == FAIL) {
xfree(p);
retval = FAIL;
@@ -4696,7 +4650,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
// Delete all the lines in "frombuf".
if (retval != FAIL) {
curbuf = frombuf;
- for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) {
+ for (linenr_T lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) {
if (ml_delete(lnum, false) == FAIL) {
// Oops! We could try putting back the saved lines, but that
// might fail again...
@@ -4720,7 +4674,6 @@ int buf_check_timestamp(buf_T *buf)
FUNC_ATTR_NONNULL_ALL
{
int retval = 0;
- char *path;
char *mesg = NULL;
char *mesg2 = "";
bool helpmesg = false;
@@ -4735,8 +4688,6 @@ int buf_check_timestamp(buf_T *buf)
uint64_t orig_size = buf->b_orig_size;
int orig_mode = buf->b_orig_mode;
static bool busy = false;
- char *s;
- char *reason;
bufref_T bufref;
set_bufref(&bufref, buf);
@@ -4784,6 +4735,7 @@ int buf_check_timestamp(buf_T *buf)
// was set, the global option value otherwise.
reload = RELOAD_NORMAL;
} else {
+ char *reason;
if (!file_info_ok) {
reason = "deleted";
} else if (bufIsChanged(buf)) {
@@ -4810,7 +4762,7 @@ int buf_check_timestamp(buf_T *buf)
if (!bufref_valid(&bufref)) {
emsg(_("E246: FileChangedShell autocommand deleted buffer"));
}
- s = get_vim_var_str(VV_FCS_CHOICE);
+ char *s = get_vim_var_str(VV_FCS_CHOICE);
if (strcmp(s, "reload") == 0 && *reason != 'd') {
reload = RELOAD_NORMAL;
} else if (strcmp(s, "edit") == 0) {
@@ -4863,7 +4815,7 @@ int buf_check_timestamp(buf_T *buf)
}
if (mesg != NULL) {
- path = home_replace_save(buf, buf->b_fname);
+ char *path = home_replace_save(buf, buf->b_fname);
if (!helpmesg) {
mesg2 = "";
}
@@ -4946,8 +4898,6 @@ int buf_check_timestamp(buf_T *buf)
void buf_reload(buf_T *buf, int orig_mode, bool reload_options)
{
exarg_T ea;
- pos_T old_cursor;
- linenr_T old_topline;
int old_ro = buf->b_p_ro;
buf_T *savebuf;
bufref_T bufref;
@@ -4967,8 +4917,8 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options)
prep_exarg(&ea, buf);
}
- old_cursor = curwin->w_cursor;
- old_topline = curwin->w_topline;
+ pos_T old_cursor = curwin->w_cursor;
+ linenr_T old_topline = curwin->w_topline;
if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) {
// Save all the text, so that the reload can be undone.
@@ -5454,24 +5404,19 @@ bool match_file_pat(char *pattern, regprog_T **prog, char *fname, char *sfname,
bool match_file_list(char *list, char *sfname, char *ffname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{
- char buf[100];
- char *tail;
- char *regpat;
- char allow_dirs;
- bool match;
- char *p;
-
- tail = path_tail(sfname);
+ char *tail = path_tail(sfname);
// try all patterns in 'wildignore'
- p = list;
+ char *p = list;
while (*p) {
+ char buf[100];
copy_option_part(&p, buf, ARRAY_SIZE(buf), ",");
- regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false);
+ char allow_dirs;
+ char *regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false);
if (regpat == NULL) {
break;
}
- match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs);
+ bool match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs);
xfree(regpat);
if (match) {
return true;
@@ -5494,15 +5439,6 @@ bool match_file_list(char *list, char *sfname, char *ffname)
char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs, int no_bslash)
FUNC_ATTR_NONNULL_ARG(1)
{
- const char *endp;
- char *reg_pat;
- const char *p;
- int nested = 0;
- bool add_dollar = true;
-
- if (allow_dirs != NULL) {
- *allow_dirs = false;
- }
if (pat_end == NULL) {
pat_end = pat + strlen(pat);
}
@@ -5511,9 +5447,13 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs
return xstrdup("^$");
}
+ if (allow_dirs != NULL) {
+ *allow_dirs = false;
+ }
+
size_t size = 2; // '^' at start, '$' at end.
- for (p = pat; p < pat_end; p++) {
+ for (const char *p = pat; p < pat_end; p++) {
switch (*p) {
case '*':
case '.':
@@ -5534,7 +5474,7 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs
break;
}
}
- reg_pat = xmalloc(size + 1);
+ char *reg_pat = xmalloc(size + 1);
size_t i = 0;
@@ -5545,14 +5485,16 @@ char *file_pat_to_reg_pat(const char *pat, const char *pat_end, char *allow_dirs
} else {
reg_pat[i++] = '^';
}
- endp = pat_end - 1;
+ const char *endp = pat_end - 1;
+ bool add_dollar = true;
if (endp >= pat && *endp == '*') {
while (endp - pat > 0 && *endp == '*') {
endp--;
}
add_dollar = false;
}
- for (p = pat; *p && nested >= 0 && p <= endp; p++) {
+ int nested = 0;
+ for (const char *p = pat; *p && nested >= 0 && p <= endp; p++) {
switch (*p) {
case '*':
reg_pat[i++] = '.';
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 9c5364e1b1..51554fea22 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -2526,10 +2526,12 @@ static int vgetorpeek(bool advance)
// move cursor left, if possible
if (curwin->w_cursor.col != 0) {
if (curwin->w_wcol > 0) {
- if (did_ai) {
- // We are expecting to truncate the trailing
- // white-space, so find the last non-white
- // character -- webb
+ // After auto-indenting and no text is following,
+ // we are expecting to truncate the trailing
+ // white-space, so find the last non-white
+ // character -- webb
+ if (did_ai
+ && *skipwhite(get_cursor_line_ptr() + curwin->w_cursor.col) == NUL) {
curwin->w_wcol = 0;
ptr = (char_u *)get_cursor_line_ptr();
chartabsize_T cts;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index b8e234981a..387b94533c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -4898,12 +4898,12 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, char *fuzzystr, int *numM
return OK;
}
-void ExpandOldSetting(int *num_file, char ***file)
+void ExpandOldSetting(int *numMatches, char ***matches)
{
char *var = NULL;
- *num_file = 0;
- *file = xmalloc(sizeof(char_u *));
+ *numMatches = 0;
+ *matches = xmalloc(sizeof(char *));
// For a terminal key code expand_option_idx is < 0.
if (expand_option_idx < 0) {
@@ -4936,8 +4936,8 @@ void ExpandOldSetting(int *num_file, char ***file)
}
#endif
- *file[0] = buf;
- *num_file = 1;
+ *matches[0] = buf;
+ *numMatches = 1;
}
/// Get the value for the numeric or string option///opp in a nice format into
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index a5a708600f..5ebff9ed77 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -615,7 +615,7 @@ char *check_stl_option(char *s)
continue;
}
if (vim_strchr(STL_ALL, (uint8_t)(*s)) == NULL) {
- return illegal_char(errbuf, sizeof(errbuf), *s);
+ return illegal_char(errbuf, sizeof(errbuf), (uint8_t)(*s));
}
if (*s == '{') {
bool reevaluate = (*++s == '%');
@@ -957,7 +957,7 @@ static void did_set_comments(char **varp, char *errbuf, size_t errbuflen, char *
while (*s && *s != ':') {
if (vim_strchr(COM_ALL, (uint8_t)(*s)) == NULL
&& !ascii_isdigit(*s) && *s != '-') {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
s++;
@@ -1029,7 +1029,7 @@ static void did_set_shada(vimoption_T **opt, int *opt_idx, bool *free_oldval, ch
for (char *s = p_shada; *s;) {
// Check it's a valid character
if (vim_strchr("!\"%'/:<@cfhnrs", (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
if (*s == 'n') { // name is always last one
@@ -1236,7 +1236,7 @@ static void did_set_complete(char **varp, char *errbuf, size_t errbuflen, char *
break;
}
if (vim_strchr(".wbuksid]tU", (uint8_t)(*s)) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
if (*++s != NUL && *s != ',' && *s != ' ') {
@@ -1497,12 +1497,12 @@ static void did_set_vartabstop(buf_T *buf, win_T *win, char **varp, char **errms
}
}
-static void did_set_optexpr(win_T *win, char **p_opt, char **varp, char **gvarp)
+static void did_set_optexpr(char **varp)
{
- char *name = get_scriptlocal_funcname(*p_opt);
+ char *name = get_scriptlocal_funcname(*varp);
if (name != NULL) {
- free_string_option(*p_opt);
- *p_opt = name;
+ free_string_option(*varp);
+ *varp = name;
}
}
@@ -1511,8 +1511,8 @@ static void did_set_option_listflag(char **varp, char *flags, char *errbuf, size
char **errmsg)
{
for (char *s = *varp; *s; s++) {
- if (vim_strchr(flags, *s) == NULL) {
- *errmsg = illegal_char(errbuf, errbuflen, *s);
+ if (vim_strchr(flags, (uint8_t)(*s)) == NULL) {
+ *errmsg = illegal_char(errbuf, errbuflen, (uint8_t)(*s));
break;
}
}
@@ -1808,23 +1808,18 @@ static char *did_set_string_option_for(buf_T *buf, win_T *win, int opt_idx, char
did_set_varsoftabstop(buf, varp, &errmsg);
} else if (varp == &buf->b_p_vts) { // 'vartabstop'
did_set_vartabstop(buf, win, varp, &errmsg);
- } else if (varp == &p_dex) { // 'diffexpr'
- did_set_optexpr(win, &p_dex, varp, gvarp);
- } else if (varp == &win->w_p_fde) { // 'foldexpr'
- did_set_optexpr(win, &win->w_p_fde, varp, gvarp);
- if (foldmethodIsExpr(win)) {
+ } else if (varp == &p_dex // 'diffexpr'
+ || gvarp == &win->w_allbuf_opt.wo_fde // 'foldexpr'
+ || gvarp == &win->w_allbuf_opt.wo_fdt // 'foldtext'
+ || gvarp == &p_fex // 'formatexpr'
+ || gvarp == &p_inex // 'includeexpr'
+ || gvarp == &p_inde // 'indentexpr'
+ || varp == &p_pex // 'patchexpr'
+ || varp == &p_ccv) { // 'charconvert'
+ did_set_optexpr(varp);
+ if (varp == &win->w_p_fde && foldmethodIsExpr(win)) {
foldUpdateAll(win);
}
- } else if (varp == &win->w_p_fdt) { // 'foldtext'
- did_set_optexpr(win, &win->w_p_fdt, varp, gvarp);
- } else if (varp == &p_pex) { // 'patchexpr'
- did_set_optexpr(win, &p_pex, varp, gvarp);
- } else if (gvarp == &p_fex) { // 'formatexpr'
- did_set_optexpr(win, &buf->b_p_fex, varp, gvarp);
- } else if (gvarp == &p_inex) { // 'includeexpr'
- did_set_optexpr(win, &buf->b_p_inex, varp, gvarp);
- } else if (gvarp == &p_inde) { // 'indentexpr'
- did_set_optexpr(win, &buf->b_p_inde, varp, gvarp);
} else if (gvarp == &p_cfu) { // 'completefunc'
set_completefunc_option(&errmsg);
} else if (gvarp == &p_ofu) { // 'omnifunc'
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 513f366a27..e4c2253357 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1138,7 +1138,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl
if (flags & EW_ADDSLASH) {
glob_flags |= WILD_ADD_SLASH;
}
- globpath(paths, pattern, gap, glob_flags);
+ globpath(paths, pattern, gap, glob_flags, false);
xfree(paths);
return gap->ga_len;
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index 24500b80b9..b071e10cf9 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -26,6 +26,7 @@
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext.h"
#include "nvim/globals.h"
@@ -208,29 +209,56 @@ void runtime_init(void)
uv_mutex_init(&runtime_search_path_mutex);
}
-/// ":runtime [what] {name}"
+/// Get DIP_ flags from the [where] argument of a :runtime command.
+/// "*argp" is advanced to after the [where] argument.
+static int get_runtime_cmd_flags(char **argp, size_t where_len)
+{
+ char *arg = *argp;
+
+ if (where_len == 0) {
+ return 0;
+ }
+
+ if (strncmp(arg, "START", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_START + DIP_NORTP;
+ }
+ if (strncmp(arg, "OPT", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_OPT + DIP_NORTP;
+ }
+ if (strncmp(arg, "PACK", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_START + DIP_OPT + DIP_NORTP;
+ }
+ if (strncmp(arg, "ALL", where_len) == 0) {
+ *argp = skipwhite(arg + where_len);
+ return DIP_START + DIP_OPT;
+ }
+
+ return 0;
+}
+
+/// ":runtime [where] {name}"
void ex_runtime(exarg_T *eap)
{
char *arg = eap->arg;
- char *p = skiptowhite(arg);
- size_t len = (size_t)(p - arg);
int flags = eap->forceit ? DIP_ALL : 0;
+ char *p = skiptowhite(arg);
+ flags += get_runtime_cmd_flags(&arg, (size_t)(p - arg));
+ source_runtime(arg, flags);
+}
- if (strncmp(arg, "START", len) == 0) {
- flags += DIP_START + DIP_NORTP;
- arg = skipwhite(arg + len);
- } else if (strncmp(arg, "OPT", len) == 0) {
- flags += DIP_OPT + DIP_NORTP;
- arg = skipwhite(arg + len);
- } else if (strncmp(arg, "PACK", len) == 0) {
- flags += DIP_START + DIP_OPT + DIP_NORTP;
- arg = skipwhite(arg + len);
- } else if (strncmp(arg, "ALL", len) == 0) {
- flags += DIP_START + DIP_OPT;
- arg = skipwhite(arg + len);
- }
+static int runtime_expand_flags;
- source_runtime(arg, flags);
+/// Set the completion context for the :runtime command.
+void set_context_in_runtime_cmd(expand_T *xp, const char *arg)
+{
+ char *p = skiptowhite(arg);
+ runtime_expand_flags
+ = *p != NUL ? get_runtime_cmd_flags((char **)&arg, (size_t)(p - arg)) : 0;
+ xp->xp_context = EXPAND_RUNTIME;
+ xp->xp_pattern = (char *)arg;
}
static void source_callback(char *fname, void *cookie)
@@ -1175,102 +1203,154 @@ void ex_packadd(exarg_T *eap)
}
}
-/// Expand color scheme, compiler or filetype names.
-/// Search from 'runtimepath':
-/// 'runtimepath'/{dirnames}/{pat}.(vim|lua)
-/// When "flags" has DIP_START: search also from "start" of 'packpath':
-/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua)
-/// When "flags" has DIP_OPT: search also from "opt" of 'packpath':
-/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua)
-/// "dirnames" is an array with one or more directory names.
-int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[])
+static void ExpandRTDir_int(char *pat, size_t pat_len, int flags, bool keep_ext, garray_T *gap,
+ char *dirnames[])
{
- *num_file = 0;
- *file = NULL;
- size_t pat_len = strlen(pat);
-
- garray_T ga;
- ga_init(&ga, (int)sizeof(char *), 10);
-
// TODO(bfredl): this is bullshit, expandpath should not reinvent path logic.
for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 16;
- char *s = xmalloc(size);
- snprintf(s, size, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat);
- globpath(p_rtp, s, &ga, 0);
- xfree(s);
- }
+ const size_t buf_len = strlen(dirnames[i]) + pat_len + 31;
+ char *const buf = xmalloc(buf_len);
+ char *const tail = buf + 15;
+ const size_t tail_buflen = buf_len - 15;
+ int glob_flags = 0;
+ bool expand_dirs = false;
+
+ if (*dirnames[i] == NUL) { // empty dir used for :runtime
+ snprintf(tail, tail_buflen, "%s*.\\(vim\\|lua\\)", pat);
+ } else {
+ snprintf(tail, tail_buflen, "%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat);
+ }
- if (flags & DIP_START) {
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 31;
- char *s = xmalloc(size);
- snprintf(s, size, "pack/*/start/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+expand:
+ if ((flags & DIP_NORTP) == 0) {
+ globpath(p_rtp, tail, gap, glob_flags, expand_dirs);
}
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 31;
- char *s = xmalloc(size);
- snprintf(s, size, "start/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+ if (flags & DIP_START) {
+ memcpy(tail - 15, "pack/*/start/*/", 15); // NOLINT
+ globpath(p_pp, tail - 15, gap, glob_flags, expand_dirs);
+ memcpy(tail - 8, "start/*/", 8); // NOLINT
+ globpath(p_pp, tail - 8, gap, glob_flags, expand_dirs);
}
- }
- if (flags & DIP_OPT) {
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 29;
- char *s = xmalloc(size);
- snprintf(s, size, "pack/*/opt/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+ if (flags & DIP_OPT) {
+ memcpy(tail - 13, "pack/*/opt/*/", 13); // NOLINT
+ globpath(p_pp, tail - 13, gap, glob_flags, expand_dirs);
+ memcpy(tail - 6, "opt/*/", 6); // NOLINT
+ globpath(p_pp, tail - 6, gap, glob_flags, expand_dirs);
}
- for (int i = 0; dirnames[i] != NULL; i++) {
- size_t size = strlen(dirnames[i]) + pat_len + 29;
- char *s = xmalloc(size);
- snprintf(s, size, "opt/*/%s/%s*.\\(vim\\|lua\\)", dirnames[i], pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
- xfree(s);
+ if (*dirnames[i] == NUL && !expand_dirs) {
+ // expand dir names in another round
+ snprintf(tail, tail_buflen, "%s*", pat);
+ glob_flags = WILD_ADD_SLASH;
+ expand_dirs = true;
+ goto expand;
}
+
+ xfree(buf);
}
- for (int i = 0; i < ga.ga_len; i++) {
- char *match = ((char **)ga.ga_data)[i];
+ int pat_pathsep_cnt = 0;
+ for (size_t i = 0; i < pat_len; i++) {
+ if (vim_ispathsep(pat[i])) {
+ pat_pathsep_cnt++;
+ }
+ }
+
+ for (int i = 0; i < gap->ga_len; i++) {
+ char *match = ((char **)gap->ga_data)[i];
char *s = match;
char *e = s + strlen(s);
- if (e - s > 4 && (STRNICMP(e - 4, ".vim", 4) == 0
- || STRNICMP(e - 4, ".lua", 4) == 0)) {
+ if (e - s > 4 && !keep_ext && (STRNICMP(e - 4, ".vim", 4) == 0
+ || STRNICMP(e - 4, ".lua", 4) == 0)) {
e -= 4;
- for (s = e; s > match; MB_PTR_BACK(match, s)) {
- if (vim_ispathsep(*s)) {
- break;
- }
- }
- s++;
*e = NUL;
+ }
+
+ int match_pathsep_cnt = (e > s && e[-1] == '/') ? -1 : 0;
+ for (s = e; s > match; MB_PTR_BACK(match, s)) {
+ if (vim_ispathsep(*s) && ++match_pathsep_cnt > pat_pathsep_cnt) {
+ break;
+ }
+ }
+ s++;
+ if (s != match) {
assert((e - s) + 1 >= 0);
memmove(match, s, (size_t)(e - s) + 1);
}
}
- if (GA_EMPTY(&ga)) {
- return FAIL;
+ if (GA_EMPTY(gap)) {
+ return;
}
// Sort and remove duplicates which can happen when specifying multiple
// directories in dirnames.
- ga_remove_duplicate_strings(&ga);
+ ga_remove_duplicate_strings(gap);
+}
+
+/// Expand color scheme, compiler or filetype names.
+/// Search from 'runtimepath':
+/// 'runtimepath'/{dirnames}/{pat}.(vim|lua)
+/// When "flags" has DIP_START: search also from "start" of 'packpath':
+/// 'packpath'/pack/*/start/*/{dirnames}/{pat}.(vim|lua)
+/// When "flags" has DIP_OPT: search also from "opt" of 'packpath':
+/// 'packpath'/pack/*/opt/*/{dirnames}/{pat}.(vim|lua)
+/// "dirnames" is an array with one or more directory names.
+int ExpandRTDir(char *pat, int flags, int *num_file, char ***file, char *dirnames[])
+{
+ *num_file = 0;
+ *file = NULL;
+
+ garray_T ga;
+ ga_init(&ga, (int)sizeof(char *), 10);
+
+ ExpandRTDir_int(pat, strlen(pat), flags, false, &ga, dirnames);
+
+ if (GA_EMPTY(&ga)) {
+ return FAIL;
+ }
*file = ga.ga_data;
*num_file = ga.ga_len;
return OK;
}
+/// Handle command line completion for :runtime command.
+int expand_runtime_cmd(char *pat, int *numMatches, char ***matches)
+{
+ *numMatches = 0;
+ *matches = NULL;
+
+ garray_T ga;
+ ga_init(&ga, sizeof(char *), 10);
+
+ const size_t pat_len = strlen(pat);
+ char *dirnames[] = { "", NULL };
+ ExpandRTDir_int(pat, pat_len, runtime_expand_flags, true, &ga, dirnames);
+
+ // Try to complete values for [where] argument when none was found.
+ if (runtime_expand_flags == 0) {
+ char *where_values[] = { "START", "OPT", "PACK", "ALL" };
+ for (size_t i = 0; i < ARRAY_SIZE(where_values); i++) {
+ if (strncmp(pat, where_values[i], pat_len) == 0) {
+ GA_APPEND(char *, &ga, xstrdup(where_values[i]));
+ }
+ }
+ }
+
+ if (GA_EMPTY(&ga)) {
+ return FAIL;
+ }
+
+ *matches = ga.ga_data;
+ *numMatches = ga.ga_len;
+ return OK;
+}
+
/// Expand loadplugin names:
-/// 'packpath'/pack/ * /opt/{pat}
+/// 'packpath'/pack/*/opt/{pat}
int ExpandPackAddDir(char *pat, int *num_file, char ***file)
{
garray_T ga;
@@ -1283,9 +1363,9 @@ int ExpandPackAddDir(char *pat, int *num_file, char ***file)
size_t buflen = pat_len + 26;
char *s = xmalloc(buflen);
snprintf(s, buflen, "pack/*/opt/%s*", pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
+ globpath(p_pp, s, &ga, 0, true);
snprintf(s, buflen, "opt/%s*", pat); // NOLINT
- globpath(p_pp, s, &ga, 0);
+ globpath(p_pp, s, &ga, 0, true);
xfree(s);
for (int i = 0; i < ga.ga_len; i++) {
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 197184c181..42618e8924 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2732,55 +2732,57 @@ static int parse_match(char *lbuf, tagptrs_T *tagp)
tagp->tagline = 0;
tagp->command_end = NULL;
- if (retval == OK) {
- // Try to find a kind field: "kind:<kind>" or just "<kind>"
- p = tagp->command;
- if (find_extra(&p) == OK) {
- tagp->command_end = p;
- if (p > tagp->command && p[-1] == '|') {
- tagp->command_end = p - 1; // drop trailing bar
- }
- p += 2; // skip ";\""
- if (*p++ == TAB) {
- // Accept ASCII alphabetic kind characters and any multi-byte
- // character.
- while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
- if (strncmp(p, "kind:", 5) == 0) {
- tagp->tagkind = p + 5;
- } else if (strncmp(p, "user_data:", 10) == 0) {
- tagp->user_data = p + 10;
- } else if (strncmp(p, "line:", 5) == 0) {
- tagp->tagline = atoi(p + 5);
- }
- if (tagp->tagkind != NULL && tagp->user_data != NULL) {
- break;
- }
+ if (retval != OK) {
+ return retval;
+ }
- pc = vim_strchr(p, ':');
- pt = vim_strchr(p, '\t');
- if (pc == NULL || (pt != NULL && pc > pt)) {
- tagp->tagkind = p;
- }
- if (pt == NULL) {
- break;
- }
- p = pt;
- MB_PTR_ADV(p);
+ // Try to find a kind field: "kind:<kind>" or just "<kind>"
+ p = tagp->command;
+ if (find_extra(&p) == OK) {
+ tagp->command_end = p;
+ if (p > tagp->command && p[-1] == '|') {
+ tagp->command_end = p - 1; // drop trailing bar
+ }
+ p += 2; // skip ";\""
+ if (*p++ == TAB) {
+ // Accept ASCII alphabetic kind characters and any multi-byte
+ // character.
+ while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) {
+ if (strncmp(p, "kind:", 5) == 0) {
+ tagp->tagkind = p + 5;
+ } else if (strncmp(p, "user_data:", 10) == 0) {
+ tagp->user_data = p + 10;
+ } else if (strncmp(p, "line:", 5) == 0) {
+ tagp->tagline = atoi(p + 5);
}
+ if (tagp->tagkind != NULL && tagp->user_data != NULL) {
+ break;
+ }
+
+ pc = vim_strchr(p, ':');
+ pt = vim_strchr(p, '\t');
+ if (pc == NULL || (pt != NULL && pc > pt)) {
+ tagp->tagkind = p;
+ }
+ if (pt == NULL) {
+ break;
+ }
+ p = pt;
+ MB_PTR_ADV(p);
}
}
- if (tagp->tagkind != NULL) {
- for (p = tagp->tagkind;
- *p && *p != '\t' && *p != '\r' && *p != '\n';
- MB_PTR_ADV(p)) {}
- tagp->tagkind_end = p;
- }
- if (tagp->user_data != NULL) {
- for (p = tagp->user_data;
- *p && *p != '\t' && *p != '\r' && *p != '\n';
- MB_PTR_ADV(p)) {}
- tagp->user_data_end = p;
- }
+ }
+ if (tagp->tagkind != NULL) {
+ for (p = tagp->tagkind;
+ *p && *p != '\t' && *p != '\r' && *p != '\n';
+ MB_PTR_ADV(p)) {}
+ tagp->tagkind_end = p;
+ }
+ if (tagp->user_data != NULL) {
+ for (p = tagp->user_data;
+ *p && *p != '\t' && *p != '\r' && *p != '\n';
+ MB_PTR_ADV(p)) {}
+ tagp->user_data_end = p;
}
return retval;
}
@@ -3329,86 +3331,88 @@ int get_tags(list_T *list, char *pat, char *buf_fname)
ret = find_tags(pat, &num_matches, &matches,
TAG_REGEXP | TAG_NOIC, MAXCOL, buf_fname);
- if (ret == OK && num_matches > 0) {
- for (i = 0; i < num_matches; i++) {
- int parse_result = parse_match(matches[i], &tp);
+ if (ret != OK || num_matches <= 0) {
+ return ret;
+ }
- // Avoid an unused variable warning in release builds.
- (void)parse_result;
- assert(parse_result == OK);
+ for (i = 0; i < num_matches; i++) {
+ int parse_result = parse_match(matches[i], &tp);
- is_static = test_for_static(&tp);
+ // Avoid an unused variable warning in release builds.
+ (void)parse_result;
+ assert(parse_result == OK);
- // Skip pseudo-tag lines.
- if (strncmp(tp.tagname, "!_TAG_", 6) == 0) {
- xfree(matches[i]);
- continue;
- }
+ is_static = test_for_static(&tp);
+
+ // Skip pseudo-tag lines.
+ if (strncmp(tp.tagname, "!_TAG_", 6) == 0) {
+ xfree(matches[i]);
+ continue;
+ }
- dict = tv_dict_alloc();
- tv_list_append_dict(list, dict);
-
- full_fname = tag_full_fname(&tp);
- if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL
- || add_tag_field(dict, "filename", full_fname, NULL) == FAIL
- || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL
- || add_tag_field(dict, "kind", tp.tagkind,
- tp.tagkind ? tp.tagkind_end : NULL) == FAIL
- || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) {
- ret = FAIL;
- }
-
- xfree(full_fname);
-
- if (tp.command_end != NULL) {
- for (char *p = tp.command_end + 3;
- *p != NUL && *p != '\n' && *p != '\r';
- MB_PTR_ADV(p)) {
- if (p == tp.tagkind
- || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) {
- // skip "kind:<kind>" and "<kind>"
- p = tp.tagkind_end - 1;
- } else if (strncmp(p, "file:", 5) == 0) {
- // skip "file:" (static tag)
- p += 4;
- } else if (!ascii_iswhite(*p)) {
- char *s, *n;
- int len;
-
- // Add extra field as a dict entry. Fields are
- // separated by Tabs.
- n = p;
- while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') {
+ dict = tv_dict_alloc();
+ tv_list_append_dict(list, dict);
+
+ full_fname = tag_full_fname(&tp);
+ if (add_tag_field(dict, "name", tp.tagname, tp.tagname_end) == FAIL
+ || add_tag_field(dict, "filename", full_fname, NULL) == FAIL
+ || add_tag_field(dict, "cmd", tp.command, tp.command_end) == FAIL
+ || add_tag_field(dict, "kind", tp.tagkind,
+ tp.tagkind ? tp.tagkind_end : NULL) == FAIL
+ || tv_dict_add_nr(dict, S_LEN("static"), is_static) == FAIL) {
+ ret = FAIL;
+ }
+
+ xfree(full_fname);
+
+ if (tp.command_end != NULL) {
+ for (char *p = tp.command_end + 3;
+ *p != NUL && *p != '\n' && *p != '\r';
+ MB_PTR_ADV(p)) {
+ if (p == tp.tagkind
+ || (p + 5 == tp.tagkind && strncmp(p, "kind:", 5) == 0)) {
+ // skip "kind:<kind>" and "<kind>"
+ p = tp.tagkind_end - 1;
+ } else if (strncmp(p, "file:", 5) == 0) {
+ // skip "file:" (static tag)
+ p += 4;
+ } else if (!ascii_iswhite(*p)) {
+ char *s, *n;
+ int len;
+
+ // Add extra field as a dict entry. Fields are
+ // separated by Tabs.
+ n = p;
+ while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') {
+ p++;
+ }
+ len = (int)(p - n);
+ if (*p == ':' && len > 0) {
+ s = ++p;
+ while (*p != NUL && (uint8_t)(*p) >= ' ') {
p++;
}
- len = (int)(p - n);
- if (*p == ':' && len > 0) {
- s = ++p;
- while (*p != NUL && (uint8_t)(*p) >= ' ') {
- p++;
- }
- n[len] = NUL;
- if (add_tag_field(dict, n, s, p) == FAIL) {
- ret = FAIL;
- }
- n[len] = ':';
- } else {
- // Skip field without colon.
- while (*p != NUL && (uint8_t)(*p) >= ' ') {
- p++;
- }
+ n[len] = NUL;
+ if (add_tag_field(dict, n, s, p) == FAIL) {
+ ret = FAIL;
}
- if (*p == NUL) {
- break;
+ n[len] = ':';
+ } else {
+ // Skip field without colon.
+ while (*p != NUL && (uint8_t)(*p) >= ' ') {
+ p++;
}
}
+ if (*p == NUL) {
+ break;
+ }
}
}
-
- xfree(matches[i]);
}
- xfree(matches);
+
+ xfree(matches[i]);
}
+ xfree(matches);
return ret;
}
diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh
index 322265737a..3a0a94b6bf 100755
--- a/src/nvim/testdir/runnvim.sh
+++ b/src/nvim/testdir/runnvim.sh
@@ -30,6 +30,9 @@ main() {(
. "$CI_DIR/common/suite.sh"
. "$CI_DIR/common/test.sh"
+ # Redirect XDG_CONFIG_HOME so users local config doesn't interfere
+ export XDG_CONFIG_HOME="$root"
+
export VIMRUNTIME="$root/runtime"
if ! "$nvim_prg" \
-u NONE -i NONE \
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index fd54f77ccb..89a9179e60 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -336,8 +336,23 @@ func Test_edit_11_indentexpr()
endfunc
set indentexpr=s:NewIndentExpr()
call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
set indentexpr=<SID>NewIndentExpr()
call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
+ setlocal indentexpr=
+ setglobal indentexpr=s:NewIndentExpr()
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
+ call assert_equal('', &indentexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ bw!
+ setglobal indentexpr=<SID>NewIndentExpr()
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &g:indentexpr)
+ call assert_equal('', &indentexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ bw!
set indentexpr&
bw!
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 19415286ad..9014948fb4 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -1305,6 +1305,7 @@ func Test_foldexpr_scriptlocal_func()
set foldmethod=expr foldexpr=s:FoldFunc()
redraw!
call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
call assert_equal(1, g:FoldLnum)
set foldmethod& foldexpr=
bw!
@@ -1314,8 +1315,31 @@ func Test_foldexpr_scriptlocal_func()
set foldmethod=expr foldexpr=<SID>FoldFunc()
redraw!
call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
call assert_equal(1, g:FoldLnum)
- set foldmethod& foldexpr=
+ bw!
+ call setline(1, 'abc')
+ setlocal foldmethod& foldexpr&
+ setglobal foldmethod=expr foldexpr=s:FoldFunc()
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
+ call assert_equal('0', &foldexpr)
+ enew!
+ call setline(1, 'abc')
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(1, g:FoldLnum)
+ bw!
+ call setline(1, 'abc')
+ setlocal foldmethod& foldexpr&
+ setglobal foldmethod=expr foldexpr=<SID>FoldFunc()
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &g:foldexpr)
+ call assert_equal('0', &foldexpr)
+ enew!
+ call setline(1, 'abc')
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(1, g:FoldLnum)
+ set foldmethod& foldexpr&
delfunc s:FoldFunc
bw!
endfunc
@@ -1329,25 +1353,53 @@ func Test_foldtext_scriptlocal_func()
new | only
call setline(1, range(50))
let g:FoldTextArgs = []
- set foldmethod=manual
set foldtext=s:FoldText()
norm! 4Gzf4j
redraw!
call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
call assert_equal([4, 8], g:FoldTextArgs)
set foldtext&
bw!
new | only
call setline(1, range(50))
let g:FoldTextArgs = []
- set foldmethod=manual
set foldtext=<SID>FoldText()
norm! 8Gzf4j
redraw!
call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
call assert_equal([8, 12], g:FoldTextArgs)
set foldtext&
bw!
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ setlocal foldtext&
+ setglobal foldtext=s:FoldText()
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
+ call assert_equal('foldtext()', &foldtext)
+ enew!
+ call setline(1, range(50))
+ norm! 12Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([12, 16], g:FoldTextArgs)
+ set foldtext&
+ bw!
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ setlocal foldtext&
+ setglobal foldtext=<SID>FoldText()
+ call assert_equal(expand('<SID>') .. 'FoldText()', &g:foldtext)
+ call assert_equal('foldtext()', &foldtext)
+ enew!
+ call setline(1, range(50))
+ norm! 16Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([16, 20], g:FoldTextArgs)
+ set foldtext&
+ bw!
delfunc s:FoldText
endfunc
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index e369645328..f09dbd72ce 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -234,6 +234,7 @@ func Test_includeexpr_scriptlocal_func()
endfunc
set includeexpr=s:IncludeFunc()
call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
new | only
call setline(1, 'TestFile1')
let g:IncludeFname = ''
@@ -242,11 +243,35 @@ func Test_includeexpr_scriptlocal_func()
bw!
set includeexpr=<SID>IncludeFunc()
call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
new | only
call setline(1, 'TestFile2')
let g:IncludeFname = ''
call assert_fails('normal! gf', 'E447:')
call assert_equal('TestFile2', g:IncludeFname)
+ bw!
+ setlocal includeexpr=
+ setglobal includeexpr=s:IncludeFunc()
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
+ call assert_equal('', &includeexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call setline(1, 'TestFile3')
+ let g:IncludeFname = ''
+ call assert_fails('normal! gf', 'E447:')
+ call assert_equal('TestFile3', g:IncludeFname)
+ bw!
+ setlocal includeexpr=
+ setglobal includeexpr=<SID>IncludeFunc()
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &g:includeexpr)
+ call assert_equal('', &includeexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ call setline(1, 'TestFile4')
+ let g:IncludeFname = ''
+ call assert_fails('normal! gf', 'E447:')
+ call assert_equal('TestFile4', g:IncludeFname)
+ bw!
set includeexpr&
delfunc s:IncludeFunc
bw!
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 7c90b444e5..2aaa1ff830 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -262,6 +262,7 @@ func Test_formatexpr_scriptlocal_func()
endfunc
set formatexpr=s:Format()
call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
@@ -270,6 +271,7 @@ func Test_formatexpr_scriptlocal_func()
bw!
set formatexpr=<SID>Format()
call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
@@ -277,6 +279,7 @@ func Test_formatexpr_scriptlocal_func()
call assert_equal([4, 2], g:FormatArgs)
bw!
let &formatexpr = 's:Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
@@ -284,12 +287,55 @@ func Test_formatexpr_scriptlocal_func()
call assert_equal([6, 2], g:FormatArgs)
bw!
let &formatexpr = '<SID>Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
new | only
call setline(1, range(1, 40))
let g:FormatArgs = []
normal! 8GVjgq
call assert_equal([8, 2], g:FormatArgs)
+ bw!
setlocal formatexpr=
+ setglobal formatexpr=s:Format()
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 10GVjgq
+ call assert_equal([10, 2], g:FormatArgs)
+ bw!
+ setglobal formatexpr=<SID>Format()
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 12GVjgq
+ call assert_equal([12, 2], g:FormatArgs)
+ bw!
+ let &g:formatexpr = 's:Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 14GVjgq
+ call assert_equal([14, 2], g:FormatArgs)
+ bw!
+ let &g:formatexpr = '<SID>Format()'
+ call assert_equal(expand('<SID>') .. 'Format()', &g:formatexpr)
+ call assert_equal('', &formatexpr)
+ new
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 16GVjgq
+ call assert_equal([16, 2], g:FormatArgs)
+ bw!
+ set formatexpr=
delfunc s:Format
bw!
endfunc
diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim
index fcb8b8033b..3121b3b4d1 100644
--- a/src/nvim/testdir/test_packadd.vim
+++ b/src/nvim/testdir/test_packadd.vim
@@ -26,7 +26,7 @@ func Test_packadd()
let rtp_entries = split(rtp, ',')
for entry in rtp_entries
- if entry =~? '\<after\>'
+ if entry =~? '\<after\>'
let first_after_entry = entry
break
endif
@@ -186,15 +186,17 @@ func Test_packadd_symlink_dir2()
exec "silent !rmdir" top2_dir
endfunc
-" Check command-line completion for 'packadd'
+" Check command-line completion for :packadd
func Test_packadd_completion()
let optdir1 = &packpath . '/pack/mine/opt'
let optdir2 = &packpath . '/pack/candidate/opt'
call mkdir(optdir1 . '/pluginA', 'p')
call mkdir(optdir1 . '/pluginC', 'p')
+ call writefile([], optdir1 . '/unrelated')
call mkdir(optdir2 . '/pluginB', 'p')
call mkdir(optdir2 . '/pluginC', 'p')
+ call writefile([], optdir2 . '/unrelated')
let li = []
call feedkeys(":packadd \<Tab>')\<C-B>call add(li, '\<CR>", 't')
@@ -260,9 +262,9 @@ func Test_helptags()
helptags ALL
- let tags1 = readfile(docdir1 . '/tags')
+ let tags1 = readfile(docdir1 . '/tags')
call assert_match('look-here', tags1[0])
- let tags2 = readfile(docdir2 . '/tags')
+ let tags2 = readfile(docdir2 . '/tags')
call assert_match('look-away', tags2[0])
call assert_fails('helptags abcxyz', 'E150:')
@@ -358,4 +360,78 @@ func Test_runtime()
call assert_equal('runstartopt', g:sequence)
endfunc
+func Test_runtime_completion()
+ let rundir = &packpath . '/runtime/Aextra'
+ let startdir = &packpath . '/pack/mine/start/foo/Aextra'
+ let optdir = &packpath . '/pack/mine/opt/bar/Aextra'
+ call mkdir(rundir . '/Arunbaz', 'p')
+ call mkdir(startdir . '/Astartbaz', 'p')
+ call mkdir(optdir . '/Aoptbaz', 'p')
+ call writefile([], rundir . '/../Arunfoo.vim')
+ call writefile([], rundir . '/Arunbar.vim')
+ call writefile([], rundir . '/Aunrelated')
+ call writefile([], rundir . '/../Aunrelated')
+ call writefile([], startdir . '/../Astartfoo.vim')
+ call writefile([], startdir . '/Astartbar.vim')
+ call writefile([], startdir . '/Aunrelated')
+ call writefile([], startdir . '/../Aunrelated')
+ call writefile([], optdir . '/../Aoptfoo.vim')
+ call writefile([], optdir . '/Aoptbar.vim')
+ call writefile([], optdir . '/Aunrelated')
+ call writefile([], optdir . '/../Aunrelated')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ func Check_runtime_completion(arg, arg1, res)
+ call feedkeys(':runtime ' .. a:arg .. "\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"runtime ' .. a:arg1 .. join(a:res), @:)
+ call assert_equal(a:res, getcompletion(a:arg, 'runtime'))
+ endfunc
+
+ call Check_runtime_completion('', '',
+ \ ['Aextra/', 'Arunfoo.vim', 'START', 'OPT', 'PACK', 'ALL'])
+ call Check_runtime_completion('S', '',
+ \ ['START'])
+ call Check_runtime_completion('O', '',
+ \ ['OPT'])
+ call Check_runtime_completion('P', '',
+ \ ['PACK'])
+ call Check_runtime_completion('A', '',
+ \ ['Aextra/', 'Arunfoo.vim', 'ALL'])
+ call Check_runtime_completion('Aextra/', '',
+ \ ['Aextra/Arunbar.vim', 'Aextra/Arunbaz/'])
+
+ call Check_runtime_completion('START ', 'START ',
+ \ ['Aextra/', 'Astartfoo.vim'])
+ call Check_runtime_completion('START A', 'START ',
+ \ ['Aextra/', 'Astartfoo.vim'])
+ call Check_runtime_completion('START Aextra/', 'START ',
+ \ ['Aextra/Astartbar.vim', 'Aextra/Astartbaz/'])
+
+ call Check_runtime_completion('OPT ', 'OPT ',
+ \ ['Aextra/', 'Aoptfoo.vim'])
+ call Check_runtime_completion('OPT A', 'OPT ',
+ \ ['Aextra/', 'Aoptfoo.vim'])
+ call Check_runtime_completion('OPT Aextra/', 'OPT ',
+ \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/'])
+
+ call Check_runtime_completion('PACK ', 'PACK ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('PACK A', 'PACK ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('PACK Aextra/', 'PACK ',
+ \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/',
+ \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/'])
+
+ call Check_runtime_completion('ALL ', 'ALL ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('ALL A', 'ALL ',
+ \ ['Aextra/', 'Aoptfoo.vim', 'Arunfoo.vim', 'Astartfoo.vim'])
+ call Check_runtime_completion('ALL Aextra/', 'ALL ',
+ \ ['Aextra/Aoptbar.vim', 'Aextra/Aoptbaz/',
+ \ 'Aextra/Arunbar.vim', 'Aextra/Arunbaz/',
+ \ 'Aextra/Astartbar.vim', 'Aextra/Astartbaz/'])
+
+ delfunc Check_runtime_completion
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index 0387ef2bd8..75d28c3ec4 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -105,8 +105,8 @@ func Test_tagfiles()
help
let tf = tagfiles()
" Nvim: expectation(s) based on tags in build dir (added to &rtp).
- " Filter out the (non-existing) '../../../runtime/doc/tags'.
- call filter(tf, 'filereadable(v:val)')
+ " Filter out the '../../../runtime/doc/tags'.
+ call filter(tf, 'v:val != "../../../runtime/doc/tags"')
call assert_equal(1, len(tf))
call assert_equal(fnamemodify(expand('$BUILD_DIR/runtime/doc/tags'), ':p:gs?\\?/?'),
\ fnamemodify(tf[0], ':p:gs?\\?/?'))
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index edf92c78ac..b5921b3445 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -77,31 +77,32 @@ static void ga_concat_esc(garray_T *gap, const char *p, int clen)
memmove(buf, p, (size_t)clen);
buf[clen] = NUL;
ga_concat(gap, buf);
- } else {
- switch (*p) {
- case BS:
- ga_concat(gap, "\\b"); break;
- case ESC:
- ga_concat(gap, "\\e"); break;
- case FF:
- ga_concat(gap, "\\f"); break;
- case NL:
- ga_concat(gap, "\\n"); break;
- case TAB:
- ga_concat(gap, "\\t"); break;
- case CAR:
- ga_concat(gap, "\\r"); break;
- case '\\':
- ga_concat(gap, "\\\\"); break;
- default:
- if ((uint8_t)(*p) < ' ' || *p == 0x7f) {
- vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p);
- ga_concat(gap, buf);
- } else {
- ga_append(gap, (uint8_t)(*p));
- }
- break;
+ return;
+ }
+
+ switch (*p) {
+ case BS:
+ ga_concat(gap, "\\b"); break;
+ case ESC:
+ ga_concat(gap, "\\e"); break;
+ case FF:
+ ga_concat(gap, "\\f"); break;
+ case NL:
+ ga_concat(gap, "\\n"); break;
+ case TAB:
+ ga_concat(gap, "\\t"); break;
+ case CAR:
+ ga_concat(gap, "\\r"); break;
+ case '\\':
+ ga_concat(gap, "\\\\"); break;
+ default:
+ if ((uint8_t)(*p) < ' ' || *p == 0x7f) {
+ vim_snprintf(buf, NUMBUFLEN, "\\x%02x", *p);
+ ga_concat(gap, buf);
+ } else {
+ ga_append(gap, (uint8_t)(*p));
}
+ break;
}
}
diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c
index fbea1ccfb7..e30580a748 100644
--- a/src/nvim/textformat.c
+++ b/src/nvim/textformat.c
@@ -736,22 +736,24 @@ void check_auto_format(bool end_insert)
int c = ' ';
int cc;
- if (did_add_space) {
- cc = gchar_cursor();
- if (!WHITECHAR(cc)) {
- // Somehow the space was removed already.
+ if (!did_add_space) {
+ return;
+ }
+
+ cc = gchar_cursor();
+ if (!WHITECHAR(cc)) {
+ // Somehow the space was removed already.
+ did_add_space = false;
+ } else {
+ if (!end_insert) {
+ inc_cursor();
+ c = gchar_cursor();
+ dec_cursor();
+ }
+ if (c != NUL) {
+ // The space is no longer at the end of the line, delete it.
+ del_char(false);
did_add_space = false;
- } else {
- if (!end_insert) {
- inc_cursor();
- c = gchar_cursor();
- dec_cursor();
- }
- if (c != NUL) {
- // The space is no longer at the end of the line, delete it.
- del_char(false);
- did_add_space = false;
- }
}
}
}
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 2b0bb1d243..0f12c00f15 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -2985,10 +2985,12 @@ void u_saveline(linenr_T lnum)
/// (this is used externally for crossing a line while in insert mode)
void u_clearline(void)
{
- if (curbuf->b_u_line_ptr != NULL) {
- XFREE_CLEAR(curbuf->b_u_line_ptr);
- curbuf->b_u_line_lnum = 0;
+ if (curbuf->b_u_line_ptr == NULL) {
+ return;
}
+
+ XFREE_CLEAR(curbuf->b_u_line_ptr);
+ curbuf->b_u_line_lnum = 0;
}
/// Implementation of the "U" command.
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index 31cb1e8936..ef13f67e49 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -89,6 +89,7 @@ static const char *command_complete[] = {
[EXPAND_SYNTIME] = "syntime",
[EXPAND_SETTINGS] = "option",
[EXPAND_PACKADD] = "packadd",
+ [EXPAND_RUNTIME] = "runtime",
[EXPAND_SHELLCMD] = "shellcmd",
[EXPAND_SIGN] = "sign",
[EXPAND_TAGS] = "tag",
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 417e5116a5..11f1d6695e 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -2785,13 +2785,6 @@ void maybe_intro_message(void)
/// @param colon true for ":intro"
void intro_message(int colon)
{
- int i;
- long row;
- long blanklines;
- int sponsor;
- char *p;
- char *mesg;
- int mesg_size;
static char *(lines[]) = {
N_(NVIM_VERSION_LONG),
"",
@@ -2813,7 +2806,7 @@ void intro_message(int colon)
size_t lines_size = ARRAY_SIZE(lines);
assert(lines_size <= LONG_MAX);
- blanklines = Rows - ((long)lines_size - 1L);
+ long blanklines = Rows - ((long)lines_size - 1L);
// Don't overwrite a statusline. Depends on 'cmdheight'.
if (p_ls > 1) {
@@ -2826,17 +2819,17 @@ void intro_message(int colon)
// Show the sponsor and register message one out of four times, the Uganda
// message two out of four times.
- sponsor = (int)time(NULL);
+ int sponsor = (int)time(NULL);
sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0);
// start displaying the message lines after half of the blank lines
- row = blanklines / 2;
+ long row = blanklines / 2;
if (((row >= 2) && (Columns >= 50)) || colon) {
- for (i = 0; i < (int)ARRAY_SIZE(lines); i++) {
- p = lines[i];
- mesg = NULL;
- mesg_size = 0;
+ for (int i = 0; i < (int)ARRAY_SIZE(lines); i++) {
+ char *p = lines[i];
+ char *mesg = NULL;
+ int mesg_size = 0;
if (strstr(p, "news") != NULL) {
p = _(p);
@@ -2846,18 +2839,15 @@ void intro_message(int colon)
mesg = xmallocz((size_t)mesg_size);
snprintf(mesg, (size_t)mesg_size + 1, p,
STR(NVIM_VERSION_MAJOR), STR(NVIM_VERSION_MINOR));
- }
-
- if (sponsor != 0) {
+ } else if (sponsor != 0) {
if (strstr(p, "children") != NULL) {
- mesg = sponsor < 0
- ? _("Sponsor Vim development!")
- : _("Become a registered Vim user!");
- }
- if (strstr(p, "iccf") != NULL) {
- mesg = sponsor < 0
- ? _("type :help sponsor<Enter> for information ")
- : _("type :help register<Enter> for information ");
+ p = sponsor < 0
+ ? N_("Sponsor Vim development!")
+ : N_("Become a registered Vim user!");
+ } else if (strstr(p, "iccf") != NULL) {
+ p = sponsor < 0
+ ? N_("type :help sponsor<Enter> for information ")
+ : N_("type :help register<Enter> for information ");
}
}
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index c4baa911f1..3c765f8eb2 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -156,6 +156,7 @@ enum {
EXPAND_DIFF_BUFFERS,
EXPAND_BREAKPOINT,
EXPAND_SCRIPTNAMES,
+ EXPAND_RUNTIME,
EXPAND_CHECKHEALTH,
EXPAND_LUA,
};
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 05f84b5a91..6b40ccdb84 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -2599,6 +2599,7 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev
if (!ONE_WINDOW) {
return false;
}
+
buf_T *old_curbuf = curbuf;
Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL;
@@ -4144,12 +4145,13 @@ int may_open_tabpage(void)
{
int n = (cmdmod.cmod_tab == 0) ? postponed_split_tab : cmdmod.cmod_tab;
- if (n != 0) {
- cmdmod.cmod_tab = 0; // reset it to avoid doing it twice
- postponed_split_tab = 0;
- return win_new_tabpage(n, NULL);
+ if (n == 0) {
+ return FAIL;
}
- return FAIL;
+
+ cmdmod.cmod_tab = 0; // reset it to avoid doing it twice
+ postponed_split_tab = 0;
+ return win_new_tabpage(n, NULL);
}
// Create up to "maxcount" tabpages with empty windows.
@@ -4494,11 +4496,12 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le
/// @return true if the tab page is valid, false otherwise.
bool goto_tabpage_lastused(void)
{
- if (valid_tabpage(lastused_tabpage)) {
- goto_tabpage_tp(lastused_tabpage, true, true);
- return true;
+ if (!valid_tabpage(lastused_tabpage)) {
+ return false;
}
- return false;
+
+ goto_tabpage_tp(lastused_tabpage, true, true);
+ return true;
}
// Enter window "wp" in tab page "tp".
@@ -7250,11 +7253,12 @@ static void clear_snapshot(tabpage_T *tp, int idx)
static void clear_snapshot_rec(frame_T *fr)
{
- if (fr != NULL) {
- clear_snapshot_rec(fr->fr_next);
- clear_snapshot_rec(fr->fr_child);
- xfree(fr);
+ if (fr == NULL) {
+ return;
}
+ clear_snapshot_rec(fr->fr_next);
+ clear_snapshot_rec(fr->fr_child);
+ xfree(fr);
}
/// Traverse a snapshot to find the previous curwin.
diff --git a/test/functional/lua/runtime_spec.lua b/test/functional/lua/runtime_spec.lua
index b659f2eacb..884ef3ef8e 100644
--- a/test/functional/lua/runtime_spec.lua
+++ b/test/functional/lua/runtime_spec.lua
@@ -18,6 +18,7 @@ describe('runtime:', function()
io.open(init, 'w'):close() -- touch init file
clear{args = {'-u', init}}
exec('set rtp+=' .. plug_dir)
+ exec('set completeslash=slash')
end)
teardown(function()
@@ -42,6 +43,7 @@ describe('runtime:', function()
write_file(colorscheme_file, [[vim.g.lua_colorscheme = 1]])
eq({'new_colorscheme'}, funcs.getcompletion('new_c', 'color'))
+ eq({'colors/new_colorscheme.lua'}, funcs.getcompletion('colors/new_c', 'runtime'))
exec('colorscheme new_colorscheme')
@@ -71,6 +73,7 @@ describe('runtime:', function()
write_file(compiler_file, [[vim.b.lua_compiler = 1]])
eq({'new_compiler'}, funcs.getcompletion('new_c', 'compiler'))
+ eq({'compiler/new_compiler.lua'}, funcs.getcompletion('compiler/new_c', 'runtime'))
exec('compiler new_compiler')
@@ -100,6 +103,7 @@ describe('runtime:', function()
write_file(ftplugin_file , [[vim.b.lua_ftplugin = 1]])
eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype'))
+ eq({'ftplugin/new-ft.lua'}, funcs.getcompletion('ftplugin/new-f', 'runtime'))
exec [[set filetype=new-ft]]
eq(1, eval('b:lua_ftplugin'))
@@ -116,6 +120,7 @@ describe('runtime:', function()
write_file(indent_file , [[vim.b.lua_indent = 1]])
eq({'new-ft'}, funcs.getcompletion('new-f', 'filetype'))
+ eq({'indent/new-ft.lua'}, funcs.getcompletion('indent/new-f', 'runtime'))
exec [[set filetype=new-ft]]
eq(1, eval('b:lua_indent'))
@@ -152,6 +157,7 @@ describe('runtime:', function()
it('lua syntaxes are included in cmdline completion', function()
eq({'my-lang'}, funcs.getcompletion('my-l', 'filetype'))
eq({'my-lang'}, funcs.getcompletion('my-l', 'syntax'))
+ eq({'syntax/my-lang.lua'}, funcs.getcompletion('syntax/my-l', 'runtime'))
end)
end)
diff --git a/test/functional/vimscript/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua
index 056f67e0ad..da3d61cbe0 100644
--- a/test/functional/vimscript/exepath_spec.lua
+++ b/test/functional/vimscript/exepath_spec.lua
@@ -5,21 +5,21 @@ local command = helpers.command
local exc_exec = helpers.exc_exec
local matches = helpers.matches
local is_os = helpers.is_os
+local set_shell_powershell = helpers.set_shell_powershell
+local eval = helpers.eval
+
+local find_dummies = function(ext_pat)
+ local tmp_path = eval('$PATH')
+ command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
+ matches('null' .. ext_pat, call('exepath', 'null'))
+ matches('true' .. ext_pat, call('exepath', 'true'))
+ matches('false' .. ext_pat, call('exepath', 'false'))
+ command("let $PATH = '"..tmp_path.."'")
+end
describe('exepath()', function()
before_each(clear)
- it('returns 1 for commands in $PATH', function()
- local exe = is_os('win') and 'ping' or 'ls'
- local ext_pat = is_os('win') and '%.EXE$' or '$'
- matches(exe .. ext_pat, call('exepath', exe))
- command('let $PATH = fnamemodify("./test/functional/fixtures/bin", ":p")')
- ext_pat = is_os('win') and '%.CMD$' or '$'
- matches('null' .. ext_pat, call('exepath', 'null'))
- matches('true' .. ext_pat, call('exepath', 'true'))
- matches('false' .. ext_pat, call('exepath', 'false'))
- end)
-
it('fails for invalid values', function()
for _, input in ipairs({'v:null', 'v:true', 'v:false', '{}', '[]'}) do
eq('Vim(call):E1174: String required for argument 1', exc_exec('call exepath('..input..')'))
@@ -32,11 +32,32 @@ describe('exepath()', function()
end)
if is_os('win') then
+ it('returns 1 for commands in $PATH (Windows)', function()
+ local exe = 'ping'
+ matches(exe .. '%.EXE$', call('exepath', exe))
+ end)
+
it('append extension if omitted', function()
local filename = 'cmd'
local pathext = '.exe'
clear({env={PATHEXT=pathext}})
eq(call('exepath', filename..pathext), call('exepath', filename))
end)
+
+ it('returns file WITH extension if files both with and without extension exist in $PATH', function()
+ local ext_pat = '%.CMD$'
+ find_dummies(ext_pat)
+ set_shell_powershell()
+ find_dummies(ext_pat)
+ end)
+ else
+ it('returns 1 for commands in $PATH (not Windows)', function()
+ local exe = 'ls'
+ matches(exe .. '$', call('exepath', exe))
+ end)
+
+ it('returns file WITHOUT extension if files both with and without extension exist in $PATH', function()
+ find_dummies('$')
+ end)
end
end)