Merge branch 'master' into luaviml'/lua

This commit is contained in:
ZyX
2017-04-08 01:54:58 +03:00
207 changed files with 16096 additions and 9169 deletions

6
.gitignore vendored
View File

@@ -39,9 +39,6 @@ tags
# generated by luacheck during `make testlint' # generated by luacheck during `make testlint'
/test/.luacheckcache /test/.luacheckcache
# luarocks, not added as a subtree because of the large number of blobs
/third-party/luarocks
# local make targets # local make targets
local.mk local.mk
@@ -49,6 +46,3 @@ local.mk
/runtime/doc/*.html /runtime/doc/*.html
/runtime/doc/tags.ref /runtime/doc/tags.ref
/runtime/doc/errors.log /runtime/doc/errors.log
# clint errors, generated by `make lint`
/errors.json

View File

@@ -10,7 +10,7 @@ env:
# http://docs.travis-ci.com/user/speeding-up-the-build/#Paralellizing-your-build-on-one-VM # http://docs.travis-ci.com/user/speeding-up-the-build/#Paralellizing-your-build-on-one-VM
- MAKE_CMD="make -j2" - MAKE_CMD="make -j2"
# Update PATH for pip. # Update PATH for pip.
- PATH="$(python2.7 -c 'import site; print(site.getuserbase())')/bin:/usr/lib/llvm-symbolizer-3.8/bin:$PATH" - PATH="$(python2.7 -c 'import site; print(site.getuserbase())')/bin:/usr/lib/llvm-symbolizer-3.9/bin:$PATH"
# Build directory for Neovim. # Build directory for Neovim.
- BUILD_DIR="$TRAVIS_BUILD_DIR/build" - BUILD_DIR="$TRAVIS_BUILD_DIR/build"
# Build directory for third-party dependencies. # Build directory for third-party dependencies.
@@ -50,6 +50,7 @@ env:
- SUCCESS_MARKER="$BUILD_DIR/.tests_successful" - SUCCESS_MARKER="$BUILD_DIR/.tests_successful"
# default target name for functional tests # default target name for functional tests
- FUNCTIONALTEST=functionaltest - FUNCTIONALTEST=functionaltest
- CI_TARGET=tests
matrix: matrix:
include: include:
@@ -68,12 +69,12 @@ matrix:
compiler: gcc-5 -m32 compiler: gcc-5 -m32
env: BUILD_32BIT=ON env: BUILD_32BIT=ON
- os: linux - os: linux
compiler: clang-3.8 compiler: clang-3.9
env: > env: >
CLANG_SANITIZER=ASAN_UBSAN CLANG_SANITIZER=ASAN_UBSAN
CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUAJIT=false" CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUAJIT=false"
- os: linux - os: linux
compiler: clang-3.8 compiler: clang-3.9
env: CLANG_SANITIZER=TSAN env: CLANG_SANITIZER=TSAN
- os: osx - os: osx
compiler: clang compiler: clang
@@ -85,24 +86,24 @@ matrix:
- env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
fast_finish: true fast_finish: true
before_install: .ci/before_install.sh before_install: ci/before_install.sh
install: .ci/install.sh install: ci/install.sh
before_script: .ci/before_script.sh before_script: ci/before_script.sh
script: .ci/script.sh script: ci/script.sh
before_cache: .ci/before_cache.sh before_cache: ci/before_cache.sh
after_success: .ci/after_success.sh after_success: ci/after_success.sh
addons: addons:
apt: apt:
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8 - llvm-toolchain-trusty-3.9
packages: packages:
- autoconf - autoconf
- automake - automake
- apport - apport
- build-essential - build-essential
- clang-3.8 - clang-3.9
- cmake - cmake
- cscope - cscope
- g++-5-multilib - g++-5-multilib
@@ -112,7 +113,7 @@ addons:
- gdb - gdb
- libc6-dev-i386 - libc6-dev-i386
- libtool - libtool
- llvm-3.8-dev - llvm-3.9-dev
- pkg-config - pkg-config
- unzip - unzip
- valgrind - valgrind

View File

@@ -318,6 +318,21 @@ if(NOT PREFER_LUAJIT)
find_package(Lua REQUIRED) find_package(Lua REQUIRED)
endif() endif()
list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}")
check_c_source_compiles("
#include <msgpack.h>
int
main(void)
{
return MSGPACK_OBJECT_FLOAT32;
}
" MSGPACK_HAS_FLOAT32)
if(MSGPACK_HAS_FLOAT32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNVIM_MSGPACK_HAS_FLOAT32")
endif()
if(UNIX) if(UNIX)
option(FEAT_TUI "Enable the Terminal UI" ON) option(FEAT_TUI "Enable the Terminal UI" ON)
else() else()

View File

@@ -126,12 +126,15 @@ distclean: clean
install: | nvim install: | nvim
+$(BUILD_CMD) -C build install +$(BUILD_CMD) -C build install
clint: clint: build/.ran-cmake
$(CMAKE_PRG) -DLINT_PRG=./src/clint.py \ +$(BUILD_CMD) -C build clint
-DLINT_DIR=src \
-DLINT_SUPPRESS_URL="$(DOC_DOWNLOAD_URL_BASE)$(CLINT_ERRORS_FILE_PATH)" \
-P cmake/RunLint.cmake
lint: clint testlint clint-full: build/.ran-cmake
+$(BUILD_CMD) -C build clint-full
check-single-includes: build/.ran-cmake
+$(BUILD_CMD) -C build check-single-includes
lint: check-single-includes clint testlint
.PHONY: test testlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install .PHONY: test testlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install

View File

@@ -43,7 +43,7 @@ Packages are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux], and
Project layout Project layout
-------------- --------------
- `.ci/`: Build server scripts - `ci/`: Build server scripts
- `cmake/`: Build scripts - `cmake/`: Build scripts
- `runtime/`: Application files - `runtime/`: Application files
- [`src/`](src/nvim/README.md): Application source code - [`src/`](src/nvim/README.md): Application source code

View File

@@ -4,9 +4,9 @@ configuration:
- MINGW_32 - MINGW_32
install: [] install: []
build_script: build_script:
- call .ci\build.bat - call ci\build.bat
cache: cache:
- C:\msys64\var\cache\pacman\pkg -> .ci\build.bat - C:\msys64\var\cache\pacman\pkg -> ci\build.bat
- .deps -> third-party/CMakeLists.txt - .deps -> third-party/CMakeLists.txt
artifacts: artifacts:
- path: build/Neovim.zip - path: build/Neovim.zip

View File

@@ -3,7 +3,7 @@
set -e set -e
set -o pipefail set -o pipefail
if [[ -n "${CI_TARGET}" ]]; then if [[ "${CI_TARGET}" == lint ]]; then
exit exit
fi fi

View File

@@ -3,7 +3,7 @@
set -e set -e
set -o pipefail set -o pipefail
if [[ -n "${CI_TARGET}" ]]; then if [[ "${CI_TARGET}" == lint ]]; then
exit exit
fi fi

View File

@@ -1,3 +1,11 @@
top_make() {
${MAKE_CMD} "$@"
}
build_make() {
top_make -C "${BUILD_DIR}" "$@"
}
build_deps() { build_deps() {
if [[ "${BUILD_32BIT}" == ON ]]; then if [[ "${BUILD_32BIT}" == ON ]]; then
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}" DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
@@ -31,7 +39,7 @@ build_deps() {
echo "Configuring with '${DEPS_CMAKE_FLAGS}'." echo "Configuring with '${DEPS_CMAKE_FLAGS}'."
CC= cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/" CC= cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/"
if ! ${MAKE_CMD}; then if ! top_make; then
exit 1 exit 1
fi fi
@@ -54,18 +62,18 @@ prepare_build() {
build_nvim() { build_nvim() {
echo "Building nvim." echo "Building nvim."
if ! ${MAKE_CMD} nvim; then if ! top_make nvim; then
exit 1 exit 1
fi fi
if [ "$CLANG_SANITIZER" != "TSAN" ]; then if [ "$CLANG_SANITIZER" != "TSAN" ]; then
echo "Building libnvim." echo "Building libnvim."
if ! ${MAKE_CMD} libnvim; then if ! top_make libnvim; then
exit 1 exit 1
fi fi
echo "Building nvim-test." echo "Building nvim-test."
if ! ${MAKE_CMD} nvim-test; then if ! top_make nvim-test; then
exit 1 exit 1
fi fi
fi fi

121
ci/common/suite.sh Normal file
View File

@@ -0,0 +1,121 @@
# HACK: get newline for use in strings given that "\n" and $'' do not work.
NL="$(printf '\nE')"
NL="${NL%E}"
FAILED=0
FAIL_SUMMARY=""
enter_suite() {
local suite_name="$1"
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE}/$suite_name"
}
exit_suite() {
if test $FAILED -ne 0 ; then
echo "Suite ${NVIM_TEST_CURRENT_SUITE} failed, summary:"
echo "${FAIL_SUMMARY}"
fi
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE%/*}"
if test "x$1" != "x--continue" ; then
exit $FAILED
fi
}
fail() {
local allow_failure=
if test "x$1" = "x--allow-failure" ; then
shift
allow_failure=A
fi
local test_name="$1"
local fail_char="$allow_failure$2"
local message="$3"
: ${fail_char:=F}
: ${message:=Test $test_name failed}
local full_msg="$fail_char $NVIM_TEST_CURRENT_SUITE|$test_name :: $message"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}"
echo "Failed: $full_msg"
if test "x$allow_failure" = "x" ; then
FAILED=1
fi
}
run_test() {
local cmd="$1"
test $# -gt 0 && shift
local test_name="$1"
: ${test_name:=$cmd}
test $# -gt 0 && shift
if ! eval "$cmd" ; then
fail "${test_name}" "$@"
fi
}
run_test_wd() {
local timeout="$1"
test $# -gt 0 && shift
local cmd="$1"
test $# -gt 0 && shift
local restart_cmd="$1"
: ${restart_cmd:=true}
test $# -gt 0 && shift
local test_name="$1"
: ${test_name:=$cmd}
test $# -gt 0 && shift
local output_file="$(mktemp)"
local status_file="$(mktemp)"
local restarts=5
local prev_tmpsize=-1
while test $restarts -gt 0 ; do
: > "${status_file}"
(
FAILED=0
if ! (
set -o pipefail
eval "$cmd" 2>&1 | tee -a "$output_file"
) ; then
fail "${test_name}" "$@"
fi
echo "$FAILED" > "$status_file"
) &
local pid=$!
while test "$(stat -c "%s" "$status_file")" -eq 0 ; do
prev_tmpsize=$tmpsize
sleep $timeout
tmpsize="$(stat -c "%s" "$output_file")"
if test $tempsize -eq $prev_temsize ; then
# no output, assuming either hang or exit
break
fi
done
restarts=$[ restarts - 1 ]
if test "$(stat -c "%s" "$status_file")" -eq 0 ; then
# status file not updated, assuming hang
kill -KILL $pid
if test $restarts -eq 0 ; then
fail "${test_name}" E "Test hang up"
else
echo "Test ${test_name} hang up, restarting"
eval "$restart_cmd"
fi
else
local new_failed="$(cat "$status_file")"
if test "x$new_failed" != "x0" ; then
fail "${test_name}" F "Test failed in run_test_wd"
fi
return 0
fi
done
}
succeeded() {
return $FAILED
}

View File

@@ -1,3 +1,5 @@
source "${CI_DIR}/common/build.sh"
print_core() { print_core() {
local app="$1" local app="$1"
local core="$2" local core="$2"
@@ -75,7 +77,7 @@ asan_check() {
run_unittests() { run_unittests() {
ulimit -c unlimited ulimit -c unlimited
if ! ${MAKE_CMD} -C "${BUILD_DIR}" unittest ; then if ! build_make unittest ; then
check_core_dumps "$(which luajit)" check_core_dumps "$(which luajit)"
exit 1 exit 1
fi fi
@@ -84,7 +86,7 @@ run_unittests() {
run_functionaltests() { run_functionaltests() {
ulimit -c unlimited ulimit -c unlimited
if ! ${MAKE_CMD} -C "${BUILD_DIR}" ${FUNCTIONALTEST}; then if ! build_make ${FUNCTIONALTEST}; then
asan_check "${LOG_DIR}" asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}" valgrind_check "${LOG_DIR}"
check_core_dumps check_core_dumps
@@ -110,7 +112,7 @@ run_oldtests() {
} }
install_nvim() { install_nvim() {
${MAKE_CMD} -C "${BUILD_DIR}" install build_make install
"${INSTALL_PREFIX}/bin/nvim" --version "${INSTALL_PREFIX}/bin/nvim" --version
"${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' || { "${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' || {

View File

@@ -3,7 +3,7 @@
set -e set -e
set -o pipefail set -o pipefail
if [[ -n "${CI_TARGET}" ]]; then if [[ "${CI_TARGET}" == lint ]]; then
exit exit
fi fi

28
ci/run_lint.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -e
set -o pipefail
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/suite.sh"
enter_suite 'lint'
set -x
csi_clean() {
find "${BUILD_DIR}/bin" -name 'test-includes-*' -delete
find "${BUILD_DIR}" -name '*test-include*.o' -delete
}
run_test 'top_make clint-full' clint
run_test 'top_make testlint' testlint
CLICOLOR_FORCE=1 run_test_wd \
5s \
'top_make check-single-includes' \
'csi_clean' \
single-includes
exit_suite

View File

@@ -6,6 +6,11 @@ set -o pipefail
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/build.sh" source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/test.sh" source "${CI_DIR}/common/test.sh"
source "${CI_DIR}/common/suite.sh"
set -x
enter_suite tests
check_core_dumps --delete quiet check_core_dumps --delete quiet
@@ -15,11 +20,15 @@ build_nvim
if [ "$CLANG_SANITIZER" != "TSAN" ]; then if [ "$CLANG_SANITIZER" != "TSAN" ]; then
# Additional threads are only created when the builtin UI starts, which # Additional threads are only created when the builtin UI starts, which
# doesn't happen in the unit/functional tests # doesn't happen in the unit/functional tests
run_unittests run_test run_unittests
run_functionaltests run_test run_functionaltests
fi fi
run_oldtests run_test run_oldtests
install_nvim run_test install_nvim
touch "${SUCCESS_MARKER}" if succeeded ; then
touch "${SUCCESS_MARKER}"
fi
exit_suite

View File

@@ -3,16 +3,11 @@
set -e set -e
set -o pipefail set -o pipefail
if [[ -n "${CI_TARGET}" ]]; then
make "${CI_TARGET}"
exit 0
fi
# This will pass the environment variables down to a bash process which runs # This will pass the environment variables down to a bash process which runs
# as $USER, while retaining the environment variables defined and belonging # as $USER, while retaining the environment variables defined and belonging
# to secondary groups given above in usermod. # to secondary groups given above in usermod.
if [[ "${TRAVIS_OS_NAME}" == osx ]]; then if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
sudo -E su "${USER}" -c ".ci/run_tests.sh" sudo -E su "${USER}" -c "ci/run_${CI_TARGET}.sh"
else else
.ci/run_tests.sh ci/run_${CI_TARGET}.sh
fi fi

18
cmake/Download.cmake Normal file
View File

@@ -0,0 +1,18 @@
file(
DOWNLOAD "${URL}" "${FILE}"
STATUS status
LOG log
)
list(GET status 0 status_code)
list(GET status 1 status_string)
if(NOT status_code EQUAL 0)
if(NOT ALLOW_FAILURE)
message(FATAL_ERROR "error: downloading '${URL}' failed
status_code: ${status_code}
status_string: ${status_string}
log: ${log}
")
endif()
endif()

View File

@@ -1,32 +0,0 @@
get_filename_component(LINT_DIR ${LINT_DIR} ABSOLUTE)
get_filename_component(LINT_PREFIX ${LINT_DIR} PATH)
set(LINT_SUPPRESS_FILE "${LINT_PREFIX}/errors.json")
if(DEFINED ENV{LINT_FILE})
file(GLOB_RECURSE LINT_FILES "$ENV{LINT_FILE}")
else()
file(GLOB_RECURSE LINT_FILES ${LINT_DIR}/*.c ${LINT_DIR}/*.h)
endif()
set(LINT_ARGS)
if(LINT_SUPPRESS_URL)
file(DOWNLOAD ${LINT_SUPPRESS_URL} ${LINT_SUPPRESS_FILE})
list(APPEND LINT_ARGS "--suppress-errors=${LINT_SUPPRESS_FILE}")
endif()
foreach(lint_file ${LINT_FILES})
file(RELATIVE_PATH lint_file "${LINT_PREFIX}" "${lint_file}")
list(APPEND LINT_ARGS "${lint_file}")
endforeach()
execute_process(
COMMAND ${LINT_PRG} ${LINT_ARGS}
RESULT_VARIABLE res
WORKING_DIRECTORY "${LINT_PREFIX}")
file(REMOVE ${LINT_SUPPRESS_FILE})
if(NOT res EQUAL 0)
message(FATAL_ERROR "Linting failed: ${res}.")
endif()

View File

@@ -25,6 +25,8 @@ if(DEFINED ENV{TEST_FILTER})
set(TEST_TAG "--filter=$ENV{TEST_FILTER}") set(TEST_TAG "--filter=$ENV{TEST_FILTER}")
endif() endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${WORKING_DIR}/Xtest-tmpdir)
set(ENV{TMPDIR} ${WORKING_DIR}/Xtest-tmpdir)
set(ENV{SYSTEM_NAME} ${SYSTEM_NAME}) set(ENV{SYSTEM_NAME} ${SYSTEM_NAME})
execute_process( execute_process(
COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE} COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE}
@@ -37,6 +39,7 @@ execute_process(
file(REMOVE ${WORKING_DIR}/Xtest_rplugin_manifest) file(REMOVE ${WORKING_DIR}/Xtest_rplugin_manifest)
file(REMOVE_RECURSE ${WORKING_DIR}/Xtest_xdg) file(REMOVE_RECURSE ${WORKING_DIR}/Xtest_xdg)
file(REMOVE_RECURSE ${WORKING_DIR}/Xtest-tmpdir)
if(NOT res EQUAL 0) if(NOT res EQUAL 0)
message(STATUS "Output to stderr:\n${err}") message(STATUS "Output to stderr:\n${err}")

View File

@@ -371,27 +371,6 @@ See
Used to set the 'shell' option, which determines the shell used by the Used to set the 'shell' option, which determines the shell used by the
.Ic :terminal .Ic :terminal
command. command.
.It Ev NVIM_TUI_ENABLE_CURSOR_SHAPE
Set to 0 to prevent Nvim from changing the cursor shape.
Set to 1 to enable non-blinking mode-sensitive cursor (this is the default).
Set to 2 to enable blinking mode-sensitive cursor.
Host terminal must support the DECSCUSR CSI escape sequence.
.Pp
Depending on the terminal emulator, using this option with
.Nm
under
.Xr tmux 1
might require adding the following to
.Pa ~/.tmux.conf :
.Bd -literal -offset indent
set -ga terminal-overrides ',*:Ss=\eE[%p1%d q:Se=\eE[2 q'
.Ed
.Pp
See
.Ic terminal-overrides
in the
.Xr tmux 1
manual page for more information.
.El .El
.Sh FILES .Sh FILES
.Bl -tag -width "~/.config/nvim/init.vim" .Bl -tag -width "~/.config/nvim/init.vim"

View File

@@ -8,6 +8,11 @@ function! s:trim(s) abort
return substitute(a:s, '^\_s*\|\_s*$', '', 'g') return substitute(a:s, '^\_s*\|\_s*$', '', 'g')
endfunction endfunction
" Convert '\' to '/'. Collapse '//' and '/./'.
function! s:normalize_path(s) abort
return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g')
endfunction
" Simple version comparison. " Simple version comparison.
function! s:version_cmp(a, b) abort function! s:version_cmp(a, b) abort
let a = split(a:a, '\.', 0) let a = split(a:a, '\.', 0)
@@ -208,7 +213,7 @@ endfunction
" Check the Python interpreter's usability. " Check the Python interpreter's usability.
function! s:check_bin(bin) abort function! s:check_bin(bin) abort
if !filereadable(a:bin) if !filereadable(a:bin) && (!has('win32') || !filereadable(a:bin.'.exe'))
call health#report_error(printf('"%s" was not found.', a:bin)) call health#report_error(printf('"%s" was not found.', a:bin))
return 0 return 0
elseif executable(a:bin) != 1 elseif executable(a:bin) != 1
@@ -287,8 +292,9 @@ function! s:check_python(version) abort
if exists('$PATH') if exists('$PATH')
for path in split($PATH, has('win32') ? ';' : ':') for path in split($PATH, has('win32') ? ';' : ':')
let path_bin = path.'/'.pyname let path_bin = s:normalize_path(path.'/'.pyname)
if path_bin != python_bin && index(python_multiple, path_bin) == -1 if path_bin != s:normalize_path(python_bin)
\ && index(python_multiple, path_bin) == -1
\ && executable(path_bin) \ && executable(path_bin)
call add(python_multiple, path_bin) call add(python_multiple, path_bin)
endif endif

View File

@@ -601,8 +601,8 @@ all files in it are deleted. When Vim has the setuid bit set this may cause
problems, the temp file is owned by the setuid user but the filter command problems, the temp file is owned by the setuid user but the filter command
probably runs as the original user. probably runs as the original user.
Directory for temporary files is created in the first suitable directory of: Directory for temporary files is created in the first suitable directory of:
For Unix: $TMPDIR, /tmp, current-dir, $HOME. Unix: $TMPDIR, /tmp, current-dir, $HOME.
For MS-Windows: $TMP, $TEMP, $USERPROFILE, current-dir. Windows: $TMPDIR, $TMP, $TEMP, $USERPROFILE, current-dir.

View File

@@ -44,6 +44,7 @@ Functions ~
Options ~ Options ~
*'fe'* 'fenc'+'enc' before Vim 6.0; no longer used. *'fe'* 'fenc'+'enc' before Vim 6.0; no longer used.
*'langnoremap'* Deprecated alias to 'nolangremap'.
*'vi'* *'vi'*
*'viminfo'* Deprecated alias to 'shada' option. *'viminfo'* Deprecated alias to 'shada' option.

View File

@@ -3999,6 +3999,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
augroup autocmd groups augroup autocmd groups
buffer buffer names buffer buffer names
behave :behave suboptions behave :behave suboptions
cmdline |cmdline-completion|
color color schemes color color schemes
command Ex command (and arguments) command Ex command (and arguments)
compiler compilers compiler compilers
@@ -4027,7 +4028,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
user user names user user names
var user variables var user variables
If {pat} is an empty string, then all the matches are returned. If {pat} is an empty string then all matches are returned.
Otherwise only items matching {pat} are returned. See Otherwise only items matching {pat} are returned. See
|wildcards| for the use of special characters in {pat}. |wildcards| for the use of special characters in {pat}.
@@ -7918,6 +7919,12 @@ writefile({list}, {fname} [, {flags}])
appended to the file: > appended to the file: >
:call writefile(["foo"], "event.log", "a") :call writefile(["foo"], "event.log", "a")
:call writefile(["bar"], "event.log", "a") :call writefile(["bar"], "event.log", "a")
<
When {flags} contains "S" fsync() call is not used, with "s"
it is used, 'fsync' option applies by default. No fsync()
means that writefile() will finish faster, but writes may be
left in OS buffers and not yet written to disk. Such changes
will disappear if system crashes before OS does writing.
All NL characters are replaced with a NUL character. All NL characters are replaced with a NUL character.
Inserting CR characters needs to be done before passing {list} Inserting CR characters needs to be done before passing {list}

View File

@@ -83,28 +83,6 @@ Recommended place for your personal GUI initializations:
The personal initialization files are searched in the order specified above The personal initialization files are searched in the order specified above
and only the first one that is found is read. and only the first one that is found is read.
There are a number of options which only have meaning in the GUI version of
Vim. These are 'guicursor', 'guifont', and 'guioptions'. They are
documented in |options.txt| with all the other options.
Another way to set the colors for different occasions is with highlight
groups. The "Normal" group is used to set the background and foreground
colors. Example (which looks nice): >
:highlight Normal guibg=grey90
The "guibg" and "guifg" settings override the normal background and
foreground settings. The other settings for the Normal highlight group are
not used. Use the 'guifont' option to set the font.
Also check out the 'guicursor' option, to set the colors for the cursor in
various modes.
Vim tries to make the window fit on the screen when it starts up. This avoids
that you can't see part of it. On the X Window System this requires a bit of
guesswork. You can change the height that is used for the window title and a
task bar with the 'guiheadroom' option.
*:winp* *:winpos* *E188* *:winp* *:winpos* *E188*
:winp[os] :winp[os]
Display current position of the top left corner of the GUI vim Display current position of the top left corner of the GUI vim
@@ -124,21 +102,6 @@ task bar with the 'guiheadroom' option.
:win[size] {width} {height} :win[size] {width} {height}
Set the window height to {width} by {height} characters. Set the window height to {width} by {height} characters.
Obsolete, use ":set lines=11 columns=22". Obsolete, use ":set lines=11 columns=22".
If you get less lines than expected, check the 'guiheadroom'
option.
If you are running the X Window System, you can get information about the
window Vim is running in with these commands: >
:!xwininfo -id $WINDOWID
:!xprop -id $WINDOWID
:execute '!xwininfo -id ' . v:windowid
:execute '!xprop -id ' . v:windowid
<
*gui-IME* *iBus*
Input methods for international characters in X that rely on the XIM
framework, most notably iBus, have been known to produce undesirable results
in gVim. These may include an inability to enter spaces, or long delays
between typing a character and it being recognized by the application.
============================================================================== ==============================================================================
2. Scrollbars *gui-scrollbars* 2. Scrollbars *gui-scrollbars*

View File

@@ -181,11 +181,6 @@ vim.eval(str) *python-eval*
# string.atoi() to convert to # string.atoi() to convert to
# a number. # a number.
:py tagList = vim.eval('taglist("eval_expr")')
< The latter will return a python list of python dicts, for instance:
[{'cmd': '/^eval_expr(arg, nextcmd)$/', 'static': 0, 'name':
'eval_expr', 'kind': 'f', 'filename': './src/eval.c'}]
vim.bindeval(str) *python-bindeval* vim.bindeval(str) *python-bindeval*
Like |python-eval|, but returns special objects described in Like |python-eval|, but returns special objects described in
|python-bindeval-objects|. These python objects let you modify (|List| |python-bindeval-objects|. These python objects let you modify (|List|

View File

@@ -250,23 +250,21 @@ connect to another with different type codes.
============================================================================== ==============================================================================
6. Remote UIs *rpc-remote-ui* 6. Remote UIs *rpc-remote-ui*
Nvim allows Graphical user interfaces to be implemented by separate processes GUIs can be implemented as external processes communicating with Nvim over the
communicating with Nvim over the RPC API. Currently the ui model conists of a RPC API. Currently the UI model consists of a terminal-like grid with one
terminal-like grid with one single, monospace font size, with a few elements single, monospace font size. Some elements (UI "widgets") can be drawn
that could be drawn separately from the grid (for the momemnt only the popup separately from the grid.
menu)
After connecting to a nvim instance (typically a spawned, embedded instance) After connecting to Nvim (usually a spawned, embedded instance) use the
use the |nvim_ui_attach|(width, height, options) API method to tell nvim that your |nvim_ui_attach| API method to tell Nvim that your program wants to draw the
program wants to draw the nvim screen on a grid with "width" times Nvim screen on a grid of width × height cells. `options` must be
"height" cells. "options" should be a dictionary with the following (all a dictionary with these (optional) keys:
optional) keys: `rgb` Controls what color format to use.
`rgb`: Controls what color format to use.
Set to true (default) to use 24-bit rgb Set to true (default) to use 24-bit rgb
colors. colors.
Set to false to use terminal color codes (at Set to false to use terminal color codes (at
most 256 different colors). most 256 different colors).
`popupmenu_external`: Instead of drawing the completion popupmenu on `popupmenu_external` Instead of drawing the completion popupmenu on
the grid, Nvim will send higher-level events to the grid, Nvim will send higher-level events to
the ui and let it draw the popupmenu. the ui and let it draw the popupmenu.
Defaults to false. Defaults to false.

View File

@@ -398,20 +398,6 @@ command, not when assigning a value to an option with ":let".
Note the maximum length of an expanded option is limited. How much depends on Note the maximum length of an expanded option is limited. How much depends on
the system, mostly it is something like 256 or 1024 characters. the system, mostly it is something like 256 or 1024 characters.
*Linux-backspace*
Note about Linux: By default the backspace key
produces CTRL-?, which is wrong. You can fix it by
putting this line in your rc.local: >
echo "keycode 14 = BackSpace" | loadkeys
<
*NetBSD-backspace*
Note about NetBSD: If your backspace doesn't produce
the right code, try this: >
xmodmap -e "keycode 22 = BackSpace"
< If this works, add this in your .Xmodmap file: >
keysym 22 = BackSpace
< You need to restart for this to take effect.
============================================================================== ==============================================================================
2. Automatically setting options *auto-setting* 2. Automatically setting options *auto-setting*
@@ -2754,6 +2740,9 @@ A jump table for the options with a short description can be found at |Q_op|.
mode, so it may be undesirable in some situations. Be warned that mode, so it may be undesirable in some situations. Be warned that
turning this off increases the chances of data loss after a crash. turning this off increases the chances of data loss after a crash.
Currently applies only to writing the buffer with e.g. |:w| and
|writefile()|.
*'gdefault'* *'gd'* *'nogdefault'* *'nogd'* *'gdefault'* *'gd'* *'nogdefault'* *'nogd'*
'gdefault' 'gd' boolean (default off) 'gdefault' 'gd' boolean (default off)
global global
@@ -2804,21 +2793,17 @@ A jump table for the options with a short description can be found at |Q_op|.
i-ci:ver25-Cursor/lCursor, i-ci:ver25-Cursor/lCursor,
r-cr:hor20-Cursor/lCursor, r-cr:hor20-Cursor/lCursor,
sm:block-Cursor sm:block-Cursor
-blinkwait175-blinkoff150-blinkon175", -blinkwait175-blinkoff150-blinkon175")
for Windows console:
"n-v-c:block,o:hor50,i-ci:hor15,
r-cr:hor30,sm:block")
global global
{only available when compiled with GUI enabled, and Configures the cursor style for each mode. Works in the GUI and some
for Windows console} terminals. Unset to disable: >
This option tells Vim what the cursor should look like in different :set guicursor=
modes. It fully works in the GUI. In a Windows console, only <
the height of the cursor can be changed. This can be done by With tmux you might need this in ~/.tmux.conf (see terminal-overrides
specifying a block cursor, or a percentage for a vertical or in the tmux(1) manual page): >
horizontal cursor. set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[2 q'
For a console the 't_SI' and 't_EI' escape sequences are used. <
The option is a comma separated list of parts. Each part consists of a
The option is a comma separated list of parts. Each part consist of a
mode-list and an argument-list: mode-list and an argument-list:
mode-list:argument-list,mode-list:argument-list,.. mode-list:argument-list,mode-list:argument-list,..
The mode-list is a dash separated list of these modes: The mode-list is a dash separated list of these modes:
@@ -2991,18 +2976,6 @@ A jump table for the options with a short description can be found at |Q_op|.
If set and valid, 'guifontwide' is used for IME instead of 'guifont'. If set and valid, 'guifontwide' is used for IME instead of 'guifont'.
*'guiheadroom'* *'ghr'*
'guiheadroom' 'ghr' number (default 50)
global
{only for X11 GUI}
The number of pixels subtracted from the screen height when fitting
the GUI window on the screen. Set this before the GUI is started,
e.g., in your |gvimrc| file. When zero, the whole screen height will
be used by the window. When positive, the specified number of pixel
lines will be left for window decorations and other items on the
screen. Set it to a negative value to allow windows taller than the
screen.
*'guioptions'* *'go'* *'guioptions'* *'go'*
'guioptions' 'go' string (default "egmrLT" (MS-Windows)) 'guioptions' 'go' string (default "egmrLT" (MS-Windows))
global global
@@ -3186,29 +3159,17 @@ A jump table for the options with a short description can be found at |Q_op|.
Think twice when using ":q!" or ":qa!". Think twice when using ":q!" or ":qa!".
*'highlight'* *'hl'* *'highlight'* *'hl'*
'highlight' 'hl' string (default (as a single string): 'highlight' 'hl' string (default: string of "c:group,..." pairs)
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,
Z:TermCursorNC,@:NonText,d:Directory,
e:ErrorMsg,i:IncSearch,l:Search,
m:MoreMsg,M:ModeMsg,n:LineNr,
N:CursorLineNr,r:Question,s:StatusLine,
S:StatusLineNC,c:VertSplit,t:Title,
v:Visual,w:WarningMsg,W:WildMenu,
f:Folded,F:FoldColumn,A:DiffAdd,
C:DiffChange,D:DiffDelete,T:DiffText,
>:SignColumn,B:SpellBad,P:SpellCap,
R:SpellRare,L:SpellLocal,-:Conceal,
+:Pmenu,=:PmenuSel,x:PmenuSbar,
X:PmenuThumb")
global global
This option can be used to set highlighting mode for various This option can be used to set highlighting mode for various
occasions. It is a comma separated list of character pairs. The occasions. It is a comma separated list of character pairs. The
first character in a pair gives the occasion, the second the mode to first character in a pair gives the occasion, the second the mode to
use for that occasion. The occasions are: use for that occasion. The occasions are:
|hl-SpecialKey| 8 Meta and special keys listed with ":map" |hl-SpecialKey| 8 Meta and special keys listed with ":map"
|hl-EndOfBuffer| ~ lines after the last line in the buffer |hl-Whitespace| 0
|hl-EndOfBuffer| ~ lines after the last line in the buffer
|hl-TermCursor| z Cursor in a focused terminal |hl-TermCursor| z Cursor in a focused terminal
|hl-TermCursorNC| Z Cursor in an unfocused terminal |hl-TermCursorNC| Z Cursor in an unfocused terminal
|hl-NonText| @ '@' at the end of the window and |hl-NonText| @ '@' at the end of the window and
characters from 'showbreak' characters from 'showbreak'
|hl-Directory| d directories in CTRL-D listing and other special |hl-Directory| d directories in CTRL-D listing and other special
@@ -3220,11 +3181,11 @@ A jump table for the options with a short description can be found at |Q_op|.
|hl-ModeMsg| M Mode (e.g., "-- INSERT --") |hl-ModeMsg| M Mode (e.g., "-- INSERT --")
|hl-LineNr| n line number for ":number" and ":#" commands, and |hl-LineNr| n line number for ":number" and ":#" commands, and
when 'number' or 'relativenumber' option is set. when 'number' or 'relativenumber' option is set.
|hl-CursorLineNr| N like n for when 'cursorline' or 'relativenumber' is |hl-CursorLineNr| N like n for when 'cursorline' or 'relativenumber' is
set. set.
|hl-Question| r |hit-enter| prompt and yes/no questions |hl-Question| r |hit-enter| prompt and yes/no questions
|hl-StatusLine| s status line of current window |status-line| |hl-StatusLine| s status line of current window |status-line|
|hl-StatusLineNC| S status lines of not-current windows |hl-StatusLineNC| S status lines of not-current windows
|hl-Title| t Titles for output from ":set all", ":autocmd" etc. |hl-Title| t Titles for output from ":set all", ":autocmd" etc.
|hl-VertSplit| c column used to separate vertically split windows |hl-VertSplit| c column used to separate vertically split windows
|hl-Visual| v Visual mode |hl-Visual| v Visual mode
@@ -3248,6 +3209,15 @@ A jump table for the options with a short description can be found at |Q_op|.
|hl-PmenuSbar| x popup menu scrollbar |hl-PmenuSbar| x popup menu scrollbar
|hl-PmenuThumb| X popup menu scrollbar thumb |hl-PmenuThumb| X popup menu scrollbar thumb
|hl-TabLine| *
|hl-TabLineFill| _
|hl-TabLineSel| #
|hl-ColorColumn| o
|hl-CursorColumn| !
|hl-CursorLine| .
|hl-QuickFixLine| q
The display modes are: The display modes are:
r reverse (termcap entry "mr" and "me") r reverse (termcap entry "mr" and "me")
i italic (termcap entry "ZH" and "ZR") i italic (termcap entry "ZH" and "ZR")
@@ -3776,12 +3746,12 @@ A jump table for the options with a short description can be found at |Q_op|.
:source $VIMRUNTIME/menu.vim :source $VIMRUNTIME/menu.vim
< Warning: This deletes all menus that you defined yourself! < Warning: This deletes all menus that you defined yourself!
*'langnoremap'* *'lnr'* *'langremap'* *'lrm'* *'nolangremap'* *'nolrm'*
'langnoremap' 'lnr' boolean (default on) 'langremap' 'lrm' boolean (default off)
global global
When on, setting 'langmap' does not apply to characters resulting from When off, setting 'langmap' does not apply to characters resulting from
a mapping. If setting 'langmap' disables some of your mappings, make a mapping. If setting 'langmap' disables some of your mappings, make
sure this option is set. sure this option is off.
*'laststatus'* *'ls'* *'laststatus'* *'ls'*
'laststatus' 'ls' number (default 2) 'laststatus' 'ls' number (default 2)
@@ -3830,9 +3800,6 @@ A jump table for the options with a short description can be found at |Q_op|.
use this command to get the tallest window possible: > use this command to get the tallest window possible: >
:set lines=999 :set lines=999
< Minimum value is 2, maximum value is 1000. < Minimum value is 2, maximum value is 1000.
If you get less lines than expected, check the 'guiheadroom' option.
When you set this option and Vim is unable to change the physical
number of lines of the display, the display may be messed up.
*'linespace'* *'lsp'* *'linespace'* *'lsp'*
'linespace' 'lsp' number (default 0, 1 for Win32 GUI) 'linespace' 'lsp' number (default 0, 1 for Win32 GUI)
@@ -3932,9 +3899,8 @@ A jump table for the options with a short description can be found at |Q_op|.
:set lcs=tab:>-,trail:- :set lcs=tab:>-,trail:-
:set lcs=tab:>-,eol:<,nbsp:% :set lcs=tab:>-,eol:<,nbsp:%
:set lcs=extends:>,precedes:< :set lcs=extends:>,precedes:<
< The "NonText" highlighting will be used for "eol", "extends" and < |hl-NonText| highlighting will be used for "eol", "extends" and
"precedes". "SpecialKey" for "nbsp", "space", "tab" and "trail". "precedes". |hl-Whitespace| for "nbsp", "space", "tab" and "trail".
|hl-NonText| |hl-SpecialKey|
*'lpl'* *'nolpl'* *'loadplugins'* *'noloadplugins'* *'lpl'* *'nolpl'* *'loadplugins'* *'noloadplugins'*
'loadplugins' 'lpl' boolean (default on) 'loadplugins' 'lpl' boolean (default on)

View File

@@ -715,7 +715,6 @@ Short explanation of each option: *option-list*
'guifont' 'gfn' GUI: Name(s) of font(s) to be used 'guifont' 'gfn' GUI: Name(s) of font(s) to be used
'guifontset' 'gfs' GUI: Names of multi-byte fonts to be used 'guifontset' 'gfs' GUI: Names of multi-byte fonts to be used
'guifontwide' 'gfw' list of font names for double-wide characters 'guifontwide' 'gfw' list of font names for double-wide characters
'guiheadroom' 'ghr' GUI: pixels room for window decorations
'guioptions' 'go' GUI: Which components and options are used 'guioptions' 'go' GUI: Which components and options are used
'guitablabel' 'gtl' GUI: custom label for a tab page 'guitablabel' 'gtl' GUI: custom label for a tab page
'guitabtooltip' 'gtt' GUI: custom tooltip for a tab page 'guitabtooltip' 'gtt' GUI: custom tooltip for a tab page

View File

@@ -4899,32 +4899,28 @@ PmenuThumb Popup menu: Thumb of the scrollbar.
*hl-Question* *hl-Question*
Question |hit-enter| prompt and yes/no questions Question |hit-enter| prompt and yes/no questions
*hl-QuickFixLine* *hl-QuickFixLine*
QuickFixLine The selected |quickfix| item in the quickfix window. QuickFixLine Current |quickfix| item in the quickfix window. Combined with
|hl-CursorLine| is combined with this when the cursor is on |hl-CursorLine| when the cursor is there.
the currently selected quickfix item.
*hl-Search* *hl-Search*
Search Last search pattern highlighting (see 'hlsearch'). Search Last search pattern highlighting (see 'hlsearch').
Also used for highlighting the current line in the quickfix Also used for similar items that need to stand out.
window and similar items that need to stand out.
*hl-SpecialKey* *hl-SpecialKey*
SpecialKey Meta and special keys listed with ":map", also for text used SpecialKey Unprintable characters: text displayed differently from what
to show unprintable characters in the text, 'listchars'. it really is. But not 'listchars' whitespace. |hl-Whitespace|
Generally: text that is displayed differently from what it
really is.
*hl-SpellBad* *hl-SpellBad*
SpellBad Word that is not recognized by the spellchecker. |spell| SpellBad Word that is not recognized by the spellchecker. |spell|
This will be combined with the highlighting used otherwise. Combined with the highlighting used otherwise.
*hl-SpellCap* *hl-SpellCap*
SpellCap Word that should start with a capital. |spell| SpellCap Word that should start with a capital. |spell|
This will be combined with the highlighting used otherwise. Combined with the highlighting used otherwise.
*hl-SpellLocal* *hl-SpellLocal*
SpellLocal Word that is recognized by the spellchecker as one that is SpellLocal Word that is recognized by the spellchecker as one that is
used in another region. |spell| used in another region. |spell|
This will be combined with the highlighting used otherwise. Combined with the highlighting used otherwise.
*hl-SpellRare* *hl-SpellRare*
SpellRare Word that is recognized by the spellchecker as one that is SpellRare Word that is recognized by the spellchecker as one that is
hardly ever used. |spell| hardly ever used. |spell|
This will be combined with the highlighting used otherwise. Combined with the highlighting used otherwise.
*hl-StatusLine* *hl-StatusLine*
StatusLine status line of current window StatusLine status line of current window
*hl-StatusLineNC* *hl-StatusLineNC*
@@ -4943,6 +4939,8 @@ Title titles for output from ":set all", ":autocmd" etc.
Visual Visual mode selection Visual Visual mode selection
*hl-WarningMsg* *hl-WarningMsg*
WarningMsg warning messages WarningMsg warning messages
*hl-Whitespace*
Whitespace "nbsp", "space", "tab" and "trail" in 'listchars'
*hl-WildMenu* *hl-WildMenu*
WildMenu current match in 'wildmenu' completion WildMenu current match in 'wildmenu' completion

View File

@@ -45,7 +45,8 @@ these differences.
- 'history' defaults to 10000 (the maximum) - 'history' defaults to 10000 (the maximum)
- 'hlsearch' is set by default - 'hlsearch' is set by default
- 'incsearch' is set by default - 'incsearch' is set by default
- 'langnoremap' is set by default - 'langnoremap' is enabled by default
- 'langremap' is disabled by default
- 'laststatus' defaults to 2 (statusline is always shown) - 'laststatus' defaults to 2 (statusline is always shown)
- 'listchars' defaults to "tab:> ,trail:-,nbsp:+" - 'listchars' defaults to "tab:> ,trail:-,nbsp:+"
- 'nocompatible' is always set - 'nocompatible' is always set
@@ -112,6 +113,7 @@ Some `CTRL-SHIFT-...` key chords are distinguished from `CTRL-...` variants
Options: Options:
'cpoptions' flags: |cpo-_| 'cpoptions' flags: |cpo-_|
'guicursor' works in the terminal
'inccommand' shows interactive results for |:substitute|-like commands 'inccommand' shows interactive results for |:substitute|-like commands
'statusline' supports unlimited alignment sections 'statusline' supports unlimited alignment sections
'tabline' %@Func@foo%X can call any function on mouse-click 'tabline' %@Func@foo%X can call any function on mouse-click
@@ -145,6 +147,7 @@ Highlight groups:
|hl-Substitute| |hl-Substitute|
|hl-TermCursor| |hl-TermCursor|
|hl-TermCursorNC| |hl-TermCursorNC|
|hl-Whitespace| highlights 'listchars' whitespace
============================================================================== ==============================================================================
4. Changed features *nvim-features-changed* 4. Changed features *nvim-features-changed*

View File

@@ -589,8 +589,6 @@ if has("gui")
call append("$", "toolbariconsize\tsize of toolbar icons") call append("$", "toolbariconsize\tsize of toolbar icons")
call <SID>OptionG("tbis", &tbis) call <SID>OptionG("tbis", &tbis)
endif endif
call append("$", "guiheadroom\troom (in pixels) left above/below the window")
call append("$", " \tset ghr=" . &ghr)
endif endif
if has("browse") if has("browse")
call append("$", "browsedir\t\"last\", \"buffer\" or \"current\": which directory used for the file browser") call append("$", "browsedir\t\"last\", \"buffer\" or \"current\": which directory used for the file browser")

View File

@@ -17,9 +17,11 @@ function! s:GetManifestPath() abort
endif endif
let dest = fnamemodify(expand(dest), ':p') let dest = fnamemodify(expand(dest), ':p')
if !empty(dest) && !filereadable(dest) if !empty(dest)
let dest .= ('/' ==# dest[-1:] ? '' : '/') . 'nvim' let dest .= ('/' ==# dest[-1:] ? '' : '/') . 'nvim'
call mkdir(dest, 'p', 0700) if !isdirectory(dest)
call mkdir(dest, 'p', 0700)
endif
let manifest_base = dest let manifest_base = dest
endif endif

66
scripts/check-includes.py Executable file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python
import sys
import re
import os
from subprocess import Popen, PIPE
from argparse import ArgumentParser
GENERATED_INCLUDE_RE = re.compile(
r'^\s*#\s*include\s*"([/a-z_0-9.]+\.generated\.h)"(\s+//.*)?$')
def main(argv):
argparser = ArgumentParser()
argparser.add_argument('--generated-includes-dir', action='append',
help='Directory where generated includes are located.')
argparser.add_argument('--file', type=open, help='File to check.')
argparser.add_argument('iwyu_args', nargs='*',
help='IWYU arguments, must go after --.')
args = argparser.parse_args(argv)
with args.file:
include_dirs = []
iwyu = Popen(['include-what-you-use', '-xc'] + args.iwyu_args + ['/dev/stdin'],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
for line in args.file:
match = GENERATED_INCLUDE_RE.match(line)
if match:
for d in args.generated_includes_dir:
try:
f = open(os.path.join(d, match.group(1)))
except IOError:
continue
else:
with f:
for generated_line in f:
iwyu.stdin.write(generated_line)
break
else:
raise IOError('Failed to find {0}'.format(match.group(1)))
else:
iwyu.stdin.write(line)
iwyu.stdin.close()
out = iwyu.stdout.read()
err = iwyu.stderr.read()
ret = iwyu.wait()
if ret != 2:
print('IWYU failed with exit code {0}:'.format(ret))
print('{0} stdout {0}'.format('=' * ((80 - len(' stdout ')) // 2)))
print(out)
print('{0} stderr {0}'.format('=' * ((80 - len(' stderr ')) // 2)))
print(err)
return 1
return 0
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))

View File

@@ -321,7 +321,7 @@ list_vim_patches() {
local is_missing local is_missing
local vim_tag local vim_tag
# This fails for untagged commits (e.g., runtime file updates) so mask the return status # This fails for untagged commits (e.g., runtime file updates) so mask the return status
vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" || true vim_tag="$(cd "${VIM_SOURCE_DIR}" && git describe --tags --exact-match "${vim_commit}" 2>/dev/null)" || true
if [[ -n "${vim_tag}" ]]; then if [[ -n "${vim_tag}" ]]; then
local patch_number="${vim_tag:5}" # Remove prefix like "v7.4." local patch_number="${vim_tag:5}" # Remove prefix like "v7.4."
# Tagged Vim patch, check version.c: # Tagged Vim patch, check version.c:

View File

@@ -1,3 +1,3 @@
# multiqueue.h pointer arithmetic is not accepted by asan # multiqueue.h pointer arithmetic is not accepted by asan
fun:multiqueue_node_data fun:multiqueue_node_data
fun:dictwatcher_node_data fun:tv_dict_watcher_node_data

View File

@@ -572,7 +572,8 @@ class _CppLintState(object):
for category, count in self.errors_by_category.items(): for category, count in self.errors_by_category.items():
sys.stderr.write('Category \'%s\' errors found: %d\n' % sys.stderr.write('Category \'%s\' errors found: %d\n' %
(category, count)) (category, count))
sys.stderr.write('Total errors found: %d\n' % self.error_count) if self.error_count:
sys.stderr.write('Total errors found: %d\n' % self.error_count)
def SuppressErrorsFrom(self, fname): def SuppressErrorsFrom(self, fname):
"""Open file and read a list of suppressed errors from it""" """Open file and read a list of suppressed errors from it"""
@@ -2273,11 +2274,14 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
# //!< Header comment # //!< Header comment
# or they begin with multiple slashes followed by a space: # or they begin with multiple slashes followed by a space:
# //////// Header comment # //////// Header comment
# or they are Vim {{{ fold markers
match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or
Search(r'^/$', line[commentend:]) or Search(r'^/$', line[commentend:]) or
Search(r'^!< ', line[commentend:]) or Search(r'^!< ', line[commentend:]) or
Search(r'^/< ', line[commentend:]) or Search(r'^/< ', line[commentend:]) or
Search(r'^/+ ', line[commentend:])) Search(r'^/+ ', line[commentend:]) or
Search(r'^(?:\{{3}|\}{3})\d*(?: |$)',
line[commentend:]))
if not match: if not match:
error(filename, linenum, 'whitespace/comments', 4, error(filename, linenum, 'whitespace/comments', 4,
'Should have a space between // and comment') 'Should have a space between // and comment')
@@ -3580,7 +3584,7 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()
# vim: ts=4 sts=4 sw=4 # vim: ts=4 sts=4 sw=4 foldmarker=▶,▲
# Ignore "too complex" warnings when using pymode. # Ignore "too complex" warnings when using pymode.
# pylama:ignore=C901 # pylama:ignore=C901

View File

@@ -64,7 +64,7 @@ void *je_realloc(void *ptr, size_t size)
// of the memory allocated for item. // of the memory allocated for item.
typedef struct {} dictitem_T; typedef struct {} dictitem_T;
typedef struct {} dict_T; typedef struct {} dict_T;
int dict_add(dict_T *d, dictitem_T *item) int tv_dict_add(dict_T *const d, dictitem_T *const item)
{ {
__coverity_escape__(item); __coverity_escape__(item);
} }

View File

@@ -10,6 +10,7 @@ if(USE_GCOV)
endif() endif()
endif() endif()
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto) set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
set(MSGPACK_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genmsgpack.lua) set(MSGPACK_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genmsgpack.lua)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack) set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
@@ -21,7 +22,6 @@ set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.genera
set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h) set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h)
set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h) set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h)
set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h) set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h)
set(GENERATED_FUNCS_HASH_INPUT ${GENERATED_DIR}/funcs.generated.h.gperf)
set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h) set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h)
set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h) set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h)
set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h) set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h)
@@ -30,29 +30,34 @@ set(EX_CMDS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genex_cmds.lua)
set(FUNCS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/geneval.lua) set(FUNCS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/geneval.lua)
set(EVENTS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gen_events.lua) set(EVENTS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gen_events.lua)
set(OPTIONS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genoptions.lua) set(OPTIONS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genoptions.lua)
set(EVENTS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua)
set(EX_CMDS_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua)
set(EVAL_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/eval.lua)
set(OPTIONS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/options.lua)
set(UNICODE_TABLES_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genunicodetables.lua) set(UNICODE_TABLES_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genunicodetables.lua)
set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/unicode) set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/unicode)
set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h) set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h)
set(VIM_MODULE_FILE ${GENERATED_DIR}/viml/executor/vim_module.generated.h) set(VIM_MODULE_FILE ${GENERATED_DIR}/viml/executor/vim_module.generated.h)
set(VIM_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/src/nvim/viml/executor/vim.lua) set(VIM_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/src/nvim/viml/executor/vim.lua)
set(CHAR_BLOB_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gencharblob.lua) set(CHAR_BLOB_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gencharblob.lua)
set(LINT_SUPPRESS_FILE ${PROJECT_BINARY_DIR}/errors.json)
set(LINT_SUPPRESS_URL_BASE "https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint")
set(LINT_SUPPRESS_URL "${LINT_SUPPRESS_URL_BASE}/errors.json")
set(LINT_PRG ${PROJECT_SOURCE_DIR}/src/clint.py)
set(DOWNLOAD_SCRIPT ${PROJECT_SOURCE_DIR}/cmake/Download.cmake)
set(LINT_SUPPRESSES_ROOT ${PROJECT_BINARY_DIR}/errors)
set(LINT_SUPPRESSES_URL "https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint/errors.tar.gz")
file(GLOB UNICODE_FILES ${UNICODE_DIR}/*.txt)
file(GLOB API_HEADERS api/*.h) file(GLOB API_HEADERS api/*.h)
file(GLOB MSGPACK_RPC_HEADERS msgpack_rpc/*.h) file(GLOB MSGPACK_RPC_HEADERS msgpack_rpc/*.h)
file(GLOB UNICODE_FILES ${UNICODE_DIR}/*.txt)
include_directories(${GENERATED_DIR}) include_directories(${GENERATED_DIR})
include_directories(${CACHED_GENERATED_DIR}) include_directories(${CACHED_GENERATED_DIR})
include_directories(${GENERATED_INCLUDES_DIR}) include_directories(${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${TOUCHES_DIR})
file(MAKE_DIRECTORY ${GENERATED_DIR}) file(MAKE_DIRECTORY ${GENERATED_DIR})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
file(GLOB NEOVIM_SOURCES *.c) file(GLOB NVIM_SOURCES *.c)
file(GLOB NVIM_HEADERS *.h)
foreach(subdir foreach(subdir
os os
@@ -72,18 +77,21 @@ foreach(subdir
file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir}) file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir})
file(GLOB sources ${subdir}/*.c) file(GLOB sources ${subdir}/*.c)
list(APPEND NEOVIM_SOURCES ${sources}) file(GLOB headers ${subdir}/*.h)
list(APPEND NVIM_SOURCES ${sources})
list(APPEND NVIM_HEADERS ${headers})
endforeach() endforeach()
file(GLOB_RECURSE NEOVIM_HEADERS *.h)
file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c) file(GLOB UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
# Sort file lists to ensure generated files are created in the same order from # Sort file lists to ensure generated files are created in the same order from
# build to build. # build to build.
list(SORT NEOVIM_SOURCES) list(SORT NVIM_SOURCES)
list(SORT NEOVIM_HEADERS) list(SORT NVIM_HEADERS)
foreach(sfile ${NEOVIM_SOURCES}) list(APPEND LINT_NVIM_SOURCES ${NVIM_SOURCES} ${NVIM_HEADERS})
foreach(sfile ${NVIM_SOURCES})
get_filename_component(f ${sfile} NAME) get_filename_component(f ${sfile} NAME)
if(${f} MATCHES "^(regexp_nfa.c)$") if(${f} MATCHES "^(regexp_nfa.c)$")
list(APPEND to_remove ${sfile}) list(APPEND to_remove ${sfile})
@@ -93,7 +101,7 @@ foreach(sfile ${NEOVIM_SOURCES})
endif() endif()
endforeach() endforeach()
list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove}) list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
# Legacy files that do not yet pass -Wconversion. # Legacy files that do not yet pass -Wconversion.
set(CONV_SOURCES set(CONV_SOURCES
@@ -117,7 +125,7 @@ set(CONV_SOURCES
window.c) window.c)
foreach(sfile ${CONV_SOURCES}) foreach(sfile ${CONV_SOURCES})
if(NOT EXISTS "${PROJECT_SOURCE_DIR}/src/nvim/${sfile}") if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/${sfile}")
message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)") message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)")
endif() endif()
endforeach() endforeach()
@@ -159,12 +167,24 @@ separate_arguments(C_FLAGS_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS})
separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}}) separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${build_type}})
set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY}) set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY})
foreach(sfile ${NEOVIM_SOURCES} function(get_preproc_output varname iname)
"${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c" if(MSVC)
set(${varname} /P /Fi${iname} PARENT_SCOPE)
else()
set(${varname} -E -o ${iname} PARENT_SCOPE)
endif()
endfunction()
# NVIM_GENERATED_FOR_HEADERS: generated headers to be included in headers
# NVIM_GENERATED_FOR_SOURCES: generated headers to be included in sources
# NVIM_GENERATED_SOURCES: generated source files
# These lists must be mutually exclusive.
foreach(sfile ${NVIM_SOURCES}
"${CMAKE_CURRENT_LIST_DIR}/regexp_nfa.c"
${GENERATED_API_DISPATCH}) ${GENERATED_API_DISPATCH})
get_filename_component(full_d ${sfile} PATH) get_filename_component(full_d ${sfile} PATH)
file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}") file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}")
if(${d} MATCHES "^([.][.]|auto/)") if(${d} MATCHES "^[.][.]|auto/")
file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}") file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
endif() endif()
get_filename_component(f ${sfile} NAME) get_filename_component(f ${sfile} NAME)
@@ -173,26 +193,22 @@ foreach(sfile ${NEOVIM_SOURCES}
set(f "${d}/${f}") set(f "${d}/${f}")
set(r "${d}/${r}") set(r "${d}/${r}")
endif() endif()
set(gf1 "${GENERATED_DIR}/${r}.c.generated.h") set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h")
set(gf2 "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h") set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h")
set(gf3 "${GENERATED_DIR}/${r}.i") set(gf_i "${GENERATED_DIR}/${r}.i")
if(MSVC) get_preproc_output(PREPROC_OUTPUT ${gf_i})
set(PREPROC_OUTPUT /P /Fi${gf3})
else()
set(PREPROC_OUTPUT -E -o ${gf3})
endif()
add_custom_command( add_custom_command(
OUTPUT "${gf1}" "${gf2}" OUTPUT "${gf_c_h}" "${gf_h_h}"
COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} ${C_FLAGS_ARRAY} COMMAND ${CMAKE_C_COMPILER} ${sfile} ${PREPROC_OUTPUT} ${gen_cflags} ${C_FLAGS_ARRAY}
COMMAND "${LUA_PRG}" "${HEADER_GENERATOR}" "${sfile}" "${gf1}" "${gf2}" "${gf3}" COMMAND "${LUA_PRG}" "${HEADER_GENERATOR}" "${sfile}" "${gf_c_h}" "${gf_h_h}" "${gf_i}"
DEPENDS "${HEADER_GENERATOR}" "${sfile}" DEPENDS "${HEADER_GENERATOR}" "${sfile}"
) )
list(APPEND NEOVIM_GENERATED_SOURCES "${gf1}") list(APPEND NVIM_GENERATED_FOR_SOURCES "${gf_c_h}")
list(APPEND NEOVIM_GENERATED_SOURCES "${gf2}") list(APPEND NVIM_GENERATED_FOR_HEADERS "${gf_h_h}")
if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$") if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$")
list(APPEND API_HEADERS ${gf2}) list(APPEND API_HEADERS ${gf_h_h})
endif() endif()
endforeach() endforeach()
@@ -229,23 +245,32 @@ add_custom_command(
${VIM_MODULE_SOURCE} ${VIM_MODULE_SOURCE}
) )
list(APPEND NEOVIM_GENERATED_SOURCES list(APPEND NVIM_GENERATED_SOURCES
"${PROJECT_BINARY_DIR}/config/auto/pathdef.c" "${MSGPACK_LUA_C_BINDINGS}"
"${GENERATED_API_DISPATCH}" )
list(APPEND NVIM_GENERATED_FOR_HEADERS
"${GENERATED_EX_CMDS_ENUM}" "${GENERATED_EX_CMDS_ENUM}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_ENUM}" "${GENERATED_EVENTS_ENUM}"
)
list(APPEND NVIM_GENERATED_FOR_SOURCES
"${GENERATED_API_DISPATCH}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_NAMES_MAP}" "${GENERATED_EVENTS_NAMES_MAP}"
"${GENERATED_OPTIONS}" "${GENERATED_OPTIONS}"
"${GENERATED_UNICODE_TABLES}" "${GENERATED_UNICODE_TABLES}"
"${MSGPACK_LUA_C_BINDINGS}"
"${VIM_MODULE_FILE}" "${VIM_MODULE_FILE}"
) )
list(APPEND NVIM_GENERATED_SOURCES
"${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
)
add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS} add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
COMMAND ${LUA_PRG} ${EX_CMDS_GENERATOR} COMMAND ${LUA_PRG} ${EX_CMDS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR} ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR}
DEPENDS ${EX_CMDS_GENERATOR} ${EX_CMDS_DEFS_FILE} DEPENDS ${EX_CMDS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/ex_cmds.lua
) )
if(NOT GPERF_PRG) if(NOT GPERF_PRG)
@@ -253,26 +278,34 @@ if(NOT GPERF_PRG)
endif() endif()
add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA} add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA}
COMMAND ${LUA_PRG} ${FUNCS_GENERATOR} COMMAND ${LUA_PRG} ${FUNCS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA} ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA}
COMMAND ${GPERF_PRG} COMMAND ${GPERF_PRG}
${GENERATED_FUNCS_HASH_INPUT} --output-file=${GENERATED_FUNCS} ${GENERATED_DIR}/funcs.generated.h.gperf --output-file=${GENERATED_FUNCS}
DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA} DEPENDS ${FUNCS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/eval.lua ${API_METADATA}
) )
list(APPEND NEOVIM_GENERATED_SOURCES list(APPEND NVIM_GENERATED_FOR_SOURCES
"${GENERATED_FUNCS}") "${GENERATED_FUNCS}")
add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
COMMAND ${LUA_PRG} ${EVENTS_GENERATOR} COMMAND ${LUA_PRG} ${EVENTS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${EVENTS_GENERATOR} ${EVENTS_LIST_FILE} DEPENDS ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
) )
add_custom_command(OUTPUT ${GENERATED_OPTIONS} add_custom_command(OUTPUT ${GENERATED_OPTIONS}
COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR} COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_OPTIONS} ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_OPTIONS}
DEPENDS ${OPTIONS_GENERATOR} ${OPTIONS_LIST_FILE} DEPENDS ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/options.lua
) )
# NVIM_GENERATED_FOR_SOURCES and NVIM_GENERATED_FOR_HEADERS must be mutually exclusive.
foreach(hfile ${NVIM_GENERATED_FOR_HEADERS})
list(FIND NVIM_GENERATED_FOR_SOURCES ${hfile} hfile_idx)
if(NOT ${hfile_idx} EQUAL -1)
message(FATAL_ERROR "File included in both NVIM_GENERATED_FOR_HEADERS and NVIM_GENERATED_FOR_SOURCES")
endif()
endforeach()
# Our dependencies come first. # Our dependencies come first.
if (LibIntl_FOUND) if (LibIntl_FOUND)
@@ -315,8 +348,8 @@ if(JEMALLOC_FOUND)
list(APPEND NVIM_EXEC_LINK_LIBRARIES ${JEMALLOC_LIBRARIES}) list(APPEND NVIM_EXEC_LINK_LIBRARIES ${JEMALLOC_LIBRARIES})
endif() endif()
add_executable(nvim ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES} add_executable(nvim ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
${NEOVIM_HEADERS}) ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS})
target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES}) target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES})
install_helper(TARGETS nvim) install_helper(TARGETS nvim)
@@ -374,26 +407,49 @@ if(WIN32)
add_dependencies(nvim_runtime_deps external_blobs) add_dependencies(nvim_runtime_deps external_blobs)
endif() endif()
add_library(libnvim STATIC EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES} add_library(
${NEOVIM_SOURCES} ${NEOVIM_HEADERS}) libnvim
STATIC
EXCLUDE_FROM_ALL
${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
)
set_property(TARGET libnvim APPEND PROPERTY set_property(TARGET libnvim APPEND PROPERTY
INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS}) INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS})
target_link_libraries(libnvim ${NVIM_TEST_LINK_LIBRARIES}) target_link_libraries(libnvim ${NVIM_TEST_LINK_LIBRARIES})
set_target_properties(libnvim PROPERTIES set_target_properties(
POSITION_INDEPENDENT_CODE ON libnvim
OUTPUT_NAME nvim) PROPERTIES
set_property(TARGET libnvim POSITION_INDEPENDENT_CODE ON
APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB ") OUTPUT_NAME nvim
)
set_property(
TARGET libnvim
APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB "
)
add_library(nvim-test MODULE EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES} add_library(
${NEOVIM_SOURCES} ${UNIT_TEST_FIXTURES} ${NEOVIM_HEADERS}) nvim-test
MODULE
EXCLUDE_FROM_ALL
${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
${UNIT_TEST_FIXTURES}
)
target_link_libraries(nvim-test ${NVIM_TEST_LINK_LIBRARIES}) target_link_libraries(nvim-test ${NVIM_TEST_LINK_LIBRARIES})
set_property(TARGET nvim-test APPEND PROPERTY set_property(
INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS}) TARGET nvim-test
set_target_properties(nvim-test PROPERTIES APPEND PROPERTY INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS}
POSITION_INDEPENDENT_CODE ON) )
set_property(TARGET nvim-test set_target_properties(
APPEND_STRING PROPERTY COMPILE_FLAGS " -DUNIT_TESTING ") nvim-test
PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
set_property(
TARGET nvim-test
APPEND_STRING PROPERTY COMPILE_FLAGS " -DUNIT_TESTING "
)
if(CLANG_ASAN_UBSAN) if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.") message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
@@ -419,4 +475,132 @@ elseif(CLANG_TSAN)
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=thread ") set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=thread ")
endif() endif()
function(get_test_target prefix sfile relative_path_var target_var)
get_filename_component(full_d "${sfile}" PATH)
file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}")
if(d MATCHES "^[.][.]")
file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
endif()
get_filename_component(r "${sfile}" NAME)
if(NOT d MATCHES "^[.]?$")
set(r "${d}/${r}")
endif()
string(REGEX REPLACE "[/.]" "-" suffix "${r}")
set(${relative_path_var} ${r} PARENT_SCOPE)
if(prefix STREQUAL "")
set(${target_var} "${suffix}" PARENT_SCOPE)
else()
set(${target_var} "${prefix}-${suffix}" PARENT_SCOPE)
endif()
endfunction()
set(NO_SINGLE_CHECK_HEADERS
cursor_shape.h
digraph.h
ex_cmds.h
ex_getln.h
file_search.h
fold.h
getchar.h
hardcopy.h
if_cscope.h
if_cscope_defs.h
mark.h
mbyte.h
memfile_defs.h
memline.h
memline_defs.h
menu.h
misc2.h
move.h
msgpack_rpc/server.h
ops.h
option.h
os/shell.h
os_unix.h
os/win_defs.h
popupmnu.h
quickfix.h
regexp.h
regexp_defs.h
screen.h
search.h
sha256.h
sign_defs.h
spell.h
spellfile.h
syntax.h
syntax_defs.h
tag.h
terminal.h
tui/tui.h
ugrid.h
ui.h
ui_bridge.h
undo.h
undo_defs.h
version.h
window.h
)
foreach(hfile ${NVIM_HEADERS})
get_test_target(test-includes "${hfile}" relative_path texe)
if(NOT ${hfile} MATCHES "[.]c[.]h$")
set(tsource "${GENERATED_DIR}/${relative_path}.test-include.c")
write_file("${tsource}" "#include \"${hfile}\"\nint main(int argc, char **argv) { return 0; }")
add_executable(
${texe}
EXCLUDE_FROM_ALL
${tsource} ${NVIM_HEADERS} ${NVIM_GENERATED_FOR_HEADERS})
list(FIND NO_SINGLE_CHECK_HEADERS "${relative_path}" hfile_exclude_idx)
if(${hfile_exclude_idx} EQUAL -1)
list(APPEND HEADER_CHECK_TARGETS ${texe})
endif()
endif()
endforeach()
add_custom_target(check-single-includes DEPENDS ${HEADER_CHECK_TARGETS})
function(add_download output url allow_failure)
add_custom_command(
OUTPUT "${output}"
COMMAND
${CMAKE_COMMAND}
-DURL=${url} -DFILE=${output}
-DALLOW_FAILURE=${allow_failure}
-P ${DOWNLOAD_SCRIPT}
DEPENDS ${DOWNLOAD_SCRIPT}
)
endfunction()
add_download(${LINT_SUPPRESS_FILE} ${LINT_SUPPRESS_URL} off)
set(LINT_NVIM_REL_SOURCES)
foreach(sfile ${LINT_NVIM_SOURCES})
get_test_target("" "${sfile}" r suffix)
set(suppress_file ${LINT_SUPPRESSES_ROOT}/${suffix}.json)
set(suppress_url "${LINT_SUPPRESS_URL_BASE}/${suffix}.json")
set(rsfile src/nvim/${r})
add_download(${suppress_file} ${suppress_url} on)
set(touch_file "${TOUCHES_DIR}/ran-clint-${suffix}")
add_custom_command(
OUTPUT ${touch_file}
COMMAND ${LINT_PRG} --suppress-errors=${suppress_file} ${rsfile}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${touch_file}
DEPENDS ${LINT_PRG} ${sfile} ${suppress_file}
)
list(APPEND LINT_TARGETS ${touch_file})
list(APPEND LINT_NVIM_REL_SOURCES ${rsfile})
endforeach()
add_custom_target(clint DEPENDS ${LINT_TARGETS})
add_custom_target(
clint-full
COMMAND
${LINT_PRG} --suppress-errors=${LINT_SUPPRESS_FILE} ${LINT_NVIM_REL_SOURCES}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
DEPENDS ${LINT_PRG} ${LINT_NVIM_SOURCES} ${LINT_SUPPRESS_FILE}
)
add_subdirectory(po) add_subdirectory(po)

View File

@@ -296,7 +296,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
tabpage_T *save_curtab = NULL; tabpage_T *save_curtab = NULL;
size_t new_len = replacement.size; size_t new_len = replacement.size;
size_t old_len = (size_t)(end - start); size_t old_len = (size_t)(end - start);
ssize_t extra = 0; // lines added to text, can be negative ptrdiff_t extra = 0; // lines added to text, can be negative
char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL; char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL;
for (size_t i = 0; i < new_len; i++) { for (size_t i = 0; i < new_len; i++) {
@@ -342,8 +342,8 @@ void nvim_buf_set_lines(uint64_t channel_id,
} }
} }
if ((ssize_t)to_delete > 0) { if (to_delete > 0) {
extra -= (ssize_t)to_delete; extra -= (ptrdiff_t)to_delete;
} }
// For as long as possible, replace the existing old_len with the // For as long as possible, replace the existing old_len with the
@@ -395,10 +395,10 @@ void nvim_buf_set_lines(uint64_t channel_id,
mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra); mark_adjust((linenr_T)start, (linenr_T)(end - 1), MAXLNUM, extra);
} }
changed_lines((linenr_T)start, 0, (linenr_T)end, extra); changed_lines((linenr_T)start, 0, (linenr_T)end, (long)extra);
if (save_curbuf.br_buf == NULL) { if (save_curbuf.br_buf == NULL) {
fix_cursor((linenr_T)start, (linenr_T)end, extra); fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
} }
end: end:

View File

@@ -14,6 +14,7 @@
#include "nvim/window.h" #include "nvim/window.h"
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/map_defs.h" #include "nvim/map_defs.h"
#include "nvim/map.h" #include "nvim/map.h"
#include "nvim/option.h" #include "nvim/option.h"
@@ -87,14 +88,13 @@ bool try_end(Error *err)
/// @param[out] err Details of an error that may have occurred /// @param[out] err Details of an error that may have occurred
Object dict_get_value(dict_T *dict, String key, Error *err) Object dict_get_value(dict_T *dict, String key, Error *err)
{ {
hashitem_T *hi = hash_find(&dict->dv_hashtab, (uint8_t *) key.data); dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (HASHITEM_EMPTY(hi)) { if (di == NULL) {
api_set_error(err, Validation, _("Key not found")); api_set_error(err, Validation, _("Key not found"));
return (Object) OBJECT_INIT; return (Object) OBJECT_INIT;
} }
dictitem_T *di = dict_lookup(hi);
return vim_to_object(&di->di_tv); return vim_to_object(&di->di_tv);
} }
@@ -129,7 +129,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
return rv; return rv;
} }
dictitem_T *di = dict_find(dict, (char_u *)key.data, (int)key.size); dictitem_T *di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size);
if (di != NULL) { if (di != NULL) {
if (di->di_flags & DI_FLAGS_RO) { if (di->di_flags & DI_FLAGS_RO) {
@@ -155,9 +155,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
rv = vim_to_object(&di->di_tv); rv = vim_to_object(&di->di_tv);
} }
// Delete the entry // Delete the entry
hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key); tv_dict_item_remove(dict, di);
hash_remove(&dict->dv_hashtab, hi);
dictitem_free(di);
} }
} else { } else {
// Update the key // Update the key
@@ -170,20 +168,20 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
if (di == NULL) { if (di == NULL) {
// Need to create an entry // Need to create an entry
di = dictitem_alloc((uint8_t *) key.data); di = tv_dict_item_alloc_len(key.data, key.size);
dict_add(dict, di); tv_dict_add(dict, di);
} else { } else {
// Return the old value // Return the old value
if (retval) { if (retval) {
rv = vim_to_object(&di->di_tv); rv = vim_to_object(&di->di_tv);
} }
clear_tv(&di->di_tv); tv_clear(&di->di_tv);
} }
// Update the value // Update the value
copy_tv(&tv, &di->di_tv); tv_copy(&tv, &di->di_tv);
// Clear the temporary variable // Clear the temporary variable
clear_tv(&tv); tv_clear(&tv);
} }
return rv; return rv;
@@ -291,7 +289,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
} }
} }
int opt_flags = (type ? OPT_LOCAL : OPT_GLOBAL); int opt_flags = (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
if (flags & SOPT_BOOL) { if (flags & SOPT_BOOL) {
if (value.type != kObjectTypeBoolean) { if (value.type != kObjectTypeBoolean) {
@@ -627,7 +625,7 @@ String cstr_as_string(char *str) FUNC_ATTR_PURE
if (str == NULL) { if (str == NULL) {
return (String) STRING_INIT; return (String) STRING_INIT;
} }
return (String) {.data = str, .size = strlen(str)}; return (String) { .data = str, .size = strlen(str) };
} }
/// Converts from type Object to a VimL value. /// Converts from type Object to a VimL value.
@@ -682,20 +680,20 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
break; break;
case kObjectTypeArray: { case kObjectTypeArray: {
list_T *list = list_alloc(); list_T *const list = tv_list_alloc();
for (uint32_t i = 0; i < obj.data.array.size; i++) { for (uint32_t i = 0; i < obj.data.array.size; i++) {
Object item = obj.data.array.items[i]; Object item = obj.data.array.items[i];
listitem_T *li = listitem_alloc(); listitem_T *li = tv_list_item_alloc();
if (!object_to_vim(item, &li->li_tv, err)) { if (!object_to_vim(item, &li->li_tv, err)) {
// cleanup // cleanup
listitem_free(li); tv_list_item_free(li);
list_free(list); tv_list_free(list);
return false; return false;
} }
list_append(list, li); tv_list_append(list, li);
} }
list->lv_refcount++; list->lv_refcount++;
@@ -705,7 +703,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
} }
case kObjectTypeDictionary: { case kObjectTypeDictionary: {
dict_T *dict = dict_alloc(); dict_T *const dict = tv_dict_alloc();
for (uint32_t i = 0; i < obj.data.dictionary.size; i++) { for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
KeyValuePair item = obj.data.dictionary.items[i]; KeyValuePair item = obj.data.dictionary.items[i];
@@ -715,20 +713,20 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
api_set_error(err, Validation, api_set_error(err, Validation,
_("Empty dictionary keys aren't allowed")); _("Empty dictionary keys aren't allowed"));
// cleanup // cleanup
dict_free(dict); tv_dict_free(dict);
return false; return false;
} }
dictitem_T *di = dictitem_alloc((uint8_t *)key.data); dictitem_T *const di = tv_dict_item_alloc(key.data);
if (!object_to_vim(item.value, &di->di_tv, err)) { if (!object_to_vim(item.value, &di->di_tv, err)) {
// cleanup // cleanup
dictitem_free(di); tv_dict_item_free(di);
dict_free(dict); tv_dict_free(dict);
return false; return false;
} }
dict_add(dict, di); tv_dict_add(dict, di);
} }
dict->dv_refcount++; dict->dv_refcount++;
@@ -962,11 +960,7 @@ static void set_option_value_err(char *key,
{ {
char *errmsg; char *errmsg;
if ((errmsg = (char *)set_option_value((uint8_t *)key, if ((errmsg = set_option_value(key, numval, stringval, opt_flags))) {
numval,
(uint8_t *)stringval,
opt_flags)))
{
if (try_end(err)) { if (try_end(err)) {
return; return;
} }

View File

@@ -12,6 +12,7 @@
#include "nvim/api/private/defs.h" #include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h" #include "nvim/api/private/helpers.h"
#include "nvim/popupmnu.h" #include "nvim/popupmnu.h"
#include "nvim/cursor_shape.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/ui.c.generated.h" # include "api/ui.c.generated.h"
@@ -69,6 +70,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->clear = remote_ui_clear; ui->clear = remote_ui_clear;
ui->eol_clear = remote_ui_eol_clear; ui->eol_clear = remote_ui_eol_clear;
ui->cursor_goto = remote_ui_cursor_goto; ui->cursor_goto = remote_ui_cursor_goto;
ui->cursor_style_set = remote_ui_cursor_style_set;
ui->update_menu = remote_ui_update_menu; ui->update_menu = remote_ui_update_menu;
ui->busy_start = remote_ui_busy_start; ui->busy_start = remote_ui_busy_start;
ui->busy_stop = remote_ui_busy_stop; ui->busy_stop = remote_ui_busy_stop;
@@ -298,6 +300,14 @@ static void remote_ui_scroll(UI *ui, int count)
push_call(ui, "scroll", args); push_call(ui, "scroll", args);
} }
static void remote_ui_cursor_style_set(UI *ui, bool enabled, Dictionary data)
{
Array args = ARRAY_DICT_INIT;
ADD(args, BOOLEAN_OBJ(enabled));
ADD(args, copy_object(DICTIONARY_OBJ(data)));
push_call(ui, "cursor_style_set", args);
}
static void remote_ui_highlight_set(UI *ui, HlAttrs attrs) static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
{ {
Array args = ARRAY_DICT_INIT; Array args = ARRAY_DICT_INIT;

View File

@@ -22,6 +22,7 @@
#include "nvim/memory.h" #include "nvim/memory.h"
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/option.h" #include "nvim/option.h"
#include "nvim/syntax.h" #include "nvim/syntax.h"
#include "nvim/getchar.h" #include "nvim/getchar.h"
@@ -181,19 +182,20 @@ Object nvim_eval(String expr, Error *err)
Object rv = OBJECT_INIT; Object rv = OBJECT_INIT;
// Evaluate the expression // Evaluate the expression
try_start(); try_start();
typval_T *expr_result = eval_expr((char_u *)expr.data, NULL);
if (!expr_result) { typval_T rettv;
api_set_error(err, Exception, _("Failed to evaluate expression")); if (eval0((char_u *)expr.data, &rettv, NULL, true) == FAIL) {
api_set_error(err, Exception, "Failed to evaluate expression");
} }
if (!try_end(err)) { if (!try_end(err)) {
// No errors, convert the result // No errors, convert the result
rv = vim_to_object(expr_result); rv = vim_to_object(&rettv);
} }
// Free the vim object // Free the Vim object
free_tv(expr_result); tv_clear(&rettv);
return rv; return rv;
} }
@@ -238,11 +240,11 @@ Object nvim_call_function(String fname, Array args, Error *err)
if (!try_end(err)) { if (!try_end(err)) {
rv = vim_to_object(&rettv); rv = vim_to_object(&rettv);
} }
clear_tv(&rettv); tv_clear(&rettv);
free_vim_args: free_vim_args:
while (i > 0) { while (i > 0) {
clear_tv(&vim_args[--i]); tv_clear(&vim_args[--i]);
} }
return rv; return rv;
@@ -439,7 +441,7 @@ Object nvim_get_vvar(String name, Error *err)
/// ///
/// @param name Option name /// @param name Option name
/// @param[out] err Error details, if any /// @param[out] err Error details, if any
/// @return Option value /// @return Option value (global)
Object nvim_get_option(String name, Error *err) Object nvim_get_option(String name, Error *err)
FUNC_API_SINCE(1) FUNC_API_SINCE(1)
{ {

View File

@@ -8,9 +8,11 @@
// Definitions of various common control characters. // Definitions of various common control characters.
#define CharOrd(x) ((x) < 'a' ? (x) - 'A' : (x) - 'a') #define CharOrd(x) ((uint8_t)(x) < 'a' \
#define CharOrdLow(x) ((x) - 'a') ? (uint8_t)(x) - 'A'\
#define CharOrdUp(x) ((x) - 'A') : (uint8_t)(x) - 'a')
#define CharOrdLow(x) ((uint8_t)(x) - 'a')
#define CharOrdUp(x) ((uint8_t)(x) - 'A')
#define ROT13(c, a) (((((c) - (a)) + 13) % 26) + (a)) #define ROT13(c, a) (((((c) - (a)) + 13) % 26) + (a))
#define NUL '\000' #define NUL '\000'
@@ -18,15 +20,14 @@
#define BS '\010' #define BS '\010'
#define TAB '\011' #define TAB '\011'
#define NL '\012' #define NL '\012'
#define NL_STR (char_u *)"\012" #define NL_STR "\012"
#define FF '\014' #define FF '\014'
#define CAR '\015' /* CR is used by Mac OS X */ #define CAR '\015' /* CR is used by Mac OS X */
#define ESC '\033' #define ESC '\033'
#define ESC_STR (char_u *)"\033" #define ESC_STR "\033"
#define ESC_STR_nc "\033"
#define DEL 0x7f #define DEL 0x7f
#define DEL_STR (char_u *)"\177" #define DEL_STR "\177"
#define CSI 0x9b /* Control Sequence Introducer */ #define CSI 0x9b // Control Sequence Introducer
#define CSI_STR "\233" #define CSI_STR "\233"
#define DCS 0x90 /* Device Control String */ #define DCS 0x90 /* Device Control String */
#define STERM 0x9c /* String Terminator */ #define STERM 0x9c /* String Terminator */

View File

@@ -627,10 +627,11 @@ void buf_freeall(buf_T *buf, int flags)
*/ */
if (buf == curbuf && !is_curbuf) if (buf == curbuf && !is_curbuf)
return; return;
diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */ diff_buf_delete(buf); // Can't use 'diff' for unloaded buffer.
/* Remove any ownsyntax, unless exiting. */ // Remove any ownsyntax, unless exiting.
if (firstwin != NULL && curwin->w_buffer == buf) if (curwin != NULL && curwin->w_buffer == buf) {
reset_synblock(curwin); reset_synblock(curwin);
}
/* No folds in an empty buffer. */ /* No folds in an empty buffer. */
FOR_ALL_TAB_WINDOWS(tp, win) { FOR_ALL_TAB_WINDOWS(tp, win) {
@@ -660,7 +661,7 @@ static void free_buffer(buf_T *buf)
free_buffer_stuff(buf, true); free_buffer_stuff(buf, true);
unref_var_dict(buf->b_vars); unref_var_dict(buf->b_vars);
aubuflocal_remove(buf); aubuflocal_remove(buf);
dict_unref(buf->additional_data); tv_dict_unref(buf->additional_data);
clear_fmark(&buf->b_last_cursor); clear_fmark(&buf->b_last_cursor);
clear_fmark(&buf->b_last_insert); clear_fmark(&buf->b_last_insert);
clear_fmark(&buf->b_last_change); clear_fmark(&buf->b_last_change);
@@ -1471,7 +1472,7 @@ static inline void buf_init_changedtick(buf_T *const buf)
{ {
STATIC_ASSERT(sizeof("changedtick") <= sizeof(buf->changedtick_di.di_key), STATIC_ASSERT(sizeof("changedtick") <= sizeof(buf->changedtick_di.di_key),
"buf->changedtick_di cannot hold large enough keys"); "buf->changedtick_di cannot hold large enough keys");
buf->changedtick_di = (dictitem16_T) { buf->changedtick_di = (ChangedtickDictItem) {
.di_flags = DI_FLAGS_RO|DI_FLAGS_FIX, // Must not include DI_FLAGS_ALLOC. .di_flags = DI_FLAGS_RO|DI_FLAGS_FIX, // Must not include DI_FLAGS_ALLOC.
.di_tv = (typval_T) { .di_tv = (typval_T) {
.v_type = VAR_NUMBER, .v_type = VAR_NUMBER,
@@ -1480,7 +1481,7 @@ static inline void buf_init_changedtick(buf_T *const buf)
}, },
.di_key = "changedtick", .di_key = "changedtick",
}; };
dict_add(buf->b_vars, (dictitem_T *)&buf->changedtick_di); tv_dict_add(buf->b_vars, (dictitem_T *)&buf->changedtick_di);
} }
/// Add a file name to the buffer list. /// Add a file name to the buffer list.
@@ -1572,7 +1573,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
if (buf != curbuf || curbuf == NULL) { if (buf != curbuf || curbuf == NULL) {
buf = xcalloc(1, sizeof(buf_T)); buf = xcalloc(1, sizeof(buf_T));
// init b: variables // init b: variables
buf->b_vars = dict_alloc(); buf->b_vars = tv_dict_alloc();
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE); init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
buf_init_changedtick(buf); buf_init_changedtick(buf);
} }
@@ -2723,7 +2724,7 @@ fileinfo (
else else
name = curbuf->b_ffname; name = curbuf->b_ffname;
home_replace(shorthelp ? curbuf : NULL, name, p, home_replace(shorthelp ? curbuf : NULL, name, p,
(int)(IOSIZE - (p - buffer)), TRUE); (size_t)(IOSIZE - (p - buffer)), true);
} }
vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s", vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
@@ -2888,7 +2889,7 @@ void maketitle(void)
buf[off++] = ' '; buf[off++] = ' ';
buf[off++] = '('; buf[off++] = '(';
home_replace(curbuf, curbuf->b_ffname, home_replace(curbuf, curbuf->b_ffname,
buf + off, SPACE_FOR_DIR - off, TRUE); buf + off, (size_t)(SPACE_FOR_DIR - off), true);
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
/* avoid "c:/name" to be reduced to "c" */ /* avoid "c:/name" to be reduced to "c" */
if (isalpha(buf[off]) && buf[off + 1] == ':') if (isalpha(buf[off]) && buf[off + 1] == ':')
@@ -3503,7 +3504,7 @@ int build_stl_str_hl(
curbuf = o_curbuf; curbuf = o_curbuf;
// Remove the variable we just stored // Remove the variable we just stored
do_unlet((char_u *)"g:actual_curbuf", true); do_unlet(S_LEN("g:actual_curbuf"), true);
// } // }
@@ -4206,11 +4207,11 @@ void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)
#ifdef WIN32 #ifdef WIN32
if (!buf->b_p_bin) { if (!buf->b_p_bin) {
// If the file name is a shortcut file, use the file it links to. // If the file name is a shortcut file, use the file it links to.
char_u *rfname = (char_u *)os_resolve_shortcut(*ffname); char *rfname = os_resolve_shortcut((const char *)(*ffname));
if (rfname != NULL) { if (rfname != NULL) {
xfree(*ffname); xfree(*ffname);
*ffname = rfname; *ffname = (char_u *)rfname;
*sfname = rfname; *sfname = (char_u *)rfname;
} }
} }
#endif #endif
@@ -5442,8 +5443,8 @@ void buf_open_scratch(handle_T bufnr, char *bufname)
{ {
(void)do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL); (void)do_ecmd((int)bufnr, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, NULL);
(void)setfname(curbuf, (char_u *)bufname, NULL, true); (void)setfname(curbuf, (char_u *)bufname, NULL, true);
set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL); set_option_value("bh", 0L, "hide", OPT_LOCAL);
set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL); set_option_value("bt", 0L, "nofile", OPT_LOCAL);
set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); set_option_value("swf", 0L, NULL, OPT_LOCAL);
RESET_BINDING(curwin); RESET_BINDING(curwin);
} }

View File

@@ -1,12 +1,14 @@
#ifndef NVIM_BUFFER_H #ifndef NVIM_BUFFER_H
#define NVIM_BUFFER_H #define NVIM_BUFFER_H
#include "nvim/vim.h"
#include "nvim/window.h" #include "nvim/window.h"
#include "nvim/pos.h" // for linenr_T #include "nvim/pos.h" // for linenr_T
#include "nvim/ex_cmds_defs.h" // for exarg_T #include "nvim/ex_cmds_defs.h" // for exarg_T
#include "nvim/screen.h" // for StlClickRecord #include "nvim/screen.h" // for StlClickRecord
#include "nvim/func_attr.h" #include "nvim/func_attr.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/macros.h"
// Values for buflist_getfile() // Values for buflist_getfile()
enum getf_values { enum getf_values {
@@ -91,8 +93,8 @@ static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
static inline void buf_set_changedtick(buf_T *const buf, const int changedtick) static inline void buf_set_changedtick(buf_T *const buf, const int changedtick)
{ {
#ifndef NDEBUG #ifndef NDEBUG
dictitem_T *const changedtick_di = dict_find( dictitem_T *const changedtick_di = tv_dict_find(
buf->b_vars, (char_u *)"changedtick", sizeof("changedtick") - 1); buf->b_vars, S_LEN("changedtick"));
assert(changedtick_di != NULL); assert(changedtick_di != NULL);
assert(changedtick_di->di_tv.v_type == VAR_NUMBER); assert(changedtick_di->di_tv.v_type == VAR_NUMBER);
assert(changedtick_di->di_tv.v_lock == VAR_FIXED); assert(changedtick_di->di_tv.v_lock == VAR_FIXED);

View File

@@ -21,8 +21,6 @@ typedef struct {
#include "nvim/pos.h" #include "nvim/pos.h"
// for the number window-local and buffer-local options // for the number window-local and buffer-local options
#include "nvim/option_defs.h" #include "nvim/option_defs.h"
// for optional iconv support
#include "nvim/iconv.h"
// for jump list and tag stack sizes in a buffer and mark types // for jump list and tag stack sizes in a buffer and mark types
#include "nvim/mark_defs.h" #include "nvim/mark_defs.h"
// for u_header_T; needs buf_T. // for u_header_T; needs buf_T.
@@ -30,7 +28,9 @@ typedef struct {
// for hashtab_T // for hashtab_T
#include "nvim/hashtab.h" #include "nvim/hashtab.h"
// for dict_T // for dict_T
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
// for proftime_T
#include "nvim/profile.h"
// for String // for String
#include "nvim/api/private/defs.h" #include "nvim/api/private/defs.h"
// for Map(K, V) // for Map(K, V)
@@ -318,25 +318,6 @@ typedef struct {
String save_inputbuf; String save_inputbuf;
} tasave_T; } tasave_T;
/*
* Used for conversion of terminal I/O and script files.
*/
typedef struct {
int vc_type; /* zero or one of the CONV_ values */
int vc_factor; /* max. expansion factor */
# ifdef USE_ICONV
iconv_t vc_fd; /* for CONV_ICONV */
# endif
bool vc_fail; /* fail for invalid char, don't use '?' */
} vimconv_T;
#define CONV_NONE 0
#define CONV_TO_UTF8 1
#define CONV_9_TO_UTF8 2
#define CONV_TO_LATIN1 3
#define CONV_TO_LATIN9 4
#define CONV_ICONV 5
/* /*
* Structure used for mappings and abbreviations. * Structure used for mappings and abbreviations.
*/ */
@@ -447,6 +428,10 @@ typedef struct {
char_u *b_syn_isk; // iskeyword option char_u *b_syn_isk; // iskeyword option
} synblock_T; } synblock_T;
/// Type used for changedtick_di member in buf_T
///
/// Primary exists so that literals of relevant type can be made.
typedef TV_DICTITEM_STRUCT(sizeof("changedtick")) ChangedtickDictItem;
#define BUF_HAS_QF_ENTRY 1 #define BUF_HAS_QF_ENTRY 1
#define BUF_HAS_LL_ENTRY 2 #define BUF_HAS_LL_ENTRY 2
@@ -491,7 +476,7 @@ struct file_buffer {
// file has been changed and not written out. // file has been changed and not written out.
/// Change identifier incremented for each change, including undo /// Change identifier incremented for each change, including undo
#define b_changedtick changedtick_di.di_tv.vval.v_number #define b_changedtick changedtick_di.di_tv.vval.v_number
dictitem16_T changedtick_di; // b:changedtick dictionary item. ChangedtickDictItem changedtick_di; // b:changedtick dictionary item.
bool b_saving; /* Set to true if we are in the middle of bool b_saving; /* Set to true if we are in the middle of
saving the buffer. */ saving the buffer. */
@@ -735,8 +720,8 @@ struct file_buffer {
int b_bad_char; /* "++bad=" argument when edit started or 0 */ int b_bad_char; /* "++bad=" argument when edit started or 0 */
int b_start_bomb; /* 'bomb' when it was read */ int b_start_bomb; /* 'bomb' when it was read */
dictitem_T b_bufvar; /* variable for "b:" Dictionary */ ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dictionary.
dict_T *b_vars; /* internal variables, local to buffer */ dict_T *b_vars; ///< b: scope dictionary.
/* When a buffer is created, it starts without a swap file. b_may_swap is /* When a buffer is created, it starts without a swap file. b_may_swap is
* then set to indicate that a swap file may be opened later. It is reset * then set to indicate that a swap file may be opened later. It is reset
@@ -824,9 +809,9 @@ struct tabpage_S {
buf_T *(tp_diffbuf[DB_COUNT]); buf_T *(tp_diffbuf[DB_COUNT]);
int tp_diff_invalid; ///< list of diffs is outdated int tp_diff_invalid; ///< list of diffs is outdated
frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots
dictitem_T tp_winvar; ///< variable for "t:" Dictionary ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dictionary.
dict_T *tp_vars; ///< internal variables, local to tab page dict_T *tp_vars; ///< Internal variables, local to tab page.
char_u *tp_localdir; ///< Absolute path of local CWD or NULL char_u *tp_localdir; ///< Absolute path of local cwd or NULL.
}; };
/* /*
@@ -1118,8 +1103,8 @@ struct window_S {
long w_scbind_pos; long w_scbind_pos;
dictitem_T w_winvar; /* variable for "w:" Dictionary */ ScopeDictDictItem w_winvar; ///< Variable for "w:" dictionary.
dict_T *w_vars; /* internal variables, local to window */ dict_T *w_vars; ///< Dictionary with w: variables.
int w_farsi; /* for the window dependent Farsi functions */ int w_farsi; /* for the window dependent Farsi functions */

View File

@@ -41,8 +41,10 @@ static bool chartab_initialized = false;
(buf)->b_chartab[(unsigned)(c) >> 6] |= (1ull << ((c) & 0x3f)) (buf)->b_chartab[(unsigned)(c) >> 6] |= (1ull << ((c) & 0x3f))
#define RESET_CHARTAB(buf, c) \ #define RESET_CHARTAB(buf, c) \
(buf)->b_chartab[(unsigned)(c) >> 6] &= ~(1ull << ((c) & 0x3f)) (buf)->b_chartab[(unsigned)(c) >> 6] &= ~(1ull << ((c) & 0x3f))
#define GET_CHARTAB_TAB(chartab, c) \
((chartab)[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
#define GET_CHARTAB(buf, c) \ #define GET_CHARTAB(buf, c) \
((buf)->b_chartab[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f))) GET_CHARTAB_TAB((buf)->b_chartab, c)
// Table used below, see init_chartab() for an explanation // Table used below, see init_chartab() for an explanation
static char_u g_chartab[256]; static char_u g_chartab[256];
@@ -88,7 +90,6 @@ int buf_init_chartab(buf_T *buf, int global)
{ {
int c; int c;
int c2; int c2;
char_u *p;
int i; int i;
bool tilde; bool tilde;
bool do_isalpha; bool do_isalpha;
@@ -142,7 +143,8 @@ int buf_init_chartab(buf_T *buf, int global)
// Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
// options Each option is a list of characters, character numbers or // options Each option is a list of characters, character numbers or
// ranges, separated by commas, e.g.: "200-210,x,#-178,-" // ranges, separated by commas, e.g.: "200-210,x,#-178,-"
for (i = global ? 0 : 3; i <= 3; ++i) { for (i = global ? 0 : 3; i <= 3; i++) {
const char_u *p;
if (i == 0) { if (i == 0) {
// first round: 'isident' // first round: 'isident'
p = p_isi; p = p_isi;
@@ -167,7 +169,7 @@ int buf_init_chartab(buf_T *buf, int global)
} }
if (ascii_isdigit(*p)) { if (ascii_isdigit(*p)) {
c = getdigits_int(&p); c = getdigits_int((char_u **)&p);
} else { } else {
c = mb_ptr2char_adv(&p); c = mb_ptr2char_adv(&p);
} }
@@ -177,7 +179,7 @@ int buf_init_chartab(buf_T *buf, int global)
++p; ++p;
if (ascii_isdigit(*p)) { if (ascii_isdigit(*p)) {
c2 = getdigits_int(&p); c2 = getdigits_int((char_u **)&p);
} else { } else {
c2 = mb_ptr2char_adv(&p); c2 = mb_ptr2char_adv(&p);
} }
@@ -634,7 +636,7 @@ int char2cells(int c)
/// @param p /// @param p
/// ///
/// @return number of display cells. /// @return number of display cells.
int ptr2cells(char_u *p) int ptr2cells(const char_u *p)
{ {
// For UTF-8 we need to look at more bytes if the first byte is >= 0x80. // For UTF-8 we need to look at more bytes if the first byte is >= 0x80.
if (*p >= 0x80) { if (*p >= 0x80) {
@@ -776,6 +778,20 @@ bool vim_iswordc(int c)
return vim_iswordc_buf(c, curbuf); return vim_iswordc_buf(c, curbuf);
} }
/// Check that "c" is a keyword character
/// Letters and characters from 'iskeyword' option for given buffer.
/// For multi-byte characters mb_get_class() is used (builtin rules).
///
/// @param[in] c Character to check.
/// @param[in] chartab Buffer chartab.
bool vim_iswordc_tab(const int c, const uint64_t *const chartab)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
return (c >= 0x100
? (utf_class(c) >= 2)
: (c > 0 && GET_CHARTAB_TAB(chartab, c) != 0));
}
/// Check that "c" is a keyword character: /// Check that "c" is a keyword character:
/// Letters and characters from 'iskeyword' option for given buffer. /// Letters and characters from 'iskeyword' option for given buffer.
/// For multi-byte characters mb_get_class() is used (builtin rules). /// For multi-byte characters mb_get_class() is used (builtin rules).
@@ -785,10 +801,7 @@ bool vim_iswordc(int c)
bool vim_iswordc_buf(int c, buf_T *buf) bool vim_iswordc_buf(int c, buf_T *buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2)
{ {
if (c >= 0x100) { return vim_iswordc_tab(c, buf->b_chartab);
return utf_class(c) >= 2;
}
return c > 0 && c < 0x100 && GET_CHARTAB(buf, c) != 0;
} }
/// Just like vim_iswordc() but uses a pointer to the (multi-byte) character. /// Just like vim_iswordc() but uses a pointer to the (multi-byte) character.
@@ -1384,7 +1397,8 @@ void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left,
/// ///
/// @return Pointer to character after the skipped whitespace. /// @return Pointer to character after the skipped whitespace.
char_u *skipwhite(const char_u *q) char_u *skipwhite(const char_u *q)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
{ {
const char_u *p = q; const char_u *p = q;
while (ascii_iswhite(*p)) { while (ascii_iswhite(*p)) {
@@ -1393,19 +1407,21 @@ char_u *skipwhite(const char_u *q)
return (char_u *)p; return (char_u *)p;
} }
/// skip over digits /// Skip over digits
/// ///
/// @param q /// @param[in] q String to skip digits in.
/// ///
/// @return Pointer to the character after the skipped digits. /// @return Pointer to the character after the skipped digits.
char_u* skipdigits(char_u *q) char_u *skipdigits(const char_u *q)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
{ {
char_u *p = q; const char_u *p = q;
while (ascii_isdigit(*p)) { while (ascii_isdigit(*p)) {
// skip to next non-digit // skip to next non-digit
p++; p++;
} }
return p; return (char_u *)p;
} }
/// skip over binary digits /// skip over binary digits
@@ -1551,17 +1567,17 @@ int vim_tolower(int c)
return TOLOWER_LOC(c); return TOLOWER_LOC(c);
} }
/// skiptowhite: skip over text until ' ' or '\t' or NUL. /// Skip over text until ' ' or '\t' or NUL
/// ///
/// @param p /// @param[in] p Text to skip over.
/// ///
/// @return Pointer to the next whitespace or NUL character. /// @return Pointer to the next whitespace or NUL character.
char_u* skiptowhite(char_u *p) char_u *skiptowhite(const char_u *p)
{ {
while (*p != ' ' && *p != '\t' && *p != NUL) { while (*p != ' ' && *p != '\t' && *p != NUL) {
p++; p++;
} }
return p; return (char_u *)p;
} }
/// skiptowhite_esc: Like skiptowhite(), but also skip escaped chars /// skiptowhite_esc: Like skiptowhite(), but also skip escaped chars

View File

@@ -1,6 +1,20 @@
#ifndef NVIM_CHARSET_H #ifndef NVIM_CHARSET_H
#define NVIM_CHARSET_H #define NVIM_CHARSET_H
#include "nvim/types.h"
#include "nvim/pos.h"
#include "nvim/buffer_defs.h"
/// Return the folded-case equivalent of the given character
///
/// @param[in] c Character to transform.
///
/// @return Folded variant.
#define CH_FOLD(c) \
utf_fold((sizeof(c) == sizeof(char)) \
?((int)(uint8_t)(c)) \
:((int)(c)))
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "charset.h.generated.h" # include "charset.h.generated.h"
#endif #endif

View File

@@ -12,6 +12,7 @@
#include "nvim/state.h" #include "nvim/state.h"
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/mark.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "cursor.c.generated.h" # include "cursor.c.generated.h"
@@ -227,9 +228,10 @@ static int coladvance2(
} }
} }
/* prevent from moving onto a trail byte */ // Prevent from moving onto a trail byte.
if (has_mbyte) if (has_mbyte) {
mb_adjustpos(curbuf, pos); mark_mb_adjustpos(curbuf, pos);
}
if (col < wcol) if (col < wcol)
return FAIL; return FAIL;
@@ -361,9 +363,10 @@ void check_cursor_col_win(win_T *win)
win->w_cursor.col = len; win->w_cursor.col = len;
} else { } else {
win->w_cursor.col = len - 1; win->w_cursor.col = len - 1;
/* Move the cursor to the head byte. */ // Move the cursor to the head byte.
if (has_mbyte) if (has_mbyte) {
mb_adjustpos(win->w_buffer, &win->w_cursor); mark_mb_adjustpos(win->w_buffer, &win->w_cursor);
}
} }
} else if (win->w_cursor.col < 0) { } else if (win->w_cursor.col < 0) {
win->w_cursor.col = 0; win->w_cursor.col = 0;

View File

@@ -7,40 +7,74 @@
#include "nvim/charset.h" #include "nvim/charset.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/syntax.h" #include "nvim/syntax.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ui.h"
/* /// Handling of cursor and mouse pointer shapes in various modes.
* Handling of cursor and mouse pointer shapes in various modes.
*/
static cursorentry_T shape_table[SHAPE_IDX_COUNT] = static cursorentry_T shape_table[SHAPE_IDX_COUNT] =
{ {
/* The values will be filled in from the 'guicursor' and 'mouseshape' // Values are set by 'guicursor' and 'mouseshape'.
* defaults when Vim starts. // Adjust the SHAPE_IDX_ defines when changing this!
* Adjust the SHAPE_IDX_ defines when making changes! */ { "normal", 0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE}, { "visual", 0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE}, { "insert", 0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE}, { "replace", 0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE}, { "cmdline_normal", 0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE}, { "cmdline_insert", 0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE}, { "cmdline_replace", 0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE}, { "operator", 0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE}, { "visual_select", 0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE },
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE}, { "cmdline_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE}, { "statusline_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE}, { "statusline_drag", 0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE}, { "vsep_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE}, { "vsep_drag", 0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE}, { "more", 0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE}, { "more_lastline", 0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE },
{0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE}, { "showmatch", 0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR },
{0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
}; };
/* /// Converts cursor_shapes into a Dictionary of dictionaries
* Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape' /// @return dictionary of the form {"normal" : { "cursor_shape": ... }, ...}
* ("what" is SHAPE_MOUSE). Dictionary cursor_shape_dict(void)
* Returns error message for an illegal option, NULL otherwise. {
*/ Dictionary all = ARRAY_DICT_INIT;
for (int i = 0; i < SHAPE_IDX_COUNT; i++) {
Dictionary dic = ARRAY_DICT_INIT;
cursorentry_T *cur = &shape_table[i];
if (cur->used_for & SHAPE_MOUSE) {
PUT(dic, "mouse_shape", INTEGER_OBJ(cur->mshape));
}
if (cur->used_for & SHAPE_CURSOR) {
String shape_str;
switch (cur->shape) {
case SHAPE_BLOCK: shape_str = cstr_to_string("block"); break;
case SHAPE_VER: shape_str = cstr_to_string("vertical"); break;
case SHAPE_HOR: shape_str = cstr_to_string("horizontal"); break;
default: shape_str = cstr_to_string("unknown");
}
PUT(dic, "cursor_shape", STRING_OBJ(shape_str));
PUT(dic, "cell_percentage", INTEGER_OBJ(cur->percentage));
PUT(dic, "blinkwait", INTEGER_OBJ(cur->blinkwait));
PUT(dic, "blinkon", INTEGER_OBJ(cur->blinkon));
PUT(dic, "blinkoff", INTEGER_OBJ(cur->blinkoff));
PUT(dic, "hl_id", INTEGER_OBJ(cur->id));
PUT(dic, "id_lm", INTEGER_OBJ(cur->id_lm));
}
PUT(dic, "short_name", STRING_OBJ(cstr_to_string(cur->name)));
PUT(all, cur->full_name, DICTIONARY_OBJ(dic));
}
return all;
}
/// Parse the 'guicursor' option
///
/// @param what SHAPE_CURSOR or SHAPE_MOUSE ('mouseshape')
///
/// @returns error message for an illegal option, NULL otherwise.
char_u *parse_shape_opt(int what) char_u *parse_shape_opt(int what)
{ {
char_u *modep; char_u *modep;
@@ -55,14 +89,13 @@ char_u *parse_shape_opt(int what)
int found_ve = false; /* found "ve" flag */ int found_ve = false; /* found "ve" flag */
int round; int round;
/* // First round: check for errors; second round: do it for real.
* First round: check for errors; second round: do it for real. for (round = 1; round <= 2; round++) {
*/ // Repeat for all comma separated parts.
for (round = 1; round <= 2; ++round) {
/*
* Repeat for all comma separated parts.
*/
modep = p_guicursor; modep = p_guicursor;
if (*p_guicursor == NUL) {
modep = (char_u *)"a:block-blinkon0";
}
while (*modep != NUL) { while (*modep != NUL) {
colonp = vim_strchr(modep, ':'); colonp = vim_strchr(modep, ':');
if (colonp == NULL) if (colonp == NULL)
@@ -71,19 +104,18 @@ char_u *parse_shape_opt(int what)
return (char_u *)N_("E546: Illegal mode"); return (char_u *)N_("E546: Illegal mode");
commap = vim_strchr(modep, ','); commap = vim_strchr(modep, ',');
/* // Repeat for all modes before the colon.
* Repeat for all mode's before the colon. // For the 'a' mode, we loop to handle all the modes.
* For the 'a' mode, we loop to handle all the modes.
*/
all_idx = -1; all_idx = -1;
assert(modep < colonp); assert(modep < colonp);
while (modep < colonp || all_idx >= 0) { while (modep < colonp || all_idx >= 0) {
if (all_idx < 0) { if (all_idx < 0) {
/* Find the mode. */ // Find the mode
if (modep[1] == '-' || modep[1] == ':') if (modep[1] == '-' || modep[1] == ':') {
len = 1; len = 1;
else } else {
len = 2; len = 2;
}
if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') { if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') {
all_idx = SHAPE_IDX_COUNT - 1; all_idx = SHAPE_IDX_COUNT - 1;
@@ -100,11 +132,11 @@ char_u *parse_shape_opt(int what)
modep += len + 1; modep += len + 1;
} }
if (all_idx >= 0) if (all_idx >= 0) {
idx = all_idx--; idx = all_idx--;
else if (round == 2) { } else if (round == 2) {
{ {
/* Set the defaults, for the missing parts */ // Set the defaults, for the missing parts
shape_table[idx].shape = SHAPE_BLOCK; shape_table[idx].shape = SHAPE_BLOCK;
shape_table[idx].blinkwait = 700L; shape_table[idx].blinkwait = 700L;
shape_table[idx].blinkon = 400L; shape_table[idx].blinkon = 400L;
@@ -208,6 +240,23 @@ char_u *parse_shape_opt(int what)
shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm; shape_table[SHAPE_IDX_VE].id_lm = shape_table[SHAPE_IDX_V].id_lm;
} }
} }
ui_cursor_style_set();
return NULL; return NULL;
} }
/// Map cursor mode from string to integer
///
/// @param mode Fullname of the mode whose id we are looking for
/// @return -1 in case of failure, else the matching SHAPE_ID* integer
int cursor_mode_str2int(const char *mode)
{
for (int current_mode = 0; current_mode < SHAPE_IDX_COUNT; current_mode++) {
if (strcmp(shape_table[current_mode].full_name, mode) == 0) {
return current_mode;
}
}
ELOG("Unknown mode %s", mode);
return -1;
}

View File

@@ -1,32 +1,34 @@
#ifndef NVIM_CURSOR_SHAPE_H #ifndef NVIM_CURSOR_SHAPE_H
#define NVIM_CURSOR_SHAPE_H #define NVIM_CURSOR_SHAPE_H
/* /// struct to store values from 'guicursor' and 'mouseshape'
* struct to store values from 'guicursor' and 'mouseshape' /// Indexes in shape_table[]
*/ typedef enum {
/* Indexes in shape_table[] */ SHAPE_IDX_N = 0, ///< Normal mode
#define SHAPE_IDX_N 0 /* Normal mode */ SHAPE_IDX_V = 1, ///< Visual mode
#define SHAPE_IDX_V 1 /* Visual mode */ SHAPE_IDX_I = 2, ///< Insert mode
#define SHAPE_IDX_I 2 /* Insert mode */ SHAPE_IDX_R = 3, ///< Replace mode
#define SHAPE_IDX_R 3 /* Replace mode */ SHAPE_IDX_C = 4, ///< Command line Normal mode
#define SHAPE_IDX_C 4 /* Command line Normal mode */ SHAPE_IDX_CI = 5, ///< Command line Insert mode
#define SHAPE_IDX_CI 5 /* Command line Insert mode */ SHAPE_IDX_CR = 6, ///< Command line Replace mode
#define SHAPE_IDX_CR 6 /* Command line Replace mode */ SHAPE_IDX_O = 7, ///< Operator-pending mode
#define SHAPE_IDX_O 7 /* Operator-pending mode */ SHAPE_IDX_VE = 8, ///< Visual mode with 'selection' exclusive
#define SHAPE_IDX_VE 8 /* Visual mode with 'selection' exclusive */ SHAPE_IDX_CLINE = 9, ///< On command line
#define SHAPE_IDX_CLINE 9 /* On command line */ SHAPE_IDX_STATUS = 10, ///< On status line
#define SHAPE_IDX_STATUS 10 /* A status line */ SHAPE_IDX_SDRAG = 11, ///< dragging a status line
#define SHAPE_IDX_SDRAG 11 /* dragging a status line */ SHAPE_IDX_VSEP = 12, ///< On vertical separator line
#define SHAPE_IDX_VSEP 12 /* A vertical separator line */ SHAPE_IDX_VDRAG = 13, ///< dragging a vertical separator line
#define SHAPE_IDX_VDRAG 13 /* dragging a vertical separator line */ SHAPE_IDX_MORE = 14, ///< Hit-return or More
#define SHAPE_IDX_MORE 14 /* Hit-return or More */ SHAPE_IDX_MOREL = 15, ///< Hit-return or More in last line
#define SHAPE_IDX_MOREL 15 /* Hit-return or More in last line */ SHAPE_IDX_SM = 16, ///< showing matching paren
#define SHAPE_IDX_SM 16 /* showing matching paren */ SHAPE_IDX_COUNT = 17
#define SHAPE_IDX_COUNT 17 } MouseMode;
#define SHAPE_BLOCK 0 /* block cursor */ typedef enum {
#define SHAPE_HOR 1 /* horizontal bar cursor */ SHAPE_BLOCK = 0, ///< block cursor
#define SHAPE_VER 2 /* vertical bar cursor */ SHAPE_HOR = 1, ///< horizontal bar cursor
SHAPE_VER = 2 ///< vertical bar cursor
} CursorShape;
#define MSHAPE_NUMBERED 1000 /* offset for shapes identified by number */ #define MSHAPE_NUMBERED 1000 /* offset for shapes identified by number */
#define MSHAPE_HIDE 1 /* hide mouse pointer */ #define MSHAPE_HIDE 1 /* hide mouse pointer */
@@ -35,16 +37,17 @@
#define SHAPE_CURSOR 2 /* used for text cursor shape */ #define SHAPE_CURSOR 2 /* used for text cursor shape */
typedef struct cursor_entry { typedef struct cursor_entry {
int shape; /* one of the SHAPE_ defines */ char *full_name; ///< mode description
int mshape; /* one of the MSHAPE defines */ CursorShape shape; ///< cursor shape: one of the SHAPE_ defines
int percentage; /* percentage of cell for bar */ int mshape; ///< mouse shape: one of the MSHAPE defines
long blinkwait; /* blinking, wait time before blinking starts */ int percentage; ///< percentage of cell for bar
long blinkon; /* blinking, on time */ long blinkwait; ///< blinking, wait time before blinking starts
long blinkoff; /* blinking, off time */ long blinkon; ///< blinking, on time
int id; /* highlight group ID */ long blinkoff; ///< blinking, off time
int id_lm; /* highlight group ID for :lmap mode */ int id; ///< highlight group ID
char *name; /* mode name (fixed) */ int id_lm; ///< highlight group ID for :lmap mode
char used_for; /* SHAPE_MOUSE and/or SHAPE_CURSOR */ char *name; ///< mode short name
char used_for; ///< SHAPE_MOUSE and/or SHAPE_CURSOR
} cursorentry_T; } cursorentry_T;

View File

@@ -1586,7 +1586,7 @@ static int diff_cmp(char_u *s1, char_u *s2)
} }
if ((diff_flags & DIFF_ICASE) && !(diff_flags & DIFF_IWHITE)) { if ((diff_flags & DIFF_ICASE) && !(diff_flags & DIFF_IWHITE)) {
return mb_stricmp(s1, s2); return mb_stricmp((const char *)s1, (const char *)s2);
} }
// Ignore white space changes and possibly ignore case. // Ignore white space changes and possibly ignore case.

View File

@@ -1,6 +1,9 @@
#ifndef NVIM_DIFF_H #ifndef NVIM_DIFF_H
#define NVIM_DIFF_H #define NVIM_DIFF_H
#include "nvim/pos.h"
#include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "diff.h.generated.h" # include "diff.h.generated.h"
#endif #endif

View File

@@ -15,6 +15,7 @@
#include "nvim/cursor.h" #include "nvim/cursor.h"
#include "nvim/digraph.h" #include "nvim/digraph.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_docmd.h" #include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h" #include "nvim/ex_getln.h"
#include "nvim/farsi.h" #include "nvim/farsi.h"
@@ -1422,7 +1423,7 @@ static void ins_ctrl_v(void)
edit_putchar('^', TRUE); edit_putchar('^', TRUE);
did_putchar = TRUE; did_putchar = TRUE;
} }
AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */ AppendToRedobuff(CTRL_V_STR);
add_to_showcmd_c(Ctrl_V); add_to_showcmd_c(Ctrl_V);
@@ -1976,7 +1977,6 @@ static bool ins_compl_accept_char(int c)
*/ */
int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int dir, int flags) int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int dir, int flags)
{ {
char_u *p;
int i, c; int i, c;
int actual_len; /* Take multi-byte characters */ int actual_len; /* Take multi-byte characters */
int actual_compl_length; /* into account. */ int actual_compl_length; /* into account. */
@@ -1986,11 +1986,11 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
int was_letter = FALSE; int was_letter = FALSE;
if (p_ic && curbuf->b_p_inf && len > 0) { if (p_ic && curbuf->b_p_inf && len > 0) {
/* Infer case of completed part. */ // Infer case of completed part.
/* Find actual length of completion. */ // Find actual length of completion.
if (has_mbyte) { if (has_mbyte) {
p = str; const char_u *p = str;
actual_len = 0; actual_len = 0;
while (*p != NUL) { while (*p != NUL) {
mb_ptr_adv(p); mb_ptr_adv(p);
@@ -2001,7 +2001,7 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
/* Find actual length of original text. */ /* Find actual length of original text. */
if (has_mbyte) { if (has_mbyte) {
p = compl_orig_text; const char_u *p = compl_orig_text;
actual_compl_length = 0; actual_compl_length = 0;
while (*p != NUL) { while (*p != NUL) {
mb_ptr_adv(p); mb_ptr_adv(p);
@@ -2017,27 +2017,35 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
/* Allocate wide character array for the completion and fill it. */ /* Allocate wide character array for the completion and fill it. */
wca = xmalloc(actual_len * sizeof(*wca)); wca = xmalloc(actual_len * sizeof(*wca));
p = str; {
for (i = 0; i < actual_len; ++i) const char_u *p = str;
if (has_mbyte) for (i = 0; i < actual_len; i++) {
wca[i] = mb_ptr2char_adv(&p); if (has_mbyte) {
else wca[i] = mb_ptr2char_adv(&p);
wca[i] = *(p++); } else {
wca[i] = *(p++);
}
}
}
/* Rule 1: Were any chars converted to lower? */ // Rule 1: Were any chars converted to lower?
p = compl_orig_text; {
for (i = 0; i < min_len; ++i) { const char_u *p = compl_orig_text;
if (has_mbyte) for (i = 0; i < min_len; i++) {
c = mb_ptr2char_adv(&p); if (has_mbyte) {
else c = mb_ptr2char_adv(&p);
c = *(p++); } else {
if (vim_islower(c)) { c = *(p++);
has_lower = TRUE; }
if (vim_isupper(wca[i])) { if (vim_islower(c)) {
/* Rule 1 is satisfied. */ has_lower = true;
for (i = actual_compl_length; i < actual_len; ++i) if (vim_isupper(wca[i])) {
wca[i] = vim_tolower(wca[i]); // Rule 1 is satisfied.
break; for (i = actual_compl_length; i < actual_len; i++) {
wca[i] = vim_tolower(wca[i]);
}
break;
}
} }
} }
} }
@@ -2047,84 +2055,110 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
* upper case. * upper case.
*/ */
if (!has_lower) { if (!has_lower) {
p = compl_orig_text; const char_u *p = compl_orig_text;
for (i = 0; i < min_len; ++i) { for (i = 0; i < min_len; i++) {
if (has_mbyte) if (has_mbyte) {
c = mb_ptr2char_adv(&p); c = mb_ptr2char_adv(&p);
else } else {
c = *(p++); c = *(p++);
}
if (was_letter && vim_isupper(c) && vim_islower(wca[i])) { if (was_letter && vim_isupper(c) && vim_islower(wca[i])) {
/* Rule 2 is satisfied. */ // Rule 2 is satisfied.
for (i = actual_compl_length; i < actual_len; ++i) for (i = actual_compl_length; i < actual_len; i++) {
wca[i] = vim_toupper(wca[i]); wca[i] = vim_toupper(wca[i]);
}
break; break;
} }
was_letter = vim_islower(c) || vim_isupper(c); was_letter = vim_islower(c) || vim_isupper(c);
} }
} }
/* Copy the original case of the part we typed. */ // Copy the original case of the part we typed.
p = compl_orig_text; {
for (i = 0; i < min_len; ++i) { const char_u *p = compl_orig_text;
if (has_mbyte) for (i = 0; i < min_len; i++) {
c = mb_ptr2char_adv(&p); if (has_mbyte) {
else c = mb_ptr2char_adv(&p);
c = *(p++); } else {
if (vim_islower(c)) c = *(p++);
wca[i] = vim_tolower(wca[i]); }
else if (vim_isupper(c)) if (vim_islower(c)) {
wca[i] = vim_toupper(wca[i]); wca[i] = vim_tolower(wca[i]);
} else if (vim_isupper(c)) {
wca[i] = vim_toupper(wca[i]);
}
}
} }
/* // Generate encoding specific output from wide character array.
* Generate encoding specific output from wide character array. // Multi-byte characters can occupy up to five bytes more than
* Multi-byte characters can occupy up to five bytes more than // ASCII characters, and we also need one byte for NUL, so stay
* ASCII characters, and we also need one byte for NUL, so stay // six bytes away from the edge of IObuff.
* six bytes away from the edge of IObuff. {
*/ char_u *p = IObuff;
p = IObuff; i = 0;
i = 0; while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
while (i < actual_len && (p - IObuff + 6) < IOSIZE) if (has_mbyte) {
if (has_mbyte) p += (*mb_char2bytes)(wca[i++], p);
p += (*mb_char2bytes)(wca[i++], p); } else {
else *(p++) = wca[i++];
*(p++) = wca[i++]; }
*p = NUL; }
*p = NUL;
}
xfree(wca); xfree(wca);
return ins_compl_add(IObuff, len, icase, fname, NULL, dir, return ins_compl_add(IObuff, len, icase, fname, NULL, false, dir, flags,
flags, FALSE); false);
} }
return ins_compl_add(str, len, icase, fname, NULL, dir, flags, FALSE); return ins_compl_add(str, len, icase, fname, NULL, false, dir, flags, false);
} }
/* /// Add a match to the list of matches
* Add a match to the list of matches. ///
* If the given string is already in the list of completions, then return /// @param[in] str Match to add.
* NOTDONE, otherwise add it to the list and return OK. If there is an error /// @param[in] len Match length, -1 to use #STRLEN.
* then FAIL is returned. /// @param[in] icase Whether case is to be ignored.
*/ /// @param[in] fname File name match comes from. May be NULL.
static int /// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
ins_compl_add ( /// must have exactly #CPT_COUNT items.
char_u *str, /// @param[in] cptext_allocated If true, will not copy cptext strings.
int len, ///
int icase, /// @note Will free strings in case of error.
char_u *fname, /// cptext itself will not be freed.
char_u **cptext, /* extra text for popup menu or NULL */ /// @param[in] cdir Completion direction.
int cdir, /// @param[in] adup True if duplicate matches are to be accepted.
int flags, ///
int adup /* accept duplicate match */ /// @return NOTDONE if the given string is already in the list of completions,
) /// otherwise it is added to the list and OK is returned. FAIL will be
/// returned in case of error.
static int ins_compl_add(char_u *const str, int len,
const bool icase, char_u *const fname,
char_u *const *const cptext,
const bool cptext_allocated,
const Direction cdir, int flags, const bool adup)
FUNC_ATTR_NONNULL_ARG(1)
{ {
compl_T *match; compl_T *match;
int dir = (cdir == 0 ? compl_direction : cdir); int dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
os_breakcheck(); os_breakcheck();
if (got_int) #define FREE_CPTEXT(cptext, cptext_allocated) \
do { \
if (cptext != NULL && cptext_allocated) { \
for (size_t i = 0; i < CPT_COUNT; i++) { \
xfree(cptext[i]); \
} \
} \
} while (0)
if (got_int) {
FREE_CPTEXT(cptext, cptext_allocated);
return FAIL; return FAIL;
if (len < 0) }
if (len < 0) {
len = (int)STRLEN(str); len = (int)STRLEN(str);
}
/* /*
* If the same match is already present, don't add it. * If the same match is already present, don't add it.
@@ -2132,10 +2166,12 @@ ins_compl_add (
if (compl_first_match != NULL && !adup) { if (compl_first_match != NULL && !adup) {
match = compl_first_match; match = compl_first_match;
do { do {
if ( !(match->cp_flags & ORIGINAL_TEXT) if (!(match->cp_flags & ORIGINAL_TEXT)
&& STRNCMP(match->cp_str, str, len) == 0 && STRNCMP(match->cp_str, str, len) == 0
&& match->cp_str[len] == NUL) && match->cp_str[len] == NUL) {
FREE_CPTEXT(cptext, cptext_allocated);
return NOTDONE; return NOTDONE;
}
match = match->cp_next; match = match->cp_next;
} while (match != NULL && match != compl_first_match); } while (match != NULL && match != compl_first_match);
} }
@@ -2166,16 +2202,26 @@ ins_compl_add (
else if (fname != NULL) { else if (fname != NULL) {
match->cp_fname = vim_strsave(fname); match->cp_fname = vim_strsave(fname);
flags |= FREE_FNAME; flags |= FREE_FNAME;
} else } else {
match->cp_fname = NULL; match->cp_fname = NULL;
}
match->cp_flags = flags; match->cp_flags = flags;
if (cptext != NULL) { if (cptext != NULL) {
int i; int i;
for (i = 0; i < CPT_COUNT; ++i) for (i = 0; i < CPT_COUNT; i++) {
if (cptext[i] != NULL && *cptext[i] != NUL) if (cptext[i] == NULL) {
match->cp_text[i] = vim_strsave(cptext[i]); continue;
}
if (*cptext[i] != NUL) {
match->cp_text[i] = (cptext_allocated
? cptext[i]
: (char_u *)xstrdup((char *)cptext[i]));
} else if (cptext_allocated) {
xfree(cptext[i]);
}
}
} }
/* /*
@@ -2298,9 +2344,10 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
for (i = 0; i < num_matches && add_r != FAIL; i++) for (i = 0; i < num_matches && add_r != FAIL; i++)
if ((add_r = ins_compl_add(matches[i], -1, icase, if ((add_r = ins_compl_add(matches[i], -1, icase,
NULL, NULL, dir, 0, FALSE)) == OK) NULL, NULL, false, dir, 0, false)) == OK) {
/* if dir was BACKWARD then honor it just once */ // If dir was BACKWARD then honor it just once.
dir = FORWARD; dir = FORWARD;
}
FreeWild(num_matches, matches); FreeWild(num_matches, matches);
} }
@@ -2364,8 +2411,8 @@ void set_completion(colnr_T startcol, list_T *list)
/* compl_pattern doesn't need to be set */ /* compl_pattern doesn't need to be set */
compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col, compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
compl_length); compl_length);
if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, 0, if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
ORIGINAL_TEXT, FALSE) != OK) { ORIGINAL_TEXT, false) != OK) {
return; return;
} }
@@ -2887,7 +2934,7 @@ static void ins_compl_clear(void)
compl_orig_text = NULL; compl_orig_text = NULL;
compl_enter_selects = FALSE; compl_enter_selects = FALSE;
// clear v:completed_item // clear v:completed_item
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc()); set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
} }
/// Check that Insert completion is active. /// Check that Insert completion is active.
@@ -3432,7 +3479,6 @@ expand_by_function (
{ {
list_T *matchlist = NULL; list_T *matchlist = NULL;
dict_T *matchdict = NULL; dict_T *matchdict = NULL;
char_u *args[2];
char_u *funcname; char_u *funcname;
pos_T pos; pos_T pos;
win_T *curwin_save; win_T *curwin_save;
@@ -3443,9 +3489,8 @@ expand_by_function (
if (*funcname == NUL) if (*funcname == NUL)
return; return;
/* Call 'completefunc' to obtain the list of matches. */ // Call 'completefunc' to obtain the list of matches.
args[0] = (char_u *)"0"; const char_u *const args[2] = { (char_u *)"0", base };
args[1] = base;
pos = curwin->w_cursor; pos = curwin->w_cursor;
curwin_save = curwin; curwin_save = curwin;
@@ -3461,8 +3506,8 @@ expand_by_function (
matchdict = rettv.vval.v_dict; matchdict = rettv.vval.v_dict;
break; break;
default: default:
/* TODO: Give error message? */ // TODO(brammool): Give error message?
clear_tv(&rettv); tv_clear(&rettv);
break; break;
} }
} }
@@ -3484,10 +3529,12 @@ expand_by_function (
ins_compl_add_dict(matchdict); ins_compl_add_dict(matchdict);
theend: theend:
if (matchdict != NULL) if (matchdict != NULL) {
dict_unref(matchdict); tv_dict_unref(matchdict);
if (matchlist != NULL) }
list_unref(matchlist); if (matchlist != NULL) {
tv_list_unref(matchlist);
}
} }
/* /*
@@ -3516,53 +3563,60 @@ static void ins_compl_add_dict(dict_T *dict)
dictitem_T *di_refresh; dictitem_T *di_refresh;
dictitem_T *di_words; dictitem_T *di_words;
/* Check for optional "refresh" item. */ // Check for optional "refresh" item.
compl_opt_refresh_always = FALSE; compl_opt_refresh_always = false;
di_refresh = dict_find(dict, (char_u *)"refresh", 7); di_refresh = tv_dict_find(dict, S_LEN("refresh"));
if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) { if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) {
char_u *v = di_refresh->di_tv.vval.v_string; const char *v = (const char *)di_refresh->di_tv.vval.v_string;
if (v != NULL && STRCMP(v, (char_u *)"always") == 0) if (v != NULL && strcmp(v, "always") == 0) {
compl_opt_refresh_always = TRUE; compl_opt_refresh_always = true;
}
} }
/* Add completions from a "words" list. */ // Add completions from a "words" list.
di_words = dict_find(dict, (char_u *)"words", 5); di_words = tv_dict_find(dict, S_LEN("words"));
if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) {
ins_compl_add_list(di_words->di_tv.vval.v_list); ins_compl_add_list(di_words->di_tv.vval.v_list);
}
} }
/* /// Add a match to the list of matches from VimL object
* Add a match to the list of matches from a typeval_T. ///
* If the given string is already in the list of completions, then return /// @param[in] tv Object to get matches from.
* NOTDONE, otherwise add it to the list and return OK. If there is an error /// @param[in] dir Completion direction.
* then FAIL is returned. ///
*/ /// @return NOTDONE if the given string is already in the list of completions,
int ins_compl_add_tv(typval_T *tv, int dir) /// otherwise it is added to the list and OK is returned. FAIL will be
/// returned in case of error.
int ins_compl_add_tv(typval_T *const tv, const Direction dir)
FUNC_ATTR_NONNULL_ALL
{ {
char_u *word; const char *word;
int icase = FALSE; bool icase = false;
int adup = FALSE; bool adup = false;
int aempty = FALSE; bool aempty = false;
char_u *(cptext[CPT_COUNT]); char *(cptext[CPT_COUNT]);
if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) { if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
word = get_dict_string(tv->vval.v_dict, "word", false); word = tv_dict_get_string(tv->vval.v_dict, "word", false);
cptext[CPT_ABBR] = get_dict_string(tv->vval.v_dict, "abbr", false); cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
cptext[CPT_MENU] = get_dict_string(tv->vval.v_dict, "menu", false); cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
cptext[CPT_KIND] = get_dict_string(tv->vval.v_dict, "kind", false); cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
cptext[CPT_INFO] = get_dict_string(tv->vval.v_dict, "info", false); cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
icase = get_dict_number(tv->vval.v_dict, "icase"); icase = (bool)tv_dict_get_number(tv->vval.v_dict, "icase");
adup = get_dict_number(tv->vval.v_dict, "dup"); adup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
aempty = get_dict_number(tv->vval.v_dict, "empty"); aempty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
} else { } else {
word = get_tv_string_chk(tv); word = (const char *)tv_get_string_chk(tv);
memset(cptext, 0, sizeof(cptext)); memset(cptext, 0, sizeof(cptext));
} }
if (word == NULL || (!aempty && *word == NUL)) if (word == NULL || (!aempty && *word == NUL)) {
return FAIL; return FAIL;
return ins_compl_add(word, -1, icase, NULL, cptext, dir, 0, adup); }
return ins_compl_add((char_u *)word, -1, icase, NULL,
(char_u **)cptext, true, dir, 0, adup);
} }
/* /*
@@ -3977,7 +4031,7 @@ static void ins_compl_delete(void)
// causes flicker, thus we can't do that. // causes flicker, thus we can't do that.
changed_cline_bef_curs(); changed_cline_bef_curs();
// clear v:completed_item // clear v:completed_item
set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc()); set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
} }
// Insert the new text being completed. // Insert the new text being completed.
@@ -3992,17 +4046,21 @@ static void ins_compl_insert(int in_compl_func)
// Set completed item. // Set completed item.
// { word, abbr, menu, kind, info } // { word, abbr, menu, kind, info }
dict_T *dict = dict_alloc(); dict_T *dict = tv_dict_alloc();
dict_add_nr_str(dict, "word", 0L, tv_dict_add_str(dict, S_LEN("word"),
EMPTY_IF_NULL(compl_shown_match->cp_str)); (const char *)EMPTY_IF_NULL(compl_shown_match->cp_str));
dict_add_nr_str(dict, "abbr", 0L, tv_dict_add_str(
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR])); dict, S_LEN("abbr"),
dict_add_nr_str(dict, "menu", 0L, (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_ABBR]));
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_MENU])); tv_dict_add_str(
dict_add_nr_str(dict, "kind", 0L, dict, S_LEN("menu"),
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_KIND])); (const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_MENU]));
dict_add_nr_str(dict, "info", 0L, tv_dict_add_str(
EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO])); dict, S_LEN("kind"),
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_KIND]));
tv_dict_add_str(
dict, S_LEN("info"),
(const char *)EMPTY_IF_NULL(compl_shown_match->cp_text[CPT_INFO]));
set_vim_var_dict(VV_COMPLETED_ITEM, dict); set_vim_var_dict(VV_COMPLETED_ITEM, dict);
if (!in_compl_func) { if (!in_compl_func) {
compl_curr_match = compl_shown_match; compl_curr_match = compl_shown_match;
@@ -4544,7 +4602,6 @@ static int ins_complete(int c, bool enable_pum)
* Call user defined function 'completefunc' with "a:findstart" * Call user defined function 'completefunc' with "a:findstart"
* set to 1 to obtain the length of text to use for completion. * set to 1 to obtain the length of text to use for completion.
*/ */
char_u *args[2];
int col; int col;
char_u *funcname; char_u *funcname;
pos_T pos; pos_T pos;
@@ -4563,8 +4620,7 @@ static int ins_complete(int c, bool enable_pum)
return FAIL; return FAIL;
} }
args[0] = (char_u *)"1"; const char_u *const args[2] = { (char_u *)"1", NULL };
args[1] = NULL;
pos = curwin->w_cursor; pos = curwin->w_cursor;
curwin_save = curwin; curwin_save = curwin;
curbuf_save = curbuf; curbuf_save = curbuf;
@@ -4664,8 +4720,8 @@ static int ins_complete(int c, bool enable_pum)
/* Always add completion for the original text. */ /* Always add completion for the original text. */
xfree(compl_orig_text); xfree(compl_orig_text);
compl_orig_text = vim_strnsave(line + compl_col, compl_length); compl_orig_text = vim_strnsave(line + compl_col, compl_length);
if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, 0, if (ins_compl_add(compl_orig_text, -1, p_ic, NULL, NULL, false, 0,
ORIGINAL_TEXT, FALSE) != OK) { ORIGINAL_TEXT, false) != OK) {
xfree(compl_pattern); xfree(compl_pattern);
compl_pattern = NULL; compl_pattern = NULL;
xfree(compl_orig_text); xfree(compl_orig_text);
@@ -5744,15 +5800,16 @@ comp_textwidth (
*/ */
static void redo_literal(int c) static void redo_literal(int c)
{ {
char_u buf[10]; char buf[10];
/* Only digits need special treatment. Translate them into a string of // Only digits need special treatment. Translate them into a string of
* three digits. */ // three digits.
if (ascii_isdigit(c)) { if (ascii_isdigit(c)) {
vim_snprintf((char *)buf, sizeof(buf), "%03d", c); vim_snprintf(buf, sizeof(buf), "%03d", c);
AppendToRedobuff(buf); AppendToRedobuff(buf);
} else } else {
AppendCharToRedobuff(c); AppendCharToRedobuff(c);
}
} }
// start_arrow() is called when an arrow key is used in insert mode. // start_arrow() is called when an arrow key is used in insert mode.
@@ -5781,8 +5838,8 @@ static void start_arrow_common(pos_T *end_insert_pos, bool end_change)
{ {
if (!arrow_used && end_change) { // something has been inserted if (!arrow_used && end_change) { // something has been inserted
AppendToRedobuff(ESC_STR); AppendToRedobuff(ESC_STR);
stop_insert(end_insert_pos, FALSE, FALSE); stop_insert(end_insert_pos, false, false);
arrow_used = TRUE; /* this means we stopped the current insert */ arrow_used = true; // This means we stopped the current insert.
} }
check_spell_redraw(); check_spell_redraw();
} }
@@ -5839,7 +5896,7 @@ int stop_arrow(void)
vr_lines_changed = 1; vr_lines_changed = 1;
} }
ResetRedobuff(); ResetRedobuff();
AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */ AppendToRedobuff("1i"); // Pretend we start an insertion.
new_insert_skip = 2; new_insert_skip = 2;
} else if (ins_need_undo) { } else if (ins_need_undo) {
if (u_save_cursor() == OK) if (u_save_cursor() == OK)
@@ -6304,12 +6361,13 @@ stuff_inserted (
} }
do { do {
stuffReadbuff(ptr); stuffReadbuff((const char *)ptr);
/* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */ // A trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^".
if (last) if (last) {
stuffReadbuff((char_u *)(last == '0' stuffReadbuff((last == '0'
? "\026\060\064\070" ? "\026\060\064\070"
: "\026^")); : "\026^"));
}
} while (--count > 0); } while (--count > 0);
if (last) if (last)
@@ -7066,8 +7124,8 @@ static void ins_ctrl_g(void)
*/ */
static void ins_ctrl_hat(void) static void ins_ctrl_hat(void)
{ {
if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) { if (map_to_exists_mode("", LANGMAP, false)) {
/* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */ // ":lmap" mappings exists, Toggle use of ":lmap" mappings.
if (State & LANGMAP) { if (State & LANGMAP) {
curbuf->b_p_iminsert = B_IMODE_NONE; curbuf->b_p_iminsert = B_IMODE_NONE;
State &= ~LANGMAP; State &= ~LANGMAP;
@@ -7102,13 +7160,12 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
disabled_redraw = false; disabled_redraw = false;
} }
if (!arrow_used) { if (!arrow_used) {
/* // Don't append the ESC for "r<CR>" and "grx".
* Don't append the ESC for "r<CR>" and "grx". // When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
* When 'insertmode' is set only CTRL-L stops Insert mode. Needed for // when "count" is non-zero.
* when "count" is non-zero. if (cmdchar != 'r' && cmdchar != 'v') {
*/ AppendToRedobuff(p_im ? "\014" : ESC_STR);
if (cmdchar != 'r' && cmdchar != 'v') }
AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
/* /*
* Repeating insert may take a long time. Check for * Repeating insert may take a long time. Check for
@@ -7262,7 +7319,8 @@ static bool ins_start_select(int c)
// Execute the key in (insert) Select mode. // Execute the key in (insert) Select mode.
stuffcharReadbuff(Ctrl_O); stuffcharReadbuff(Ctrl_O);
if (mod_mask) { if (mod_mask) {
char_u buf[4] = { K_SPECIAL, KS_MODIFIER, mod_mask, NUL }; const char buf[] = { (char)K_SPECIAL, (char)KS_MODIFIER,
(char)(uint8_t)mod_mask, NUL };
stuffReadbuff(buf); stuffReadbuff(buf);
} }
stuffcharReadbuff(c); stuffcharReadbuff(c);
@@ -8070,11 +8128,11 @@ static bool ins_tab(void)
return true; return true;
} }
did_ai = FALSE; did_ai = false;
did_si = FALSE; did_si = false;
can_si = FALSE; can_si = false;
can_si_back = FALSE; can_si_back = false;
AppendToRedobuff((char_u *)"\t"); AppendToRedobuff("\t");
if (p_sta && ind) { // insert tab in indent, use "shiftwidth" if (p_sta && ind) { // insert tab in indent, use "shiftwidth"
temp = get_sw_value(curbuf); temp = get_sw_value(curbuf);
@@ -8339,8 +8397,8 @@ static int ins_digraph(void)
edit_unputchar(); edit_unputchar();
} }
if (cc != ESC) { if (cc != ESC) {
AppendToRedobuff((char_u *)CTRL_V_STR); AppendToRedobuff(CTRL_V_STR);
c = getdigraph(c, cc, TRUE); c = getdigraph(c, cc, true);
clear_showcmd(); clear_showcmd();
return c; return c;
} }
@@ -8402,12 +8460,13 @@ static int ins_ctrl_ey(int tc)
if (c != NUL) { if (c != NUL) {
long tw_save; long tw_save;
/* The character must be taken literally, insert like it // The character must be taken literally, insert like it
* was typed after a CTRL-V, and pretend 'textwidth' // was typed after a CTRL-V, and pretend 'textwidth'
* wasn't set. Digits, 'o' and 'x' are special after a // wasn't set. Digits, 'o' and 'x' are special after a
* CTRL-V, don't use it for these. */ // CTRL-V, don't use it for these.
if (c < 256 && !isalnum(c)) if (c < 256 && !isalnum(c)) {
AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */ AppendToRedobuff(CTRL_V_STR);
}
tw_save = curbuf->b_p_tw; tw_save = curbuf->b_p_tw;
curbuf->b_p_tw = -1; curbuf->b_p_tw = -1;
insert_special(c, TRUE, FALSE); insert_special(c, TRUE, FALSE);

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,23 @@
#ifndef NVIM_EVAL_H #ifndef NVIM_EVAL_H
#define NVIM_EVAL_H #define NVIM_EVAL_H
#include "nvim/profile.h"
#include "nvim/hashtab.h" // For hashtab_T #include "nvim/hashtab.h" // For hashtab_T
#include "nvim/garray.h" // For garray_T #include "nvim/buffer_defs.h"
#include "nvim/buffer_defs.h" // For scid_T
#include "nvim/ex_cmds_defs.h" // For exarg_T #include "nvim/ex_cmds_defs.h" // For exarg_T
#include "nvim/eval/typval.h"
#include "nvim/profile.h"
#include "nvim/garray.h"
#define COPYID_INC 2 #define COPYID_INC 2
#define COPYID_MASK (~0x1) #define COPYID_MASK (~0x1)
// All user-defined functions are found in this hashtable. // All user-defined functions are found in this hashtable.
extern hashtab_T func_hashtab; extern hashtab_T func_hashtab;
// From user function to hashitem and back. // From user function to hashitem and back.
EXTERN ufunc_T dumuf; EXTERN ufunc_T dumuf;
#define UF2HIKEY(fp) ((fp)->uf_name) #define UF2HIKEY(fp) ((fp)->uf_name)
#define HIKEY2UF(p) ((ufunc_T *)(p - (dumuf.uf_name - (char_u *)&dumuf))) #define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name)))
#define HI2UF(hi) HIKEY2UF((hi)->hi_key) #define HI2UF(hi) HIKEY2UF((hi)->hi_key)
/// Defines for Vim variables /// Defines for Vim variables

View File

@@ -2,10 +2,11 @@
#include <msgpack.h> #include <msgpack.h>
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/encode.h" #include "nvim/eval/encode.h"
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/macros.h"
#include "nvim/message.h" #include "nvim/message.h"
#include "nvim/globals.h" #include "nvim/globals.h"
#include "nvim/charset.h" // vim_str2nr #include "nvim/charset.h" // vim_str2nr
@@ -52,16 +53,16 @@ static inline void create_special_dict(typval_T *const rettv,
typval_T val) typval_T val)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
dict_T *const dict = dict_alloc(); dict_T *const dict = tv_dict_alloc();
dictitem_T *const type_di = dictitem_alloc((char_u *) "_TYPE"); dictitem_T *const type_di = tv_dict_item_alloc_len(S_LEN("_TYPE"));
type_di->di_tv.v_type = VAR_LIST; type_di->di_tv.v_type = VAR_LIST;
type_di->di_tv.v_lock = VAR_UNLOCKED; type_di->di_tv.v_lock = VAR_UNLOCKED;
type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type]; type_di->di_tv.vval.v_list = (list_T *) eval_msgpack_type_lists[type];
type_di->di_tv.vval.v_list->lv_refcount++; type_di->di_tv.vval.v_list->lv_refcount++;
dict_add(dict, type_di); tv_dict_add(dict, type_di);
dictitem_T *const val_di = dictitem_alloc((char_u *) "_VAL"); dictitem_T *const val_di = tv_dict_item_alloc_len(S_LEN("_VAL"));
val_di->di_tv = val; val_di->di_tv = val;
dict_add(dict, val_di); tv_dict_add(dict, val_di);
dict->dv_refcount++; dict->dv_refcount++;
*rettv = (typval_T) { *rettv = (typval_T) {
.v_type = VAR_DICT, .v_type = VAR_DICT,
@@ -119,18 +120,18 @@ static inline int json_decoder_pop(ValuesStackItem obj,
if (last_container.container.vval.v_list->lv_len != 0 if (last_container.container.vval.v_list->lv_len != 0
&& !obj.didcomma) { && !obj.didcomma) {
EMSG2(_("E474: Expected comma before list item: %s"), val_location); EMSG2(_("E474: Expected comma before list item: %s"), val_location);
clear_tv(&obj.val); tv_clear(&obj.val);
return FAIL; return FAIL;
} }
assert(last_container.special_val == NULL); assert(last_container.special_val == NULL);
listitem_T *obj_li = listitem_alloc(); listitem_T *obj_li = tv_list_item_alloc();
obj_li->li_tv = obj.val; obj_li->li_tv = obj.val;
list_append(last_container.container.vval.v_list, obj_li); tv_list_append(last_container.container.vval.v_list, obj_li);
} else if (last_container.stack_index == kv_size(*stack) - 2) { } else if (last_container.stack_index == kv_size(*stack) - 2) {
if (!obj.didcolon) { if (!obj.didcolon) {
EMSG2(_("E474: Expected colon before dictionary value: %s"), EMSG2(_("E474: Expected colon before dictionary value: %s"),
val_location); val_location);
clear_tv(&obj.val); tv_clear(&obj.val);
return FAIL; return FAIL;
} }
ValuesStackItem key = kv_pop(*stack); ValuesStackItem key = kv_pop(*stack);
@@ -139,34 +140,35 @@ static inline int json_decoder_pop(ValuesStackItem obj,
assert(!(key.is_special_string assert(!(key.is_special_string
|| key.val.vval.v_string == NULL || key.val.vval.v_string == NULL
|| *key.val.vval.v_string == NUL)); || *key.val.vval.v_string == NUL));
dictitem_T *obj_di = dictitem_alloc(key.val.vval.v_string); dictitem_T *const obj_di = tv_dict_item_alloc(
clear_tv(&key.val); (const char *)key.val.vval.v_string);
if (dict_add(last_container.container.vval.v_dict, obj_di) tv_clear(&key.val);
if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
== FAIL) { == FAIL) {
assert(false); assert(false);
} }
obj_di->di_tv = obj.val; obj_di->di_tv = obj.val;
} else { } else {
list_T *const kv_pair = list_alloc(); list_T *const kv_pair = tv_list_alloc();
list_append_list(last_container.special_val, kv_pair); tv_list_append_list(last_container.special_val, kv_pair);
listitem_T *const key_li = listitem_alloc(); listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv = key.val; key_li->li_tv = key.val;
list_append(kv_pair, key_li); tv_list_append(kv_pair, key_li);
listitem_T *const val_li = listitem_alloc(); listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv = obj.val; val_li->li_tv = obj.val;
list_append(kv_pair, val_li); tv_list_append(kv_pair, val_li);
} }
} else { } else {
// Object with key only // Object with key only
if (!obj.is_special_string && obj.val.v_type != VAR_STRING) { if (!obj.is_special_string && obj.val.v_type != VAR_STRING) {
EMSG2(_("E474: Expected string key: %s"), *pp); EMSG2(_("E474: Expected string key: %s"), *pp);
clear_tv(&obj.val); tv_clear(&obj.val);
return FAIL; return FAIL;
} else if (!obj.didcomma } else if (!obj.didcomma
&& (last_container.special_val == NULL && (last_container.special_val == NULL
&& (DICT_LEN(last_container.container.vval.v_dict) != 0))) { && (DICT_LEN(last_container.container.vval.v_dict) != 0))) {
EMSG2(_("E474: Expected comma before dictionary key: %s"), val_location); EMSG2(_("E474: Expected comma before dictionary key: %s"), val_location);
clear_tv(&obj.val); tv_clear(&obj.val);
return FAIL; return FAIL;
} }
// Handle empty key and key represented as special dictionary // Handle empty key and key represented as special dictionary
@@ -174,16 +176,16 @@ static inline int json_decoder_pop(ValuesStackItem obj,
&& (obj.is_special_string && (obj.is_special_string
|| obj.val.vval.v_string == NULL || obj.val.vval.v_string == NULL
|| *obj.val.vval.v_string == NUL || *obj.val.vval.v_string == NUL
|| dict_find(last_container.container.vval.v_dict, || tv_dict_find(last_container.container.vval.v_dict,
obj.val.vval.v_string, -1))) { (const char *)obj.val.vval.v_string, -1))) {
clear_tv(&obj.val); tv_clear(&obj.val);
// Restart // Restart
(void) kv_pop(*container_stack); (void) kv_pop(*container_stack);
ValuesStackItem last_container_val = ValuesStackItem last_container_val =
kv_A(*stack, last_container.stack_index); kv_A(*stack, last_container.stack_index);
while (kv_size(*stack) > last_container.stack_index) { while (kv_size(*stack) > last_container.stack_index) {
clear_tv(&(kv_pop(*stack).val)); tv_clear(&(kv_pop(*stack).val));
} }
*pp = last_container.s; *pp = last_container.s;
*didcomma = last_container_val.didcomma; *didcomma = last_container_val.didcomma;
@@ -228,7 +230,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
list_T *decode_create_map_special_dict(typval_T *const ret_tv) list_T *decode_create_map_special_dict(typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
list_T *const list = list_alloc(); list_T *const list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
create_special_dict(ret_tv, kMPMap, ((typval_T) { create_special_dict(ret_tv, kMPMap, ((typval_T) {
.v_type = VAR_LIST, .v_type = VAR_LIST,
@@ -264,7 +266,7 @@ typval_T decode_string(const char *const s, const size_t len,
? memchr(s, NUL, len) != NULL ? memchr(s, NUL, len) != NULL
: (bool)hasnul); : (bool)hasnul);
if (really_hasnul) { if (really_hasnul) {
list_T *const list = list_alloc(); list_T *const list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
typval_T tv; typval_T tv;
create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) { create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
@@ -277,7 +279,7 @@ typval_T decode_string(const char *const s, const size_t len,
xfree((void *)s); xfree((void *)s);
} }
if (elw_ret == -1) { if (elw_ret == -1) {
clear_tv(&tv); tv_clear(&tv);
return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED }; return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
} }
return tv; return tv;
@@ -502,9 +504,8 @@ static inline int parse_json_string(vimconv_T *const conv,
str_end = new_str + str_len; str_end = new_str + str_len;
} }
*str_end = NUL; *str_end = NUL;
typval_T obj; typval_T obj = decode_string(
obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
false, true);
if (obj.v_type == VAR_UNKNOWN) { if (obj.v_type == VAR_UNKNOWN) {
goto parse_json_string_fail; goto parse_json_string_fail;
} }
@@ -864,7 +865,7 @@ json_decode_string_cycle_start:
break; break;
} }
case '[': { case '[': {
list_T *list = list_alloc(); list_T *list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
typval_T tv = { typval_T tv = {
.v_type = VAR_LIST, .v_type = VAR_LIST,
@@ -887,7 +888,7 @@ json_decode_string_cycle_start:
next_map_special = false; next_map_special = false;
val_list = decode_create_map_special_dict(&tv); val_list = decode_create_map_special_dict(&tv);
} else { } else {
dict_T *dict = dict_alloc(); dict_T *dict = tv_dict_alloc();
dict->dv_refcount++; dict->dv_refcount++;
tv = (typval_T) { tv = (typval_T) {
.v_type = VAR_DICT, .v_type = VAR_DICT,
@@ -939,7 +940,7 @@ json_decode_string_after_cycle:
json_decode_string_fail: json_decode_string_fail:
ret = FAIL; ret = FAIL;
while (kv_size(stack)) { while (kv_size(stack)) {
clear_tv(&(kv_pop(stack).val)); tv_clear(&(kv_pop(stack).val));
} }
json_decode_string_ret: json_decode_string_ret:
kv_destroy(stack); kv_destroy(stack);
@@ -985,7 +986,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_number = (varnumber_T) mobj.via.u64 }, .vval = { .v_number = (varnumber_T) mobj.via.u64 },
}; };
} else { } else {
list_T *const list = list_alloc(); list_T *const list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
create_special_dict(rettv, kMPInteger, ((typval_T) { create_special_dict(rettv, kMPInteger, ((typval_T) {
.v_type = VAR_LIST, .v_type = VAR_LIST,
@@ -993,10 +994,10 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_list = list }, .vval = { .v_list = list },
})); }));
uint64_t n = mobj.via.u64; uint64_t n = mobj.via.u64;
list_append_number(list, 1); tv_list_append_number(list, 1);
list_append_number(list, (varnumber_T) ((n >> 62) & 0x3)); tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF)); tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF)); tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
} }
break; break;
} }
@@ -1008,22 +1009,28 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_number = (varnumber_T) mobj.via.i64 }, .vval = { .v_number = (varnumber_T) mobj.via.i64 },
}; };
} else { } else {
list_T *const list = list_alloc(); list_T *const list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
create_special_dict(rettv, kMPInteger, ((typval_T) { create_special_dict(rettv, kMPInteger, ((typval_T) {
.v_type = VAR_LIST, .v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED, .v_lock = VAR_UNLOCKED,
.vval = { .v_list = list }, .vval = { .v_list = list },
})); }));
uint64_t n = -((uint64_t) mobj.via.i64); uint64_t n = -((uint64_t)mobj.via.i64);
list_append_number(list, -1); tv_list_append_number(list, -1);
list_append_number(list, (varnumber_T) ((n >> 62) & 0x3)); tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
list_append_number(list, (varnumber_T) ((n >> 31) & 0x7FFFFFFF)); tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
list_append_number(list, (varnumber_T) (n & 0x7FFFFFFF)); tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
} }
break; break;
} }
case MSGPACK_OBJECT_FLOAT: { #ifdef NVIM_MSGPACK_HAS_FLOAT32
case MSGPACK_OBJECT_FLOAT32:
case MSGPACK_OBJECT_FLOAT64:
#else
case MSGPACK_OBJECT_FLOAT:
#endif
{
*rettv = (typval_T) { *rettv = (typval_T) {
.v_type = VAR_FLOAT, .v_type = VAR_FLOAT,
.v_lock = VAR_UNLOCKED, .v_lock = VAR_UNLOCKED,
@@ -1048,7 +1055,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
break; break;
} }
case MSGPACK_OBJECT_ARRAY: { case MSGPACK_OBJECT_ARRAY: {
list_T *const list = list_alloc(); list_T *const list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
*rettv = (typval_T) { *rettv = (typval_T) {
.v_type = VAR_LIST, .v_type = VAR_LIST,
@@ -1056,9 +1063,9 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
.vval = { .v_list = list }, .vval = { .v_list = list },
}; };
for (size_t i = 0; i < mobj.via.array.size; i++) { for (size_t i = 0; i < mobj.via.array.size; i++) {
listitem_T *const li = listitem_alloc(); listitem_T *const li = tv_list_item_alloc();
li->li_tv.v_type = VAR_UNKNOWN; li->li_tv.v_type = VAR_UNKNOWN;
list_append(list, li); tv_list_append(list, li);
if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) { if (msgpack_to_vim(mobj.via.array.ptr[i], &li->li_tv) == FAIL) {
return FAIL; return FAIL;
} }
@@ -1074,7 +1081,7 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
goto msgpack_to_vim_generic_map; goto msgpack_to_vim_generic_map;
} }
} }
dict_T *const dict = dict_alloc(); dict_T *const dict = tv_dict_alloc();
dict->dv_refcount++; dict->dv_refcount++;
*rettv = (typval_T) { *rettv = (typval_T) {
.v_type = VAR_DICT, .v_type = VAR_DICT,
@@ -1087,9 +1094,9 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr, memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
mobj.via.map.ptr[i].key.via.str.size); mobj.via.map.ptr[i].key.via.str.size);
di->di_tv.v_type = VAR_UNKNOWN; di->di_tv.v_type = VAR_UNKNOWN;
if (dict_add(dict, di) == FAIL) { if (tv_dict_add(dict, di) == FAIL) {
// Duplicate key: fallback to generic map // Duplicate key: fallback to generic map
clear_tv(rettv); tv_clear(rettv);
xfree(di); xfree(di);
goto msgpack_to_vim_generic_map; goto msgpack_to_vim_generic_map;
} }
@@ -1101,14 +1108,14 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
msgpack_to_vim_generic_map: {} msgpack_to_vim_generic_map: {}
list_T *const list = decode_create_map_special_dict(rettv); list_T *const list = decode_create_map_special_dict(rettv);
for (size_t i = 0; i < mobj.via.map.size; i++) { for (size_t i = 0; i < mobj.via.map.size; i++) {
list_T *const kv_pair = list_alloc(); list_T *const kv_pair = tv_list_alloc();
list_append_list(list, kv_pair); tv_list_append_list(list, kv_pair);
listitem_T *const key_li = listitem_alloc(); listitem_T *const key_li = tv_list_item_alloc();
key_li->li_tv.v_type = VAR_UNKNOWN; key_li->li_tv.v_type = VAR_UNKNOWN;
list_append(kv_pair, key_li); tv_list_append(kv_pair, key_li);
listitem_T *const val_li = listitem_alloc(); listitem_T *const val_li = tv_list_item_alloc();
val_li->li_tv.v_type = VAR_UNKNOWN; val_li->li_tv.v_type = VAR_UNKNOWN;
list_append(kv_pair, val_li); tv_list_append(kv_pair, val_li);
if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) { if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_li->li_tv) == FAIL) {
return FAIL; return FAIL;
} }
@@ -1119,11 +1126,11 @@ msgpack_to_vim_generic_map: {}
break; break;
} }
case MSGPACK_OBJECT_EXT: { case MSGPACK_OBJECT_EXT: {
list_T *const list = list_alloc(); list_T *const list = tv_list_alloc();
list->lv_refcount++; list->lv_refcount++;
list_append_number(list, mobj.via.ext.type); tv_list_append_number(list, mobj.via.ext.type);
list_T *const ext_val_list = list_alloc(); list_T *const ext_val_list = tv_list_alloc();
list_append_list(list, ext_val_list); tv_list_append_list(list, ext_val_list);
create_special_dict(rettv, kMPExt, ((typval_T) { create_special_dict(rettv, kMPExt, ((typval_T) {
.v_type = VAR_LIST, .v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED, .v_lock = VAR_UNLOCKED,

View File

@@ -5,7 +5,7 @@
#include <msgpack.h> #include <msgpack.h>
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/decode.h.generated.h" # include "eval/decode.h.generated.h"

View File

@@ -13,7 +13,7 @@
#include "nvim/eval/encode.h" #include "nvim/eval/encode.h"
#include "nvim/buffer_defs.h" // vimconv_T #include "nvim/buffer_defs.h" // vimconv_T
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
#include "nvim/garray.h" #include "nvim/garray.h"
#include "nvim/mbyte.h" #include "nvim/mbyte.h"
#include "nvim/message.h" #include "nvim/message.h"
@@ -45,7 +45,8 @@ const char *const encode_special_var_names[] = {
#endif #endif
/// Msgpack callback for writing to readfile()-style list /// Msgpack callback for writing to readfile()-style list
int encode_list_write(void *data, const char *buf, size_t len) int encode_list_write(void *const data, const char *const buf, const size_t len)
FUNC_ATTR_NONNULL_ARG(1)
{ {
if (len == 0) { if (len == 0) {
return 0; return 0;
@@ -80,11 +81,11 @@ int encode_list_write(void *data, const char *buf, size_t len)
str = xmemdupz(line_start, line_length); str = xmemdupz(line_start, line_length);
memchrsub(str, NUL, NL, line_length); memchrsub(str, NUL, NL, line_length);
} }
list_append_allocated_string(list, str); tv_list_append_allocated_string(list, str);
line_end++; line_end++;
} }
if (line_end == end) { if (line_end == end) {
list_append_allocated_string(list, NULL); tv_list_append_allocated_string(list, NULL);
} }
return 0; return 0;
} }
@@ -743,11 +744,11 @@ bool encode_check_json_key(const typval_T *const tv)
} }
const dictitem_T *type_di; const dictitem_T *type_di;
const dictitem_T *val_di; const dictitem_T *val_di;
if ((type_di = dict_find((dict_T *) spdict, (char_u *) "_TYPE", -1)) == NULL if ((type_di = tv_dict_find(spdict, S_LEN("_TYPE"))) == NULL
|| type_di->di_tv.v_type != VAR_LIST || type_di->di_tv.v_type != VAR_LIST
|| (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString] || (type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPString]
&& type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary]) && type_di->di_tv.vval.v_list != eval_msgpack_type_lists[kMPBinary])
|| (val_di = dict_find((dict_T *) spdict, (char_u *) "_VAL", -1)) == NULL || (val_di = tv_dict_find(spdict, S_LEN("_VAL"))) == NULL
|| val_di->di_tv.v_type != VAR_LIST) { || val_di->di_tv.v_type != VAR_LIST) {
return false; return false;
} }

115
src/nvim/eval/executor.c Normal file
View File

@@ -0,0 +1,115 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval.h"
#include "nvim/message.h"
#include "nvim/vim.h"
#include "nvim/globals.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/executor.c.generated.h"
#endif
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
char *e_listidx = N_("E684: list index out of range: %" PRId64);
/// Hanle tv1 += tv2, -=, .=
///
/// @param[in,out] tv1 First operand, modified typval.
/// @param[in] tv2 Second operand.
/// @param[in] op Used operator.
///
/// @return OK or FAIL.
int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
const char *const op)
FUNC_ATTR_NONNULL_ALL
{
// Can't do anything with a Funcref, a Dict or special value on the right.
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
switch (tv1->v_type) {
case VAR_DICT:
case VAR_FUNC:
case VAR_PARTIAL:
case VAR_SPECIAL: {
break;
}
case VAR_LIST: {
if (*op != '+' || tv2->v_type != VAR_LIST) {
break;
}
// List += List
if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) {
tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
}
return OK;
}
case VAR_NUMBER:
case VAR_STRING: {
if (tv2->v_type == VAR_LIST) {
break;
}
if (*op == '+' || *op == '-') {
// nr += nr or nr -= nr
varnumber_T n = tv_get_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
float_T f = n;
if (*op == '+') {
f += tv2->vval.v_float;
} else {
f -= tv2->vval.v_float;
}
tv_clear(tv1);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f;
} else {
if (*op == '+') {
n += tv_get_number(tv2);
} else {
n -= tv_get_number(tv2);
}
tv_clear(tv1);
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n;
}
} else {
// str .= str
if (tv2->v_type == VAR_FLOAT) {
break;
}
const char *tvs = tv_get_string(tv1);
char numbuf[NUMBUFLEN];
char *const s = (char *)concat_str(
(const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2,
numbuf));
tv_clear(tv1);
tv1->v_type = VAR_STRING;
tv1->vval.v_string = (char_u *)s;
}
return OK;
}
case VAR_FLOAT: {
if (*op == '.' || (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING)) {
break;
}
const float_T f = (tv2->v_type == VAR_FLOAT
? tv2->vval.v_float
: tv_get_number(tv2));
if (*op == '+') {
tv1->vval.v_float += f;
} else {
tv1->vval.v_float -= f;
}
return OK;
}
case VAR_UNKNOWN: {
assert(false);
}
}
}
EMSG2(_(e_letwrong), op);
return FAIL;
}

11
src/nvim/eval/executor.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef NVIM_EVAL_EXECUTOR_H
#define NVIM_EVAL_EXECUTOR_H
#include "nvim/eval/typval.h"
extern char *e_listidx;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/executor.h.generated.h"
#endif
#endif // NVIM_EVAL_EXECUTOR_H

11
src/nvim/eval/gc.c Normal file
View File

@@ -0,0 +1,11 @@
#include "nvim/eval/typval.h"
#include "nvim/eval/gc.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/gc.c.generated.h"
#endif
/// Head of list of all dictionaries
dict_T *gc_first_dict = NULL;
/// Head of list of all lists
list_T *gc_first_list = NULL;

12
src/nvim/eval/gc.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef NVIM_EVAL_GC_H
#define NVIM_EVAL_GC_H
#include "nvim/eval/typval.h"
extern dict_T *gc_first_dict;
extern list_T *gc_first_list;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/gc.h.generated.h"
#endif
#endif // NVIM_EVAL_GC_H

2556
src/nvim/eval/typval.c Normal file

File diff suppressed because it is too large Load Diff

429
src/nvim/eval/typval.h Normal file
View File

@@ -0,0 +1,429 @@
#ifndef NVIM_EVAL_TYPVAL_H
#define NVIM_EVAL_TYPVAL_H
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "nvim/types.h"
#include "nvim/hashtab.h"
#include "nvim/garray.h"
#include "nvim/mbyte.h"
#include "nvim/func_attr.h"
#include "nvim/lib/queue.h"
#include "nvim/profile.h" // for proftime_T
#include "nvim/pos.h" // for linenr_T
#include "nvim/gettext.h"
#include "nvim/message.h"
/// Type used for VimL VAR_NUMBER values
typedef int varnumber_T;
/// Type used for VimL VAR_FLOAT values
typedef double float_T;
/// Maximal possible value of varnumber_T variable
#define VARNUMBER_MAX INT_MAX
/// Mimimal possible value of varnumber_T variable
#define VARNUMBER_MIN INT_MIN
#define PRIdVARNUMBER "d"
/// %d printf format specifier for varnumber_T
#define PRIdVARNUMBER "d"
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
typedef struct partial_S partial_T;
typedef struct ufunc ufunc_T;
typedef enum {
kCallbackNone,
kCallbackFuncref,
kCallbackPartial,
} CallbackType;
typedef struct {
union {
char_u *funcref;
partial_T *partial;
} data;
CallbackType type;
} Callback;
#define CALLBACK_NONE ((Callback){ .type = kCallbackNone })
/// Structure holding dictionary watcher
typedef struct dict_watcher {
Callback callback;
char *key_pattern;
size_t key_pattern_len;
QUEUE node;
bool busy; // prevent recursion if the dict is changed in the callback
} DictWatcher;
/// Special variable values
typedef enum {
kSpecialVarFalse, ///< v:false
kSpecialVarTrue, ///< v:true
kSpecialVarNull, ///< v:null
} SpecialVarValue;
/// Variable lock status for typval_T.v_lock
typedef enum {
VAR_UNLOCKED = 0, ///< Not locked.
VAR_LOCKED = 1, ///< User lock, can be unlocked.
VAR_FIXED = 2, ///< Locked forever.
} VarLockStatus;
/// VimL variable types, for use in typval_T.v_type
typedef enum {
VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
VAR_NUMBER, ///< Number, .v_number is used.
VAR_STRING, ///< String, .v_string is used.
VAR_FUNC, ///< Function reference, .v_string is used as function name.
VAR_LIST, ///< List, .v_list is used.
VAR_DICT, ///< Dictionary, .v_dict is used.
VAR_FLOAT, ///< Floating-point value, .v_float is used.
VAR_SPECIAL, ///< Special value (true, false, null), .v_special
///< is used.
VAR_PARTIAL, ///< Partial, .v_partial is used.
} VarType;
/// Structure that holds an internal variable value
typedef struct {
VarType v_type; ///< Variable type.
VarLockStatus v_lock; ///< Variable lock status.
union typval_vval_union {
varnumber_T v_number; ///< Number, for VAR_NUMBER.
SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
float_T v_float; ///< Floating-point number, for VAR_FLOAT.
char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
list_T *v_list; ///< List for VAR_LIST, can be NULL.
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
partial_T *v_partial; ///< Closure: function with args.
} vval; ///< Actual value.
} typval_T;
/// Values for (struct dictvar_S).dv_scope
typedef enum {
VAR_NO_SCOPE = 0, ///< Not a scope dictionary.
VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …).
VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix
///< (l:, g:).
} ScopeType;
/// Structure to hold an item of a list
typedef struct listitem_S listitem_T;
struct listitem_S {
listitem_T *li_next; ///< Next item in list.
listitem_T *li_prev; ///< Previous item in list.
typval_T li_tv; ///< Item value.
};
/// Structure used by those that are using an item in a list
typedef struct listwatch_S listwatch_T;
struct listwatch_S {
listitem_T *lw_item; ///< Item being watched.
listwatch_T *lw_next; ///< Next watcher.
};
/// Structure to hold info about a list
struct listvar_S {
listitem_T *lv_first; ///< First item, NULL if none.
listitem_T *lv_last; ///< Last item, NULL if none.
int lv_refcount; ///< Reference count.
int lv_len; ///< Number of items.
listwatch_T *lv_watch; ///< First watcher, NULL if none.
int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
int lv_copyID; ///< ID used by deepcopy().
list_T *lv_copylist; ///< Copied list used by deepcopy().
VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
list_T *lv_used_next; ///< next list in used lists list.
list_T *lv_used_prev; ///< Previous list in used lists list.
};
// Static list with 10 items. Use init_static_list() to initialize.
typedef struct {
list_T sl_list; // must be first
listitem_T sl_items[10];
} staticList10_T;
// Structure to hold an item of a Dictionary.
// Also used for a variable.
// The key is copied into "di_key" to avoid an extra alloc/free for it.
struct dictitem_S {
typval_T di_tv; ///< type and value of the variable
char_u di_flags; ///< flags (only used for variable)
char_u di_key[1]; ///< key (actually longer!)
};
#define TV_DICTITEM_STRUCT(KEY_LEN) \
struct { \
typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
uint8_t di_flags; /* Flags. */ \
char_u di_key[KEY_LEN]; /* Key value. */ \
}
/// Structure to hold a scope dictionary
///
/// @warning Must be compatible with dictitem_T.
///
/// For use in find_var_in_ht to pretend that it found dictionary item when it
/// finds scope dictionary.
typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem;
/// Structure to hold an item of a Dictionary
///
/// @warning Must be compatible with ScopeDictDictItem.
///
/// Also used for a variable.
typedef TV_DICTITEM_STRUCT() dictitem_T;
/// Flags for dictitem_T.di_flags
typedef enum {
DI_FLAGS_RO = 1, ///< Read-only value
DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox
DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d.
DI_FLAGS_LOCK = 8, ///< Locked value.
DI_FLAGS_ALLOC = 16, ///< Separately allocated.
} DictItemFlags;
/// Structure representing a Dictionary
struct dictvar_S {
VarLockStatus dv_lock; ///< Whole dictionary lock status.
ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
///< dictionary represents a scope (i.e. g:, l: …).
int dv_refcount; ///< Reference count.
int dv_copyID; ///< ID used when recursivery traversing a value.
hashtab_T dv_hashtab; ///< Hashtab containing all items.
dict_T *dv_copydict; ///< Copied dict used by deepcopy().
dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
QUEUE watchers; ///< Dictionary key watchers set by user code.
};
/// Type used for script ID
typedef int scid_T;
/// Format argument for scid_T
#define PRIdSCID "d"
// Structure to hold info for a function that is currently being executed.
typedef struct funccall_S funccall_T;
/// Structure to hold info for a user function.
struct ufunc {
int uf_varargs; ///< variable nr of arguments
int uf_flags;
int uf_calls; ///< nr of active calls
bool uf_cleared; ///< func_clear() was already called
garray_T uf_args; ///< arguments
garray_T uf_lines; ///< function lines
int uf_profiling; ///< true when func is being profiled
// Profiling the function as a whole.
int uf_tm_count; ///< nr of calls
proftime_T uf_tm_total; ///< time spent in function + children
proftime_T uf_tm_self; ///< time spent in function itself
proftime_T uf_tm_children; ///< time spent in children this call
// Profiling the function per line.
int *uf_tml_count; ///< nr of times line was executed
proftime_T *uf_tml_total; ///< time spent in a line + children
proftime_T *uf_tml_self; ///< time spent in a line itself
proftime_T uf_tml_start; ///< start time for current line
proftime_T uf_tml_children; ///< time spent in children for this line
proftime_T uf_tml_wait; ///< start wait time for current line
int uf_tml_idx; ///< index of line being timed; -1 if none
int uf_tml_execed; ///< line being timed was executed
scid_T uf_script_ID; ///< ID of script where function was defined,
///< used for s: variables
int uf_refcount; ///< reference count, see func_name_refcount()
funccall_T *uf_scoped; ///< l: local variables for closure
char_u uf_name[1]; ///< name of function (actually longer); can
///< start with <SNR>123_ (<SNR> is K_SPECIAL
///< KS_EXTRA KE_SNR)
};
/// Maximum number of function arguments
#define MAX_FUNC_ARGS 20
struct partial_S {
int pt_refcount; ///< Reference count.
char_u *pt_name; ///< Function name; when NULL use pt_func->name.
ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with
///< pt_name.
bool pt_auto; ///< When true the partial was created by using dict.member
///< in handle_subscript().
int pt_argc; ///< Number of arguments.
typval_T *pt_argv; ///< Arguments in allocated array.
dict_T *pt_dict; ///< Dict for "self".
};
/// Structure used for explicit stack while garbage collecting hash tables
typedef struct ht_stack_S {
hashtab_T *ht;
struct ht_stack_S *prev;
} ht_stack_T;
/// Structure used for explicit stack while garbage collecting lists
typedef struct list_stack_S {
list_T *list;
struct list_stack_S *prev;
} list_stack_T;
// In a hashtab item "hi_key" points to "di_key" in a dictitem.
// This avoids adding a pointer to the hashtab item.
/// Convert a hashitem pointer to a dictitem pointer
#define TV_DICT_HI2DI(hi) \
((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
static inline long tv_list_len(const list_T *const l)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a list
///
/// @param[in] l List to check.
static inline long tv_list_len(const list_T *const l)
{
if (l == NULL) {
return 0;
}
return l->lv_len;
}
static inline long tv_dict_len(const dict_T *const d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Get the number of items in a Dictionary
///
/// @param[in] d Dictionary to check.
static inline long tv_dict_len(const dict_T *const d)
{
if (d == NULL) {
return 0L;
}
return (long)d->dv_hashtab.ht_used;
}
static inline bool tv_dict_is_watched(const dict_T *const d)
REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Check if dictionary is watched
///
/// @param[in] d Dictionary to check.
///
/// @return true if there is at least one watcher.
static inline bool tv_dict_is_watched(const dict_T *const d)
{
return d && !QUEUE_EMPTY(&d->watchers);
}
/// Initialize VimL object
///
/// Initializes to unlocked VAR_UNKNOWN object.
///
/// @param[out] tv Object to initialize.
static inline void tv_init(typval_T *const tv)
{
if (tv != NULL) {
memset(tv, 0, sizeof(*tv));
}
}
#define TV_INITIAL_VALUE \
((typval_T) { \
.v_type = VAR_UNKNOWN, \
.v_lock = VAR_UNLOCKED, \
})
/// Empty string
///
/// Needed for hack which allows not allocating empty string and still not
/// crashing when freeing it.
extern const char *const tv_empty_string;
/// Specifies that free_unref_items() function has (not) been entered
extern bool tv_in_free_unref_items;
/// Iterate over a dictionary
///
/// @param[in] d Dictionary to iterate over.
/// @param di Name of the variable with current dictitem_T entry.
/// @param code Cycle body.
#define TV_DICT_ITER(d, di, code) \
HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \
{ \
dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \
{ \
code \
} \
} \
})
static inline bool tv_get_float_chk(const typval_T *const tv,
float_T *const ret_f)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
// FIXME circular dependency, cannot import message.h.
bool emsgf(const char *const fmt, ...);
/// Get the float value
///
/// Raises an error if object is not number or floating-point.
///
/// @param[in] tv VimL object to get value from.
/// @param[out] ret_f Location where resulting float is stored.
///
/// @return true in case of success, false if tv is not a number or float.
static inline bool tv_get_float_chk(const typval_T *const tv,
float_T *const ret_f)
{
if (tv->v_type == VAR_FLOAT) {
*ret_f = tv->vval.v_float;
return true;
}
if (tv->v_type == VAR_NUMBER) {
*ret_f = (float_T)tv->vval.v_number;
return true;
}
emsgf(_("E808: Number or Float required"));
return false;
}
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE
REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE;
/// Compute the `DictWatcher` address from a QUEUE node.
///
/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer
/// arithmetic).
static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
{
return QUEUE_DATA(q, DictWatcher, node);
}
static inline bool tv_is_func(const typval_T tv)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
/// Check whether given typval_T contains a function
///
/// That is, whether it contains VAR_FUNC or VAR_PARTIAL.
///
/// @param[in] tv Typval to check.
///
/// @return True if it is a function or a partial, false otherwise.
static inline bool tv_is_func(const typval_T tv)
{
return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL;
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval.h.generated.h"
#endif
#endif // NVIM_EVAL_TYPVAL_H

View File

@@ -238,7 +238,7 @@
#include <assert.h> #include <assert.h>
#include "nvim/lib/kvec.h" #include "nvim/lib/kvec.h"
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
#include "nvim/eval/encode.h" #include "nvim/eval/encode.h"
#include "nvim/func_attr.h" #include "nvim/func_attr.h"
#include "nvim/eval/typval_encode.h" #include "nvim/eval/typval_encode.h"
@@ -402,11 +402,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const dictitem_T *val_di; const dictitem_T *val_di;
if (TYPVAL_ENCODE_ALLOW_SPECIALS if (TYPVAL_ENCODE_ALLOW_SPECIALS
&& tv->vval.v_dict->dv_hashtab.ht_used == 2 && tv->vval.v_dict->dv_hashtab.ht_used == 2
&& (type_di = dict_find((dict_T *)tv->vval.v_dict, && (type_di = tv_dict_find((dict_T *)tv->vval.v_dict,
(char_u *)"_TYPE", -1)) != NULL S_LEN("_TYPE"))) != NULL
&& type_di->di_tv.v_type == VAR_LIST && type_di->di_tv.v_type == VAR_LIST
&& (val_di = dict_find((dict_T *)tv->vval.v_dict, && (val_di = tv_dict_find((dict_T *)tv->vval.v_dict,
(char_u *)"_VAL", -1)) != NULL) { S_LEN("_VAL"))) != NULL) {
size_t i; size_t i;
for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) { for (i = 0; i < ARRAY_SIZE(eval_msgpack_type_lists); i++) {
if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) { if (type_di->di_tv.vval.v_list == eval_msgpack_type_lists[i]) {
@@ -658,7 +658,7 @@ typval_encode_stop_converting_one_item:
while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) { while (HASHITEM_EMPTY(cur_mpsv->data.d.hi)) {
cur_mpsv->data.d.hi++; cur_mpsv->data.d.hi++;
} }
dictitem_T *const di = HI2DI(cur_mpsv->data.d.hi); dictitem_T *const di = TV_DICT_HI2DI(cur_mpsv->data.d.hi);
cur_mpsv->data.d.todo--; cur_mpsv->data.d.todo--;
cur_mpsv->data.d.hi++; cur_mpsv->data.d.hi++;
TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0], TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0],

View File

@@ -11,7 +11,7 @@
#include <assert.h> #include <assert.h>
#include "nvim/lib/kvec.h" #include "nvim/lib/kvec.h"
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
#include "nvim/func_attr.h" #include "nvim/func_attr.h"
/// Type of the stack entry /// Type of the stack entry

View File

@@ -1,285 +0,0 @@
#ifndef NVIM_EVAL_DEFS_H
#define NVIM_EVAL_DEFS_H
#include <limits.h>
#include <stddef.h>
#include "nvim/hashtab.h"
#include "nvim/lib/queue.h"
#include "nvim/garray.h" // for garray_T
#include "nvim/profile.h" // for proftime_T
#include "nvim/pos.h" // for linenr_T
typedef int varnumber_T;
typedef double float_T;
#define VARNUMBER_MAX INT_MAX
#define VARNUMBER_MIN INT_MIN
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
typedef struct partial_S partial_T;
/// Special variable values
typedef enum {
kSpecialVarFalse, ///< v:false
kSpecialVarTrue, ///< v:true
kSpecialVarNull, ///< v:null
} SpecialVarValue;
/// Variable lock status for typval_T.v_lock
typedef enum {
VAR_UNLOCKED = 0, ///< Not locked.
VAR_LOCKED = 1, ///< User lock, can be unlocked.
VAR_FIXED = 2, ///< Locked forever.
} VarLockStatus;
/// VimL variable types, for use in typval_T.v_type
typedef enum {
VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
VAR_NUMBER, ///< Number, .v_number is used.
VAR_STRING, ///< String, .v_string is used.
VAR_FUNC, ///< Function reference, .v_string is used as function name.
VAR_LIST, ///< List, .v_list is used.
VAR_DICT, ///< Dictionary, .v_dict is used.
VAR_FLOAT, ///< Floating-point value, .v_float is used.
VAR_SPECIAL, ///< Special value (true, false, null), .v_special
///< is used.
VAR_PARTIAL, ///< Partial, .v_partial is used.
} VarType;
/// Structure that holds an internal variable value
typedef struct {
VarType v_type; ///< Variable type.
VarLockStatus v_lock; ///< Variable lock status.
union typval_vval_union {
varnumber_T v_number; ///< Number, for VAR_NUMBER.
SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
float_T v_float; ///< Floating-point number, for VAR_FLOAT.
char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
list_T *v_list; ///< List for VAR_LIST, can be NULL.
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
partial_T *v_partial; ///< Closure: function with args.
} vval; ///< Actual value.
} typval_T;
/* Values for "dv_scope". */
#define VAR_SCOPE 1 /* a:, v:, s:, etc. scope dictionaries */
#define VAR_DEF_SCOPE 2 /* l:, g: scope dictionaries: here funcrefs are not
allowed to mask existing functions */
/*
* Structure to hold an item of a list: an internal variable without a name.
*/
typedef struct listitem_S listitem_T;
struct listitem_S {
listitem_T *li_next; /* next item in list */
listitem_T *li_prev; /* previous item in list */
typval_T li_tv; /* type and value of the variable */
};
/*
* Struct used by those that are using an item in a list.
*/
typedef struct listwatch_S listwatch_T;
struct listwatch_S {
listitem_T *lw_item; /* item being watched */
listwatch_T *lw_next; /* next watcher */
};
/*
* Structure to hold info about a list.
*/
struct listvar_S {
listitem_T *lv_first; ///< First item, NULL if none.
listitem_T *lv_last; ///< Last item, NULL if none.
int lv_refcount; ///< Reference count.
int lv_len; ///< Number of items.
listwatch_T *lv_watch; ///< First watcher, NULL if none.
int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
int lv_copyID; ///< ID used by deepcopy().
list_T *lv_copylist; ///< Copied list used by deepcopy().
VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
list_T *lv_used_next; ///< next list in used lists list.
list_T *lv_used_prev; ///< Previous list in used lists list.
};
// Static list with 10 items. Use init_static_list() to initialize.
typedef struct {
list_T sl_list; // must be first
listitem_T sl_items[10];
} staticList10_T;
// Structure to hold an item of a Dictionary.
// Also used for a variable.
// The key is copied into "di_key" to avoid an extra alloc/free for it.
struct dictitem_S {
typval_T di_tv; ///< type and value of the variable
char_u di_flags; ///< flags (only used for variable)
char_u di_key[1]; ///< key (actually longer!)
};
typedef struct dictitem_S dictitem_T;
/// A dictitem with a 16 character key (plus NUL)
struct dictitem16_S {
typval_T di_tv; ///< type and value of the variable
char_u di_flags; ///< flags (only used for variable)
char_u di_key[17]; ///< key
};
typedef struct dictitem16_S dictitem16_T;
#define DI_FLAGS_RO 1 // "di_flags" value: read-only variable
#define DI_FLAGS_RO_SBX 2 // "di_flags" value: read-only in the sandbox
#define DI_FLAGS_FIX 4 // "di_flags" value: fixed: no :unlet or remove()
#define DI_FLAGS_LOCK 8 // "di_flags" value: locked variable
#define DI_FLAGS_ALLOC 16 // "di_flags" value: separately allocated
/// Structure representing a Dictionary
struct dictvar_S {
VarLockStatus dv_lock; ///< Whole dictionary lock status.
char dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
///< dictionary represents a scope (i.e. g:, l: …).
int dv_refcount; ///< Reference count.
int dv_copyID; ///< ID used when recursivery traversing a value.
hashtab_T dv_hashtab; ///< Hashtab containing all items.
dict_T *dv_copydict; ///< Copied dict used by deepcopy().
dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
QUEUE watchers; ///< Dictionary key watchers set by user code.
};
typedef int scid_T; // script ID
typedef struct funccall_S funccall_T;
// Structure to hold info for a user function.
typedef struct ufunc ufunc_T;
struct ufunc {
int uf_varargs; ///< variable nr of arguments
int uf_flags;
int uf_calls; ///< nr of active calls
bool uf_cleared; ///< func_clear() was already called
garray_T uf_args; ///< arguments
garray_T uf_lines; ///< function lines
int uf_profiling; ///< true when func is being profiled
// Profiling the function as a whole.
int uf_tm_count; ///< nr of calls
proftime_T uf_tm_total; ///< time spent in function + children
proftime_T uf_tm_self; ///< time spent in function itself
proftime_T uf_tm_children; ///< time spent in children this call
// Profiling the function per line.
int *uf_tml_count; ///< nr of times line was executed
proftime_T *uf_tml_total; ///< time spent in a line + children
proftime_T *uf_tml_self; ///< time spent in a line itself
proftime_T uf_tml_start; ///< start time for current line
proftime_T uf_tml_children; ///< time spent in children for this line
proftime_T uf_tml_wait; ///< start wait time for current line
int uf_tml_idx; ///< index of line being timed; -1 if none
int uf_tml_execed; ///< line being timed was executed
scid_T uf_script_ID; ///< ID of script where function was defined,
// used for s: variables
int uf_refcount; ///< reference count, see func_name_refcount()
funccall_T *uf_scoped; ///< l: local variables for closure
char_u uf_name[1]; ///< name of function (actually longer); can
// start with <SNR>123_ (<SNR> is K_SPECIAL
// KS_EXTRA KE_SNR)
};
/// Maximum number of function arguments
#define MAX_FUNC_ARGS 20
#define VAR_SHORT_LEN 20 // short variable name length
#define FIXVAR_CNT 12 // number of fixed variables
// structure to hold info for a function that is currently being executed.
struct funccall_S {
ufunc_T *func; ///< function being called
int linenr; ///< next line to be executed
int returned; ///< ":return" used
struct { ///< fixed variables for arguments
dictitem_T var; ///< variable (without room for name)
char_u room[VAR_SHORT_LEN]; ///< room for the name
} fixvar[FIXVAR_CNT];
dict_T l_vars; ///< l: local function variables
dictitem_T l_vars_var; ///< variable for l: scope
dict_T l_avars; ///< a: argument variables
dictitem_T l_avars_var; ///< variable for a: scope
list_T l_varlist; ///< list for a:000
listitem_T l_listitems[MAX_FUNC_ARGS]; ///< listitems for a:000
typval_T *rettv; ///< return value
linenr_T breakpoint; ///< next line with breakpoint or zero
int dbg_tick; ///< debug_tick when breakpoint was set
int level; ///< top nesting level of executed function
proftime_T prof_child; ///< time spent in a child
funccall_T *caller; ///< calling function or NULL
int fc_refcount; ///< number of user functions that reference
// this funccal
int fc_copyID; ///< for garbage collection
garray_T fc_funcs; ///< list of ufunc_T* which keep a reference
// to "func"
};
// structure used by trans_function_name()
typedef struct {
dict_T *fd_dict; ///< Dictionary used.
char_u *fd_newkey; ///< New key in "dict" in allocated memory.
dictitem_T *fd_di; ///< Dictionary item used.
} funcdict_T;
struct partial_S {
int pt_refcount; ///< Reference count.
char_u *pt_name; ///< Function name; when NULL use pt_func->name.
ufunc_T *pt_func; ///< Function pointer; when NULL lookup function
///< with pt_name.
bool pt_auto; ///< when true the partial was created for using
///< dict.member in handle_subscript().
int pt_argc; ///< Number of arguments.
typval_T *pt_argv; ///< Arguments in allocated array.
dict_T *pt_dict; ///< Dict for "self".
};
// structure used for explicit stack while garbage collecting hash tables
typedef struct ht_stack_S {
hashtab_T *ht;
struct ht_stack_S *prev;
} ht_stack_T;
// structure used for explicit stack while garbage collecting lists
typedef struct list_stack_S {
list_T *list;
struct list_stack_S *prev;
} list_stack_T;
// In a hashtab item "hi_key" points to "di_key" in a dictitem.
// This avoids adding a pointer to the hashtab item.
/// Convert a dictitem pointer to a hashitem key pointer
#define DI2HIKEY(di) ((di)->di_key)
/// Convert a hashitem key pointer to a dictitem pointer
#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
/// Convert a hashitem value pointer to a dictitem pointer
#define HIVAL2DI(p) \
((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv)))
/// Convert a hashitem pointer to a dictitem pointer
#define HI2DI(hi) HIKEY2DI((hi)->hi_key)
/// Type of assert_* check being performed
typedef enum
{
ASSERT_EQUAL,
ASSERT_NOTEQUAL,
ASSERT_MATCH,
ASSERT_NOTMATCH,
ASSERT_INRANGE,
ASSERT_OTHER,
} assert_type_T;
#endif // NVIM_EVAL_DEFS_H

View File

@@ -21,7 +21,7 @@ struct process {
int pid, status, refcount; int pid, status, refcount;
// set to the hrtime of when process_stop was called for the process. // set to the hrtime of when process_stop was called for the process.
uint64_t stopped_time; uint64_t stopped_time;
char *cwd; const char *cwd;
char **argv; char **argv;
Stream *in, *out, *err; Stream *in, *out, *err;
process_exit_cb cb; process_exit_cb cb;

View File

@@ -89,7 +89,10 @@ static void on_rbuffer_nonfull(RBuffer *buf, void *data)
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf) static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
{ {
Stream *stream = handle->data; Stream *stream = handle->data;
buf->base = rbuffer_write_ptr(stream->buffer, &buf->len); // `uv_buf_t.len` happens to have different size on Windows.
size_t write_count;
buf->base = rbuffer_write_ptr(stream->buffer, &write_count);
buf->len = write_count;
} }
// Callback invoked by libuv after it copies the data into the buffer provided // Callback invoked by libuv after it copies the data into the buffer provided
@@ -136,7 +139,10 @@ static void fread_idle_cb(uv_idle_t *handle)
uv_fs_t req; uv_fs_t req;
Stream *stream = handle->data; Stream *stream = handle->data;
stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &stream->uvbuf.len); // `uv_buf_t.len` happens to have different size on Windows.
size_t write_count;
stream->uvbuf.base = rbuffer_write_ptr(stream->buffer, &write_count);
stream->uvbuf.len = write_count;
// the offset argument to uv_fs_read is int64_t, could someone really try // the offset argument to uv_fs_read is int64_t, could someone really try
// to read more than 9 quintillion (9e18) bytes? // to read more than 9 quintillion (9e18) bytes?

View File

@@ -1008,8 +1008,8 @@ void do_bang(int addr_count, exarg_T *eap, int forceit, int do_in, int do_out)
AppendToRedobuffLit(cmd, -1); AppendToRedobuffLit(cmd, -1);
xfree(cmd); xfree(cmd);
AppendToRedobuff((char_u *)"\n"); AppendToRedobuff("\n");
bangredo = FALSE; bangredo = false;
} }
/* /*
* Add quotes around the command, for shells that need them. * Add quotes around the command, for shells that need them.
@@ -2958,7 +2958,7 @@ void sub_set_replacement(SubReplacementString sub)
{ {
xfree(old_sub.sub); xfree(old_sub.sub);
if (sub.additional_elements != old_sub.additional_elements) { if (sub.additional_elements != old_sub.additional_elements) {
list_unref(old_sub.additional_elements); tv_list_unref(old_sub.additional_elements);
} }
old_sub = sub; old_sub = sub;
} }
@@ -4764,8 +4764,8 @@ void fix_help_buffer(void)
char_u *p; char_u *p;
char_u *rt; char_u *rt;
/* set filetype to "help". */ // Set filetype to "help".
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL); set_option_value("ft", 0L, "help", OPT_LOCAL);
if (!syntax_present(curwin)) { if (!syntax_present(curwin)) {
for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) { for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {

View File

@@ -4,8 +4,8 @@
#include <stdbool.h> #include <stdbool.h>
#include "nvim/os/time.h" #include "nvim/os/time.h"
#include "nvim/eval_defs.h"
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/eval/typval.h"
// flags for do_ecmd() // flags for do_ecmd()
#define ECMD_HIDE 0x01 // don't free the current buffer #define ECMD_HIDE 0x01 // don't free the current buffer

View File

@@ -957,23 +957,21 @@ char_u *get_profile_name(expand_T *xp, int idx)
} }
/// Handle command line completion for :profile command. /// Handle command line completion for :profile command.
void set_context_in_profile_cmd(expand_T *xp, char_u *arg) void set_context_in_profile_cmd(expand_T *xp, const char *arg)
{ {
char_u *end_subcmd;
// Default: expand subcommands. // Default: expand subcommands.
xp->xp_context = EXPAND_PROFILE; xp->xp_context = EXPAND_PROFILE;
pexpand_what = PEXP_SUBCMD; pexpand_what = PEXP_SUBCMD;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
end_subcmd = skiptowhite(arg); char_u *const end_subcmd = skiptowhite((const char_u *)arg);
if (*end_subcmd == NUL) { if (*end_subcmd == NUL) {
return; return;
} }
if (end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0) { if ((const char *)end_subcmd - arg == 5 && strncmp(arg, "start", 5) == 0) {
xp->xp_context = EXPAND_FILES; xp->xp_context = EXPAND_FILES;
xp->xp_pattern = skipwhite(end_subcmd); xp->xp_pattern = skipwhite((const char_u *)end_subcmd);
return; return;
} }
@@ -2073,9 +2071,9 @@ void ex_listdo(exarg_T *eap)
// Clear 'shm' to avoid that the file message overwrites // Clear 'shm' to avoid that the file message overwrites
// any output from the command. // any output from the command.
p_shm_save = vim_strsave(p_shm); p_shm_save = vim_strsave(p_shm);
set_option_value((char_u *)"shm", 0L, (char_u *)"", 0); set_option_value("shm", 0L, "", 0);
do_argfile(eap, i); do_argfile(eap, i);
set_option_value((char_u *)"shm", 0L, p_shm_save, 0); set_option_value("shm", 0L, (char *)p_shm_save, 0);
xfree(p_shm_save); xfree(p_shm_save);
} }
if (curwin->w_arg_idx != i) { if (curwin->w_arg_idx != i) {
@@ -2138,9 +2136,9 @@ void ex_listdo(exarg_T *eap)
// Go to the next buffer. Clear 'shm' to avoid that the file // Go to the next buffer. Clear 'shm' to avoid that the file
// message overwrites any output from the command. // message overwrites any output from the command.
p_shm_save = vim_strsave(p_shm); p_shm_save = vim_strsave(p_shm);
set_option_value((char_u *)"shm", 0L, (char_u *)"", 0); set_option_value("shm", 0L, "", 0);
goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum); goto_buffer(eap, DOBUF_FIRST, FORWARD, next_fnum);
set_option_value((char_u *)"shm", 0L, p_shm_save, 0); set_option_value("shm", 0L, (char *)p_shm_save, 0);
xfree(p_shm_save); xfree(p_shm_save);
// If autocommands took us elsewhere, quit here. // If autocommands took us elsewhere, quit here.
@@ -2256,8 +2254,8 @@ void ex_compiler(exarg_T *eap)
} }
do_cmdline_cmd("command -nargs=* CompilerSet setlocal <args>"); do_cmdline_cmd("command -nargs=* CompilerSet setlocal <args>");
} }
do_unlet((char_u *)"g:current_compiler", true); do_unlet(S_LEN("g:current_compiler"), true);
do_unlet((char_u *)"b:current_compiler", true); do_unlet(S_LEN("b:current_compiler"), true);
snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg); snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg);
if (source_runtime(buf, DIP_ALL) == FAIL) { if (source_runtime(buf, DIP_ALL) == FAIL) {
@@ -2280,7 +2278,7 @@ void ex_compiler(exarg_T *eap)
old_cur_comp); old_cur_comp);
xfree(old_cur_comp); xfree(old_cur_comp);
} else { } else {
do_unlet((char_u *)"g:current_compiler", true); do_unlet(S_LEN("g:current_compiler"), true);
} }
} }
} }
@@ -2496,16 +2494,16 @@ static int APP_BOTH;
static void add_pack_plugin(char_u *fname, void *cookie) static void add_pack_plugin(char_u *fname, void *cookie)
{ {
char_u *p4, *p3, *p2, *p1, *p; char_u *p4, *p3, *p2, *p1, *p;
char_u *new_rtp;
char_u *ffname = (char_u *)fix_fname((char *)fname); char *const ffname = fix_fname((char *)fname);
if (ffname == NULL) { if (ffname == NULL) {
return; return;
} }
if (cookie != &APP_LOAD && strstr((char *)p_rtp, (char *)ffname) == NULL) { if (cookie != &APP_LOAD && strstr((char *)p_rtp, ffname) == NULL) {
// directory is not yet in 'runtimepath', add it // directory is not yet in 'runtimepath', add it
p4 = p3 = p2 = p1 = get_past_head(ffname); p4 = p3 = p2 = p1 = get_past_head((char_u *)ffname);
for (p = p1; *p; mb_ptr_adv(p)) { for (p = p1; *p; mb_ptr_adv(p)) {
if (vim_ispathsep_nocolon(*p)) { if (vim_ispathsep_nocolon(*p)) {
p4 = p3; p3 = p2; p2 = p1; p1 = p; p4 = p3; p3 = p2; p2 = p1; p1 = p;
@@ -2521,13 +2519,13 @@ static void add_pack_plugin(char_u *fname, void *cookie)
*p4 = NUL; *p4 = NUL;
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences // Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
size_t fname_len = STRLEN(ffname); size_t fname_len = strlen(ffname);
char_u *insp = p_rtp; const char *insp = (const char *)p_rtp;
for (;;) { for (;;) {
if (vim_fnamencmp(insp, ffname, fname_len) == 0) { if (path_fnamencmp(insp, ffname, fname_len) == 0) {
break; break;
} }
insp = vim_strchr(insp, ','); insp = strchr(insp, ',');
if (insp == NULL) { if (insp == NULL) {
break; break;
} }
@@ -2536,10 +2534,10 @@ static void add_pack_plugin(char_u *fname, void *cookie)
if (insp == NULL) { if (insp == NULL) {
// not found, append at the end // not found, append at the end
insp = p_rtp + STRLEN(p_rtp); insp = (const char *)p_rtp + STRLEN(p_rtp);
} else { } else {
// append after the matching directory. // append after the matching directory.
insp += STRLEN(ffname); insp += strlen(ffname);
while (*insp != NUL && *insp != ',') { while (*insp != NUL && *insp != ',') {
insp++; insp++;
} }
@@ -2547,31 +2545,40 @@ static void add_pack_plugin(char_u *fname, void *cookie)
*p4 = c; *p4 = c;
// check if rtp/pack/name/start/name/after exists // check if rtp/pack/name/start/name/after exists
char *afterdir = concat_fnames((char *)ffname, "after", true); char *afterdir = concat_fnames(ffname, "after", true);
size_t afterlen = 0; size_t afterlen = 0;
if (os_isdir((char_u *)afterdir)) { if (os_isdir((char_u *)afterdir)) {
afterlen = STRLEN(afterdir) + 1; // add one for comma afterlen = strlen(afterdir) + 1; // add one for comma
} }
size_t oldlen = STRLEN(p_rtp); const size_t oldlen = STRLEN(p_rtp);
size_t addlen = STRLEN(ffname) + 1; // add one for comma const size_t addlen = strlen(ffname) + 1; // add one for comma
new_rtp = try_malloc(oldlen + addlen + afterlen + 1); // add one for NUL const size_t new_rtp_len = oldlen + addlen + afterlen + 1;
// add one for NUL -------------------------------------^
char *const new_rtp = try_malloc(new_rtp_len);
if (new_rtp == NULL) { if (new_rtp == NULL) {
goto theend; goto theend;
} }
uintptr_t keep = (uintptr_t)(insp - p_rtp); const size_t keep = (size_t)(insp - (const char *)p_rtp);
size_t new_rtp_fill = 0;
memmove(new_rtp, p_rtp, keep); memmove(new_rtp, p_rtp, keep);
new_rtp[keep] = ','; new_rtp_fill += keep;
memmove(new_rtp + keep + 1, ffname, addlen); new_rtp[new_rtp_fill++] = ',';
memmove(new_rtp + new_rtp_fill, ffname, addlen);
new_rtp_fill += addlen - 1;
assert(new_rtp[new_rtp_fill] == NUL || new_rtp[new_rtp_fill] == ',');
if (p_rtp[keep] != NUL) { if (p_rtp[keep] != NUL) {
memmove(new_rtp + keep + addlen, p_rtp + keep, memmove(new_rtp + new_rtp_fill, p_rtp + keep, oldlen - keep + 1);
oldlen - keep + 1); new_rtp_fill += oldlen - keep;
} }
if (afterlen > 0) { if (afterlen > 0) {
STRCAT(new_rtp, ","); assert(new_rtp[new_rtp_fill] == NUL);
STRCAT(new_rtp, afterdir); new_rtp[new_rtp_fill++] = ',';
memmove(new_rtp + new_rtp_fill, afterdir, afterlen - 1);
new_rtp_fill += afterlen - 1;
} }
set_option_value((char_u *)"rtp", 0L, new_rtp, 0); new_rtp[new_rtp_fill] = NUL;
set_option_value("rtp", 0L, new_rtp, 0);
xfree(new_rtp); xfree(new_rtp);
xfree(afterdir); xfree(afterdir);
} }
@@ -2580,7 +2587,7 @@ static void add_pack_plugin(char_u *fname, void *cookie)
static const char *plugpat = "%s/plugin/**/*.vim"; // NOLINT static const char *plugpat = "%s/plugin/**/*.vim"; // NOLINT
static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT
size_t len = STRLEN(ffname) + STRLEN(ftpat); size_t len = strlen(ffname) + STRLEN(ftpat);
char_u *pat = try_malloc(len + 1); char_u *pat = try_malloc(len + 1);
if (pat == NULL) { if (pat == NULL) {
goto theend; goto theend;
@@ -3699,12 +3706,12 @@ static void script_host_execute(char *name, exarg_T *eap)
char *const script = script_get(eap, &len); char *const script = script_get(eap, &len);
if (script != NULL) { if (script != NULL) {
list_T *const args = list_alloc(); list_T *const args = tv_list_alloc();
// script // script
list_append_allocated_string(args, script); tv_list_append_allocated_string(args, script);
// current range // current range
list_append_number(args, (int)eap->line1); tv_list_append_number(args, (int)eap->line1);
list_append_number(args, (int)eap->line2); tv_list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute", args); (void)eval_call_provider(name, "execute", args);
} }
} }
@@ -3714,21 +3721,21 @@ static void script_host_execute_file(char *name, exarg_T *eap)
uint8_t buffer[MAXPATHL]; uint8_t buffer[MAXPATHL];
vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false); vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false);
list_T *args = list_alloc(); list_T *args = tv_list_alloc();
// filename // filename
list_append_string(args, buffer, -1); tv_list_append_string(args, (const char *)buffer, -1);
// current range // current range
list_append_number(args, (int)eap->line1); tv_list_append_number(args, (int)eap->line1);
list_append_number(args, (int)eap->line2); tv_list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute_file", args); (void)eval_call_provider(name, "execute_file", args);
} }
static void script_host_do_range(char *name, exarg_T *eap) static void script_host_do_range(char *name, exarg_T *eap)
{ {
list_T *args = list_alloc(); list_T *args = tv_list_alloc();
list_append_number(args, (int)eap->line1); tv_list_append_number(args, (int)eap->line1);
list_append_number(args, (int)eap->line2); tv_list_append_number(args, (int)eap->line2);
list_append_string(args, eap->arg, -1); tv_list_append_string(args, (const char *)eap->arg, -1);
(void)eval_call_provider(name, "do_range", args); (void)eval_call_provider(name, "do_range", args);
} }

View File

@@ -68,6 +68,7 @@
#include "nvim/event/wstream.h" #include "nvim/event/wstream.h"
#include "nvim/shada.h" #include "nvim/shada.h"
#include "nvim/viml/executor/executor.h" #include "nvim/viml/executor/executor.h"
#include "nvim/globals.h"
static int quitmore = 0; static int quitmore = 0;
static int ex_pressedreturn = FALSE; static int ex_pressedreturn = FALSE;
@@ -270,7 +271,7 @@ do_exmode (
/* /*
* Execute a simple command line. Used for translated commands like "*". * Execute a simple command line. Used for translated commands like "*".
*/ */
int do_cmdline_cmd(char *cmd) int do_cmdline_cmd(const char *cmd)
{ {
return do_cmdline((char_u *)cmd, NULL, NULL, return do_cmdline((char_u *)cmd, NULL, NULL,
DOCMD_NOWAIT|DOCMD_KEYTYPED); DOCMD_NOWAIT|DOCMD_KEYTYPED);
@@ -2633,32 +2634,27 @@ int cmd_exists(const char *const name)
* perfectly compatible with each other, but then the command line syntax * perfectly compatible with each other, but then the command line syntax
* probably won't change that much -- webb. * probably won't change that much -- webb.
*/ */
char_u * const char * set_one_cmd_context(
set_one_cmd_context (
expand_T *xp, expand_T *xp,
char_u *buff /* buffer for command string */ const char *buff // buffer for command string
) )
{ {
char_u *p; size_t len = 0;
char_u *cmd, *arg;
int len = 0;
exarg_T ea; exarg_T ea;
int compl = EXPAND_NOTHING; int context = EXPAND_NOTHING;
int delim; int forceit = false;
int forceit = FALSE; int usefilter = false; // Filter instead of file name.
int usefilter = FALSE; /* filter instead of file name */
ExpandInit(xp); ExpandInit(xp);
xp->xp_pattern = buff; xp->xp_pattern = (char_u *)buff;
xp->xp_context = EXPAND_COMMANDS; /* Default until we get past command */ xp->xp_context = EXPAND_COMMANDS; // Default until we get past command
ea.argt = 0; ea.argt = 0;
/* // 2. skip comment lines and leading space, colons or bars
* 2. skip comment lines and leading space, colons or bars const char *cmd;
*/ for (cmd = buff; strchr(" \t:|", *cmd) != NULL; cmd++) {
for (cmd = buff; vim_strchr((char_u *)" \t:|", *cmd) != NULL; cmd++) }
; xp->xp_pattern = (char_u *)cmd;
xp->xp_pattern = cmd;
if (*cmd == NUL) if (*cmd == NUL)
return NULL; return NULL;
@@ -2670,14 +2666,15 @@ set_one_cmd_context (
/* /*
* 3. parse a range specifier of the form: addr [,addr] [;addr] .. * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
*/ */
cmd = skip_range(cmd, &xp->xp_context); cmd = (const char *)skip_range((const char_u *)cmd, &xp->xp_context);
/* /*
* 4. parse command * 4. parse command
*/ */
xp->xp_pattern = cmd; xp->xp_pattern = (char_u *)cmd;
if (*cmd == NUL) if (*cmd == NUL) {
return NULL; return NULL;
}
if (*cmd == '"') { if (*cmd == '"') {
xp->xp_context = EXPAND_NOTHING; xp->xp_context = EXPAND_NOTHING;
return NULL; return NULL;
@@ -2693,6 +2690,7 @@ set_one_cmd_context (
* do accept "keepmarks", "keepalt" and "keepjumps". * do accept "keepmarks", "keepalt" and "keepjumps".
* - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
*/ */
const char *p;
if (*cmd == 'k' && cmd[1] != 'e') { if (*cmd == 'k' && cmd[1] != 'e') {
ea.cmdidx = CMD_k; ea.cmdidx = CMD_k;
p = cmd + 1; p = cmd + 1;
@@ -2715,20 +2713,21 @@ set_one_cmd_context (
} }
} }
// check for non-alpha command // check for non-alpha command
if (p == cmd && vim_strchr((char_u *)"@*!=><&~#", *p) != NULL) { if (p == cmd && strchr("@*!=><&~#", *p) != NULL) {
p++; p++;
} }
len = (int)(p - cmd); len = (size_t)(p - cmd);
if (len == 0) { if (len == 0) {
xp->xp_context = EXPAND_UNSUCCESSFUL; xp->xp_context = EXPAND_UNSUCCESSFUL;
return NULL; return NULL;
} }
for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE; for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE;
ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1)) ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1)) {
if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd, if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd, len) == 0) {
(size_t)len) == 0)
break; break;
}
}
if (cmd[0] >= 'A' && cmd[0] <= 'Z') { if (cmd[0] >= 'A' && cmd[0] <= 'Z') {
while (ASCII_ISALNUM(*p) || *p == '*') { // Allow * wild card while (ASCII_ISALNUM(*p) || *p == '*') { // Allow * wild card
@@ -2745,16 +2744,15 @@ set_one_cmd_context (
return NULL; return NULL;
if (ea.cmdidx == CMD_SIZE) { if (ea.cmdidx == CMD_SIZE) {
if (*cmd == 's' && vim_strchr((char_u *)"cgriI", cmd[1]) != NULL) { if (*cmd == 's' && strchr("cgriI", cmd[1]) != NULL) {
ea.cmdidx = CMD_substitute; ea.cmdidx = CMD_substitute;
p = cmd + 1; p = cmd + 1;
} else if (cmd[0] >= 'A' && cmd[0] <= 'Z') { } else if (cmd[0] >= 'A' && cmd[0] <= 'Z') {
ea.cmd = cmd; ea.cmd = (char_u *)cmd;
p = find_ucmd(&ea, p, NULL, xp, p = (const char *)find_ucmd(&ea, (char_u *)p, NULL, xp, &context);
&compl if (p == NULL) {
); ea.cmdidx = CMD_SIZE; // Ambiguous user command.
if (p == NULL) }
ea.cmdidx = CMD_SIZE; /* ambiguous user command */
} }
} }
if (ea.cmdidx == CMD_SIZE) { if (ea.cmdidx == CMD_SIZE) {
@@ -2777,16 +2775,17 @@ set_one_cmd_context (
ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt; ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt;
} }
arg = skipwhite(p); const char *arg = (const char *)skipwhite((const char_u *)p);
if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) { if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) {
if (*arg == '>') { /* append */ if (*arg == '>') { // Append.
if (*++arg == '>') if (*++arg == '>') {
++arg; arg++;
arg = skipwhite(arg); }
} else if (*arg == '!' && ea.cmdidx == CMD_write) { /* :w !filter */ arg = (const char *)skipwhite((const char_u *)arg);
++arg; } else if (*arg == '!' && ea.cmdidx == CMD_write) { // :w !filter
usefilter = TRUE; arg++;
usefilter = true;
} }
} }
@@ -2799,23 +2798,24 @@ set_one_cmd_context (
} }
if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) { if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) {
while (*arg == *cmd) /* allow any number of '>' or '<' */ while (*arg == *cmd) { // allow any number of '>' or '<'
++arg; arg++;
arg = skipwhite(arg); }
arg = (const char *)skipwhite((const char_u *)arg);
} }
/* Does command allow "+command"? */ /* Does command allow "+command"? */
if ((ea.argt & EDITCMD) && !usefilter && *arg == '+') { if ((ea.argt & EDITCMD) && !usefilter && *arg == '+') {
/* Check if we're in the +command */ /* Check if we're in the +command */
p = arg + 1; p = arg + 1;
arg = skip_cmd_arg(arg, FALSE); arg = (const char *)skip_cmd_arg((char_u *)arg, false);
/* Still touching the command after '+'? */ /* Still touching the command after '+'? */
if (*arg == NUL) if (*arg == NUL)
return p; return p;
/* Skip space(s) after +command to get to the real argument */ // Skip space(s) after +command to get to the real argument.
arg = skipwhite(arg); arg = (const char *)skipwhite((const char_u *)arg);
} }
/* /*
@@ -2844,19 +2844,18 @@ set_one_cmd_context (
} }
// no arguments allowed // no arguments allowed
if (!(ea.argt & EXTRA) && *arg != NUL if (!(ea.argt & EXTRA) && *arg != NUL && strchr("|\"", *arg) == NULL) {
&& vim_strchr((char_u *)"|\"", *arg) == NULL) {
return NULL; return NULL;
} }
/* Find start of last argument (argument just before cursor): */ /* Find start of last argument (argument just before cursor): */
p = buff; p = buff;
xp->xp_pattern = p; xp->xp_pattern = (char_u *)p;
len = (int)STRLEN(buff); len = strlen(buff);
while (*p && p < buff + len) { while (*p && p < buff + len) {
if (*p == ' ' || *p == TAB) { if (*p == ' ' || *p == TAB) {
/* argument starts after a space */ // Argument starts after a space.
xp->xp_pattern = ++p; xp->xp_pattern = (char_u *)++p;
} else { } else {
if (*p == '\\' && *(p + 1) != NUL) if (*p == '\\' && *(p + 1) != NUL)
++p; /* skip over escaped character */ ++p; /* skip over escaped character */
@@ -2866,25 +2865,26 @@ set_one_cmd_context (
if (ea.argt & XFILE) { if (ea.argt & XFILE) {
int c; int c;
int in_quote = FALSE; int in_quote = false;
char_u *bow = NULL; /* Beginning of word */ const char *bow = NULL; // Beginning of word.
/* /*
* Allow spaces within back-quotes to count as part of the argument * Allow spaces within back-quotes to count as part of the argument
* being expanded. * being expanded.
*/ */
xp->xp_pattern = skipwhite(arg); xp->xp_pattern = skipwhite((const char_u *)arg);
p = xp->xp_pattern; p = (const char *)xp->xp_pattern;
while (*p != NUL) { while (*p != NUL) {
if (has_mbyte) if (has_mbyte) {
c = mb_ptr2char(p); c = mb_ptr2char((const char_u *)p);
else } else {
c = *p; c = (uint8_t)(*p);
if (c == '\\' && p[1] != NUL) }
++p; if (c == '\\' && p[1] != NUL) {
else if (c == '`') { p++;
} else if (c == '`') {
if (!in_quote) { if (!in_quote) {
xp->xp_pattern = p; xp->xp_pattern = (char_u *)p;
bow = p + 1; bow = p + 1;
} }
in_quote = !in_quote; in_quote = !in_quote;
@@ -2897,22 +2897,26 @@ set_one_cmd_context (
|| ascii_iswhite(c)) { || ascii_iswhite(c)) {
len = 0; /* avoid getting stuck when space is in 'isfname' */ len = 0; /* avoid getting stuck when space is in 'isfname' */
while (*p != NUL) { while (*p != NUL) {
if (has_mbyte) if (has_mbyte) {
c = mb_ptr2char(p); c = mb_ptr2char((const char_u *)p);
else } else {
c = *p; c = *p;
if (c == '`' || vim_isfilec_or_wc(c)) }
if (c == '`' || vim_isfilec_or_wc(c)) {
break; break;
if (has_mbyte) }
len = (*mb_ptr2len)(p); if (has_mbyte) {
else len = (size_t)(*mb_ptr2len)((const char_u *)p);
} else {
len = 1; len = 1;
}
mb_ptr_adv(p); mb_ptr_adv(p);
} }
if (in_quote) if (in_quote) {
bow = p; bow = p;
else } else {
xp->xp_pattern = p; xp->xp_pattern = (char_u *)p;
}
p -= len; p -= len;
} }
mb_ptr_adv(p); mb_ptr_adv(p);
@@ -2922,8 +2926,9 @@ set_one_cmd_context (
* If we are still inside the quotes, and we passed a space, just * If we are still inside the quotes, and we passed a space, just
* expand from there. * expand from there.
*/ */
if (bow != NULL && in_quote) if (bow != NULL && in_quote) {
xp->xp_pattern = bow; xp->xp_pattern = (char_u *)bow;
}
xp->xp_context = EXPAND_FILES; xp->xp_context = EXPAND_FILES;
/* For a shell command more chars need to be escaped. */ /* For a shell command more chars need to be escaped. */
@@ -2931,33 +2936,36 @@ set_one_cmd_context (
#ifndef BACKSLASH_IN_FILENAME #ifndef BACKSLASH_IN_FILENAME
xp->xp_shell = TRUE; xp->xp_shell = TRUE;
#endif #endif
/* When still after the command name expand executables. */ // When still after the command name expand executables.
if (xp->xp_pattern == skipwhite(arg)) if (xp->xp_pattern == skipwhite((const char_u *)arg)) {
xp->xp_context = EXPAND_SHELLCMD; xp->xp_context = EXPAND_SHELLCMD;
}
} }
/* Check for environment variable */ // Check for environment variable.
if (*xp->xp_pattern == '$' if (*xp->xp_pattern == '$') {
) { for (p = (const char *)xp->xp_pattern + 1; *p != NUL; p++) {
for (p = xp->xp_pattern + 1; *p != NUL; ++p) if (!vim_isIDc((uint8_t)(*p))) {
if (!vim_isIDc(*p))
break; break;
}
}
if (*p == NUL) { if (*p == NUL) {
xp->xp_context = EXPAND_ENV_VARS; xp->xp_context = EXPAND_ENV_VARS;
++xp->xp_pattern; xp->xp_pattern++;
/* Avoid that the assignment uses EXPAND_FILES again. */ // Avoid that the assignment uses EXPAND_FILES again.
if (compl != EXPAND_USER_DEFINED && compl != EXPAND_USER_LIST) if (context != EXPAND_USER_DEFINED && context != EXPAND_USER_LIST) {
compl = EXPAND_ENV_VARS; context = EXPAND_ENV_VARS;
}
} }
} }
/* Check for user names */ /* Check for user names */
if (*xp->xp_pattern == '~') { if (*xp->xp_pattern == '~') {
for (p = xp->xp_pattern + 1; *p != NUL && *p != '/'; ++p) for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {
; }
/* Complete ~user only if it partially matches a user name. // Complete ~user only if it partially matches a user name.
* A full match ~user<Tab> will be replaced by user's home // A full match ~user<Tab> will be replaced by user's home
* directory i.e. something like ~user<Tab> -> /home/user/ */ // directory i.e. something like ~user<Tab> -> /home/user/
if (*p == NUL && p > xp->xp_pattern + 1 if (*p == NUL && p > (const char *)xp->xp_pattern + 1
&& match_user(xp->xp_pattern + 1) == 1) { && match_user(xp->xp_pattern + 1) == 1) {
xp->xp_context = EXPAND_USER; xp->xp_context = EXPAND_USER;
++xp->xp_pattern; ++xp->xp_pattern;
@@ -2987,7 +2995,7 @@ set_one_cmd_context (
break; break;
case CMD_help: case CMD_help:
xp->xp_context = EXPAND_HELP; xp->xp_context = EXPAND_HELP;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
/* Command modifiers: return the argument. /* Command modifiers: return the argument.
@@ -3030,13 +3038,14 @@ set_one_cmd_context (
if (*arg == NUL || !ends_excmd(*arg)) { if (*arg == NUL || !ends_excmd(*arg)) {
/* also complete "None" */ /* also complete "None" */
set_context_in_echohl_cmd(xp, arg); set_context_in_echohl_cmd(xp, arg);
arg = skipwhite(skiptowhite(arg)); arg = (const char *)skipwhite(skiptowhite((const char_u *)arg));
if (*arg != NUL) { if (*arg != NUL) {
xp->xp_context = EXPAND_NOTHING; xp->xp_context = EXPAND_NOTHING;
arg = skip_regexp(arg + 1, *arg, p_magic, NULL); arg = (const char *)skip_regexp((char_u *)arg + 1, (uint8_t)(*arg),
p_magic, NULL);
} }
} }
return find_nextcmd(arg); return (const char *)find_nextcmd((char_u *)arg);
/* /*
* All completion for the +cmdline_compl feature goes here. * All completion for the +cmdline_compl feature goes here.
@@ -3045,15 +3054,15 @@ set_one_cmd_context (
case CMD_command: case CMD_command:
/* Check for attributes */ /* Check for attributes */
while (*arg == '-') { while (*arg == '-') {
arg++; /* Skip "-" */ arg++; // Skip "-".
p = skiptowhite(arg); p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) { if (*p == NUL) {
/* Cursor is still in the attribute */ // Cursor is still in the attribute.
p = vim_strchr(arg, '='); p = strchr(arg, '=');
if (p == NULL) { if (p == NULL) {
/* No "=", so complete attribute names */ // No "=", so complete attribute names.
xp->xp_context = EXPAND_USER_CMD_FLAGS; xp->xp_context = EXPAND_USER_CMD_FLAGS;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
return NULL; return NULL;
} }
@@ -3061,73 +3070,81 @@ set_one_cmd_context (
// their arguments as well. // their arguments as well.
if (STRNICMP(arg, "complete", p - arg) == 0) { if (STRNICMP(arg, "complete", p - arg) == 0) {
xp->xp_context = EXPAND_USER_COMPLETE; xp->xp_context = EXPAND_USER_COMPLETE;
xp->xp_pattern = p + 1; xp->xp_pattern = (char_u *)p + 1;
return NULL; return NULL;
} else if (STRNICMP(arg, "nargs", p - arg) == 0) { } else if (STRNICMP(arg, "nargs", p - arg) == 0) {
xp->xp_context = EXPAND_USER_NARGS; xp->xp_context = EXPAND_USER_NARGS;
xp->xp_pattern = p + 1; xp->xp_pattern = (char_u *)p + 1;
return NULL; return NULL;
} else if (STRNICMP(arg, "addr", p - arg) == 0) { } else if (STRNICMP(arg, "addr", p - arg) == 0) {
xp->xp_context = EXPAND_USER_ADDR_TYPE; xp->xp_context = EXPAND_USER_ADDR_TYPE;
xp->xp_pattern = p + 1; xp->xp_pattern = (char_u *)p + 1;
return NULL; return NULL;
} }
return NULL; return NULL;
} }
arg = skipwhite(p); arg = (const char *)skipwhite((char_u *)p);
} }
/* After the attributes comes the new command name */ // After the attributes comes the new command name.
p = skiptowhite(arg); p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) { if (*p == NUL) {
xp->xp_context = EXPAND_USER_COMMANDS; xp->xp_context = EXPAND_USER_COMMANDS;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
} }
/* And finally comes a normal command */ // And finally comes a normal command.
return skipwhite(p); return (const char *)skipwhite((const char_u *)p);
case CMD_delcommand: case CMD_delcommand:
xp->xp_context = EXPAND_USER_COMMANDS; xp->xp_context = EXPAND_USER_COMMANDS;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_global: case CMD_global:
case CMD_vglobal: case CMD_vglobal: {
delim = *arg; /* get the delimiter */ const int delim = (uint8_t)(*arg); // Get the delimiter.
if (delim) if (delim) {
++arg; /* skip delimiter if there is one */ arg++; // Skip delimiter if there is one.
}
while (arg[0] != NUL && arg[0] != delim) { while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
if (arg[0] == '\\' && arg[1] != NUL) if (arg[0] == '\\' && arg[1] != NUL) {
++arg; arg++;
++arg; }
arg++;
} }
if (arg[0] != NUL) if (arg[0] != NUL)
return arg + 1; return arg + 1;
break; break;
}
case CMD_and: case CMD_and:
case CMD_substitute: case CMD_substitute: {
delim = *arg; const int delim = (uint8_t)(*arg);
if (delim) { if (delim) {
/* skip "from" part */ // Skip "from" part.
++arg; arg++;
arg = skip_regexp(arg, delim, p_magic, NULL); arg = (const char *)skip_regexp((char_u *)arg, delim, p_magic, NULL);
} }
/* skip "to" part */ // Skip "to" part.
while (arg[0] != NUL && arg[0] != delim) { while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
if (arg[0] == '\\' && arg[1] != NUL) if (arg[0] == '\\' && arg[1] != NUL) {
++arg; arg++;
++arg; }
arg++;
} }
if (arg[0] != NUL) /* skip delimiter */ if (arg[0] != NUL) { // Skip delimiter.
++arg; arg++;
while (arg[0] && vim_strchr((char_u *)"|\"#", arg[0]) == NULL) }
++arg; while (arg[0] && strchr("|\"#", arg[0]) == NULL) {
if (arg[0] != NUL) arg++;
}
if (arg[0] != NUL) {
return arg; return arg;
}
break; break;
}
case CMD_isearch: case CMD_isearch:
case CMD_dsearch: case CMD_dsearch:
case CMD_ilist: case CMD_ilist:
@@ -3137,36 +3154,40 @@ set_one_cmd_context (
case CMD_djump: case CMD_djump:
case CMD_isplit: case CMD_isplit:
case CMD_dsplit: case CMD_dsplit:
arg = skipwhite(skipdigits(arg)); /* skip count */ // Skip count.
if (*arg == '/') { /* Match regexp, not just whole words */ arg = (const char *)skipwhite(skipdigits((const char_u *)arg));
for (++arg; *arg && *arg != '/'; arg++) if (*arg == '/') { // Match regexp, not just whole words.
if (*arg == '\\' && arg[1] != NUL) for (++arg; *arg && *arg != '/'; arg++) {
if (*arg == '\\' && arg[1] != NUL) {
arg++; arg++;
}
}
if (*arg) { if (*arg) {
arg = skipwhite(arg + 1); arg = (const char *)skipwhite((const char_u *)arg + 1);
/* Check for trailing illegal characters */ // Check for trailing illegal characters.
if (*arg && vim_strchr((char_u *)"|\"\n", *arg) == NULL) if (*arg && strchr("|\"\n", *arg) == NULL) {
xp->xp_context = EXPAND_NOTHING; xp->xp_context = EXPAND_NOTHING;
else } else {
return arg; return arg;
}
} }
} }
break; break;
case CMD_autocmd: case CMD_autocmd:
return set_context_in_autocmd(xp, arg, FALSE); return (const char *)set_context_in_autocmd(xp, (char_u *)arg, false);
case CMD_doautocmd: case CMD_doautocmd:
case CMD_doautoall: case CMD_doautoall:
return set_context_in_autocmd(xp, arg, TRUE); return (const char *)set_context_in_autocmd(xp, (char_u *)arg, true);
case CMD_set: case CMD_set:
set_context_in_set_cmd(xp, arg, 0); set_context_in_set_cmd(xp, (char_u *)arg, 0);
break; break;
case CMD_setglobal: case CMD_setglobal:
set_context_in_set_cmd(xp, arg, OPT_GLOBAL); set_context_in_set_cmd(xp, (char_u *)arg, OPT_GLOBAL);
break; break;
case CMD_setlocal: case CMD_setlocal:
set_context_in_set_cmd(xp, arg, OPT_LOCAL); set_context_in_set_cmd(xp, (char_u *)arg, OPT_LOCAL);
break; break;
case CMD_tag: case CMD_tag:
case CMD_stag: case CMD_stag:
@@ -3178,15 +3199,16 @@ set_one_cmd_context (
case CMD_tjump: case CMD_tjump:
case CMD_stjump: case CMD_stjump:
case CMD_ptjump: case CMD_ptjump:
if (*p_wop != NUL) if (*p_wop != NUL) {
xp->xp_context = EXPAND_TAGS_LISTFILES; xp->xp_context = EXPAND_TAGS_LISTFILES;
else } else {
xp->xp_context = EXPAND_TAGS; xp->xp_context = EXPAND_TAGS;
xp->xp_pattern = arg; }
xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_augroup: case CMD_augroup:
xp->xp_context = EXPAND_AUGROUP; xp->xp_context = EXPAND_AUGROUP;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_syntax: case CMD_syntax:
set_context_in_syntax_cmd(xp, arg); set_context_in_syntax_cmd(xp, arg);
@@ -3203,20 +3225,21 @@ set_one_cmd_context (
case CMD_echoerr: case CMD_echoerr:
case CMD_call: case CMD_call:
case CMD_return: case CMD_return:
set_context_for_expression(xp, arg, ea.cmdidx); set_context_for_expression(xp, (char_u *)arg, ea.cmdidx);
break; break;
case CMD_unlet: case CMD_unlet:
while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) while ((xp->xp_pattern = (char_u *)strchr(arg, ' ')) != NULL) {
arg = xp->xp_pattern + 1; arg = (const char *)xp->xp_pattern + 1;
}
xp->xp_context = EXPAND_USER_VARS; xp->xp_context = EXPAND_USER_VARS;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_function: case CMD_function:
case CMD_delfunction: case CMD_delfunction:
xp->xp_context = EXPAND_USER_FUNC; xp->xp_context = EXPAND_USER_FUNC;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_echohl: case CMD_echohl:
@@ -3231,33 +3254,37 @@ set_one_cmd_context (
set_context_in_cscope_cmd(xp, arg, ea.cmdidx); set_context_in_cscope_cmd(xp, arg, ea.cmdidx);
break; break;
case CMD_sign: case CMD_sign:
set_context_in_sign_cmd(xp, arg); set_context_in_sign_cmd(xp, (char_u *)arg);
break; break;
case CMD_bdelete: case CMD_bdelete:
case CMD_bwipeout: case CMD_bwipeout:
case CMD_bunload: case CMD_bunload:
while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) while ((xp->xp_pattern = (char_u *)strchr(arg, ' ')) != NULL) {
arg = xp->xp_pattern + 1; arg = (const char *)xp->xp_pattern + 1;
/*FALLTHROUGH*/ }
// FALLTHROUGH
case CMD_buffer: case CMD_buffer:
case CMD_sbuffer: case CMD_sbuffer:
case CMD_checktime: case CMD_checktime:
xp->xp_context = EXPAND_BUFFERS; xp->xp_context = EXPAND_BUFFERS;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_USER: case CMD_USER:
case CMD_USER_BUF: case CMD_USER_BUF:
if (compl != EXPAND_NOTHING) { if (context != EXPAND_NOTHING) {
/* XFILE: file names are handled above */ // XFILE: file names are handled above.
if (!(ea.argt & XFILE)) { if (!(ea.argt & XFILE)) {
if (compl == EXPAND_MENUS) if (context == EXPAND_MENUS) {
return set_context_in_menu_cmd(xp, cmd, arg, forceit); return (const char *)set_context_in_menu_cmd(xp, (char_u *)cmd,
if (compl == EXPAND_COMMANDS) (char_u *)arg, forceit);
} else if (context == EXPAND_COMMANDS) {
return arg; return arg;
if (compl == EXPAND_MAPPINGS) } else if (context == EXPAND_MAPPINGS) {
return set_context_in_map_cmd(xp, (char_u *)"map", return (const char *)set_context_in_map_cmd(
arg, forceit, FALSE, FALSE, CMD_map); xp, (char_u *)"map", (char_u *)arg, forceit, false, false,
/* Find start of last argument. */ CMD_map);
}
// Find start of last argument.
p = arg; p = arg;
while (*p) { while (*p) {
if (*p == ' ') if (*p == ' ')
@@ -3267,9 +3294,9 @@ set_one_cmd_context (
++p; /* skip over escaped character */ ++p; /* skip over escaped character */
mb_ptr_adv(p); mb_ptr_adv(p);
} }
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
} }
xp->xp_context = compl; xp->xp_context = context;
} }
break; break;
case CMD_map: case CMD_noremap: case CMD_map: case CMD_noremap:
@@ -3281,8 +3308,8 @@ set_one_cmd_context (
case CMD_lmap: case CMD_lnoremap: case CMD_lmap: case CMD_lnoremap:
case CMD_smap: case CMD_snoremap: case CMD_smap: case CMD_snoremap:
case CMD_xmap: case CMD_xnoremap: case CMD_xmap: case CMD_xnoremap:
return set_context_in_map_cmd(xp, cmd, arg, forceit, return (const char *)set_context_in_map_cmd(
FALSE, FALSE, ea.cmdidx); xp, (char_u *)cmd, (char_u *)arg, forceit, false, false, ea.cmdidx);
case CMD_unmap: case CMD_unmap:
case CMD_nunmap: case CMD_nunmap:
case CMD_vunmap: case CMD_vunmap:
@@ -3292,18 +3319,18 @@ set_one_cmd_context (
case CMD_lunmap: case CMD_lunmap:
case CMD_sunmap: case CMD_sunmap:
case CMD_xunmap: case CMD_xunmap:
return set_context_in_map_cmd(xp, cmd, arg, forceit, return (const char *)set_context_in_map_cmd(
FALSE, TRUE, ea.cmdidx); xp, (char_u *)cmd, (char_u *)arg, forceit, false, true, ea.cmdidx);
case CMD_abbreviate: case CMD_noreabbrev: case CMD_abbreviate: case CMD_noreabbrev:
case CMD_cabbrev: case CMD_cnoreabbrev: case CMD_cabbrev: case CMD_cnoreabbrev:
case CMD_iabbrev: case CMD_inoreabbrev: case CMD_iabbrev: case CMD_inoreabbrev:
return set_context_in_map_cmd(xp, cmd, arg, forceit, return (const char *)set_context_in_map_cmd(
TRUE, FALSE, ea.cmdidx); xp, (char_u *)cmd, (char_u *)arg, forceit, true, false, ea.cmdidx);
case CMD_unabbreviate: case CMD_unabbreviate:
case CMD_cunabbrev: case CMD_cunabbrev:
case CMD_iunabbrev: case CMD_iunabbrev:
return set_context_in_map_cmd(xp, cmd, arg, forceit, return (const char *)set_context_in_map_cmd(
TRUE, TRUE, ea.cmdidx); xp, (char_u *)cmd, (char_u *)arg, forceit, true, true, ea.cmdidx);
case CMD_menu: case CMD_noremenu: case CMD_unmenu: case CMD_menu: case CMD_noremenu: case CMD_unmenu:
case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu: case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu: case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
@@ -3313,47 +3340,49 @@ set_one_cmd_context (
case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu: case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
case CMD_tmenu: case CMD_tunmenu: case CMD_tmenu: case CMD_tunmenu:
case CMD_popup: case CMD_emenu: case CMD_popup: case CMD_emenu:
return set_context_in_menu_cmd(xp, cmd, arg, forceit); return (const char *)set_context_in_menu_cmd(
xp, (char_u *)cmd, (char_u *)arg, forceit);
case CMD_colorscheme: case CMD_colorscheme:
xp->xp_context = EXPAND_COLORS; xp->xp_context = EXPAND_COLORS;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_compiler: case CMD_compiler:
xp->xp_context = EXPAND_COMPILER; xp->xp_context = EXPAND_COMPILER;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_ownsyntax: case CMD_ownsyntax:
xp->xp_context = EXPAND_OWNSYNTAX; xp->xp_context = EXPAND_OWNSYNTAX;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_setfiletype: case CMD_setfiletype:
xp->xp_context = EXPAND_FILETYPE; xp->xp_context = EXPAND_FILETYPE;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_packadd: case CMD_packadd:
xp->xp_context = EXPAND_PACKADD; xp->xp_context = EXPAND_PACKADD;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
#ifdef HAVE_WORKING_LIBINTL #ifdef HAVE_WORKING_LIBINTL
case CMD_language: case CMD_language:
p = skiptowhite(arg); p = (const char *)skiptowhite((const char_u *)arg);
if (*p == NUL) { if (*p == NUL) {
xp->xp_context = EXPAND_LANGUAGE; xp->xp_context = EXPAND_LANGUAGE;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
} else { } else {
if ( STRNCMP(arg, "messages", p - arg) == 0 if (strncmp(arg, "messages", p - arg) == 0
|| STRNCMP(arg, "ctype", p - arg) == 0 || strncmp(arg, "ctype", p - arg) == 0
|| STRNCMP(arg, "time", p - arg) == 0) { || strncmp(arg, "time", p - arg) == 0) {
xp->xp_context = EXPAND_LOCALES; xp->xp_context = EXPAND_LOCALES;
xp->xp_pattern = skipwhite(p); xp->xp_pattern = skipwhite((const char_u *)p);
} else } else {
xp->xp_context = EXPAND_NOTHING; xp->xp_context = EXPAND_NOTHING;
}
} }
break; break;
#endif #endif
@@ -3362,16 +3391,16 @@ set_one_cmd_context (
break; break;
case CMD_behave: case CMD_behave:
xp->xp_context = EXPAND_BEHAVE; xp->xp_context = EXPAND_BEHAVE;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_history: case CMD_history:
xp->xp_context = EXPAND_HISTORY; xp->xp_context = EXPAND_HISTORY;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
case CMD_syntime: case CMD_syntime:
xp->xp_context = EXPAND_SYNTIME; xp->xp_context = EXPAND_SYNTIME;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
break; break;
@@ -3390,10 +3419,9 @@ set_one_cmd_context (
* Also skip white space and ":" characters. * Also skip white space and ":" characters.
* Returns the "cmd" pointer advanced to beyond the range. * Returns the "cmd" pointer advanced to beyond the range.
*/ */
char_u * char_u *skip_range(
skip_range ( const char_u *cmd,
char_u *cmd, int *ctx // pointer to xp_context or NULL
int *ctx /* pointer to xp_context or NULL */
) )
{ {
unsigned delim; unsigned delim;
@@ -3418,7 +3446,7 @@ skip_range (
while (*cmd == ':') while (*cmd == ':')
cmd = skipwhite(cmd + 1); cmd = skipwhite(cmd + 1);
return cmd; return (char_u *)cmd;
} }
/* /*
@@ -4587,14 +4615,15 @@ int ends_excmd(int c) FUNC_ATTR_CONST
* Return the next command, after the first '|' or '\n'. * Return the next command, after the first '|' or '\n'.
* Return NULL if not found. * Return NULL if not found.
*/ */
char_u *find_nextcmd(char_u *p) char_u *find_nextcmd(const char_u *p)
{ {
while (*p != '|' && *p != '\n') { while (*p != '|' && *p != '\n') {
if (*p == NUL) if (*p == NUL) {
return NULL; return NULL;
++p; }
p++;
} }
return p + 1; return (char_u *)p + 1;
} }
/* /*
@@ -6796,7 +6825,7 @@ do_exedit (
int ms = msg_scroll; int ms = msg_scroll;
if (eap->nextcmd != NULL) { if (eap->nextcmd != NULL) {
stuffReadbuff(eap->nextcmd); stuffReadbuff((const char *)eap->nextcmd);
eap->nextcmd = NULL; eap->nextcmd = NULL;
} }
@@ -7726,7 +7755,7 @@ static void ex_mkrc(exarg_T *eap)
/* When using 'viewdir' may have to create the directory. */ /* When using 'viewdir' may have to create the directory. */
if (using_vdir && !os_isdir(p_vdir)) { if (using_vdir && !os_isdir(p_vdir)) {
vim_mkdir_emsg(p_vdir, 0755); vim_mkdir_emsg((const char *)p_vdir, 0755);
} }
fd = open_exfile((char_u *) fname, eap->forceit, WRITEBIN); fd = open_exfile((char_u *) fname, eap->forceit, WRITEBIN);
@@ -7838,10 +7867,17 @@ static void ex_mkrc(exarg_T *eap)
xfree(viewFile); xfree(viewFile);
} }
int vim_mkdir_emsg(char_u *name, int prot) /// Try creating a directory, give error message on failure
///
/// @param[in] name Directory to create.
/// @param[in] prot Directory permissions.
///
/// @return OK in case of success, FAIL otherwise.
int vim_mkdir_emsg(const char *const name, const int prot)
FUNC_ATTR_NONNULL_ALL
{ {
int ret; int ret;
if ((ret = os_mkdir((char *)name, prot)) != 0) { if ((ret = os_mkdir(name, prot)) != 0) {
EMSG3(_(e_mkdir), name, os_strerror(ret)); EMSG3(_(e_mkdir), name, os_strerror(ret));
return FAIL; return FAIL;
} }
@@ -8418,8 +8454,8 @@ eval_vars (
*usedlen = 1; *usedlen = 1;
return NULL; return NULL;
} }
result = list_find_str(get_vim_var_list(VV_OLDFILES), result = (char_u *)tv_list_find_str(get_vim_var_list(VV_OLDFILES),
(long)i); i - 1);
if (result == NULL) { if (result == NULL) {
*errormsg = (char_u *)""; *errormsg = (char_u *)"";
return NULL; return NULL;
@@ -9349,8 +9385,8 @@ static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
*p = '/'; *p = '/';
} }
/* escape special characters */ // Escape special characters.
p = vim_strsave_fnameescape(sname, FALSE); p = (char_u *)vim_strsave_fnameescape((const char *)sname, false);
xfree(sname); xfree(sname);
/* write the result */ /* write the result */
@@ -9485,18 +9521,18 @@ void dialog_msg(char_u *buff, char *format, char_u *fname)
static void ex_behave(exarg_T *eap) static void ex_behave(exarg_T *eap)
{ {
if (STRCMP(eap->arg, "mswin") == 0) { if (STRCMP(eap->arg, "mswin") == 0) {
set_option_value((char_u *)"selection", 0L, (char_u *)"exclusive", 0); set_option_value("selection", 0L, "exclusive", 0);
set_option_value((char_u *)"selectmode", 0L, (char_u *)"mouse,key", 0); set_option_value("selectmode", 0L, "mouse,key", 0);
set_option_value((char_u *)"mousemodel", 0L, (char_u *)"popup", 0); set_option_value("mousemodel", 0L, "popup", 0);
set_option_value((char_u *)"keymodel", 0L, set_option_value("keymodel", 0L, "startsel,stopsel", 0);
(char_u *)"startsel,stopsel", 0);
} else if (STRCMP(eap->arg, "xterm") == 0) { } else if (STRCMP(eap->arg, "xterm") == 0) {
set_option_value((char_u *)"selection", 0L, (char_u *)"inclusive", 0); set_option_value("selection", 0L, "inclusive", 0);
set_option_value((char_u *)"selectmode", 0L, (char_u *)"", 0); set_option_value("selectmode", 0L, "", 0);
set_option_value((char_u *)"mousemodel", 0L, (char_u *)"extend", 0); set_option_value("mousemodel", 0L, "extend", 0);
set_option_value((char_u *)"keymodel", 0L, (char_u *)"", 0); set_option_value("keymodel", 0L, "", 0);
} else } else {
EMSG2(_(e_invarg2), eap->arg); EMSG2(_(e_invarg2), eap->arg);
}
} }
/* /*
@@ -9610,8 +9646,9 @@ void filetype_maybe_enable(void)
*/ */
static void ex_setfiletype(exarg_T *eap) static void ex_setfiletype(exarg_T *eap)
{ {
if (!did_filetype) if (!did_filetype) {
set_option_value((char_u *)"filetype", 0L, eap->arg, OPT_LOCAL); set_option_value("filetype", 0L, (char *)eap->arg, OPT_LOCAL);
}
} }
static void ex_digraphs(exarg_T *eap) static void ex_digraphs(exarg_T *eap)
@@ -9697,7 +9734,8 @@ static void ex_match(exarg_T *eap)
c = *end; c = *end;
*end = NUL; *end = NUL;
match_add(curwin, g, p + 1, 10, id, NULL, NULL); match_add(curwin, (const char *)g, (const char *)p + 1, 10, id,
NULL, NULL);
xfree(g); xfree(g);
*end = c; *end = c;
} }

View File

@@ -2,6 +2,7 @@
#define NVIM_EX_DOCMD_H #define NVIM_EX_DOCMD_H
#include "nvim/ex_cmds_defs.h" #include "nvim/ex_cmds_defs.h"
#include "nvim/globals.h"
// flags for do_cmdline() // flags for do_cmdline()
#define DOCMD_VERBOSE 0x01 // included command in error message #define DOCMD_VERBOSE 0x01 // included command in error message

View File

@@ -1,6 +1,8 @@
/* // TODO(ZyX-I): move to eval/executor
* ex_eval.c: functions for Ex command line for the +eval feature.
*/ /// @file ex_eval.c
///
/// Functions for Ex command line for the +eval feature.
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@@ -12,6 +14,7 @@
#include "nvim/ex_eval.h" #include "nvim/ex_eval.h"
#include "nvim/charset.h" #include "nvim/charset.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h" #include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h" #include "nvim/ex_docmd.h"
#include "nvim/message.h" #include "nvim/message.h"
@@ -19,8 +22,6 @@
#include "nvim/regexp.h" #include "nvim/regexp.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_eval.c.generated.h" # include "ex_eval.c.generated.h"
#endif #endif
@@ -57,12 +58,14 @@
* is an error exception.) - The macros can be defined as expressions checking * is an error exception.) - The macros can be defined as expressions checking
* for a variable that is allowed to be changed during execution of a script. * for a variable that is allowed to be changed during execution of a script.
*/ */
/* Values used for the Vim release. */
# define THROW_ON_ERROR TRUE
# define THROW_ON_ERROR_TRUE
# define THROW_ON_INTERRUPT TRUE
# define THROW_ON_INTERRUPT_TRUE
// Values used for the Vim release.
#define THROW_ON_ERROR true
#define THROW_ON_ERROR_TRUE
#define THROW_ON_INTERRUPT true
#define THROW_ON_INTERRUPT_TRUE
#define discard_pending_return(p) tv_free((typval_T *)(p))
/* /*
* When several errors appear in a row, setting "force_abort" is delayed until * When several errors appear in a row, setting "force_abort" is delayed until
@@ -779,7 +782,6 @@ void report_discard_pending(int pending, void *value)
*/ */
void ex_if(exarg_T *eap) void ex_if(exarg_T *eap)
{ {
int error;
int skip; int skip;
int result; int result;
struct condstack *cstack = eap->cstack; struct condstack *cstack = eap->cstack;
@@ -800,6 +802,7 @@ void ex_if(exarg_T *eap)
1] & 1] &
CSF_ACTIVE)); CSF_ACTIVE));
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
if (!skip && !error) { if (!skip && !error) {
@@ -844,7 +847,6 @@ void ex_endif(exarg_T *eap)
*/ */
void ex_else(exarg_T *eap) void ex_else(exarg_T *eap)
{ {
int error;
int skip; int skip;
int result; int result;
struct condstack *cstack = eap->cstack; struct condstack *cstack = eap->cstack;
@@ -901,6 +903,7 @@ void ex_else(exarg_T *eap)
} }
if (eap->cmdidx == CMD_elseif) { if (eap->cmdidx == CMD_elseif) {
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
/* When throwing error exceptions, we want to throw always the first /* When throwing error exceptions, we want to throw always the first
* of several errors in a row. This is what actually happens when * of several errors in a row. This is what actually happens when
@@ -925,7 +928,7 @@ void ex_else(exarg_T *eap)
*/ */
void ex_while(exarg_T *eap) void ex_while(exarg_T *eap)
{ {
int error; bool error;
int skip; int skip;
int result; int result;
struct condstack *cstack = eap->cstack; struct condstack *cstack = eap->cstack;
@@ -1147,23 +1150,25 @@ void ex_endwhile(exarg_T *eap)
*/ */
void ex_throw(exarg_T *eap) void ex_throw(exarg_T *eap)
{ {
char_u *arg = eap->arg; const char *arg = (const char *)eap->arg;
char_u *value; char *value;
if (*arg != NUL && *arg != '|' && *arg != '\n') if (*arg != NUL && *arg != '|' && *arg != '\n') {
value = eval_to_string_skip(arg, &eap->nextcmd, eap->skip); value = eval_to_string_skip(arg, (const char **)&eap->nextcmd,
else { (bool)eap->skip);
} else {
EMSG(_(e_argreq)); EMSG(_(e_argreq));
value = NULL; value = NULL;
} }
/* On error or when an exception is thrown during argument evaluation, do // On error or when an exception is thrown during argument evaluation, do
* not throw. */ // not throw.
if (!eap->skip && value != NULL) { if (!eap->skip && value != NULL) {
if (throw_exception(value, ET_USER, NULL) == FAIL) if (throw_exception((char_u *)value, ET_USER, NULL) == FAIL) {
xfree(value); xfree(value);
else } else {
do_throw(eap->cstack); do_throw(eap->cstack);
}
} }
} }

View File

@@ -8,6 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#include "nvim/assert.h"
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/arabic.h" #include "nvim/arabic.h"
@@ -578,7 +579,7 @@ static int command_line_execute(VimState *state, int key)
} }
if (vim_ispathsep(ccline.cmdbuff[s->j]) if (vim_ispathsep(ccline.cmdbuff[s->j])
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
&& vim_strchr(" *?[{`$%#", ccline.cmdbuff[s->j + 1]) && strchr(" *?[{`$%#", ccline.cmdbuff[s->j + 1])
== NULL == NULL
#endif #endif
) { ) {
@@ -960,7 +961,7 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s); return command_line_not_changed(s);
case Ctrl_HAT: case Ctrl_HAT:
if (map_to_exists_mode((char_u *)"", LANGMAP, false)) { if (map_to_exists_mode("", LANGMAP, false)) {
// ":lmap" mappings exists, toggle use of mappings. // ":lmap" mappings exists, toggle use of mappings.
State ^= LANGMAP; State ^= LANGMAP;
if (s->b_im_ptr != NULL) { if (s->b_im_ptr != NULL) {
@@ -2553,19 +2554,22 @@ void cmdline_paste_str(char_u *s, int literally)
else else
while (*s != NUL) { while (*s != NUL) {
cv = *s; cv = *s;
if (cv == Ctrl_V && s[1]) if (cv == Ctrl_V && s[1]) {
++s; s++;
if (has_mbyte) }
c = mb_cptr2char_adv(&s); if (has_mbyte) {
else c = mb_cptr2char_adv((const char_u **)&s);
} else {
c = *s++; c = *s++;
}
if (cv == Ctrl_V || c == ESC || c == Ctrl_C if (cv == Ctrl_V || c == ESC || c == Ctrl_C
|| c == CAR || c == NL || c == Ctrl_L || c == CAR || c == NL || c == Ctrl_L
#ifdef UNIX #ifdef UNIX
|| c == intr_char || c == intr_char
#endif #endif
|| (c == Ctrl_BSL && *s == Ctrl_N)) || (c == Ctrl_BSL && *s == Ctrl_N)) {
stuffcharReadbuff(Ctrl_V); stuffcharReadbuff(Ctrl_V);
}
stuffcharReadbuff(c); stuffcharReadbuff(c);
} }
} }
@@ -3120,9 +3124,10 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
#endif #endif
} }
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
p = vim_strsave_fnameescape(files[i], FALSE); p = (char_u *)vim_strsave_fnameescape((const char *)files[i], false);
#else #else
p = vim_strsave_fnameescape(files[i], xp->xp_shell); p = (char_u *)vim_strsave_fnameescape((const char *)files[i],
xp->xp_shell);
#endif #endif
xfree(files[i]); xfree(files[i]);
files[i] = p; files[i] = p;
@@ -3152,42 +3157,49 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
} }
} }
/* /// Escape special characters in a file name for use as a command argument
* Escape special characters in "fname" for when used as a file name argument ///
* after a Vim command, or, when "shell" is non-zero, a shell command. /// @param[in] fname File name to escape.
* Returns the result in allocated memory. /// @param[in] shell What to escape for: if false, escapes for VimL command,
*/ /// if true then it escapes for a shell command.
char_u *vim_strsave_fnameescape(char_u *fname, int shell) FUNC_ATTR_NONNULL_RET ///
/// @return [allocated] escaped file name.
char *vim_strsave_fnameescape(const char *const fname, const bool shell)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{ {
char_u *p;
#ifdef BACKSLASH_IN_FILENAME #ifdef BACKSLASH_IN_FILENAME
#define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`%#'\"|!<") #define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<"
char_u buf[20]; char_u buf[sizeof(PATH_ESC_CHARS)];
int j = 0; int j = 0;
/* Don't escape '[', '{' and '!' if they are in 'isfname'. */ // Don't escape '[', '{' and '!' if they are in 'isfname'.
for (p = PATH_ESC_CHARS; *p != NUL; ++p) for (const char *s = PATH_ESC_CHARS; *s != NUL; s++) {
if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p)) if ((*s != '[' && *s != '{' && *s != '!') || !vim_isfilec(*s)) {
buf[j++] = *p; buf[j++] = *s;
}
}
buf[j] = NUL; buf[j] = NUL;
p = vim_strsave_escaped(fname, buf); char *p = (char *)vim_strsave_escaped((const char_u *)fname,
(const char_u *)buf);
#else #else
#define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<") #define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
#define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&") #define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
p = vim_strsave_escaped(fname, shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS); char *p = (char *)vim_strsave_escaped(
(const char_u *)fname, (shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS));
if (shell && csh_like_shell()) { if (shell && csh_like_shell()) {
/* For csh and similar shells need to put two backslashes before '!'. // For csh and similar shells need to put two backslashes before '!'.
* One is taken by Vim, one by the shell. */ // One is taken by Vim, one by the shell.
char_u *s = vim_strsave_escaped(p, (char_u *)"!"); char *s = (char *)vim_strsave_escaped((const char_u *)p,
(const char_u *)"!");
xfree(p); xfree(p);
p = s; p = s;
} }
#endif #endif
/* '>' and '+' are special at the start of some commands, e.g. ":edit" and // '>' and '+' are special at the start of some commands, e.g. ":edit" and
* ":write". "cd -" has a special meaning. */ // ":write". "cd -" has a special meaning.
if (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)) { if (*p == '>' || *p == '+' || (*p == '-' && p[1] == NUL)) {
escape_fname(&p); escape_fname((char_u **)&p);
} }
return p; return p;
@@ -3624,7 +3636,6 @@ set_cmd_context (
) )
{ {
int old_char = NUL; int old_char = NUL;
char_u *nextcomm;
/* /*
* Avoid a UMR warning from Purify, only save the character if it has been * Avoid a UMR warning from Purify, only save the character if it has been
@@ -3633,7 +3644,7 @@ set_cmd_context (
if (col < len) if (col < len)
old_char = str[col]; old_char = str[col];
str[col] = NUL; str[col] = NUL;
nextcomm = str; const char *nextcomm = (const char *)str;
if (use_ccline && ccline.cmdfirstc == '=') { if (use_ccline && ccline.cmdfirstc == '=') {
// pass CMD_SIZE because there is no real command // pass CMD_SIZE because there is no real command
@@ -3642,9 +3653,11 @@ set_cmd_context (
xp->xp_context = ccline.xp_context; xp->xp_context = ccline.xp_context;
xp->xp_pattern = ccline.cmdbuff; xp->xp_pattern = ccline.cmdbuff;
xp->xp_arg = ccline.xp_arg; xp->xp_arg = ccline.xp_arg;
} else } else {
while (nextcomm != NULL) while (nextcomm != NULL) {
nextcomm = set_one_cmd_context(xp, nextcomm); nextcomm = set_one_cmd_context(xp, nextcomm);
}
}
/* Store the string here so that call_user_expand_func() can get to them /* Store the string here so that call_user_expand_func() can get to them
* easily. */ * easily. */
@@ -4197,9 +4210,11 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
char_u keep; char_u keep;
garray_T ga; garray_T ga;
retstr = call_user_expand_func(call_func_retstr, xp, num_file, file); retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp,
if (retstr == NULL) num_file, file);
if (retstr == NULL) {
return FAIL; return FAIL;
}
ga_init(&ga, (int)sizeof(char *), 3); ga_init(&ga, (int)sizeof(char *), 3);
for (s = retstr; *s != NUL; s = e) { for (s = retstr; *s != NUL; s = e) {
@@ -4237,9 +4252,11 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
listitem_T *li; listitem_T *li;
garray_T ga; garray_T ga;
retlist = call_user_expand_func(call_func_retlist, xp, num_file, file); retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp,
if (retlist == NULL) num_file, file);
if (retlist == NULL) {
return FAIL; return FAIL;
}
ga_init(&ga, (int)sizeof(char *), 3); ga_init(&ga, (int)sizeof(char *), 3);
/* Loop over the items in the list. */ /* Loop over the items in the list. */
@@ -4249,7 +4266,7 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
GA_APPEND(char_u *, &ga, vim_strsave(li->li_tv.vval.v_string)); GA_APPEND(char_u *, &ga, vim_strsave(li->li_tv.vval.v_string));
} }
list_unref(retlist); tv_list_unref(retlist);
*file = ga.ga_data; *file = ga.ga_data;
*num_file = ga.ga_len; *num_file = ga.ga_len;
@@ -4545,7 +4562,7 @@ static inline void hist_free_entry(histentry_T *hisptr)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
xfree(hisptr->hisstr); xfree(hisptr->hisstr);
list_unref(hisptr->additional_elements); tv_list_unref(hisptr->additional_elements);
clear_hist_entry(hisptr); clear_hist_entry(hisptr);
} }
@@ -4601,7 +4618,7 @@ in_history (
history[type][last_i] = history[type][i]; history[type][last_i] = history[type][i];
last_i = i; last_i = i;
} }
list_unref(list); tv_list_unref(list);
history[type][i].hisnum = ++hisnum[type]; history[type][i].hisnum = ++hisnum[type];
history[type][i].hisstr = str; history[type][i].hisstr = str;
history[type][i].timestamp = os_time(); history[type][i].timestamp = os_time();
@@ -4623,7 +4640,7 @@ in_history (
/// ///
/// @return Any value from HistoryType enum, including HIST_INVALID. May not /// @return Any value from HistoryType enum, including HIST_INVALID. May not
/// return HIST_DEFAULT unless return_default is true. /// return HIST_DEFAULT unless return_default is true.
HistoryType get_histtype(const char_u *const name, const size_t len, HistoryType get_histtype(const char *const name, const size_t len,
const bool return_default) const bool return_default)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{ {
@@ -4677,8 +4694,8 @@ add_to_history (
* down, only lines that were added. * down, only lines that were added.
*/ */
if (histype == HIST_SEARCH && in_map) { if (histype == HIST_SEARCH && in_map) {
if (maptick == last_maptick) { if (maptick == last_maptick && hisidx[HIST_SEARCH] >= 0) {
/* Current line is from the same mapping, remove it */ // Current line is from the same mapping, remove it
hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]]; hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
hist_free_entry(hisptr); hist_free_entry(hisptr);
--hisnum[histype]; --hisnum[histype];
@@ -5016,7 +5033,7 @@ void ex_history(exarg_T *eap)
while (ASCII_ISALPHA(*end) while (ASCII_ISALPHA(*end)
|| vim_strchr((char_u *)":=@>/?", *end) != NULL) || vim_strchr((char_u *)":=@>/?", *end) != NULL)
end++; end++;
histype1 = get_histtype(arg, end - arg, false); histype1 = get_histtype((const char *)arg, end - arg, false);
if (histype1 == HIST_INVALID) { if (histype1 == HIST_INVALID) {
if (STRNICMP(arg, "all", end - arg) == 0) { if (STRNICMP(arg, "all", end - arg) == 0) {
histype1 = 0; histype1 = 0;
@@ -5173,7 +5190,7 @@ static int ex_window(void)
// Create empty command-line buffer. // Create empty command-line buffer.
buf_open_scratch(0, "[Command Line]"); buf_open_scratch(0, "[Command Line]");
// Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer. // Command-line buffer has bufhidden=wipe, unlike a true "scratch" buffer.
set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL); set_option_value("bh", 0L, "wipe", OPT_LOCAL);
curwin->w_p_rl = cmdmsg_rl; curwin->w_p_rl = cmdmsg_rl;
cmdmsg_rl = false; cmdmsg_rl = false;
curbuf->b_p_ma = true; curbuf->b_p_ma = true;
@@ -5191,7 +5208,7 @@ static int ex_window(void)
add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT); add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL); add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
} }
set_option_value((char_u *)"ft", 0L, (char_u *)"vim", OPT_LOCAL); set_option_value("ft", 0L, "vim", OPT_LOCAL);
} }
/* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin /* Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
@@ -5275,18 +5292,18 @@ static int ex_window(void)
cmdwin_result = Ctrl_C; cmdwin_result = Ctrl_C;
/* Set the new command line from the cmdline buffer. */ /* Set the new command line from the cmdline buffer. */
xfree(ccline.cmdbuff); xfree(ccline.cmdbuff);
if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { /* :qa[!] typed */ if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed
char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!"; const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
if (histtype == HIST_CMD) { if (histtype == HIST_CMD) {
/* Execute the command directly. */ // Execute the command directly.
ccline.cmdbuff = vim_strsave((char_u *)p); ccline.cmdbuff = (char_u *)xstrdup(p);
cmdwin_result = CAR; cmdwin_result = CAR;
} else { } else {
/* First need to cancel what we were doing. */ // First need to cancel what we were doing.
ccline.cmdbuff = NULL; ccline.cmdbuff = NULL;
stuffcharReadbuff(':'); stuffcharReadbuff(':');
stuffReadbuff((char_u *)p); stuffReadbuff(p);
stuffcharReadbuff(CAR); stuffcharReadbuff(CAR);
} }
} else if (cmdwin_result == K_XF2) { /* :qa typed */ } else if (cmdwin_result == K_XF2) { /* :qa typed */

View File

@@ -1,7 +1,7 @@
#ifndef NVIM_EX_GETLN_H #ifndef NVIM_EX_GETLN_H
#define NVIM_EX_GETLN_H #define NVIM_EX_GETLN_H
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h" #include "nvim/ex_cmds.h"
/* Values for nextwild() and ExpandOne(). See ExpandOne() for meaning. */ /* Values for nextwild() and ExpandOne(). See ExpandOne() for meaning. */

View File

@@ -322,8 +322,11 @@ vim_findfile_init (
drive[0] = path[0]; drive[0] = path[0];
drive[1] = ':'; drive[1] = ':';
drive[2] = NUL; drive[2] = NUL;
if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL) if (vim_FullName((const char *)drive, (char *)ff_expand_buffer, MAXPATHL,
true)
== FAIL) {
goto error_return; goto error_return;
}
path += 2; path += 2;
} else } else
#endif #endif
@@ -1549,14 +1552,14 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope)
assert(false); assert(false);
} }
dict_add_nr_str(dict, "scope", 0L, (char_u *)buf); tv_dict_add_str(dict, S_LEN("scope"), buf);
dict_add_nr_str(dict, "cwd", 0L, (char_u *)new_dir); tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
dict_set_keys_readonly(dict); tv_dict_set_keys_readonly(dict);
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false, apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
NULL); NULL);
dict_clear(dict); tv_dict_clear(dict);
recursive = false; recursive = false;
} }

View File

@@ -200,18 +200,14 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
{ {
int msg_scroll_save; int msg_scroll_save;
if (msg_silent != 0) if (msg_silent != 0) {
return; return;
msg_add_fname(buf, name); /* put file name in IObuff with quotes */ }
/* If it's extremely long, truncate it. */ add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name);
if (STRLEN(IObuff) > IOSIZE - 80) xstrlcat((char *)IObuff, (const char *)s, IOSIZE);
IObuff[IOSIZE - 80] = NUL; // For the first message may have to start a new line.
STRCAT(IObuff, s); // For further ones overwrite the previous one, reset msg_scroll before
/* // calling filemess().
* For the first message may have to start a new line.
* For further ones overwrite the previous one, reset msg_scroll before
* calling filemess().
*/
msg_scroll_save = msg_scroll; msg_scroll_save = msg_scroll;
if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
msg_scroll = FALSE; msg_scroll = FALSE;
@@ -428,7 +424,7 @@ readfile (
} }
if (!read_buffer && !read_stdin) { if (!read_buffer && !read_stdin) {
perm = os_getperm(fname); perm = os_getperm((const char *)fname);
#ifdef UNIX #ifdef UNIX
// On Unix it is possible to read a directory, so we have to // On Unix it is possible to read a directory, so we have to
// check for it before os_open(). // check for it before os_open().
@@ -614,10 +610,12 @@ readfile (
return FAIL; return FAIL;
} }
#ifdef UNIX #ifdef UNIX
/* Set swap file protection bits after creating it. */ // Set swap file protection bits after creating it.
if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL if (swap_mode > 0 && curbuf->b_ml.ml_mfp != NULL
&& curbuf->b_ml.ml_mfp->mf_fname != NULL) && curbuf->b_ml.ml_mfp->mf_fname != NULL) {
(void)os_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode); (void)os_setperm((const char *)curbuf->b_ml.ml_mfp->mf_fname,
(long)swap_mode);
}
#endif #endif
} }
@@ -1798,8 +1796,8 @@ failed:
} }
if (!filtering && !(flags & READ_DUMMY)) { if (!filtering && !(flags & READ_DUMMY)) {
msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */ add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname);
c = FALSE; c = false;
#ifdef UNIX #ifdef UNIX
# ifdef S_ISFIFO # ifdef S_ISFIFO
@@ -2256,9 +2254,16 @@ buf_write (
int len; int len;
linenr_T lnum; linenr_T lnum;
long nchars; long nchars;
char_u *errmsg = NULL; #define SET_ERRMSG_NUM(num, msg) \
int errmsg_allocated = FALSE; errnum = num, errmsg = msg, errmsgarg = 0
char_u *errnum = NULL; #define SET_ERRMSG_ARG(msg, error) \
errnum = NULL, errmsg = msg, errmsgarg = error
#define SET_ERRMSG(msg) \
errnum = NULL, errmsg = msg, errmsgarg = 0
const char *errnum = NULL;
char *errmsg = NULL;
int errmsgarg = 0;
bool errmsg_allocated = false;
char_u *buffer; char_u *buffer;
char_u smallbuf[SMBUFSIZE]; char_u smallbuf[SMBUFSIZE];
char_u *backup_ext; char_u *backup_ext;
@@ -2280,7 +2285,6 @@ buf_write (
/* writing everything */ /* writing everything */
int whole = (start == 1 && end == buf->b_ml.ml_line_count); int whole = (start == 1 && end == buf->b_ml.ml_line_count);
linenr_T old_line_count = buf->b_ml.ml_line_count; linenr_T old_line_count = buf->b_ml.ml_line_count;
int attr;
int fileformat; int fileformat;
int write_bin; int write_bin;
struct bw_info write_info; /* info for buf_write_bytes() */ struct bw_info write_info; /* info for buf_write_bytes() */
@@ -2575,13 +2579,11 @@ buf_write (
perm = file_info_old.stat.st_mode; perm = file_info_old.stat.st_mode;
if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */ if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */
if (S_ISDIR(file_info_old.stat.st_mode)) { if (S_ISDIR(file_info_old.stat.st_mode)) {
errnum = (char_u *)"E502: "; SET_ERRMSG_NUM("E502", _("is a directory"));
errmsg = (char_u *)_("is a directory");
goto fail; goto fail;
} }
if (os_nodetype((char *)fname) != NODE_WRITABLE) { if (os_nodetype((char *)fname) != NODE_WRITABLE) {
errnum = (char_u *)"E503: "; SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
errmsg = (char_u *)_("is not a file or writable device");
goto fail; goto fail;
} }
/* It's a device of some kind (or a fifo) which we can write to /* It's a device of some kind (or a fifo) which we can write to
@@ -2597,8 +2599,7 @@ buf_write (
*/ */
c = os_nodetype((char *)fname); c = os_nodetype((char *)fname);
if (c == NODE_OTHER) { if (c == NODE_OTHER) {
errnum = (char_u *)"E503: "; SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
errmsg = (char_u *)_("is not a file or writable device");
goto fail; goto fail;
} }
if (c == NODE_WRITABLE) { if (c == NODE_WRITABLE) {
@@ -2606,12 +2607,11 @@ buf_write (
newfile = TRUE; newfile = TRUE;
perm = -1; perm = -1;
} else { } else {
perm = os_getperm(fname); perm = os_getperm((const char *)fname);
if (perm < 0) if (perm < 0) {
newfile = TRUE; newfile = true;
else if (os_isdir(fname)) { } else if (os_isdir(fname)) {
errnum = (char_u *)"E502: "; SET_ERRMSG_NUM("E502", _("is a directory"));
errmsg = (char_u *)_("is a directory");
goto fail; goto fail;
} }
if (overwriting) { if (overwriting) {
@@ -2630,11 +2630,9 @@ buf_write (
if (!forceit && file_readonly) { if (!forceit && file_readonly) {
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) { if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
errnum = (char_u *)"E504: "; SET_ERRMSG_NUM("E504", _(err_readonly));
errmsg = (char_u *)_(err_readonly);
} else { } else {
errnum = (char_u *)"E505: "; SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)"));
errmsg = (char_u *)_("is read-only (add ! to override)");
} }
goto fail; goto fail;
} }
@@ -2870,9 +2868,9 @@ buf_write (
xfree(backup); xfree(backup);
backup = NULL; backup = NULL;
} else { } else {
/* set file protection same as original file, but // set file protection same as original file, but
* strip s-bit */ // strip s-bit.
(void)os_setperm(backup, perm & 0777); (void)os_setperm((const char *)backup, perm & 0777);
#ifdef UNIX #ifdef UNIX
/* /*
@@ -2883,7 +2881,8 @@ buf_write (
*/ */
if (file_info_new.stat.st_gid != file_info_old.stat.st_gid if (file_info_new.stat.st_gid != file_info_old.stat.st_gid
&& os_fchown(bfd, -1, file_info_old.stat.st_gid) != 0) { && os_fchown(bfd, -1, file_info_old.stat.st_gid) != 0) {
os_setperm(backup, (perm & 0707) | ((perm & 07) << 3)); os_setperm((const char *)backup,
(perm & 0707) | ((perm & 07) << 3));
} }
# ifdef HAVE_SELINUX # ifdef HAVE_SELINUX
mch_copy_sec(fname, backup); mch_copy_sec(fname, backup);
@@ -2901,23 +2900,27 @@ buf_write (
while ((write_info.bw_len = read_eintr(fd, copybuf, while ((write_info.bw_len = read_eintr(fd, copybuf,
BUFSIZE)) > 0) { BUFSIZE)) > 0) {
if (buf_write_bytes(&write_info) == FAIL) { if (buf_write_bytes(&write_info) == FAIL) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E506: Can't write to backup file (add ! to override)"); "E506: Can't write to backup file (add ! to override)"));
break; break;
} }
os_breakcheck(); os_breakcheck();
if (got_int) { if (got_int) {
errmsg = (char_u *)_(e_interr); SET_ERRMSG(_(e_interr));
break; break;
} }
} }
if (close(bfd) < 0 && errmsg == NULL) int error;
errmsg = (char_u *)_( if ((error = os_close(bfd)) != 0 && errmsg == NULL) {
"E507: Close error for backup file (add ! to override)"); SET_ERRMSG_ARG(_("E507: Close error for backup file "
if (write_info.bw_len < 0) "(add ! to override): %s"),
errmsg = (char_u *)_( error);
"E508: Can't read file for backup (add ! to override)"); }
if (write_info.bw_len < 0) {
SET_ERRMSG(_(
"E508: Can't read file for backup (add ! to override)"));
}
#ifdef UNIX #ifdef UNIX
set_file_time(backup, set_file_time(backup,
file_info_old.stat.st_atim.tv_sec, file_info_old.stat.st_atim.tv_sec,
@@ -2934,18 +2937,19 @@ buf_write (
} }
} }
nobackup: nobackup:
close(fd); /* ignore errors for closing read file */ os_close(fd); // Ignore errors for closing read file.
xfree(copybuf); xfree(copybuf);
if (backup == NULL && errmsg == NULL) if (backup == NULL && errmsg == NULL) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E509: Cannot create backup file (add ! to override)"); "E509: Cannot create backup file (add ! to override)"));
/* ignore errors when forceit is TRUE */ }
// Ignore errors when forceit is TRUE.
if ((some_error || errmsg != NULL) && !forceit) { if ((some_error || errmsg != NULL) && !forceit) {
retval = FAIL; retval = FAIL;
goto fail; goto fail;
} }
errmsg = NULL; SET_ERRMSG(NULL);
} else { } else {
char_u *dirp; char_u *dirp;
char_u *p; char_u *p;
@@ -2960,8 +2964,7 @@ nobackup:
* anyway, thus we need an extra check here. * anyway, thus we need an extra check here.
*/ */
if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) { if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
errnum = (char_u *)"E504: "; SET_ERRMSG_NUM("E504", _(err_readonly));
errmsg = (char_u *)_(err_readonly);
goto fail; goto fail;
} }
@@ -3025,7 +3028,7 @@ nobackup:
} }
} }
if (backup == NULL && !forceit) { if (backup == NULL && !forceit) {
errmsg = (char_u *)_("E510: Can't make backup file (add ! to override)"); SET_ERRMSG(_("E510: Can't make backup file (add ! to override)"));
goto fail; goto fail;
} }
} }
@@ -3037,8 +3040,8 @@ nobackup:
&& file_info_old.stat.st_uid == getuid() && file_info_old.stat.st_uid == getuid()
&& vim_strchr(p_cpo, CPO_FWRITE) == NULL) { && vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
perm |= 0200; perm |= 0200;
(void)os_setperm(fname, perm); (void)os_setperm((const char *)fname, perm);
made_writable = TRUE; made_writable = true;
} }
#endif #endif
@@ -3066,7 +3069,7 @@ nobackup:
&& !(exiting && backup != NULL)) { && !(exiting && backup != NULL)) {
ml_preserve(buf, FALSE); ml_preserve(buf, FALSE);
if (got_int) { if (got_int) {
errmsg = (char_u *)_(e_interr); SET_ERRMSG(_(e_interr));
goto restore_backup; goto restore_backup;
} }
} }
@@ -3137,8 +3140,8 @@ nobackup:
*/ */
if (*p_ccv != NUL) { if (*p_ccv != NUL) {
wfname = vim_tempname(); wfname = vim_tempname();
if (wfname == NULL) { /* Can't write without a tempfile! */ if (wfname == NULL) { // Can't write without a tempfile!
errmsg = (char_u *)_("E214: Can't find temp file for writing"); SET_ERRMSG(_("E214: Can't find temp file for writing"));
goto restore_backup; goto restore_backup;
} }
} }
@@ -3150,8 +3153,8 @@ nobackup:
&& wfname == fname && wfname == fname
) { ) {
if (!forceit) { if (!forceit) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E213: Cannot convert (add ! to write without conversion)"); "E213: Cannot convert (add ! to write without conversion)"));
goto restore_backup; goto restore_backup;
} }
notconverted = TRUE; notconverted = TRUE;
@@ -3186,11 +3189,10 @@ nobackup:
if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1) if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1)
|| (os_fileinfo_link((char *)fname, &file_info) || (os_fileinfo_link((char *)fname, &file_info)
&& !os_fileinfo_id_equal(&file_info, &file_info_old))) { && !os_fileinfo_id_equal(&file_info, &file_info_old))) {
errmsg = (char_u *)_("E166: Can't open linked file for writing"); SET_ERRMSG(_("E166: Can't open linked file for writing"));
} else } else {
#endif #endif
{ SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd);
errmsg = (char_u *)_("E212: Can't open file for writing");
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
&& perm >= 0) { && perm >= 0) {
#ifdef UNIX #ifdef UNIX
@@ -3208,7 +3210,9 @@ nobackup:
os_remove((char *)wfname); os_remove((char *)wfname);
continue; continue;
} }
#ifdef UNIX
} }
#endif
} }
restore_backup: restore_backup:
@@ -3250,7 +3254,7 @@ restore_backup:
xfree(wfname); xfree(wfname);
goto fail; goto fail;
} }
errmsg = NULL; SET_ERRMSG(NULL);
write_info.bw_fd = fd; write_info.bw_fd = fd;
@@ -3370,7 +3374,6 @@ restore_backup:
nchars += len; nchars += len;
} }
#if defined(UNIX)
// On many journalling file systems there is a bug that causes both the // On many journalling file systems there is a bug that causes both the
// original and the backup file to be lost when halting the system right // original and the backup file to be lost when halting the system right
// after writing the file. That's because only the meta-data is // after writing the file. That's because only the meta-data is
@@ -3379,11 +3382,11 @@ restore_backup:
// For a device do try the fsync() but don't complain if it does not work // For a device do try the fsync() but don't complain if it does not work
// (could be a pipe). // (could be a pipe).
// If the 'fsync' option is FALSE, don't fsync(). Useful for laptops. // If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
if (p_fs && os_fsync(fd) != 0 && !device) { int error;
errmsg = (char_u *)_("E667: Fsync failed"); if (p_fs && (error = os_fsync(fd)) != 0 && !device) {
SET_ERRMSG_ARG(_("E667: Fsync failed: %s"), error);
end = 0; end = 0;
} }
#endif
#ifdef HAVE_SELINUX #ifdef HAVE_SELINUX
/* Probably need to set the security context. */ /* Probably need to set the security context. */
@@ -3402,8 +3405,9 @@ restore_backup:
|| file_info.stat.st_uid != file_info_old.stat.st_uid || file_info.stat.st_uid != file_info_old.stat.st_uid
|| file_info.stat.st_gid != file_info_old.stat.st_gid) { || file_info.stat.st_gid != file_info_old.stat.st_gid) {
os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid); os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
if (perm >= 0) /* set permission again, may have changed */ if (perm >= 0) { // Set permission again, may have changed.
(void)os_setperm(wfname, perm); (void)os_setperm((const char *)wfname, perm);
}
} }
buf_set_file_id(buf); buf_set_file_id(buf);
} else if (!buf->file_id_valid) { } else if (!buf->file_id_valid) {
@@ -3412,8 +3416,8 @@ restore_backup:
} }
#endif #endif
if (close(fd) != 0) { if ((error = os_close(fd)) != 0) {
errmsg = (char_u *)_("E512: Close failed"); SET_ERRMSG_ARG(_("E512: Close failed: %s"), error);
end = 0; end = 0;
} }
@@ -3421,8 +3425,9 @@ restore_backup:
if (made_writable) if (made_writable)
perm &= ~0200; /* reset 'w' bit for security reasons */ perm &= ~0200; /* reset 'w' bit for security reasons */
#endif #endif
if (perm >= 0) /* set perm. of new file same as old file */ if (perm >= 0) { // Set perm. of new file same as old file.
(void)os_setperm(wfname, perm); (void)os_setperm((const char *)wfname, perm);
}
#ifdef HAVE_ACL #ifdef HAVE_ACL
/* Probably need to set the ACL before changing the user (can't set the /* Probably need to set the ACL before changing the user (can't set the
* ACL on a file the user doesn't own). */ * ACL on a file the user doesn't own). */
@@ -3449,21 +3454,24 @@ restore_backup:
if (end == 0) { if (end == 0) {
if (errmsg == NULL) { if (errmsg == NULL) {
if (write_info.bw_conv_error) { if (write_info.bw_conv_error) {
if (write_info.bw_conv_error_lnum == 0) if (write_info.bw_conv_error_lnum == 0) {
errmsg = (char_u *)_( SET_ERRMSG(_(
"E513: write error, conversion failed (make 'fenc' empty to override)"); "E513: write error, conversion failed "
else { "(make 'fenc' empty to override)"));
errmsg_allocated = TRUE; } else {
errmsg = xmalloc(300); errmsg_allocated = true;
vim_snprintf((char *)errmsg, 300, SET_ERRMSG(xmalloc(300));
_("E513: write error, conversion failed in line %" PRId64 vim_snprintf(
errmsg, 300,
_("E513: write error, conversion failed in line %" PRIdLINENR
" (make 'fenc' empty to override)"), " (make 'fenc' empty to override)"),
(int64_t)write_info.bw_conv_error_lnum); write_info.bw_conv_error_lnum);
} }
} else if (got_int) } else if (got_int) {
errmsg = (char_u *)_(e_interr); SET_ERRMSG(_(e_interr));
else } else {
errmsg = (char_u *)_("E514: write error (file system full?)"); SET_ERRMSG(_("E514: write error (file system full?)"));
}
} }
/* /*
@@ -3518,8 +3526,8 @@ restore_backup:
fname = sfname; /* use shortname now, for the messages */ fname = sfname; /* use shortname now, for the messages */
#endif #endif
if (!filtering) { if (!filtering) {
msg_add_fname(buf, fname); /* put fname in IObuff with quotes */ add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname);
c = FALSE; c = false;
if (write_info.bw_conv_error) { if (write_info.bw_conv_error) {
STRCAT(IObuff, _(" CONVERSION ERROR")); STRCAT(IObuff, _(" CONVERSION ERROR"));
c = TRUE; c = TRUE;
@@ -3628,7 +3636,7 @@ restore_backup:
close(empty_fd); close(empty_fd);
} }
if (org != NULL) { if (org != NULL) {
os_setperm((char_u *)org, os_getperm(fname) & 0777); os_setperm(org, os_getperm((const char *)fname) & 0777);
xfree(org); xfree(org);
} }
} }
@@ -3668,33 +3676,32 @@ nofail:
#endif #endif
if (errmsg != NULL) { if (errmsg != NULL) {
int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0; // - 100 to save some space for further error message
attr = hl_attr(HLF_E); /* set highlight for error messages */
msg_add_fname(buf,
#ifndef UNIX #ifndef UNIX
sfname add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname);
#else #else
fname add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname);
#endif #endif
); /* put file name in IObuff with quotes */
if (STRLEN(IObuff) + STRLEN(errmsg) + numlen >= IOSIZE)
IObuff[IOSIZE - STRLEN(errmsg) - numlen - 1] = NUL;
/* If the error message has the form "is ...", put the error number in
* front of the file name. */
if (errnum != NULL) { if (errnum != NULL) {
STRMOVE(IObuff + numlen, IObuff); if (errmsgarg != 0) {
memmove(IObuff, errnum, (size_t)numlen); emsgf("%s: %s%s: %s", errnum, IObuff, errmsg, os_strerror(errmsgarg));
} else {
emsgf("%s: %s%s", errnum, IObuff, errmsg);
}
} else if (errmsgarg != 0) {
emsgf(errmsg, os_strerror(errmsgarg));
} else {
emsgf(errmsg);
} }
STRCAT(IObuff, errmsg); if (errmsg_allocated) {
emsg(IObuff);
if (errmsg_allocated)
xfree(errmsg); xfree(errmsg);
}
retval = FAIL; retval = FAIL;
if (end == 0) { if (end == 0) {
const int attr = hl_attr(HLF_E); // Set highlight for error messages.
MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"), MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
attr | MSG_HIST); attr | MSG_HIST);
MSG_PUTS_ATTR(_( MSG_PUTS_ATTR(_(
"don't quit the editor until the file is successfully written!"), "don't quit the editor until the file is successfully written!"),
attr | MSG_HIST); attr | MSG_HIST);
@@ -3754,6 +3761,9 @@ nofail:
got_int |= prev_got_int; got_int |= prev_got_int;
return retval; return retval;
#undef SET_ERRMSG
#undef SET_ERRMSG_ARG
#undef SET_ERRMSG_NUM
} }
/* /*
@@ -3797,16 +3807,25 @@ static int set_rw_fname(char_u *fname, char_u *sfname)
return OK; return OK;
} }
/* /// Put file name into the specified buffer with quotes
* Put file name into IObuff with quotes. ///
*/ /// Replaces home directory at the start with `~`.
void msg_add_fname(buf_T *buf, char_u *fname) ///
/// @param[out] ret_buf Buffer to save results to.
/// @param[in] buf_len ret_buf length.
/// @param[in] buf buf_T file name is coming from.
/// @param[in] fname File name to write.
static void add_quoted_fname(char *const ret_buf, const size_t buf_len,
const buf_T *const buf, const char *fname)
FUNC_ATTR_NONNULL_ARG(1)
{ {
if (fname == NULL) if (fname == NULL) {
fname = (char_u *)"-stdin-"; fname = "-stdin-";
home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE); }
IObuff[0] = '"'; ret_buf[0] = '"';
STRCAT(IObuff, "\" "); home_replace(buf, (const char_u *)fname, (char_u *)ret_buf + 1,
(int)buf_len - 4, true);
xstrlcat(ret_buf, "\" ", buf_len);
} }
/// Append message for text mode to IObuff. /// Append message for text mode to IObuff.
@@ -4548,9 +4567,9 @@ int put_time(FILE *fd, time_t time_)
/// os_rename() only works if both files are on the same file system, this /// os_rename() only works if both files are on the same file system, this
/// function will (attempts to?) copy the file across if rename fails -- webb /// function will (attempts to?) copy the file across if rename fails -- webb
// ///
/// @return -1 for failure, 0 for success /// @return -1 for failure, 0 for success
int vim_rename(char_u *from, char_u *to) int vim_rename(const char_u *from, const char_u *to)
{ {
int fd_in; int fd_in;
int fd_out; int fd_out;
@@ -4569,10 +4588,12 @@ int vim_rename(char_u *from, char_u *to)
* the file name differs we need to go through a temp file. * the file name differs we need to go through a temp file.
*/ */
if (fnamecmp(from, to) == 0) { if (fnamecmp(from, to) == 0) {
if (p_fic && STRCMP(path_tail(from), path_tail(to)) != 0) if (p_fic && (STRCMP(path_tail((char_u *)from), path_tail((char_u *)to))
!= 0)) {
use_tmp_file = true; use_tmp_file = true;
else } else {
return 0; return 0;
}
} }
// Fail if the "from" file doesn't exist. Avoids that "to" is deleted. // Fail if the "from" file doesn't exist. Avoids that "to" is deleted.
@@ -4638,9 +4659,9 @@ int vim_rename(char_u *from, char_u *to)
/* /*
* Rename() failed, try copying the file. * Rename() failed, try copying the file.
*/ */
perm = os_getperm(from); perm = os_getperm((const char *)from);
#ifdef HAVE_ACL #ifdef HAVE_ACL
/* For systems that support ACL: get the ACL from the original file. */ // For systems that support ACL: get the ACL from the original file.
acl = mch_get_acl(from); acl = mch_get_acl(from);
#endif #endif
fd_in = os_open((char *)from, O_RDONLY, 0); fd_in = os_open((char *)from, O_RDONLY, 0);
@@ -4688,8 +4709,8 @@ int vim_rename(char_u *from, char_u *to)
errmsg = _("E210: Error reading \"%s\""); errmsg = _("E210: Error reading \"%s\"");
to = from; to = from;
} }
#ifndef UNIX /* for Unix os_open() already set the permission */ #ifndef UNIX // For Unix os_open() already set the permission.
os_setperm(to, perm); os_setperm((const char *)to, perm);
#endif #endif
#ifdef HAVE_ACL #ifdef HAVE_ACL
mch_set_acl(to, acl); mch_set_acl(to, acl);
@@ -5200,7 +5221,7 @@ void forward_slash(char_u *fname)
{ {
char_u *p; char_u *p;
if (path_with_url(fname)) { if (path_with_url((const char *)fname)) {
return; return;
} }
for (p = fname; *p != NUL; p++) { for (p = fname; *p != NUL; p++) {
@@ -5261,7 +5282,7 @@ static void vim_maketempdir(void)
/// Delete "name" and everything in it, recursively. /// Delete "name" and everything in it, recursively.
/// @param name The path which should be deleted. /// @param name The path which should be deleted.
/// @return 0 for success, -1 if some file was not deleted. /// @return 0 for success, -1 if some file was not deleted.
int delete_recursive(char_u *name) int delete_recursive(const char *name)
{ {
int result = 0; int result = 0;
@@ -5275,7 +5296,7 @@ int delete_recursive(char_u *name)
EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS
| EW_DODOT | EW_EMPTYOK) == OK) { | EW_DODOT | EW_EMPTYOK) == OK) {
for (int i = 0; i < file_count; i++) { for (int i = 0; i < file_count; i++) {
if (delete_recursive(files[i]) != 0) { if (delete_recursive((const char *)files[i]) != 0) {
result = -1; result = -1;
} }
} }
@@ -5285,9 +5306,9 @@ int delete_recursive(char_u *name)
} }
xfree(exp); xfree(exp);
os_rmdir((char *)name); os_rmdir(name);
} else { } else {
result = os_remove((char *)name) == 0 ? 0 : -1; result = os_remove(name) == 0 ? 0 : -1;
} }
return result; return result;
@@ -5299,7 +5320,7 @@ void vim_deltempdir(void)
if (vim_tempdir != NULL) { if (vim_tempdir != NULL) {
// remove the trailing path separator // remove the trailing path separator
path_tail(vim_tempdir)[-1] = NUL; path_tail(vim_tempdir)[-1] = NUL;
delete_recursive(vim_tempdir); delete_recursive((const char *)vim_tempdir);
xfree(vim_tempdir); xfree(vim_tempdir);
vim_tempdir = NULL; vim_tempdir = NULL;
} }

View File

@@ -2232,32 +2232,51 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
* before where we started looking, extend it. If it * before where we started looking, extend it. If it
* starts at another line, update nested folds to keep * starts at another line, update nested folds to keep
* their position, compensating for the new fd_top. */ * their position, compensating for the new fd_top. */
if (fp->fd_top >= startlnum && fp->fd_top != firstlnum) { if (fp->fd_top == firstlnum) {
if (fp->fd_top > firstlnum) // We have found a fold beginning exactly where we want one.
/* like lines are inserted */ } else if (fp->fd_top >= startlnum) {
if (fp->fd_top > firstlnum) {
// We will move the start of this fold up, hence we move all
// nested folds (with relative line numbers) down.
foldMarkAdjustRecurse(&fp->fd_nested, foldMarkAdjustRecurse(&fp->fd_nested,
(linenr_T)0, (linenr_T)MAXLNUM, (linenr_T)0, (linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum), 0L); (long)(fp->fd_top - firstlnum), 0L);
else } else {
/* like lines are deleted */ // Will move fold down, move nested folds relatively up.
foldMarkAdjustRecurse(&fp->fd_nested, foldMarkAdjustRecurse(&fp->fd_nested,
(linenr_T)0, (linenr_T)0,
(long)(firstlnum - fp->fd_top - 1), (long)(firstlnum - fp->fd_top - 1),
(linenr_T)MAXLNUM, (linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum)); (long)(fp->fd_top - firstlnum));
}
fp->fd_len += fp->fd_top - firstlnum; fp->fd_len += fp->fd_top - firstlnum;
fp->fd_top = firstlnum; fp->fd_top = firstlnum;
fold_changed = TRUE; fold_changed = true;
} else if (flp->start != 0 && lvl == level } else if ((flp->start != 0 && lvl == level)
&& fp->fd_top != firstlnum) { || (firstlnum != startlnum)) {
/* Existing fold that includes startlnum must stop // Before there was a fold spanning from above startlnum to below
* if we find the start of a new fold at the same // firstlnum. This fold is valid above startlnum (because we are
* level. Split it. Delete contained folds at // not updating that range), but there is now a break in it.
* this point to split them too. */ // If the break is because we are now forced to start a new fold
foldRemove(&fp->fd_nested, flp->lnum - fp->fd_top, // at the level "level" at line fline->lnum, then we need to
flp->lnum - fp->fd_top); // split the fold at fline->lnum.
// If the break is because the range [startlnum, firstlnum) is
// now at a lower indent than "level", we need to split the fold
// in this range.
// Any splits have to be done recursively.
linenr_T breakstart;
linenr_T breakend;
if (firstlnum != startlnum) {
breakstart = startlnum;
breakend = firstlnum;
} else {
breakstart = flp->lnum;
breakend = flp->lnum;
}
foldRemove(&fp->fd_nested, breakstart - fp->fd_top,
breakend - fp->fd_top);
i = (int)(fp - (fold_T *)gap->ga_data); i = (int)(fp - (fold_T *)gap->ga_data);
foldSplit(gap, i, flp->lnum, flp->lnum - 1); foldSplit(gap, i, breakstart, breakend - 1);
fp = (fold_T *)gap->ga_data + i + 1; fp = (fold_T *)gap->ga_data + i + 1;
/* If using the "marker" or "syntax" method, we /* If using the "marker" or "syntax" method, we
* need to continue until the end of the fold is * need to continue until the end of the fold is
@@ -2267,6 +2286,16 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level,
|| getlevel == foldlevelSyntax) || getlevel == foldlevelSyntax)
finish = TRUE; finish = TRUE;
} }
if (fp->fd_top == startlnum && concat) {
i = (int)(fp - (fold_T *)gap->ga_data);
if (i != 0) {
fp2 = fp - 1;
if (fp2->fd_top + fp2->fd_len == fp->fd_top) {
foldMerge(fp2, gap, fp);
fp = fp2;
}
}
}
break; break;
} }
if (fp->fd_top >= startlnum) { if (fp->fd_top >= startlnum) {

View File

@@ -235,19 +235,18 @@ char_u *get_inserted(void)
return get_buffcont(&redobuff, FALSE); return get_buffcont(&redobuff, FALSE);
} }
/* /// Add string after the current block of the given buffer
* Add string "s" after the current block of buffer "buf". ///
* K_SPECIAL and CSI should have been escaped already. /// K_SPECIAL and CSI should have been escaped already.
*/ ///
static void /// @param[out] buf Buffer to add to.
add_buff ( /// @param[in] s String to add.
buffheader_T *buf, /// @param[in] slen String length or -1 for NUL-terminated string.
char_u *s, static void add_buff(buffheader_T *const buf, const char *const s,
ssize_t slen // length of "s" or -1 ptrdiff_t slen)
)
{ {
if (slen < 0) { if (slen < 0) {
slen = (ssize_t)STRLEN(s); slen = (ptrdiff_t)strlen(s);
} }
if (slen == 0) { // don't add empty strings if (slen == 0) { // don't add empty strings
return; return;
@@ -292,9 +291,8 @@ add_buff (
*/ */
static void add_num_buff(buffheader_T *buf, long n) static void add_num_buff(buffheader_T *buf, long n)
{ {
char_u number[32]; char number[32];
snprintf(number, sizeof(number), "%ld", n);
sprintf((char *)number, "%" PRId64, (int64_t)n);
add_buff(buf, number, -1L); add_buff(buf, number, -1L);
} }
@@ -304,27 +302,29 @@ static void add_num_buff(buffheader_T *buf, long n)
*/ */
static void add_char_buff(buffheader_T *buf, int c) static void add_char_buff(buffheader_T *buf, int c)
{ {
char_u bytes[MB_MAXBYTES + 1]; char bytes[MB_MAXBYTES + 1];
int len; int len;
int i; if (IS_SPECIAL(c)) {
char_u temp[4];
if (IS_SPECIAL(c))
len = 1; len = 1;
else } else {
len = (*mb_char2bytes)(c, bytes); len = (*mb_char2bytes)(c, (char_u *)bytes);
for (i = 0; i < len; ++i) { }
if (!IS_SPECIAL(c))
c = bytes[i];
for (int i = 0; i < len; i++) {
if (!IS_SPECIAL(c)) {
c = bytes[i];
}
char temp[4];
if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) { if (IS_SPECIAL(c) || c == K_SPECIAL || c == NUL) {
/* translate special key code into three byte sequence */ // Translate special key code into three byte sequence.
temp[0] = K_SPECIAL; temp[0] = (char)K_SPECIAL;
temp[1] = (char_u)K_SECOND(c); temp[1] = (char)K_SECOND(c);
temp[2] = (char_u)K_THIRD(c); temp[2] = (char)K_THIRD(c);
temp[3] = NUL; temp[3] = NUL;
} else { } else {
temp[0] = (char_u)c; temp[0] = (char)c;
temp[1] = NUL; temp[1] = NUL;
} }
add_buff(buf, temp, -1L); add_buff(buf, temp, -1L);
@@ -479,16 +479,14 @@ static int save_level = 0;
void saveRedobuff(void) void saveRedobuff(void)
{ {
char_u *s;
if (save_level++ == 0) { if (save_level++ == 0) {
save_redobuff = redobuff; save_redobuff = redobuff;
redobuff.bh_first.b_next = NULL; redobuff.bh_first.b_next = NULL;
save_old_redobuff = old_redobuff; save_old_redobuff = old_redobuff;
old_redobuff.bh_first.b_next = NULL; old_redobuff.bh_first.b_next = NULL;
/* Make a copy, so that ":normal ." in a function works. */ // Make a copy, so that ":normal ." in a function works.
s = get_buffcont(&save_redobuff, FALSE); char *const s = (char *)get_buffcont(&save_redobuff, false);
if (s != NULL) { if (s != NULL) {
add_buff(&redobuff, s, -1L); add_buff(&redobuff, s, -1L);
xfree(s); xfree(s);
@@ -514,10 +512,11 @@ void restoreRedobuff(void)
* Append "s" to the redo buffer. * Append "s" to the redo buffer.
* K_SPECIAL and CSI should already have been escaped. * K_SPECIAL and CSI should already have been escaped.
*/ */
void AppendToRedobuff(char_u *s) void AppendToRedobuff(const char *s)
{ {
if (!block_redo) if (!block_redo) {
add_buff(&redobuff, s, -1L); add_buff(&redobuff, (const char *)s, -1L);
}
} }
/* /*
@@ -530,44 +529,47 @@ AppendToRedobuffLit (
int len /* length of "str" or -1 for up to the NUL */ int len /* length of "str" or -1 for up to the NUL */
) )
{ {
char_u *s = str; if (block_redo) {
int c;
char_u *start;
if (block_redo)
return; return;
}
while (len < 0 ? *s != NUL : s - str < len) { const char *s = (const char *)str;
/* Put a string of normal characters in the redo buffer (that's while (len < 0 ? *s != NUL : s - (const char *)str < len) {
* faster). */ // Put a string of normal characters in the redo buffer (that's
start = s; // faster).
while (*s >= ' ' && *s < DEL && (len < 0 || s - str < len)) const char *start = s;
++s; while (*s >= ' ' && *s < DEL && (len < 0 || s - (const char *)str < len)) {
s++;
}
/* Don't put '0' or '^' as last character, just in case a CTRL-D is // Don't put '0' or '^' as last character, just in case a CTRL-D is
* typed next. */ // typed next.
if (*s == NUL && (s[-1] == '0' || s[-1] == '^')) if (*s == NUL && (s[-1] == '0' || s[-1] == '^')) {
--s; s--;
if (s > start) }
if (s > start) {
add_buff(&redobuff, start, (long)(s - start)); add_buff(&redobuff, start, (long)(s - start));
}
if (*s == NUL || (len >= 0 && s - str >= len)) if (*s == NUL || (len >= 0 && s - (const char *)str >= len)) {
break; break;
}
/* Handle a special or multibyte character. */ // Handle a special or multibyte character.
if (has_mbyte) // Composing chars separately are handled separately.
/* Handle composing chars separately. */ const int c = (has_mbyte
c = mb_cptr2char_adv(&s); ? mb_cptr2char_adv((const char_u **)&s)
else : (uint8_t)(*s++));
c = *s++; if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^'))) {
if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^')))
add_char_buff(&redobuff, Ctrl_V); add_char_buff(&redobuff, Ctrl_V);
}
/* CTRL-V '0' must be inserted as CTRL-V 048 */ // CTRL-V '0' must be inserted as CTRL-V 048.
if (*s == NUL && c == '0') if (*s == NUL && c == '0') {
add_buff(&redobuff, (char_u *)"048", 3L); add_buff(&redobuff, "048", 3L);
else } else {
add_char_buff(&redobuff, c); add_char_buff(&redobuff, c);
}
} }
} }
@@ -594,19 +596,19 @@ void AppendNumberToRedobuff(long n)
* Append string "s" to the stuff buffer. * Append string "s" to the stuff buffer.
* CSI and K_SPECIAL must already have been escaped. * CSI and K_SPECIAL must already have been escaped.
*/ */
void stuffReadbuff(char_u *s) void stuffReadbuff(const char *s)
{ {
add_buff(&readbuf1, s, -1L); add_buff(&readbuf1, s, -1L);
} }
/// Append string "s" to the redo stuff buffer. /// Append string "s" to the redo stuff buffer.
/// @remark CSI and K_SPECIAL must already have been escaped. /// @remark CSI and K_SPECIAL must already have been escaped.
void stuffRedoReadbuff(char_u *s) void stuffRedoReadbuff(const char *s)
{ {
add_buff(&readbuf2, s, -1L); add_buff(&readbuf2, s, -1L);
} }
void stuffReadbuffLen(char_u *s, long len) void stuffReadbuffLen(const char *s, long len)
{ {
add_buff(&readbuf1, s, len); add_buff(&readbuf1, s, len);
} }
@@ -616,19 +618,18 @@ void stuffReadbuffLen(char_u *s, long len)
* escaping other K_SPECIAL and CSI bytes. * escaping other K_SPECIAL and CSI bytes.
* Change CR, LF and ESC into a space. * Change CR, LF and ESC into a space.
*/ */
void stuffReadbuffSpec(char_u *s) void stuffReadbuffSpec(const char *s)
{ {
int c;
while (*s != NUL) { while (*s != NUL) {
if (*s == K_SPECIAL && s[1] != NUL && s[2] != NUL) { if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
/* Insert special key literally. */ // Insert special key literally.
stuffReadbuffLen(s, 3L); stuffReadbuffLen(s, 3);
s += 3; s += 3;
} else { } else {
c = mb_ptr2char_adv(&s); int c = mb_ptr2char_adv((const char_u **)&s);
if (c == CAR || c == NL || c == ESC) if (c == CAR || c == NL || c == ESC) {
c = ' '; c = ' ';
}
stuffcharReadbuff(c); stuffcharReadbuff(c);
} }
} }
@@ -747,8 +748,8 @@ int start_redo(long count, int old_redo)
/* copy the buffer name, if present */ /* copy the buffer name, if present */
if (c == '"') { if (c == '"') {
add_buff(&readbuf2, (char_u *)"\"", 1L); add_buff(&readbuf2, "\"", 1L);
c = read_redo(FALSE, old_redo); c = read_redo(false, old_redo);
/* if a numbered buffer is used, increment the number */ /* if a numbered buffer is used, increment the number */
if (c >= '1' && c < '9') if (c >= '1' && c < '9')
@@ -1091,21 +1092,19 @@ static void gotchars(char_u *chars, size_t len)
{ {
char_u *s = chars; char_u *s = chars;
int c; int c;
char_u buf[2];
// remember how many chars were last recorded // remember how many chars were last recorded
if (Recording) { if (Recording) {
last_recorded_len += len; last_recorded_len += len;
} }
buf[1] = NUL;
while (len--) { while (len--) {
// Handle one byte at a time; no translation to be done. // Handle one byte at a time; no translation to be done.
c = *s++; c = *s++;
updatescript(c); updatescript(c);
if (Recording) { if (Recording) {
buf[0] = (char_u)c; char buf[2] = { (char)c, NUL };
add_buff(&recordbuff, buf, 1L); add_buff(&recordbuff, buf, 1L);
} }
} }
@@ -1881,9 +1880,8 @@ static int vgetorpeek(int advance)
(size_t)(mlen - typebuf.tb_maplen)); (size_t)(mlen - typebuf.tb_maplen));
} }
del_typebuf(mlen, 0); /* remove the chars */ del_typebuf(mlen, 0); // Remove the chars.
set_option_value((char_u *)"paste", set_option_value("paste", !p_paste, NULL, 0);
(long)!p_paste, NULL, 0);
if (!(State & INSERT)) { if (!(State & INSERT)) {
msg_col = 0; msg_col = 0;
msg_row = (int)Rows - 1; msg_row = (int)Rows - 1;
@@ -1905,7 +1903,7 @@ static int vgetorpeek(int advance)
} }
if ((mp == NULL || max_mlen >= mp_match_len) if ((mp == NULL || max_mlen >= mp_match_len)
&& keylen != KEYLEN_PART_MAP) { && keylen != KEYLEN_PART_MAP && keylen != KEYLEN_PART_KEY) {
// No matching mapping found or found a non-matching mapping that // No matching mapping found or found a non-matching mapping that
// matches at least what the matching mapping matched // matches at least what the matching mapping matched
keylen = 0; keylen = 0;
@@ -3219,82 +3217,99 @@ showmap (
ui_flush(); /* show one line at a time */ ui_flush(); /* show one line at a time */
} }
/* /// Check if a map exists that has given string in the rhs
* Return TRUE if a map exists that has "str" in the rhs for mode "modechars". ///
* Recognize termcap codes in "str". /// Also checks mappings local to the current buffer.
* Also checks mappings local to the current buffer. ///
*/ /// @param[in] str String which mapping must have in the rhs. Termcap codes
int map_to_exists(char_u *str, char_u *modechars, int abbr) /// are recognized in this argument.
/// @param[in] modechars Mode(s) in which mappings are checked.
/// @param[in] abbr true if checking abbreviations in place of mappings.
///
/// @return true if there is at least one mapping with given parameters.
bool map_to_exists(const char *const str, const char *const modechars,
const bool abbr)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{ {
int mode = 0; int mode = 0;
char_u *rhs;
char_u *buf;
int retval; int retval;
rhs = replace_termcodes(str, STRLEN(str), &buf, false, true, false, char_u *buf;
CPO_TO_CPO_FLAGS); char_u *const rhs = replace_termcodes((const char_u *)str, strlen(str), &buf,
false, true, false,
CPO_TO_CPO_FLAGS);
if (vim_strchr(modechars, 'n') != NULL) #define MAPMODE(mode, modechars, chr, modeflags) \
mode |= NORMAL; do { \
if (vim_strchr(modechars, 'v') != NULL) if (strchr(modechars, chr) != NULL) { \
mode |= VISUAL + SELECTMODE; mode |= modeflags; \
if (vim_strchr(modechars, 'x') != NULL) } \
mode |= VISUAL; } while (0)
if (vim_strchr(modechars, 's') != NULL) MAPMODE(mode, modechars, 'n', NORMAL);
mode |= SELECTMODE; MAPMODE(mode, modechars, 'v', VISUAL|SELECTMODE);
if (vim_strchr(modechars, 'o') != NULL) MAPMODE(mode, modechars, 'x', VISUAL);
mode |= OP_PENDING; MAPMODE(mode, modechars, 's', SELECTMODE);
if (vim_strchr(modechars, 'i') != NULL) MAPMODE(mode, modechars, 'o', OP_PENDING);
mode |= INSERT; MAPMODE(mode, modechars, 'i', INSERT);
if (vim_strchr(modechars, 'l') != NULL) MAPMODE(mode, modechars, 'l', LANGMAP);
mode |= LANGMAP; MAPMODE(mode, modechars, 'c', CMDLINE);
if (vim_strchr(modechars, 'c') != NULL) #undef MAPMODE
mode |= CMDLINE;
retval = map_to_exists_mode(rhs, mode, abbr); retval = map_to_exists_mode((const char *)rhs, mode, abbr);
xfree(buf); xfree(buf);
return retval; return retval;
} }
/* /// Check if a map exists that has given string in the rhs
* Return TRUE if a map exists that has "str" in the rhs for mode "mode". ///
* Also checks mappings local to the current buffer. /// Also checks mappings local to the current buffer.
*/ ///
int map_to_exists_mode(char_u *rhs, int mode, int abbr) /// @param[in] rhs String which mapping must have in the rhs. Termcap codes
/// are recognized in this argument.
/// @param[in] mode Mode(s) in which mappings are checked.
/// @param[in] abbr true if checking abbreviations in place of mappings.
///
/// @return true if there is at least one mapping with given parameters.
int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
{ {
mapblock_T *mp; mapblock_T *mp;
int hash; int hash;
int expand_buffer = FALSE; bool expand_buffer = false;
validate_maphash(); validate_maphash();
/* Do it twice: once for global maps and once for local maps. */ // Do it twice: once for global maps and once for local maps.
for (;; ) { for (;;) {
for (hash = 0; hash < 256; ++hash) { for (hash = 0; hash < 256; hash++) {
if (abbr) { if (abbr) {
if (hash > 0) /* there is only one abbr list */ if (hash > 0) { // There is only one abbr list.
break; break;
if (expand_buffer) }
if (expand_buffer) {
mp = curbuf->b_first_abbr; mp = curbuf->b_first_abbr;
else } else {
mp = first_abbr; mp = first_abbr;
} else if (expand_buffer) }
} else if (expand_buffer) {
mp = curbuf->b_maphash[hash]; mp = curbuf->b_maphash[hash];
else } else {
mp = maphash[hash]; mp = maphash[hash];
}
for (; mp; mp = mp->m_next) { for (; mp; mp = mp->m_next) {
if ((mp->m_mode & mode) if ((mp->m_mode & mode)
&& strstr((char *)mp->m_str, (char *)rhs) != NULL) && strstr((char *)mp->m_str, rhs) != NULL) {
return TRUE; return true;
}
} }
} }
if (expand_buffer) if (expand_buffer) {
break; break;
expand_buffer = TRUE; }
expand_buffer = true;
} }
return FALSE; return false;
} }
/* /*

21
src/nvim/gettext.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef NVIM_GETTEXT_H
#define NVIM_GETTEXT_H
#ifdef HAVE_WORKING_LIBINTL
# include <libintl.h>
# define _(x) gettext((char *)(x))
// XXX do we actually need this?
# ifdef gettext_noop
# define N_(x) gettext_noop(x)
# else
# define N_(x) x
# endif
#else
# define _(x) ((char *)(x))
# define N_(x) x
# define bindtextdomain(x, y) // empty
# define bind_textdomain_codeset(x, y) // empty
# define textdomain(x) // empty
#endif
#endif // NVIM_GETTEXT_H

View File

@@ -12,6 +12,7 @@
#include "nvim/syntax_defs.h" #include "nvim/syntax_defs.h"
#include "nvim/types.h" #include "nvim/types.h"
#include "nvim/event/loop.h" #include "nvim/event/loop.h"
#include "nvim/os/os_defs.h"
#define IOSIZE (1024+1) // file I/O and sprintf buffer size #define IOSIZE (1024+1) // file I/O and sprintf buffer size
@@ -21,16 +22,6 @@
# define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8 # define MSG_BUF_CLEN (MSG_BUF_LEN / 6) // cell length (worst case: utf-8
// takes 6 bytes for one cell) // takes 6 bytes for one cell)
// Maximum length of a file path. Make it a bit long, to stay
// on the safe side. But not too long to put on the stack.
#ifndef MAXPATHL
# ifdef MAXPATHLEN
# define MAXPATHL MAXPATHLEN
# else
# define MAXPATHL 256
# endif
#endif
#ifdef WIN32 #ifdef WIN32
# define _PATHSEPSTR "\\" # define _PATHSEPSTR "\\"
#else #else
@@ -473,6 +464,7 @@ typedef enum {
, HLF_CUL // 'cursurline' , HLF_CUL // 'cursurline'
, HLF_MC // 'colorcolumn' , HLF_MC // 'colorcolumn'
, HLF_QFL // selected quickfix line , HLF_QFL // selected quickfix line
, HLF_0 // Whitespace
, HLF_COUNT // MUST be the last one , HLF_COUNT // MUST be the last one
} hlf_T; } hlf_T;
@@ -481,7 +473,7 @@ typedef enum {
#define HL_FLAGS { '8', '~', 'z', 'Z', '@', 'd', 'e', 'i', 'l', 'm', 'M', 'n', \ #define HL_FLAGS { '8', '~', 'z', 'Z', '@', 'd', 'e', 'i', 'l', 'm', 'M', 'n', \
'N', 'r', 's', 'S', 'c', 't', 'v', 'V', 'w', 'W', 'f', 'F', \ 'N', 'r', 's', 'S', 'c', 't', 'v', 'V', 'w', 'W', 'f', 'F', \
'A', 'C', 'D', 'T', '-', '>', 'B', 'P', 'R', 'L', '+', '=', \ 'A', 'C', 'D', 'T', '-', '>', 'B', 'P', 'R', 'L', '+', '=', \
'x', 'X', '*', '#', '_', '!', '.', 'o', 'q' } 'x', 'X', '*', '#', '_', '!', '.', 'o', 'q', '0' }
EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */ EXTERN int highlight_attr[HLF_COUNT]; /* Highl. attr for each context. */
EXTERN int highlight_user[9]; /* User[1-9] attributes */ EXTERN int highlight_user[9]; /* User[1-9] attributes */
@@ -1208,6 +1200,7 @@ EXTERN char_u e_dirnotf[] INIT(= N_(
"E919: Directory not found in '%s': \"%s\"")); "E919: Directory not found in '%s': \"%s\""));
EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported")); EXTERN char_u e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long")); EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long"));
EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String"));
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM")); EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
@@ -1226,11 +1219,6 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
EXTERN int ignored; EXTERN int ignored;
EXTERN char *ignoredp; EXTERN char *ignoredp;
EXTERN bool in_free_unref_items INIT(= false);
// Used for checking if local variables or arguments used in a lambda.
EXTERN int *eval_lavars_used INIT(= NULL);
// If a msgpack-rpc channel should be started over stdin/stdout // If a msgpack-rpc channel should be started over stdin/stdout
EXTERN bool embedded_mode INIT(= false); EXTERN bool embedded_mode INIT(= false);
@@ -1255,7 +1243,7 @@ typedef enum {
kCdScopeInvalid = -1, kCdScopeInvalid = -1,
kCdScopeWindow, ///< Affects one window. kCdScopeWindow, ///< Affects one window.
kCdScopeTab, ///< Affects one tab page. kCdScopeTab, ///< Affects one tab page.
kCdScopeGlobal, ///< Affects the entire instance of Neovim. kCdScopeGlobal, ///< Affects the entire Nvim instance.
} CdScope; } CdScope;
#define MIN_CD_SCOPE kCdScopeWindow #define MIN_CD_SCOPE kCdScopeWindow

View File

@@ -369,7 +369,6 @@ static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec)
{ {
int colorindex; int colorindex;
uint32_t fg_color; uint32_t fg_color;
char *color;
pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL); pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, modec) != NULL);
pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL); pattr->italic = (highlight_has_attr(hl_id, HL_ITALIC, modec) != NULL);
@@ -377,11 +376,12 @@ static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec)
pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL); pattr->undercurl = (highlight_has_attr(hl_id, HL_UNDERCURL, modec) != NULL);
{ {
color = (char *)highlight_color(hl_id, (char_u *)"fg", modec); const char *color = highlight_color(hl_id, "fg", modec);
if (color == NULL) if (color == NULL) {
colorindex = 0; colorindex = 0;
else } else {
colorindex = atoi(color); colorindex = atoi(color);
}
if (colorindex >= 0 && colorindex < t_colors) if (colorindex >= 0 && colorindex < t_colors)
fg_color = prt_get_term_color(colorindex); fg_color = prt_get_term_color(colorindex);

View File

@@ -82,7 +82,7 @@ void hash_clear_all(hashtab_T *ht, unsigned int off)
/// used for that key. /// used for that key.
/// WARNING: Returned pointer becomes invalid as soon as the hash table /// WARNING: Returned pointer becomes invalid as soon as the hash table
/// is changed in any way. /// is changed in any way.
hashitem_T *hash_find(hashtab_T *ht, const char_u *key) hashitem_T *hash_find(const hashtab_T *const ht, const char_u *const key)
{ {
return hash_lookup(ht, (const char *)key, STRLEN(key), hash_hash(key)); return hash_lookup(ht, (const char *)key, STRLEN(key), hash_hash(key));
} }
@@ -99,7 +99,8 @@ hashitem_T *hash_find(hashtab_T *ht, const char_u *key)
/// ///
/// @warning Returned pointer becomes invalid as soon as the hash table /// @warning Returned pointer becomes invalid as soon as the hash table
/// is changed in any way. /// is changed in any way.
hashitem_T *hash_find_len(hashtab_T *ht, const char *key, const size_t len) hashitem_T *hash_find_len(const hashtab_T *const ht, const char *const key,
const size_t len)
{ {
return hash_lookup(ht, key, len, hash_hash_len(key, len)); return hash_lookup(ht, key, len, hash_hash_len(key, len));
} }
@@ -115,7 +116,7 @@ hashitem_T *hash_find_len(hashtab_T *ht, const char *key, const size_t len)
/// used for that key. /// used for that key.
/// WARNING: Returned pointer becomes invalid as soon as the hash table /// WARNING: Returned pointer becomes invalid as soon as the hash table
/// is changed in any way. /// is changed in any way.
hashitem_T *hash_lookup(hashtab_T *const ht, hashitem_T *hash_lookup(const hashtab_T *const ht,
const char *const key, const size_t key_len, const char *const key, const size_t key_len,
const hash_T hash) const hash_T hash)
{ {

View File

@@ -70,6 +70,25 @@ typedef struct hashtable_S {
hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array
} hashtab_T; } hashtab_T;
/// Iterate over a hashtab
///
/// @param[in] ht Hashtab to iterate over.
/// @param hi Name of the variable with current hashtab entry.
/// @param code Cycle body.
#define HASHTAB_ITER(ht, hi, code) \
do { \
hashtab_T *const hi##ht_ = (ht); \
size_t hi##todo_ = hi##ht_->ht_used; \
for (hashitem_T *hi = hi##ht_->ht_array; hi##todo_; hi++) { \
if (!HASHITEM_EMPTY(hi)) { \
{ \
code \
} \
hi##todo_--; \
} \
} \
} while (0)
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "hashtab.h.generated.h" # include "hashtab.h.generated.h"
#endif #endif

View File

@@ -140,31 +140,30 @@ char_u *get_cscope_name(expand_T *xp, int idx)
/* /*
* Handle command line completion for :cscope command. * Handle command line completion for :cscope command.
*/ */
void set_context_in_cscope_cmd(expand_T *xp, char_u *arg, cmdidx_T cmdidx) void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx)
{ {
char_u *p; // Default: expand subcommands.
/* Default: expand subcommands */
xp->xp_context = EXPAND_CSCOPE; xp->xp_context = EXPAND_CSCOPE;
xp->xp_pattern = arg; xp->xp_pattern = (char_u *)arg;
expand_what = (cmdidx == CMD_scscope) expand_what = ((cmdidx == CMD_scscope)
? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD; ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD);
/* (part of) subcommand already typed */ /* (part of) subcommand already typed */
if (*arg != NUL) { if (*arg != NUL) {
p = skiptowhite(arg); const char *p = (const char *)skiptowhite((const char_u *)arg);
if (*p != NUL) { /* past first word */ if (*p != NUL) { // Past first word.
xp->xp_pattern = skipwhite(p); xp->xp_pattern = skipwhite((const char_u *)p);
if (*skiptowhite(xp->xp_pattern) != NUL) if (*skiptowhite(xp->xp_pattern) != NUL) {
xp->xp_context = EXPAND_NOTHING; xp->xp_context = EXPAND_NOTHING;
else if (STRNICMP(arg, "add", p - arg) == 0) } else if (STRNICMP(arg, "add", p - arg) == 0) {
xp->xp_context = EXPAND_FILES; xp->xp_context = EXPAND_FILES;
else if (STRNICMP(arg, "kill", p - arg) == 0) } else if (STRNICMP(arg, "kill", p - arg) == 0) {
expand_what = EXP_CSCOPE_KILL; expand_what = EXP_CSCOPE_KILL;
else if (STRNICMP(arg, "find", p - arg) == 0) } else if (STRNICMP(arg, "find", p - arg) == 0) {
expand_what = EXP_CSCOPE_FIND; expand_what = EXP_CSCOPE_FIND;
else } else {
xp->xp_context = EXPAND_NOTHING; xp->xp_context = EXPAND_NOTHING;
}
} }
} }
} }

View File

@@ -174,7 +174,7 @@ static char_u *skip_string(char_u *p)
char_u *paren = vim_strchr(delim, '('); char_u *paren = vim_strchr(delim, '(');
if (paren != NULL) { if (paren != NULL) {
ptrdiff_t delim_len = paren - delim; const ptrdiff_t delim_len = paren - delim;
for (p += 3; *p; ++p) for (p += 3; *p; ++p)
if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0 if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0

View File

@@ -94,7 +94,7 @@
do { \ do { \
if (*p_langmap \ if (*p_langmap \
&& (condition) \ && (condition) \
&& (!p_lnr || (p_lnr && typebuf_maplen() == 0)) \ && (p_lrm || (!p_lrm && KeyTyped)) \
&& !KeyStuffed \ && !KeyStuffed \
&& (c) >= 0) \ && (c) >= 0) \
{ \ { \

View File

@@ -283,7 +283,7 @@ int main(int argc, char **argv)
cmdline_row = (int)(Rows - p_ch); cmdline_row = (int)(Rows - p_ch);
msg_row = cmdline_row; msg_row = cmdline_row;
screenalloc(false); /* allocate screen buffers */ screenalloc(false); /* allocate screen buffers */
set_init_2(); set_init_2(params.headless);
TIME_MSG("inits 2"); TIME_MSG("inits 2");
msg_scroll = TRUE; msg_scroll = TRUE;
@@ -391,9 +391,10 @@ int main(int argc, char **argv)
shada_read_everything(NULL, false, true); shada_read_everything(NULL, false, true);
TIME_MSG("reading ShaDa"); TIME_MSG("reading ShaDa");
} }
/* It's better to make v:oldfiles an empty list than NULL. */ // It's better to make v:oldfiles an empty list than NULL.
if (get_vim_var_list(VV_OLDFILES) == NULL) if (get_vim_var_list(VV_OLDFILES) == NULL) {
set_vim_var_list(VV_OLDFILES, list_alloc()); set_vim_var_list(VV_OLDFILES, tv_list_alloc());
}
/* /*
* "-q errorfile": Load the error file now. * "-q errorfile": Load the error file now.
@@ -802,17 +803,18 @@ static void command_line_scan(mparm_T *parmp)
argv_idx = -1; /* skip to next argument */ argv_idx = -1; /* skip to next argument */
break; break;
case 'A': /* "-A" start in Arabic mode */ case 'A': { // "-A" start in Arabic mode.
set_option_value((char_u *)"arabic", 1L, NULL, 0); set_option_value("arabic", 1L, NULL, 0);
break; break;
}
case 'b': /* "-b" binary mode */ case 'b': { // "-b" binary mode.
/* Needs to be effective before expanding file names, because // Needs to be effective before expanding file names, because
* for Win32 this makes us edit a shortcut file itself, // for Win32 this makes us edit a shortcut file itself,
* instead of the file it links to. */ // instead of the file it links to.
set_options_bin(curbuf->b_p_bin, 1, 0); set_options_bin(curbuf->b_p_bin, 1, 0);
curbuf->b_p_bin = 1; /* binary file I/O */ curbuf->b_p_bin = 1; // Binary file I/O.
break; break;
}
case 'e': /* "-e" Ex mode */ case 'e': /* "-e" Ex mode */
exmode_active = EXMODE_NORMAL; exmode_active = EXMODE_NORMAL;
@@ -829,24 +831,27 @@ static void command_line_scan(mparm_T *parmp)
main_start_gui(); main_start_gui();
break; break;
case 'F': /* "-F" start in Farsi mode: rl + fkmap set */ case 'F': { // "-F" start in Farsi mode: rl + fkmap set.
p_fkmap = TRUE; p_fkmap = true;
set_option_value((char_u *)"rl", 1L, NULL, 0); set_option_value("rl", 1L, NULL, 0);
break; break;
}
case 'h': /* "-h" give help message */ case 'h': /* "-h" give help message */
usage(); usage();
mch_exit(0); mch_exit(0);
case 'H': /* "-H" start in Hebrew mode: rl + hkmap set */ case 'H': { // "-H" start in Hebrew mode: rl + hkmap set.
p_hkmap = TRUE; p_hkmap = true;
set_option_value((char_u *)"rl", 1L, NULL, 0); set_option_value("rl", 1L, NULL, 0);
break; break;
}
case 'l': /* "-l" lisp mode, 'lisp' and 'showmatch' on */ case 'l': { // "-l" lisp mode, 'lisp' and 'showmatch' on.
set_option_value((char_u *)"lisp", 1L, NULL, 0); set_option_value("lisp", 1L, NULL, 0);
p_sm = TRUE; p_sm = true;
break; break;
}
case 'M': /* "-M" no changes or writing of files */ case 'M': /* "-M" no changes or writing of files */
reset_modifiable(); reset_modifiable();
@@ -945,8 +950,7 @@ static void command_line_scan(mparm_T *parmp)
/* default is 10: a little bit verbose */ /* default is 10: a little bit verbose */
p_verbose = get_number_arg(argv[0], &argv_idx, 10); p_verbose = get_number_arg(argv[0], &argv_idx, 10);
if (argv[0][argv_idx] != NUL) { if (argv[0][argv_idx] != NUL) {
set_option_value((char_u *)"verbosefile", 0L, set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0);
(char_u *)argv[0] + argv_idx, 0);
argv_idx = (int)STRLEN(argv[0]); argv_idx = (int)STRLEN(argv[0]);
} }
break; break;
@@ -955,7 +959,7 @@ static void command_line_scan(mparm_T *parmp)
/* "-w {scriptout}" write to script */ /* "-w {scriptout}" write to script */
if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) { if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) {
n = get_number_arg(argv[0], &argv_idx, 10); n = get_number_arg(argv[0], &argv_idx, 10);
set_option_value((char_u *)"window", n, NULL, 0); set_option_value("window", n, NULL, 0);
break; break;
} }
want_argument = TRUE; want_argument = TRUE;
@@ -1087,7 +1091,7 @@ scripterror:
if (ascii_isdigit(*((char_u *)argv[0]))) { if (ascii_isdigit(*((char_u *)argv[0]))) {
argv_idx = 0; argv_idx = 0;
n = get_number_arg(argv[0], &argv_idx, 10); n = get_number_arg(argv[0], &argv_idx, 10);
set_option_value((char_u *)"window", n, NULL, 0); set_option_value("window", n, NULL, 0);
argv_idx = -1; argv_idx = -1;
break; break;
} }

View File

@@ -62,7 +62,7 @@ int setmark(int c)
/// Free fmark_T item /// Free fmark_T item
void free_fmark(fmark_T fm) void free_fmark(fmark_T fm)
{ {
dict_unref(fm.additional_data); tv_dict_unref(fm.additional_data);
} }
/// Free xfmark_T item /// Free xfmark_T item
@@ -1431,3 +1431,26 @@ void free_all_marks(void)
memset(&namedfm[0], 0, sizeof(namedfm)); memset(&namedfm[0], 0, sizeof(namedfm));
} }
#endif #endif
/// Adjust position to point to the first byte of a multi-byte character
///
/// If it points to a tail byte it is move backwards to the head byte.
///
/// @param[in] buf Buffer to adjust position in.
/// @param[out] lp Position to adjust.
void mark_mb_adjustpos(buf_T *buf, pos_T *lp)
FUNC_ATTR_NONNULL_ALL
{
if (lp->col > 0 || lp->coladd > 1) {
const char_u *const p = ml_get_buf(buf, lp->lnum, false);
lp->col -= (*mb_head_off)(p, p + lp->col);
// Reset "coladd" when the cursor would be on the right half of a
// double-wide character.
if (lp->coladd == 1
&& p[lp->col] != TAB
&& vim_isprintc((*mb_ptr2char)(p + lp->col))
&& ptr2cells(p + lp->col) > 1) {
lp->coladd = 0;
}
}
}

View File

@@ -29,7 +29,7 @@
/// Clear given fmark /// Clear given fmark
#define CLEAR_FMARK(fmarkp_) \ #define CLEAR_FMARK(fmarkp_) \
RESET_FMARK(fmarkp_, ((pos_T) {0, 0, 0}), 0) RESET_FMARK(fmarkp_, ((pos_T) { 0, 0, 0 }), 0)
/// Set given extended mark (regular mark + file name) /// Set given extended mark (regular mark + file name)
#define SET_XFMARK(xfmarkp_, mark_, fnum_, fname_) \ #define SET_XFMARK(xfmarkp_, mark_, fnum_, fname_) \

View File

@@ -3,7 +3,7 @@
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/os/time.h" #include "nvim/os/time.h"
#include "nvim/eval_defs.h" #include "nvim/eval/typval.h"
/* /*
* marks: positions in a file * marks: positions in a file

View File

@@ -50,6 +50,7 @@
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/os/os.h" #include "nvim/os/os.h"
#include "nvim/arabic.h" #include "nvim/arabic.h"
#include "nvim/mark.h"
typedef struct { typedef struct {
int rangeStart; int rangeStart;
@@ -375,16 +376,18 @@ void remove_bom(char_u *s)
*/ */
int mb_get_class(const char_u *p) int mb_get_class(const char_u *p)
{ {
return mb_get_class_buf(p, curbuf); return mb_get_class_tab(p, curbuf->b_chartab);
} }
int mb_get_class_buf(const char_u *p, buf_T *buf) int mb_get_class_tab(const char_u *p, const uint64_t *const chartab)
{ {
if (MB_BYTE2LEN(p[0]) == 1) { if (MB_BYTE2LEN(p[0]) == 1) {
if (p[0] == NUL || ascii_iswhite(p[0])) if (p[0] == NUL || ascii_iswhite(p[0])) {
return 0; return 0;
if (vim_iswordc_buf(p[0], buf)) }
if (vim_iswordc_tab(p[0], chartab)) {
return 2; return 2;
}
return 1; return 1;
} }
return utf_class(utf_ptr2char(p)); return utf_class(utf_ptr2char(p));
@@ -580,7 +583,7 @@ int utf_ptr2char(const char_u *p)
* If byte sequence is illegal or incomplete, returns -1 and does not advance * If byte sequence is illegal or incomplete, returns -1 and does not advance
* "s". * "s".
*/ */
static int utf_safe_read_char_adv(char_u **s, size_t *n) static int utf_safe_read_char_adv(const char_u **s, size_t *n)
{ {
int c; int c;
@@ -622,7 +625,7 @@ static int utf_safe_read_char_adv(char_u **s, size_t *n)
* Get character at **pp and advance *pp to the next character. * Get character at **pp and advance *pp to the next character.
* Note: composing characters are skipped! * Note: composing characters are skipped!
*/ */
int mb_ptr2char_adv(char_u **pp) int mb_ptr2char_adv(const char_u **const pp)
{ {
int c; int c;
@@ -635,7 +638,7 @@ int mb_ptr2char_adv(char_u **pp)
* Get character at **pp and advance *pp to the next character. * Get character at **pp and advance *pp to the next character.
* Note: composing characters are returned as separate characters. * Note: composing characters are returned as separate characters.
*/ */
int mb_cptr2char_adv(char_u **pp) int mb_cptr2char_adv(const char_u **pp)
{ {
int c; int c;
@@ -1230,7 +1233,8 @@ bool utf_isupper(int a)
return utf_tolower(a) != a; return utf_tolower(a) != a;
} }
static int utf_strnicmp(char_u *s1, char_u *s2, size_t n1, size_t n2) static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
size_t n2)
{ {
int c1, c2, cdiff; int c1, c2, cdiff;
char_u buffer[6]; char_u buffer[6];
@@ -1300,6 +1304,7 @@ static int utf_strnicmp(char_u *s1, char_u *s2, size_t n1, size_t n2)
# define CP_UTF8 65001 /* magic number from winnls.h */ # define CP_UTF8 65001 /* magic number from winnls.h */
#endif #endif
/// Reassigns `strw` to a new, allocated pointer to a UTF16 string.
int utf8_to_utf16(const char *str, WCHAR **strw) int utf8_to_utf16(const char *str, WCHAR **strw)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
@@ -1341,40 +1346,40 @@ int utf8_to_utf16(const char *str, WCHAR **strw)
return 0; return 0;
} }
/// Reassigns `str` to a new, allocated pointer to a UTF8 string.
int utf16_to_utf8(const WCHAR *strw, char **str) int utf16_to_utf8(const WCHAR *strw, char **str)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_ALL
{ {
// Compute the space required to store the string as UTF-8. // Compute the space required to store the string as UTF-8.
ssize_t utf8_len = WideCharToMultiByte(CP_UTF8, DWORD utf8_len = WideCharToMultiByte(CP_UTF8,
0, 0,
strw, strw,
-1, -1,
NULL, NULL,
0, 0,
NULL, NULL,
NULL); NULL);
if (utf8_len == 0) { if (utf8_len == 0) {
return GetLastError(); return GetLastError();
} }
ssize_t buf_sz = utf8_len * sizeof(char); *str = xmalloc(utf8_len);
char *buf = xmalloc(buf_sz);
char *pos = buf;
// Convert string to UTF-8. // Convert to UTF-8.
int r = WideCharToMultiByte(CP_UTF8, utf8_len = WideCharToMultiByte(CP_UTF8,
0, 0,
strw, strw,
-1, -1,
pos, *str,
utf8_len, utf8_len,
NULL, NULL,
NULL); NULL);
assert(r == utf8_len); if (utf8_len == 0) {
if (r != utf8_len) { free(*str);
EMSG2("WideCharToMultiByte failed: %d", r); *str = NULL;
return GetLastError();
} }
*str = pos; (*str)[utf8_len] = '\0';
return 0; return 0;
} }
@@ -1389,19 +1394,26 @@ int utf16_to_utf8(const WCHAR *strw, char **str)
* Returns zero if s1 and s2 are equal (ignoring case), the difference between * Returns zero if s1 and s2 are equal (ignoring case), the difference between
* two characters otherwise. * two characters otherwise.
*/ */
int mb_strnicmp(char_u *s1, char_u *s2, size_t nn) int mb_strnicmp(const char_u *s1, const char_u *s2, const size_t nn)
{ {
return utf_strnicmp(s1, s2, nn, nn); return utf_strnicmp(s1, s2, nn, nn);
} }
/* We need to call mb_stricmp() even when we aren't dealing with a multi-byte /// Compare strings case-insensitively
* encoding because mb_stricmp() takes care of all ascii and non-ascii ///
* encodings, including characters with umlauts in latin1, etc., while /// @note We need to call mb_stricmp() even when we aren't dealing with
* STRICMP() only handles the system locale version, which often does not /// a multi-byte encoding because mb_stricmp() takes care of all ASCII and
* handle non-ascii properly. */ /// non-ascii encodings, including characters with umlauts in latin1,
int mb_stricmp(char_u *s1, char_u *s2) /// etc., while STRICMP() only handles the system locale version, which
/// often does not handle non-ascii properly.
///
/// @param[in] s1 First string to compare, not more then #MAXCOL characters.
/// @param[in] s2 Second string to compare, not more then #MAXCOL characters.
///
/// @return 0 if strings are equal, <0 if s1 < s2, >0 if s1 > s2.
int mb_stricmp(const char *s1, const char *s2)
{ {
return mb_strnicmp(s1, s2, MAXCOL); return mb_strnicmp((const char_u *)s1, (const char_u *)s2, MAXCOL);
} }
/* /*
@@ -1639,38 +1651,16 @@ theend:
*/ */
void mb_adjust_cursor(void) void mb_adjust_cursor(void)
{ {
mb_adjustpos(curbuf, &curwin->w_cursor); mark_mb_adjustpos(curbuf, &curwin->w_cursor);
}
/*
* Adjust position "*lp" to point to the first byte of a multi-byte character.
* If it points to a tail byte it's moved backwards to the head byte.
*/
void mb_adjustpos(buf_T *buf, pos_T *lp)
{
char_u *p;
if (lp->col > 0
|| lp->coladd > 1
) {
p = ml_get_buf(buf, lp->lnum, FALSE);
lp->col -= (*mb_head_off)(p, p + lp->col);
/* Reset "coladd" when the cursor would be on the right half of a
* double-wide character. */
if (lp->coladd == 1
&& p[lp->col] != TAB
&& vim_isprintc((*mb_ptr2char)(p + lp->col))
&& ptr2cells(p + lp->col) > 1)
lp->coladd = 0;
}
} }
/// Checks and adjusts cursor column. Not mode-dependent. /// Checks and adjusts cursor column. Not mode-dependent.
/// @see check_cursor_col_win /// @see check_cursor_col_win
/// ///
/// @param win Places cursor on a valid column for this window. /// @param win_ Places cursor on a valid column for this window.
void mb_check_adjust_col(win_T *win) void mb_check_adjust_col(void *win_)
{ {
win_T *win = (win_T *)win_;
colnr_T oldcol = win->w_cursor.col; colnr_T oldcol = win->w_cursor.col;
// Column 0 is always valid. // Column 0 is always valid.
@@ -2039,8 +2029,8 @@ void * my_iconv_open(char_u *to, char_u *from)
* Returns the converted string in allocated memory. NULL for an error. * Returns the converted string in allocated memory. NULL for an error.
* If resultlenp is not NULL, sets it to the result length in bytes. * If resultlenp is not NULL, sets it to the result length in bytes.
*/ */
static char_u * iconv_string(vimconv_T *vcp, char_u *str, size_t slen, static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
size_t *unconvlenp, size_t *resultlenp) size_t slen, size_t *unconvlenp, size_t *resultlenp)
{ {
const char *from; const char *from;
size_t fromlen; size_t fromlen;
@@ -2325,7 +2315,7 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
* Illegal chars are often changed to "?", unless vcp->vc_fail is set. * Illegal chars are often changed to "?", unless vcp->vc_fail is set.
* When something goes wrong, NULL is returned and "*lenp" is unchanged. * When something goes wrong, NULL is returned and "*lenp" is unchanged.
*/ */
char_u * string_convert(vimconv_T *vcp, char_u *ptr, size_t *lenp) char_u *string_convert(const vimconv_T *const vcp, char_u *ptr, size_t *lenp)
{ {
return string_convert_ext(vcp, ptr, lenp, NULL); return string_convert_ext(vcp, ptr, lenp, NULL);
} }
@@ -2335,7 +2325,7 @@ char_u * string_convert(vimconv_T *vcp, char_u *ptr, size_t *lenp)
* an incomplete sequence at the end it is not converted and "*unconvlenp" is * an incomplete sequence at the end it is not converted and "*unconvlenp" is
* set to the number of remaining bytes. * set to the number of remaining bytes.
*/ */
char_u * string_convert_ext(vimconv_T *vcp, char_u *ptr, char_u * string_convert_ext(const vimconv_T *const vcp, char_u *ptr,
size_t *lenp, size_t *unconvlenp) size_t *lenp, size_t *unconvlenp)
{ {
char_u *retval = NULL; char_u *retval = NULL;

View File

@@ -2,6 +2,11 @@
#define NVIM_MBYTE_H #define NVIM_MBYTE_H
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include "nvim/iconv.h"
#include "nvim/func_attr.h"
#include "nvim/os/os_defs.h" // For WCHAR, indirect
/* /*
* Return byte length of character that starts with byte "b". * Return byte length of character that starts with byte "b".
@@ -40,7 +45,41 @@
#define mb_ptr2char utf_ptr2char #define mb_ptr2char utf_ptr2char
#define mb_head_off utf_head_off #define mb_head_off utf_head_off
/// Flags for vimconv_T
typedef enum {
CONV_NONE = 0,
CONV_TO_UTF8 = 1,
CONV_9_TO_UTF8 = 2,
CONV_TO_LATIN1 = 3,
CONV_TO_LATIN9 = 4,
CONV_ICONV = 5,
} ConvFlags;
/// Structure used for string conversions
typedef struct {
int vc_type; ///< Zero or more ConvFlags.
int vc_factor; ///< Maximal expansion factor.
# ifdef USE_ICONV
iconv_t vc_fd; ///< Value for CONV_ICONV.
# endif
bool vc_fail; ///< What to do with invalid characters: if true, fail,
///< otherwise use '?'.
} vimconv_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mbyte.h.generated.h" # include "mbyte.h.generated.h"
#endif #endif
static inline int mb_strcmp_ic(bool ic, const char *s1, const char *s2)
REAL_FATTR_NONNULL_ALL REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
/// Compare strings
///
/// @param[in] ic True if case is to be ignored.
///
/// @return 0 if s1 == s2, <0 if s1 < s2, >0 if s1 > s2.
static inline int mb_strcmp_ic(bool ic, const char *s1, const char *s2)
{
return (ic ? mb_stricmp(s1, s2) : strcmp(s1, s2));
}
#endif // NVIM_MBYTE_H #endif // NVIM_MBYTE_H

View File

@@ -992,7 +992,7 @@ void ml_recover(void)
if (b0_ff != 0) if (b0_ff != 0)
set_fileformat(b0_ff - 1, OPT_LOCAL); set_fileformat(b0_ff - 1, OPT_LOCAL);
if (b0_fenc != NULL) { if (b0_fenc != NULL) {
set_option_value((char_u *)"fenc", 0L, b0_fenc, OPT_LOCAL); set_option_value("fenc", 0L, (char *)b0_fenc, OPT_LOCAL);
xfree(b0_fenc); xfree(b0_fenc);
} }
unchanged(curbuf, TRUE); unchanged(curbuf, TRUE);

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