Merge branch 'master' into luaviml'/lua

This commit is contained in:
ZyX 2017-04-08 01:54:58 +03:00
commit 043d8ff9f2
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'
/test/.luacheckcache
# luarocks, not added as a subtree because of the large number of blobs
/third-party/luarocks
# local make targets
local.mk
@ -49,6 +46,3 @@ local.mk
/runtime/doc/*.html
/runtime/doc/tags.ref
/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
- MAKE_CMD="make -j2"
# 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_DIR="$TRAVIS_BUILD_DIR/build"
# Build directory for third-party dependencies.
@ -50,6 +50,7 @@ env:
- SUCCESS_MARKER="$BUILD_DIR/.tests_successful"
# default target name for functional tests
- FUNCTIONALTEST=functionaltest
- CI_TARGET=tests
matrix:
include:
@ -68,12 +69,12 @@ matrix:
compiler: gcc-5 -m32
env: BUILD_32BIT=ON
- os: linux
compiler: clang-3.8
compiler: clang-3.9
env: >
CLANG_SANITIZER=ASAN_UBSAN
CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUAJIT=false"
- os: linux
compiler: clang-3.8
compiler: clang-3.9
env: CLANG_SANITIZER=TSAN
- os: osx
compiler: clang
@ -85,24 +86,24 @@ matrix:
- env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
fast_finish: true
before_install: .ci/before_install.sh
install: .ci/install.sh
before_script: .ci/before_script.sh
script: .ci/script.sh
before_cache: .ci/before_cache.sh
after_success: .ci/after_success.sh
before_install: ci/before_install.sh
install: ci/install.sh
before_script: ci/before_script.sh
script: ci/script.sh
before_cache: ci/before_cache.sh
after_success: ci/after_success.sh
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.8
- llvm-toolchain-trusty-3.9
packages:
- autoconf
- automake
- apport
- build-essential
- clang-3.8
- clang-3.9
- cmake
- cscope
- g++-5-multilib
@ -112,7 +113,7 @@ addons:
- gdb
- libc6-dev-i386
- libtool
- llvm-3.8-dev
- llvm-3.9-dev
- pkg-config
- unzip
- valgrind

View File

@ -318,6 +318,21 @@ if(NOT PREFER_LUAJIT)
find_package(Lua REQUIRED)
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)
option(FEAT_TUI "Enable the Terminal UI" ON)
else()

View File

@ -126,12 +126,15 @@ distclean: clean
install: | nvim
+$(BUILD_CMD) -C build install
clint:
$(CMAKE_PRG) -DLINT_PRG=./src/clint.py \
-DLINT_DIR=src \
-DLINT_SUPPRESS_URL="$(DOC_DOWNLOAD_URL_BASE)$(CLINT_ERRORS_FILE_PATH)" \
-P cmake/RunLint.cmake
clint: build/.ran-cmake
+$(BUILD_CMD) -C build clint
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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,11 @@
top_make() {
${MAKE_CMD} "$@"
}
build_make() {
top_make -C "${BUILD_DIR}" "$@"
}
build_deps() {
if [[ "${BUILD_32BIT}" == ON ]]; then
DEPS_CMAKE_FLAGS="${DEPS_CMAKE_FLAGS} ${CMAKE_FLAGS_32BIT}"
@ -31,7 +39,7 @@ build_deps() {
echo "Configuring with '${DEPS_CMAKE_FLAGS}'."
CC= cmake ${DEPS_CMAKE_FLAGS} "${TRAVIS_BUILD_DIR}/third-party/"
if ! ${MAKE_CMD}; then
if ! top_make; then
exit 1
fi
@ -54,18 +62,18 @@ prepare_build() {
build_nvim() {
echo "Building nvim."
if ! ${MAKE_CMD} nvim; then
if ! top_make nvim; then
exit 1
fi
if [ "$CLANG_SANITIZER" != "TSAN" ]; then
echo "Building libnvim."
if ! ${MAKE_CMD} libnvim; then
if ! top_make libnvim; then
exit 1
fi
echo "Building nvim-test."
if ! ${MAKE_CMD} nvim-test; then
if ! top_make nvim-test; then
exit 1
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() {
local app="$1"
local core="$2"
@ -75,7 +77,7 @@ asan_check() {
run_unittests() {
ulimit -c unlimited
if ! ${MAKE_CMD} -C "${BUILD_DIR}" unittest ; then
if ! build_make unittest ; then
check_core_dumps "$(which luajit)"
exit 1
fi
@ -84,7 +86,7 @@ run_unittests() {
run_functionaltests() {
ulimit -c unlimited
if ! ${MAKE_CMD} -C "${BUILD_DIR}" ${FUNCTIONALTEST}; then
if ! build_make ${FUNCTIONALTEST}; then
asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}"
check_core_dumps
@ -110,7 +112,7 @@ run_oldtests() {
}
install_nvim() {
${MAKE_CMD} -C "${BUILD_DIR}" install
build_make install
"${INSTALL_PREFIX}/bin/nvim" --version
"${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' || {

View File

@ -3,7 +3,7 @@
set -e
set -o pipefail
if [[ -n "${CI_TARGET}" ]]; then
if [[ "${CI_TARGET}" == lint ]]; then
exit
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)"
source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/test.sh"
source "${CI_DIR}/common/suite.sh"
set -x
enter_suite tests
check_core_dumps --delete quiet
@ -15,11 +20,15 @@ build_nvim
if [ "$CLANG_SANITIZER" != "TSAN" ]; then
# Additional threads are only created when the builtin UI starts, which
# doesn't happen in the unit/functional tests
run_unittests
run_functionaltests
run_test run_unittests
run_test run_functionaltests
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 -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
# as $USER, while retaining the environment variables defined and belonging
# to secondary groups given above in usermod.
if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
sudo -E su "${USER}" -c ".ci/run_tests.sh"
sudo -E su "${USER}" -c "ci/run_${CI_TARGET}.sh"
else
.ci/run_tests.sh
ci/run_${CI_TARGET}.sh
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}")
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})
execute_process(
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_RECURSE ${WORKING_DIR}/Xtest_xdg)
file(REMOVE_RECURSE ${WORKING_DIR}/Xtest-tmpdir)
if(NOT res EQUAL 0)
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
.Ic :terminal
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
.Sh FILES
.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')
endfunction
" Convert '\' to '/'. Collapse '//' and '/./'.
function! s:normalize_path(s) abort
return substitute(substitute(a:s, '\', '/', 'g'), '/\./\|/\+', '/', 'g')
endfunction
" Simple version comparison.
function! s:version_cmp(a, b) abort
let a = split(a:a, '\.', 0)
@ -208,7 +213,7 @@ endfunction
" Check the Python interpreter's usability.
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))
return 0
elseif executable(a:bin) != 1
@ -287,8 +292,9 @@ function! s:check_python(version) abort
if exists('$PATH')
for path in split($PATH, has('win32') ? ';' : ':')
let path_bin = path.'/'.pyname
if path_bin != python_bin && index(python_multiple, path_bin) == -1
let path_bin = s:normalize_path(path.'/'.pyname)
if path_bin != s:normalize_path(python_bin)
\ && index(python_multiple, path_bin) == -1
\ && executable(path_bin)
call add(python_multiple, path_bin)
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
probably runs as the original user.
Directory for temporary files is created in the first suitable directory of:
For Unix: $TMPDIR, /tmp, current-dir, $HOME.
For MS-Windows: $TMP, $TEMP, $USERPROFILE, current-dir.
Unix: $TMPDIR, /tmp, current-dir, $HOME.
Windows: $TMPDIR, $TMP, $TEMP, $USERPROFILE, current-dir.

View File

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

View File

@ -3999,6 +3999,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
augroup autocmd groups
buffer buffer names
behave :behave suboptions
cmdline |cmdline-completion|
color color schemes
command Ex command (and arguments)
compiler compilers
@ -4027,7 +4028,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
user user names
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
|wildcards| for the use of special characters in {pat}.
@ -7918,6 +7919,12 @@ writefile({list}, {fname} [, {flags}])
appended to the file: >
:call writefile(["foo"], "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.
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
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[os]
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}
Set the window height to {width} by {height} characters.
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*

View File

@ -181,11 +181,6 @@ vim.eval(str) *python-eval*
# string.atoi() to convert to
# 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*
Like |python-eval|, but returns special objects described in
|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*
Nvim allows Graphical user interfaces to be implemented by separate processes
communicating with Nvim over the RPC API. Currently the ui model conists of a
terminal-like grid with one single, monospace font size, with a few elements
that could be drawn separately from the grid (for the momemnt only the popup
menu)
GUIs can be implemented as external processes communicating with Nvim over the
RPC API. Currently the UI model consists of a terminal-like grid with one
single, monospace font size. Some elements (UI "widgets") can be drawn
separately from the grid.
After connecting to a nvim instance (typically a spawned, embedded instance)
use the |nvim_ui_attach|(width, height, options) API method to tell nvim that your
program wants to draw the nvim screen on a grid with "width" times
"height" cells. "options" should be a dictionary with the following (all
optional) keys:
`rgb`: Controls what color format to use.
After connecting to Nvim (usually a spawned, embedded instance) use the
|nvim_ui_attach| API method to tell Nvim that your program wants to draw the
Nvim screen on a grid of width × height cells. `options` must be
a dictionary with these (optional) keys:
`rgb` Controls what color format to use.
Set to true (default) to use 24-bit rgb
colors.
Set to false to use terminal color codes (at
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 ui and let it draw the popupmenu.
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
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*
@ -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
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' boolean (default off)
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,
r-cr:hor20-Cursor/lCursor,
sm:block-Cursor
-blinkwait175-blinkoff150-blinkon175",
for Windows console:
"n-v-c:block,o:hor50,i-ci:hor15,
r-cr:hor30,sm:block")
-blinkwait175-blinkoff150-blinkon175")
global
{only available when compiled with GUI enabled, and
for Windows console}
This option tells Vim what the cursor should look like in different
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
specifying a block cursor, or a percentage for a vertical or
horizontal cursor.
For a console the 't_SI' and 't_EI' escape sequences are used.
The option is a comma separated list of parts. Each part consist of a
Configures the cursor style for each mode. Works in the GUI and some
terminals. Unset to disable: >
:set guicursor=
<
With tmux you might need this in ~/.tmux.conf (see terminal-overrides
in the tmux(1) manual page): >
set -ga terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[2 q'
<
The option is a comma separated list of parts. Each part consists of a
mode-list and an argument-list:
mode-list:argument-list,mode-list:argument-list,..
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'.
*'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' string (default "egmrLT" (MS-Windows))
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!".
*'highlight'* *'hl'*
'highlight' 'hl' string (default (as a single string):
"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")
'highlight' 'hl' string (default: string of "c:group,..." pairs)
global
This option can be used to set highlighting mode for various
occasions. It is a comma separated list of character pairs. The
first character in a pair gives the occasion, the second the mode to
use for that occasion. The occasions are:
|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-TermCursorNC| Z Cursor in an unfocused terminal
|hl-TermCursorNC| Z Cursor in an unfocused terminal
|hl-NonText| @ '@' at the end of the window and
characters from 'showbreak'
|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-LineNr| n line number for ":number" and ":#" commands, and
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.
|hl-Question| r |hit-enter| prompt and yes/no questions
|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-VertSplit| c column used to separate vertically split windows
|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-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:
r reverse (termcap entry "mr" and "me")
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
< Warning: This deletes all menus that you defined yourself!
*'langnoremap'* *'lnr'*
'langnoremap' 'lnr' boolean (default on)
*'langremap'* *'lrm'* *'nolangremap'* *'nolrm'*
'langremap' 'lrm' boolean (default off)
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
sure this option is set.
sure this option is off.
*'laststatus'* *'ls'*
'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: >
:set lines=999
< 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' 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:>-,eol:<,nbsp:%
:set lcs=extends:>,precedes:<
< The "NonText" highlighting will be used for "eol", "extends" and
"precedes". "SpecialKey" for "nbsp", "space", "tab" and "trail".
|hl-NonText| |hl-SpecialKey|
< |hl-NonText| highlighting will be used for "eol", "extends" and
"precedes". |hl-Whitespace| for "nbsp", "space", "tab" and "trail".
*'lpl'* *'nolpl'* *'loadplugins'* *'noloadplugins'*
'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
'guifontset' 'gfs' GUI: Names of multi-byte fonts to be used
'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
'guitablabel' 'gtl' GUI: custom label 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*
Question |hit-enter| prompt and yes/no questions
*hl-QuickFixLine*
QuickFixLine The selected |quickfix| item in the quickfix window.
|hl-CursorLine| is combined with this when the cursor is on
the currently selected quickfix item.
QuickFixLine Current |quickfix| item in the quickfix window. Combined with
|hl-CursorLine| when the cursor is there.
*hl-Search*
Search Last search pattern highlighting (see 'hlsearch').
Also used for highlighting the current line in the quickfix
window and similar items that need to stand out.
Also used for similar items that need to stand out.
*hl-SpecialKey*
SpecialKey Meta and special keys listed with ":map", also for text used
to show unprintable characters in the text, 'listchars'.
Generally: text that is displayed differently from what it
really is.
SpecialKey Unprintable characters: text displayed differently from what
it really is. But not 'listchars' whitespace. |hl-Whitespace|
*hl-SpellBad*
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*
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*
SpellLocal Word that is recognized by the spellchecker as one that is
used in another region. |spell|
This will be combined with the highlighting used otherwise.
Combined with the highlighting used otherwise.
*hl-SpellRare*
SpellRare Word that is recognized by the spellchecker as one that is
hardly ever used. |spell|
This will be combined with the highlighting used otherwise.
Combined with the highlighting used otherwise.
*hl-StatusLine*
StatusLine status line of current window
*hl-StatusLineNC*
@ -4943,6 +4939,8 @@ Title titles for output from ":set all", ":autocmd" etc.
Visual Visual mode selection
*hl-WarningMsg*
WarningMsg warning messages
*hl-Whitespace*
Whitespace "nbsp", "space", "tab" and "trail" in 'listchars'
*hl-WildMenu*
WildMenu current match in 'wildmenu' completion

View File

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

View File

@ -589,8 +589,6 @@ if has("gui")
call append("$", "toolbariconsize\tsize of toolbar icons")
call <SID>OptionG("tbis", &tbis)
endif
call append("$", "guiheadroom\troom (in pixels) left above/below the window")
call append("$", " \tset ghr=" . &ghr)
endif
if has("browse")
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
let dest = fnamemodify(expand(dest), ':p')
if !empty(dest) && !filereadable(dest)
if !empty(dest)
let dest .= ('/' ==# dest[-1:] ? '' : '/') . 'nvim'
call mkdir(dest, 'p', 0700)
if !isdirectory(dest)
call mkdir(dest, 'p', 0700)
endif
let manifest_base = dest
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() {
if [[ -n "${vim_tag}" ]]; then
local patch_number="${vim_tag:5}" # Remove prefix like "v7.4."
# Tagged Vim patch, check version.c:
is_missing="$(sed -n '/static int included_patches/,/}/p' "${NVIM_SOURCE_DIR}/src/nvim/version.c" |
is_missing="$(sed -n '/static const int included_patches/,/}/p' "${NVIM_SOURCE_DIR}/src/nvim/version.c" |
grep -x -e "[[:space:]]*//[[:space:]]${patch_number} NA.*" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")"
vim_commit="${vim_tag#v}"
if (cd "${VIM_SOURCE_DIR}" && git --no-pager show --color=never --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then

View File

@ -1,3 +1,3 @@
# multiqueue.h pointer arithmetic is not accepted by asan
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():
sys.stderr.write('Category \'%s\' errors found: %d\n' %
(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):
"""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
# or they begin with multiple slashes followed by a space:
# //////// Header comment
# or they are Vim {{{ fold markers
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:]))
Search(r'^/+ ', line[commentend:]) or
Search(r'^(?:\{{3}|\}{3})\d*(?: |$)',
line[commentend:]))
if not match:
error(filename, linenum, 'whitespace/comments', 4,
'Should have a space between // and comment')
@ -3580,7 +3584,7 @@ def main():
if __name__ == '__main__':
main()
# vim: ts=4 sts=4 sw=4
# vim: ts=4 sts=4 sw=4 foldmarker=▶,▲
# Ignore "too complex" warnings when using pymode.
# pylama:ignore=C901

View File

@ -64,7 +64,7 @@ void *je_realloc(void *ptr, size_t size)
// of the memory allocated for item.
typedef struct {} dictitem_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);
}

View File

@ -10,6 +10,7 @@ if(USE_GCOV)
endif()
endif()
set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches)
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
set(MSGPACK_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genmsgpack.lua)
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_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_FUNCS_HASH_INPUT ${GENERATED_DIR}/funcs.generated.h.gperf)
set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.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)
@ -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(EVENTS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gen_events.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_DIR ${PROJECT_SOURCE_DIR}/unicode)
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_SOURCE ${PROJECT_SOURCE_DIR}/src/nvim/viml/executor/vim.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 MSGPACK_RPC_HEADERS msgpack_rpc/*.h)
file(GLOB UNICODE_FILES ${UNICODE_DIR}/*.txt)
include_directories(${GENERATED_DIR})
include_directories(${CACHED_GENERATED_DIR})
include_directories(${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${TOUCHES_DIR})
file(MAKE_DIRECTORY ${GENERATED_DIR})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
file(GLOB NEOVIM_SOURCES *.c)
file(GLOB NVIM_SOURCES *.c)
file(GLOB NVIM_HEADERS *.h)
foreach(subdir
os
@ -72,18 +77,21 @@ foreach(subdir
file(MAKE_DIRECTORY ${GENERATED_DIR}/${subdir})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}/${subdir})
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()
file(GLOB_RECURSE NEOVIM_HEADERS *.h)
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
# build to build.
list(SORT NEOVIM_SOURCES)
list(SORT NEOVIM_HEADERS)
list(SORT NVIM_SOURCES)
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)
if(${f} MATCHES "^(regexp_nfa.c)$")
list(APPEND to_remove ${sfile})
@ -93,7 +101,7 @@ foreach(sfile ${NEOVIM_SOURCES})
endif()
endforeach()
list(REMOVE_ITEM NEOVIM_SOURCES ${to_remove})
list(REMOVE_ITEM NVIM_SOURCES ${to_remove})
# Legacy files that do not yet pass -Wconversion.
set(CONV_SOURCES
@ -117,7 +125,7 @@ set(CONV_SOURCES
window.c)
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)")
endif()
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}})
set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY})
foreach(sfile ${NEOVIM_SOURCES}
"${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c"
function(get_preproc_output varname iname)
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})
get_filename_component(full_d ${sfile} PATH)
file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}")
if(${d} MATCHES "^([.][.]|auto/)")
file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}")
if(${d} MATCHES "^[.][.]|auto/")
file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
endif()
get_filename_component(f ${sfile} NAME)
@ -173,26 +193,22 @@ foreach(sfile ${NEOVIM_SOURCES}
set(f "${d}/${f}")
set(r "${d}/${r}")
endif()
set(gf1 "${GENERATED_DIR}/${r}.c.generated.h")
set(gf2 "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h")
set(gf3 "${GENERATED_DIR}/${r}.i")
set(gf_c_h "${GENERATED_DIR}/${r}.c.generated.h")
set(gf_h_h "${GENERATED_INCLUDES_DIR}/${r}.h.generated.h")
set(gf_i "${GENERATED_DIR}/${r}.i")
if(MSVC)
set(PREPROC_OUTPUT /P /Fi${gf3})
else()
set(PREPROC_OUTPUT -E -o ${gf3})
endif()
get_preproc_output(PREPROC_OUTPUT ${gf_i})
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 "${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}"
)
list(APPEND NEOVIM_GENERATED_SOURCES "${gf1}")
list(APPEND NEOVIM_GENERATED_SOURCES "${gf2}")
list(APPEND NVIM_GENERATED_FOR_SOURCES "${gf_c_h}")
list(APPEND NVIM_GENERATED_FOR_HEADERS "${gf_h_h}")
if(${d} MATCHES "^api$" AND NOT ${f} MATCHES "^api/helpers.c$")
list(APPEND API_HEADERS ${gf2})
list(APPEND API_HEADERS ${gf_h_h})
endif()
endforeach()
@ -229,23 +245,32 @@ add_custom_command(
${VIM_MODULE_SOURCE}
)
list(APPEND NEOVIM_GENERATED_SOURCES
"${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
"${GENERATED_API_DISPATCH}"
list(APPEND NVIM_GENERATED_SOURCES
"${MSGPACK_LUA_C_BINDINGS}"
)
list(APPEND NVIM_GENERATED_FOR_HEADERS
"${GENERATED_EX_CMDS_ENUM}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_ENUM}"
)
list(APPEND NVIM_GENERATED_FOR_SOURCES
"${GENERATED_API_DISPATCH}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_NAMES_MAP}"
"${GENERATED_OPTIONS}"
"${GENERATED_UNICODE_TABLES}"
"${MSGPACK_LUA_C_BINDINGS}"
"${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}
COMMAND ${LUA_PRG} ${EX_CMDS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR}
DEPENDS ${EX_CMDS_GENERATOR} ${EX_CMDS_DEFS_FILE}
${CMAKE_CURRENT_LIST_DIR} ${GENERATED_INCLUDES_DIR} ${GENERATED_DIR}
DEPENDS ${EX_CMDS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/ex_cmds.lua
)
if(NOT GPERF_PRG)
@ -253,26 +278,34 @@ if(NOT GPERF_PRG)
endif()
add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA}
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}
${GENERATED_FUNCS_HASH_INPUT} --output-file=${GENERATED_FUNCS}
DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA}
${GENERATED_DIR}/funcs.generated.h.gperf --output-file=${GENERATED_FUNCS}
DEPENDS ${FUNCS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/eval.lua ${API_METADATA}
)
list(APPEND NEOVIM_GENERATED_SOURCES
list(APPEND NVIM_GENERATED_FOR_SOURCES
"${GENERATED_FUNCS}")
add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
COMMAND ${LUA_PRG} ${EVENTS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${EVENTS_GENERATOR} ${EVENTS_LIST_FILE}
${CMAKE_CURRENT_LIST_DIR} ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
DEPENDS ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua
)
add_custom_command(OUTPUT ${GENERATED_OPTIONS}
COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_OPTIONS}
DEPENDS ${OPTIONS_GENERATOR} ${OPTIONS_LIST_FILE}
${CMAKE_CURRENT_LIST_DIR} ${GENERATED_OPTIONS}
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.
if (LibIntl_FOUND)
@ -315,8 +348,8 @@ if(JEMALLOC_FOUND)
list(APPEND NVIM_EXEC_LINK_LIBRARIES ${JEMALLOC_LIBRARIES})
endif()
add_executable(nvim ${NEOVIM_GENERATED_SOURCES} ${NEOVIM_SOURCES}
${NEOVIM_HEADERS})
add_executable(nvim ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS})
target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES})
install_helper(TARGETS nvim)
@ -374,26 +407,49 @@ if(WIN32)
add_dependencies(nvim_runtime_deps external_blobs)
endif()
add_library(libnvim STATIC EXCLUDE_FROM_ALL ${NEOVIM_GENERATED_SOURCES}
${NEOVIM_SOURCES} ${NEOVIM_HEADERS})
add_library(
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
INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS})
target_link_libraries(libnvim ${NVIM_TEST_LINK_LIBRARIES})
set_target_properties(libnvim PROPERTIES
POSITION_INDEPENDENT_CODE ON
OUTPUT_NAME nvim)
set_property(TARGET libnvim
APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB ")
set_target_properties(
libnvim
PROPERTIES
POSITION_INDEPENDENT_CODE ON
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}
${NEOVIM_SOURCES} ${UNIT_TEST_FIXTURES} ${NEOVIM_HEADERS})
add_library(
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})
set_property(TARGET nvim-test APPEND PROPERTY
INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS})
set_target_properties(nvim-test PROPERTIES
POSITION_INDEPENDENT_CODE ON)
set_property(TARGET nvim-test
APPEND_STRING PROPERTY COMPILE_FLAGS " -DUNIT_TESTING ")
set_property(
TARGET nvim-test
APPEND PROPERTY INCLUDE_DIRECTORIES ${LUAJIT_INCLUDE_DIRS}
)
set_target_properties(
nvim-test
PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
set_property(
TARGET nvim-test
APPEND_STRING PROPERTY COMPILE_FLAGS " -DUNIT_TESTING "
)
if(CLANG_ASAN_UBSAN)
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 ")
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)

View File

@ -296,7 +296,7 @@ void nvim_buf_set_lines(uint64_t channel_id,
tabpage_T *save_curtab = NULL;
size_t new_len = replacement.size;
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;
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) {
extra -= (ssize_t)to_delete;
if (to_delete > 0) {
extra -= (ptrdiff_t)to_delete;
}
// 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);
}
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) {
fix_cursor((linenr_T)start, (linenr_T)end, extra);
fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
}
end:

View File

@ -14,6 +14,7 @@
#include "nvim/window.h"
#include "nvim/memory.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/map_defs.h"
#include "nvim/map.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
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"));
return (Object) OBJECT_INIT;
}
dictitem_T *di = dict_lookup(hi);
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;
}
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->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);
}
// Delete the entry
hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key);
hash_remove(&dict->dv_hashtab, hi);
dictitem_free(di);
tv_dict_item_remove(dict, di);
}
} else {
// Update the key
@ -170,20 +168,20 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del,
if (di == NULL) {
// Need to create an entry
di = dictitem_alloc((uint8_t *) key.data);
dict_add(dict, di);
di = tv_dict_item_alloc_len(key.data, key.size);
tv_dict_add(dict, di);
} else {
// Return the old value
if (retval) {
rv = vim_to_object(&di->di_tv);
}
clear_tv(&di->di_tv);
tv_clear(&di->di_tv);
}
// Update the value
copy_tv(&tv, &di->di_tv);
tv_copy(&tv, &di->di_tv);
// Clear the temporary variable
clear_tv(&tv);
tv_clear(&tv);
}
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 (value.type != kObjectTypeBoolean) {
@ -627,7 +625,7 @@ String cstr_as_string(char *str) FUNC_ATTR_PURE
if (str == NULL) {
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.
@ -682,20 +680,20 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
break;
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++) {
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)) {
// cleanup
listitem_free(li);
list_free(list);
tv_list_item_free(li);
tv_list_free(list);
return false;
}
list_append(list, li);
tv_list_append(list, li);
}
list->lv_refcount++;
@ -705,7 +703,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
}
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++) {
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,
_("Empty dictionary keys aren't allowed"));
// cleanup
dict_free(dict);
tv_dict_free(dict);
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)) {
// cleanup
dictitem_free(di);
dict_free(dict);
tv_dict_item_free(di);
tv_dict_free(dict);
return false;
}
dict_add(dict, di);
tv_dict_add(dict, di);
}
dict->dv_refcount++;
@ -962,11 +960,7 @@ static void set_option_value_err(char *key,
{
char *errmsg;
if ((errmsg = (char *)set_option_value((uint8_t *)key,
numval,
(uint8_t *)stringval,
opt_flags)))
{
if ((errmsg = set_option_value(key, numval, stringval, opt_flags))) {
if (try_end(err)) {
return;
}

View File

@ -12,6 +12,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/popupmnu.h"
#include "nvim/cursor_shape.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# 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->eol_clear = remote_ui_eol_clear;
ui->cursor_goto = remote_ui_cursor_goto;
ui->cursor_style_set = remote_ui_cursor_style_set;
ui->update_menu = remote_ui_update_menu;
ui->busy_start = remote_ui_busy_start;
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);
}
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)
{
Array args = ARRAY_DICT_INIT;

View File

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

View File

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

View File

@ -627,10 +627,11 @@ void buf_freeall(buf_T *buf, int flags)
*/
if (buf == curbuf && !is_curbuf)
return;
diff_buf_delete(buf); /* Can't use 'diff' for unloaded buffer. */
/* Remove any ownsyntax, unless exiting. */
if (firstwin != NULL && curwin->w_buffer == buf)
diff_buf_delete(buf); // Can't use 'diff' for unloaded buffer.
// Remove any ownsyntax, unless exiting.
if (curwin != NULL && curwin->w_buffer == buf) {
reset_synblock(curwin);
}
/* No folds in an empty buffer. */
FOR_ALL_TAB_WINDOWS(tp, win) {
@ -660,7 +661,7 @@ static void free_buffer(buf_T *buf)
free_buffer_stuff(buf, true);
unref_var_dict(buf->b_vars);
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_insert);
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),
"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_tv = (typval_T) {
.v_type = VAR_NUMBER,
@ -1480,7 +1481,7 @@ static inline void buf_init_changedtick(buf_T *const buf)
},
.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.
@ -1572,7 +1573,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags)
if (buf != curbuf || curbuf == NULL) {
buf = xcalloc(1, sizeof(buf_T));
// 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);
buf_init_changedtick(buf);
}
@ -2723,7 +2724,7 @@ fileinfo (
else
name = curbuf->b_ffname;
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",
@ -2888,7 +2889,7 @@ void maketitle(void)
buf[off++] = ' ';
buf[off++] = '(';
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
/* avoid "c:/name" to be reduced to "c" */
if (isalpha(buf[off]) && buf[off + 1] == ':')
@ -3503,7 +3504,7 @@ int build_stl_str_hl(
curbuf = o_curbuf;
// 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
if (!buf->b_p_bin) {
// 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) {
xfree(*ffname);
*ffname = rfname;
*sfname = rfname;
*ffname = (char_u *)rfname;
*sfname = (char_u *)rfname;
}
}
#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)setfname(curbuf, (char_u *)bufname, NULL, true);
set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
set_option_value((char_u *)"bt", 0L, (char_u *)"nofile", OPT_LOCAL);
set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
set_option_value("bh", 0L, "hide", OPT_LOCAL);
set_option_value("bt", 0L, "nofile", OPT_LOCAL);
set_option_value("swf", 0L, NULL, OPT_LOCAL);
RESET_BINDING(curwin);
}

View File

@ -1,12 +1,14 @@
#ifndef NVIM_BUFFER_H
#define NVIM_BUFFER_H
#include "nvim/vim.h"
#include "nvim/window.h"
#include "nvim/pos.h" // for linenr_T
#include "nvim/ex_cmds_defs.h" // for exarg_T
#include "nvim/screen.h" // for StlClickRecord
#include "nvim/func_attr.h"
#include "nvim/eval.h"
#include "nvim/macros.h"
// Values for buflist_getfile()
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)
{
#ifndef NDEBUG
dictitem_T *const changedtick_di = dict_find(
buf->b_vars, (char_u *)"changedtick", sizeof("changedtick") - 1);
dictitem_T *const changedtick_di = tv_dict_find(
buf->b_vars, S_LEN("changedtick"));
assert(changedtick_di != NULL);
assert(changedtick_di->di_tv.v_type == VAR_NUMBER);
assert(changedtick_di->di_tv.v_lock == VAR_FIXED);

View File

@ -21,8 +21,6 @@ typedef struct {
#include "nvim/pos.h"
// for the number window-local and buffer-local options
#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
#include "nvim/mark_defs.h"
// for u_header_T; needs buf_T.
@ -30,7 +28,9 @@ typedef struct {
// for hashtab_T
#include "nvim/hashtab.h"
// for dict_T
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
// for proftime_T
#include "nvim/profile.h"
// for String
#include "nvim/api/private/defs.h"
// for Map(K, V)
@ -318,25 +318,6 @@ typedef struct {
String save_inputbuf;
} 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.
*/
@ -447,6 +428,10 @@ typedef struct {
char_u *b_syn_isk; // iskeyword option
} 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_LL_ENTRY 2
@ -491,7 +476,7 @@ struct file_buffer {
// file has been changed and not written out.
/// Change identifier incremented for each change, including undo
#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
saving the buffer. */
@ -735,8 +720,8 @@ struct file_buffer {
int b_bad_char; /* "++bad=" argument when edit started or 0 */
int b_start_bomb; /* 'bomb' when it was read */
dictitem_T b_bufvar; /* variable for "b:" Dictionary */
dict_T *b_vars; /* internal variables, local to buffer */
ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dictionary.
dict_T *b_vars; ///< b: scope dictionary.
/* 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
@ -824,9 +809,9 @@ struct tabpage_S {
buf_T *(tp_diffbuf[DB_COUNT]);
int tp_diff_invalid; ///< list of diffs is outdated
frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots
dictitem_T tp_winvar; ///< variable for "t:" Dictionary
dict_T *tp_vars; ///< internal variables, local to tab page
char_u *tp_localdir; ///< Absolute path of local CWD or NULL
ScopeDictDictItem tp_winvar; ///< Variable for "t:" Dictionary.
dict_T *tp_vars; ///< Internal variables, local to tab page.
char_u *tp_localdir; ///< Absolute path of local cwd or NULL.
};
/*
@ -1118,8 +1103,8 @@ struct window_S {
long w_scbind_pos;
dictitem_T w_winvar; /* variable for "w:" Dictionary */
dict_T *w_vars; /* internal variables, local to window */
ScopeDictDictItem w_winvar; ///< Variable for "w:" dictionary.
dict_T *w_vars; ///< Dictionary with w: variables.
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))
#define RESET_CHARTAB(buf, c) \
(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) \
((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
static char_u g_chartab[256];
@ -88,7 +90,6 @@ int buf_init_chartab(buf_T *buf, int global)
{
int c;
int c2;
char_u *p;
int i;
bool tilde;
bool do_isalpha;
@ -142,7 +143,8 @@ int buf_init_chartab(buf_T *buf, int global)
// Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint'
// options Each option is a list of characters, character numbers or
// 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) {
// first round: 'isident'
p = p_isi;
@ -167,7 +169,7 @@ int buf_init_chartab(buf_T *buf, int global)
}
if (ascii_isdigit(*p)) {
c = getdigits_int(&p);
c = getdigits_int((char_u **)&p);
} else {
c = mb_ptr2char_adv(&p);
}
@ -177,7 +179,7 @@ int buf_init_chartab(buf_T *buf, int global)
++p;
if (ascii_isdigit(*p)) {
c2 = getdigits_int(&p);
c2 = getdigits_int((char_u **)&p);
} else {
c2 = mb_ptr2char_adv(&p);
}
@ -634,7 +636,7 @@ int char2cells(int c)
/// @param p
///
/// @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.
if (*p >= 0x80) {
@ -776,6 +778,20 @@ bool vim_iswordc(int c)
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:
/// Letters and characters from 'iskeyword' option for given buffer.
/// 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)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2)
{
if (c >= 0x100) {
return utf_class(c) >= 2;
}
return c > 0 && c < 0x100 && GET_CHARTAB(buf, c) != 0;
return vim_iswordc_tab(c, buf->b_chartab);
}
/// 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.
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;
while (ascii_iswhite(*p)) {
@ -1393,19 +1407,21 @@ char_u *skipwhite(const char_u *q)
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.
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)) {
// skip to next non-digit
p++;
}
return p;
return (char_u *)p;
}
/// skip over binary digits
@ -1551,17 +1567,17 @@ int vim_tolower(int 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.
char_u* skiptowhite(char_u *p)
char_u *skiptowhite(const char_u *p)
{
while (*p != ' ' && *p != '\t' && *p != NUL) {
p++;
}
return p;
return (char_u *)p;
}
/// skiptowhite_esc: Like skiptowhite(), but also skip escaped chars

View File

@ -1,6 +1,20 @@
#ifndef 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
# include "charset.h.generated.h"
#endif

View File

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

View File

@ -7,40 +7,74 @@
#include "nvim/charset.h"
#include "nvim/strings.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] =
{
/* The values will be filled in from the 'guicursor' and 'mouseshape'
* defaults when Vim starts.
* Adjust the SHAPE_IDX_ defines when making changes! */
{0, 0, 0, 700L, 400L, 250L, 0, 0, "n", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "v", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "i", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "r", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "c", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ci", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "cr", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "o", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 700L, 400L, 250L, 0, 0, "ve", SHAPE_CURSOR+SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "e", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE},
{0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE},
{0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR},
// Values are set by 'guicursor' and 'mouseshape'.
// Adjust the SHAPE_IDX_ defines when changing this!
{ "normal", 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 },
{ "insert", 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 },
{ "cmdline_normal", 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 },
{ "cmdline_replace", 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 },
{ "visual_select", 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 },
{ "statusline_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "s", SHAPE_MOUSE },
{ "statusline_drag", 0, 0, 0, 0L, 0L, 0L, 0, 0, "sd", SHAPE_MOUSE },
{ "vsep_hover", 0, 0, 0, 0L, 0L, 0L, 0, 0, "vs", SHAPE_MOUSE },
{ "vsep_drag", 0, 0, 0, 0L, 0L, 0L, 0, 0, "vd", SHAPE_MOUSE },
{ "more", 0, 0, 0, 0L, 0L, 0L, 0, 0, "m", SHAPE_MOUSE },
{ "more_lastline", 0, 0, 0, 0L, 0L, 0L, 0, 0, "ml", SHAPE_MOUSE },
{ "showmatch", 0, 0, 0, 100L, 100L, 100L, 0, 0, "sm", SHAPE_CURSOR },
};
/*
* Parse the 'guicursor' option ("what" is SHAPE_CURSOR) or 'mouseshape'
* ("what" is SHAPE_MOUSE).
* Returns error message for an illegal option, NULL otherwise.
*/
/// Converts cursor_shapes into a Dictionary of dictionaries
/// @return dictionary of the form {"normal" : { "cursor_shape": ... }, ...}
Dictionary cursor_shape_dict(void)
{
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 *modep;
@ -55,14 +89,13 @@ char_u *parse_shape_opt(int what)
int found_ve = false; /* found "ve" flag */
int round;
/*
* First round: check for errors; second round: do it for real.
*/
for (round = 1; round <= 2; ++round) {
/*
* Repeat for all comma separated parts.
*/
// First round: check for errors; second round: do it for real.
for (round = 1; round <= 2; round++) {
// Repeat for all comma separated parts.
modep = p_guicursor;
if (*p_guicursor == NUL) {
modep = (char_u *)"a:block-blinkon0";
}
while (*modep != NUL) {
colonp = vim_strchr(modep, ':');
if (colonp == NULL)
@ -71,19 +104,18 @@ char_u *parse_shape_opt(int what)
return (char_u *)N_("E546: Illegal mode");
commap = vim_strchr(modep, ',');
/*
* Repeat for all mode's before the colon.
* For the 'a' mode, we loop to handle all the modes.
*/
// Repeat for all modes before the colon.
// For the 'a' mode, we loop to handle all the modes.
all_idx = -1;
assert(modep < colonp);
while (modep < colonp || all_idx >= 0) {
if (all_idx < 0) {
/* Find the mode. */
if (modep[1] == '-' || modep[1] == ':')
// Find the mode
if (modep[1] == '-' || modep[1] == ':') {
len = 1;
else
} else {
len = 2;
}
if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') {
all_idx = SHAPE_IDX_COUNT - 1;
@ -100,11 +132,11 @@ char_u *parse_shape_opt(int what)
modep += len + 1;
}
if (all_idx >= 0)
if (all_idx >= 0) {
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].blinkwait = 700L;
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;
}
}
ui_cursor_style_set();
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
#define NVIM_CURSOR_SHAPE_H
/*
* struct to store values from 'guicursor' and 'mouseshape'
*/
/* Indexes in shape_table[] */
#define SHAPE_IDX_N 0 /* Normal mode */
#define SHAPE_IDX_V 1 /* Visual mode */
#define SHAPE_IDX_I 2 /* Insert mode */
#define SHAPE_IDX_R 3 /* Replace mode */
#define SHAPE_IDX_C 4 /* Command line Normal mode */
#define SHAPE_IDX_CI 5 /* Command line Insert mode */
#define SHAPE_IDX_CR 6 /* Command line Replace mode */
#define SHAPE_IDX_O 7 /* Operator-pending mode */
#define SHAPE_IDX_VE 8 /* Visual mode with 'selection' exclusive */
#define SHAPE_IDX_CLINE 9 /* On command line */
#define SHAPE_IDX_STATUS 10 /* A status line */
#define SHAPE_IDX_SDRAG 11 /* dragging a status line */
#define SHAPE_IDX_VSEP 12 /* A vertical separator line */
#define SHAPE_IDX_VDRAG 13 /* dragging a vertical separator line */
#define SHAPE_IDX_MORE 14 /* Hit-return or More */
#define SHAPE_IDX_MOREL 15 /* Hit-return or More in last line */
#define SHAPE_IDX_SM 16 /* showing matching paren */
#define SHAPE_IDX_COUNT 17
/// struct to store values from 'guicursor' and 'mouseshape'
/// Indexes in shape_table[]
typedef enum {
SHAPE_IDX_N = 0, ///< Normal mode
SHAPE_IDX_V = 1, ///< Visual mode
SHAPE_IDX_I = 2, ///< Insert mode
SHAPE_IDX_R = 3, ///< Replace mode
SHAPE_IDX_C = 4, ///< Command line Normal mode
SHAPE_IDX_CI = 5, ///< Command line Insert mode
SHAPE_IDX_CR = 6, ///< Command line Replace mode
SHAPE_IDX_O = 7, ///< Operator-pending mode
SHAPE_IDX_VE = 8, ///< Visual mode with 'selection' exclusive
SHAPE_IDX_CLINE = 9, ///< On command line
SHAPE_IDX_STATUS = 10, ///< On status line
SHAPE_IDX_SDRAG = 11, ///< dragging a status line
SHAPE_IDX_VSEP = 12, ///< On vertical separator line
SHAPE_IDX_VDRAG = 13, ///< dragging a vertical separator line
SHAPE_IDX_MORE = 14, ///< Hit-return or More
SHAPE_IDX_MOREL = 15, ///< Hit-return or More in last line
SHAPE_IDX_SM = 16, ///< showing matching paren
SHAPE_IDX_COUNT = 17
} MouseMode;
#define SHAPE_BLOCK 0 /* block cursor */
#define SHAPE_HOR 1 /* horizontal bar cursor */
#define SHAPE_VER 2 /* vertical bar cursor */
typedef enum {
SHAPE_BLOCK = 0, ///< block 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_HIDE 1 /* hide mouse pointer */
@ -35,16 +37,17 @@
#define SHAPE_CURSOR 2 /* used for text cursor shape */
typedef struct cursor_entry {
int shape; /* one of the SHAPE_ defines */
int mshape; /* one of the MSHAPE defines */
int percentage; /* percentage of cell for bar */
long blinkwait; /* blinking, wait time before blinking starts */
long blinkon; /* blinking, on time */
long blinkoff; /* blinking, off time */
int id; /* highlight group ID */
int id_lm; /* highlight group ID for :lmap mode */
char *name; /* mode name (fixed) */
char used_for; /* SHAPE_MOUSE and/or SHAPE_CURSOR */
char *full_name; ///< mode description
CursorShape shape; ///< cursor shape: one of the SHAPE_ defines
int mshape; ///< mouse shape: one of the MSHAPE defines
int percentage; ///< percentage of cell for bar
long blinkwait; ///< blinking, wait time before blinking starts
long blinkon; ///< blinking, on time
long blinkoff; ///< blinking, off time
int id; ///< highlight group ID
int id_lm; ///< highlight group ID for :lmap mode
char *name; ///< mode short name
char used_for; ///< SHAPE_MOUSE and/or SHAPE_CURSOR
} 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)) {
return mb_stricmp(s1, s2);
return mb_stricmp((const char *)s1, (const char *)s2);
}
// Ignore white space changes and possibly ignore case.

View File

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

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@
#include "nvim/eval/encode.h"
#include "nvim/buffer_defs.h" // vimconv_T
#include "nvim/eval.h"
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/garray.h"
#include "nvim/mbyte.h"
#include "nvim/message.h"
@ -45,7 +45,8 @@ const char *const encode_special_var_names[] = {
#endif
/// 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) {
return 0;
@ -80,11 +81,11 @@ int encode_list_write(void *data, const char *buf, size_t len)
str = xmemdupz(line_start, line_length);
memchrsub(str, NUL, NL, line_length);
}
list_append_allocated_string(list, str);
tv_list_append_allocated_string(list, str);
line_end++;
}
if (line_end == end) {
list_append_allocated_string(list, NULL);
tv_list_append_allocated_string(list, NULL);
}
return 0;
}
@ -743,11 +744,11 @@ bool encode_check_json_key(const typval_T *const tv)
}
const dictitem_T *type_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.vval.v_list != eval_msgpack_type_lists[kMPString]
&& 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) {
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 "nvim/lib/kvec.h"
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/encode.h"
#include "nvim/func_attr.h"
#include "nvim/eval/typval_encode.h"
@ -402,11 +402,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
const dictitem_T *val_di;
if (TYPVAL_ENCODE_ALLOW_SPECIALS
&& tv->vval.v_dict->dv_hashtab.ht_used == 2
&& (type_di = dict_find((dict_T *)tv->vval.v_dict,
(char_u *)"_TYPE", -1)) != NULL
&& (type_di = tv_dict_find((dict_T *)tv->vval.v_dict,
S_LEN("_TYPE"))) != NULL
&& type_di->di_tv.v_type == VAR_LIST
&& (val_di = dict_find((dict_T *)tv->vval.v_dict,
(char_u *)"_VAL", -1)) != NULL) {
&& (val_di = tv_dict_find((dict_T *)tv->vval.v_dict,
S_LEN("_VAL"))) != NULL) {
size_t 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]) {
@ -658,7 +658,7 @@ typval_encode_stop_converting_one_item:
while (HASHITEM_EMPTY(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.hi++;
TYPVAL_ENCODE_CONV_STR_STRING(NULL, &di->di_key[0],

View File

@ -11,7 +11,7 @@
#include <assert.h>
#include "nvim/lib/kvec.h"
#include "nvim/eval_defs.h"
#include "nvim/eval/typval.h"
#include "nvim/func_attr.h"
/// 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;
// set to the hrtime of when process_stop was called for the process.
uint64_t stopped_time;
char *cwd;
const char *cwd;
char **argv;
Stream *in, *out, *err;
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)
{
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
@ -136,7 +139,10 @@ static void fread_idle_cb(uv_idle_t *handle)
uv_fs_t req;
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
// 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);
xfree(cmd);
AppendToRedobuff((char_u *)"\n");
bangredo = FALSE;
AppendToRedobuff("\n");
bangredo = false;
}
/*
* Add quotes around the command, for shells that need them.
@ -2958,7 +2958,7 @@ void sub_set_replacement(SubReplacementString sub)
{
xfree(old_sub.sub);
if (sub.additional_elements != old_sub.additional_elements) {
list_unref(old_sub.additional_elements);
tv_list_unref(old_sub.additional_elements);
}
old_sub = sub;
}
@ -4764,8 +4764,8 @@ void fix_help_buffer(void)
char_u *p;
char_u *rt;
/* set filetype to "help". */
set_option_value((char_u *)"ft", 0L, (char_u *)"help", OPT_LOCAL);
// Set filetype to "help".
set_option_value("ft", 0L, "help", OPT_LOCAL);
if (!syntax_present(curwin)) {
for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {

View File

@ -4,8 +4,8 @@
#include <stdbool.h>
#include "nvim/os/time.h"
#include "nvim/eval_defs.h"
#include "nvim/pos.h"
#include "nvim/eval/typval.h"
// flags for do_ecmd()
#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.
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.
xp->xp_context = EXPAND_PROFILE;
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) {
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_pattern = skipwhite(end_subcmd);
xp->xp_pattern = skipwhite((const char_u *)end_subcmd);
return;
}
@ -2073,9 +2071,9 @@ void ex_listdo(exarg_T *eap)
// Clear 'shm' to avoid that the file message overwrites
// any output from the command.
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);
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);
}
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
// message overwrites any output from the command.
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);
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);
// 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_unlet((char_u *)"g:current_compiler", true);
do_unlet((char_u *)"b:current_compiler", true);
do_unlet(S_LEN("g:current_compiler"), true);
do_unlet(S_LEN("b:current_compiler"), true);
snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg);
if (source_runtime(buf, DIP_ALL) == FAIL) {
@ -2280,7 +2278,7 @@ void ex_compiler(exarg_T *eap)
old_cur_comp);
xfree(old_cur_comp);
} 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)
{
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) {
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
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)) {
if (vim_ispathsep_nocolon(*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;
// Find "ffname" in "p_rtp", ignoring '/' vs '\' differences
size_t fname_len = STRLEN(ffname);
char_u *insp = p_rtp;
size_t fname_len = strlen(ffname);
const char *insp = (const char *)p_rtp;
for (;;) {
if (vim_fnamencmp(insp, ffname, fname_len) == 0) {
if (path_fnamencmp(insp, ffname, fname_len) == 0) {
break;
}
insp = vim_strchr(insp, ',');
insp = strchr(insp, ',');
if (insp == NULL) {
break;
}
@ -2536,10 +2534,10 @@ static void add_pack_plugin(char_u *fname, void *cookie)
if (insp == NULL) {
// not found, append at the end
insp = p_rtp + STRLEN(p_rtp);
insp = (const char *)p_rtp + STRLEN(p_rtp);
} else {
// append after the matching directory.
insp += STRLEN(ffname);
insp += strlen(ffname);
while (*insp != NUL && *insp != ',') {
insp++;
}
@ -2547,31 +2545,40 @@ static void add_pack_plugin(char_u *fname, void *cookie)
*p4 = c;
// 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;
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);
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 oldlen = STRLEN(p_rtp);
const size_t addlen = strlen(ffname) + 1; // add one for comma
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) {
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);
new_rtp[keep] = ',';
memmove(new_rtp + keep + 1, ffname, addlen);
new_rtp_fill += keep;
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) {
memmove(new_rtp + keep + addlen, p_rtp + keep,
oldlen - keep + 1);
memmove(new_rtp + new_rtp_fill, p_rtp + keep, oldlen - keep + 1);
new_rtp_fill += oldlen - keep;
}
if (afterlen > 0) {
STRCAT(new_rtp, ",");
STRCAT(new_rtp, afterdir);
assert(new_rtp[new_rtp_fill] == NUL);
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(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 *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);
if (pat == NULL) {
goto theend;
@ -3699,12 +3706,12 @@ static void script_host_execute(char *name, exarg_T *eap)
char *const script = script_get(eap, &len);
if (script != NULL) {
list_T *const args = list_alloc();
list_T *const args = tv_list_alloc();
// script
list_append_allocated_string(args, script);
tv_list_append_allocated_string(args, script);
// current range
list_append_number(args, (int)eap->line1);
list_append_number(args, (int)eap->line2);
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
(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];
vim_FullName((char *)eap->arg, (char *)buffer, sizeof(buffer), false);
list_T *args = list_alloc();
list_T *args = tv_list_alloc();
// filename
list_append_string(args, buffer, -1);
tv_list_append_string(args, (const char *)buffer, -1);
// current range
list_append_number(args, (int)eap->line1);
list_append_number(args, (int)eap->line2);
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
(void)eval_call_provider(name, "execute_file", args);
}
static void script_host_do_range(char *name, exarg_T *eap)
{
list_T *args = list_alloc();
list_append_number(args, (int)eap->line1);
list_append_number(args, (int)eap->line2);
list_append_string(args, eap->arg, -1);
list_T *args = tv_list_alloc();
tv_list_append_number(args, (int)eap->line1);
tv_list_append_number(args, (int)eap->line2);
tv_list_append_string(args, (const char *)eap->arg, -1);
(void)eval_call_provider(name, "do_range", args);
}

View File

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

View File

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

View File

@ -1,6 +1,8 @@
/*
* ex_eval.c: functions for Ex command line for the +eval feature.
*/
// TODO(ZyX-I): move to eval/executor
/// @file ex_eval.c
///
/// Functions for Ex command line for the +eval feature.
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
@ -12,6 +14,7 @@
#include "nvim/ex_eval.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/message.h"
@ -19,8 +22,6 @@
#include "nvim/regexp.h"
#include "nvim/strings.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_eval.c.generated.h"
#endif
@ -57,12 +58,14 @@
* 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.
*/
/* 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
@ -779,7 +782,6 @@ void report_discard_pending(int pending, void *value)
*/
void ex_if(exarg_T *eap)
{
int error;
int skip;
int result;
struct condstack *cstack = eap->cstack;
@ -800,6 +802,7 @@ void ex_if(exarg_T *eap)
1] &
CSF_ACTIVE));
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
if (!skip && !error) {
@ -844,7 +847,6 @@ void ex_endif(exarg_T *eap)
*/
void ex_else(exarg_T *eap)
{
int error;
int skip;
int result;
struct condstack *cstack = eap->cstack;
@ -901,6 +903,7 @@ void ex_else(exarg_T *eap)
}
if (eap->cmdidx == CMD_elseif) {
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
/* When throwing error exceptions, we want to throw always the first
* 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)
{
int error;
bool error;
int skip;
int result;
struct condstack *cstack = eap->cstack;
@ -1147,23 +1150,25 @@ void ex_endwhile(exarg_T *eap)
*/
void ex_throw(exarg_T *eap)
{
char_u *arg = eap->arg;
char_u *value;
const char *arg = (const char *)eap->arg;
char *value;
if (*arg != NUL && *arg != '|' && *arg != '\n')
value = eval_to_string_skip(arg, &eap->nextcmd, eap->skip);
else {
if (*arg != NUL && *arg != '|' && *arg != '\n') {
value = eval_to_string_skip(arg, (const char **)&eap->nextcmd,
(bool)eap->skip);
} else {
EMSG(_(e_argreq));
value = NULL;
}
/* On error or when an exception is thrown during argument evaluation, do
* not throw. */
// On error or when an exception is thrown during argument evaluation, do
// not throw.
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);
else
} else {
do_throw(eap->cstack);
}
}
}

View File

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

View File

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

View File

@ -322,8 +322,11 @@ vim_findfile_init (
drive[0] = path[0];
drive[1] = ':';
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;
}
path += 2;
} else
#endif
@ -1549,14 +1552,14 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope)
assert(false);
}
dict_add_nr_str(dict, "scope", 0L, (char_u *)buf);
dict_add_nr_str(dict, "cwd", 0L, (char_u *)new_dir);
dict_set_keys_readonly(dict);
tv_dict_add_str(dict, S_LEN("scope"), buf);
tv_dict_add_str(dict, S_LEN("cwd"), new_dir);
tv_dict_set_keys_readonly(dict);
apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false,
NULL);
dict_clear(dict);
tv_dict_clear(dict);
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;
if (msg_silent != 0)
if (msg_silent != 0) {
return;
msg_add_fname(buf, name); /* put file name in IObuff with quotes */
/* If it's extremely long, truncate it. */
if (STRLEN(IObuff) > IOSIZE - 80)
IObuff[IOSIZE - 80] = NUL;
STRCAT(IObuff, s);
/*
* For the first message may have to start a new line.
* For further ones overwrite the previous one, reset msg_scroll before
* calling filemess().
*/
}
add_quoted_fname((char *)IObuff, IOSIZE - 80, buf, (const char *)name);
xstrlcat((char *)IObuff, (const char *)s, IOSIZE);
// 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;
if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
msg_scroll = FALSE;
@ -428,7 +424,7 @@ readfile (
}
if (!read_buffer && !read_stdin) {
perm = os_getperm(fname);
perm = os_getperm((const char *)fname);
#ifdef UNIX
// On Unix it is possible to read a directory, so we have to
// check for it before os_open().
@ -614,10 +610,12 @@ readfile (
return FAIL;
}
#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
&& curbuf->b_ml.ml_mfp->mf_fname != NULL)
(void)os_setperm(curbuf->b_ml.ml_mfp->mf_fname, (long)swap_mode);
&& curbuf->b_ml.ml_mfp->mf_fname != NULL) {
(void)os_setperm((const char *)curbuf->b_ml.ml_mfp->mf_fname,
(long)swap_mode);
}
#endif
}
@ -1798,8 +1796,8 @@ failed:
}
if (!filtering && !(flags & READ_DUMMY)) {
msg_add_fname(curbuf, sfname); /* fname in IObuff with quotes */
c = FALSE;
add_quoted_fname((char *)IObuff, IOSIZE, curbuf, (const char *)sfname);
c = false;
#ifdef UNIX
# ifdef S_ISFIFO
@ -2256,9 +2254,16 @@ buf_write (
int len;
linenr_T lnum;
long nchars;
char_u *errmsg = NULL;
int errmsg_allocated = FALSE;
char_u *errnum = NULL;
#define SET_ERRMSG_NUM(num, msg) \
errnum = num, errmsg = msg, errmsgarg = 0
#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 smallbuf[SMBUFSIZE];
char_u *backup_ext;
@ -2280,7 +2285,6 @@ buf_write (
/* writing everything */
int whole = (start == 1 && end == buf->b_ml.ml_line_count);
linenr_T old_line_count = buf->b_ml.ml_line_count;
int attr;
int fileformat;
int write_bin;
struct bw_info write_info; /* info for buf_write_bytes() */
@ -2575,13 +2579,11 @@ buf_write (
perm = file_info_old.stat.st_mode;
if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */
if (S_ISDIR(file_info_old.stat.st_mode)) {
errnum = (char_u *)"E502: ";
errmsg = (char_u *)_("is a directory");
SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
}
if (os_nodetype((char *)fname) != NODE_WRITABLE) {
errnum = (char_u *)"E503: ";
errmsg = (char_u *)_("is not a file or writable device");
SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
goto fail;
}
/* 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);
if (c == NODE_OTHER) {
errnum = (char_u *)"E503: ";
errmsg = (char_u *)_("is not a file or writable device");
SET_ERRMSG_NUM("E503", _("is not a file or writable device"));
goto fail;
}
if (c == NODE_WRITABLE) {
@ -2606,12 +2607,11 @@ buf_write (
newfile = TRUE;
perm = -1;
} else {
perm = os_getperm(fname);
if (perm < 0)
newfile = TRUE;
else if (os_isdir(fname)) {
errnum = (char_u *)"E502: ";
errmsg = (char_u *)_("is a directory");
perm = os_getperm((const char *)fname);
if (perm < 0) {
newfile = true;
} else if (os_isdir(fname)) {
SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
}
if (overwriting) {
@ -2630,11 +2630,9 @@ buf_write (
if (!forceit && file_readonly) {
if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
errnum = (char_u *)"E504: ";
errmsg = (char_u *)_(err_readonly);
SET_ERRMSG_NUM("E504", _(err_readonly));
} else {
errnum = (char_u *)"E505: ";
errmsg = (char_u *)_("is read-only (add ! to override)");
SET_ERRMSG_NUM("E505", _("is read-only (add ! to override)"));
}
goto fail;
}
@ -2870,9 +2868,9 @@ buf_write (
xfree(backup);
backup = NULL;
} else {
/* set file protection same as original file, but
* strip s-bit */
(void)os_setperm(backup, perm & 0777);
// set file protection same as original file, but
// strip s-bit.
(void)os_setperm((const char *)backup, perm & 0777);
#ifdef UNIX
/*
@ -2883,7 +2881,8 @@ buf_write (
*/
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_setperm(backup, (perm & 0707) | ((perm & 07) << 3));
os_setperm((const char *)backup,
(perm & 0707) | ((perm & 07) << 3));
}
# ifdef HAVE_SELINUX
mch_copy_sec(fname, backup);
@ -2901,23 +2900,27 @@ buf_write (
while ((write_info.bw_len = read_eintr(fd, copybuf,
BUFSIZE)) > 0) {
if (buf_write_bytes(&write_info) == FAIL) {
errmsg = (char_u *)_(
"E506: Can't write to backup file (add ! to override)");
SET_ERRMSG(_(
"E506: Can't write to backup file (add ! to override)"));
break;
}
os_breakcheck();
if (got_int) {
errmsg = (char_u *)_(e_interr);
SET_ERRMSG(_(e_interr));
break;
}
}
if (close(bfd) < 0 && errmsg == NULL)
errmsg = (char_u *)_(
"E507: Close error for backup file (add ! to override)");
if (write_info.bw_len < 0)
errmsg = (char_u *)_(
"E508: Can't read file for backup (add ! to override)");
int error;
if ((error = os_close(bfd)) != 0 && errmsg == NULL) {
SET_ERRMSG_ARG(_("E507: Close error for backup file "
"(add ! to override): %s"),
error);
}
if (write_info.bw_len < 0) {
SET_ERRMSG(_(
"E508: Can't read file for backup (add ! to override)"));
}
#ifdef UNIX
set_file_time(backup,
file_info_old.stat.st_atim.tv_sec,
@ -2934,18 +2937,19 @@ buf_write (
}
}
nobackup:
close(fd); /* ignore errors for closing read file */
os_close(fd); // Ignore errors for closing read file.
xfree(copybuf);
if (backup == NULL && errmsg == NULL)
errmsg = (char_u *)_(
"E509: Cannot create backup file (add ! to override)");
/* ignore errors when forceit is TRUE */
if (backup == NULL && errmsg == NULL) {
SET_ERRMSG(_(
"E509: Cannot create backup file (add ! to override)"));
}
// Ignore errors when forceit is TRUE.
if ((some_error || errmsg != NULL) && !forceit) {
retval = FAIL;
goto fail;
}
errmsg = NULL;
SET_ERRMSG(NULL);
} else {
char_u *dirp;
char_u *p;
@ -2960,8 +2964,7 @@ nobackup:
* anyway, thus we need an extra check here.
*/
if (file_readonly && vim_strchr(p_cpo, CPO_FWRITE) != NULL) {
errnum = (char_u *)"E504: ";
errmsg = (char_u *)_(err_readonly);
SET_ERRMSG_NUM("E504", _(err_readonly));
goto fail;
}
@ -3025,7 +3028,7 @@ nobackup:
}
}
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;
}
}
@ -3037,8 +3040,8 @@ nobackup:
&& file_info_old.stat.st_uid == getuid()
&& vim_strchr(p_cpo, CPO_FWRITE) == NULL) {
perm |= 0200;
(void)os_setperm(fname, perm);
made_writable = TRUE;
(void)os_setperm((const char *)fname, perm);
made_writable = true;
}
#endif
@ -3066,7 +3069,7 @@ nobackup:
&& !(exiting && backup != NULL)) {
ml_preserve(buf, FALSE);
if (got_int) {
errmsg = (char_u *)_(e_interr);
SET_ERRMSG(_(e_interr));
goto restore_backup;
}
}
@ -3137,8 +3140,8 @@ nobackup:
*/
if (*p_ccv != NUL) {
wfname = vim_tempname();
if (wfname == NULL) { /* Can't write without a tempfile! */
errmsg = (char_u *)_("E214: Can't find temp file for writing");
if (wfname == NULL) { // Can't write without a tempfile!
SET_ERRMSG(_("E214: Can't find temp file for writing"));
goto restore_backup;
}
}
@ -3150,8 +3153,8 @@ nobackup:
&& wfname == fname
) {
if (!forceit) {
errmsg = (char_u *)_(
"E213: Cannot convert (add ! to write without conversion)");
SET_ERRMSG(_(
"E213: Cannot convert (add ! to write without conversion)"));
goto restore_backup;
}
notconverted = TRUE;
@ -3186,11 +3189,10 @@ nobackup:
if ((!newfile && os_fileinfo_hardlinks(&file_info) > 1)
|| (os_fileinfo_link((char *)fname, &file_info)
&& !os_fileinfo_id_equal(&file_info, &file_info_old))) {
errmsg = (char_u *)_("E166: Can't open linked file for writing");
} else
SET_ERRMSG(_("E166: Can't open linked file for writing"));
} else {
#endif
{
errmsg = (char_u *)_("E212: Can't open file for writing");
SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd);
if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
&& perm >= 0) {
#ifdef UNIX
@ -3208,7 +3210,9 @@ nobackup:
os_remove((char *)wfname);
continue;
}
#ifdef UNIX
}
#endif
}
restore_backup:
@ -3250,7 +3254,7 @@ restore_backup:
xfree(wfname);
goto fail;
}
errmsg = NULL;
SET_ERRMSG(NULL);
write_info.bw_fd = fd;
@ -3370,7 +3374,6 @@ restore_backup:
nchars += len;
}
#if defined(UNIX)
// 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
// 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
// (could be a pipe).
// If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
if (p_fs && os_fsync(fd) != 0 && !device) {
errmsg = (char_u *)_("E667: Fsync failed");
int error;
if (p_fs && (error = os_fsync(fd)) != 0 && !device) {
SET_ERRMSG_ARG(_("E667: Fsync failed: %s"), error);
end = 0;
}
#endif
#ifdef HAVE_SELINUX
/* 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_gid != 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 */
(void)os_setperm(wfname, perm);
if (perm >= 0) { // Set permission again, may have changed.
(void)os_setperm((const char *)wfname, perm);
}
}
buf_set_file_id(buf);
} else if (!buf->file_id_valid) {
@ -3412,8 +3416,8 @@ restore_backup:
}
#endif
if (close(fd) != 0) {
errmsg = (char_u *)_("E512: Close failed");
if ((error = os_close(fd)) != 0) {
SET_ERRMSG_ARG(_("E512: Close failed: %s"), error);
end = 0;
}
@ -3421,8 +3425,9 @@ restore_backup:
if (made_writable)
perm &= ~0200; /* reset 'w' bit for security reasons */
#endif
if (perm >= 0) /* set perm. of new file same as old file */
(void)os_setperm(wfname, perm);
if (perm >= 0) { // Set perm. of new file same as old file.
(void)os_setperm((const char *)wfname, perm);
}
#ifdef HAVE_ACL
/* Probably need to set the ACL before changing the user (can't set the
* ACL on a file the user doesn't own). */
@ -3449,21 +3454,24 @@ restore_backup:
if (end == 0) {
if (errmsg == NULL) {
if (write_info.bw_conv_error) {
if (write_info.bw_conv_error_lnum == 0)
errmsg = (char_u *)_(
"E513: write error, conversion failed (make 'fenc' empty to override)");
else {
errmsg_allocated = TRUE;
errmsg = xmalloc(300);
vim_snprintf((char *)errmsg, 300,
_("E513: write error, conversion failed in line %" PRId64
if (write_info.bw_conv_error_lnum == 0) {
SET_ERRMSG(_(
"E513: write error, conversion failed "
"(make 'fenc' empty to override)"));
} else {
errmsg_allocated = true;
SET_ERRMSG(xmalloc(300));
vim_snprintf(
errmsg, 300,
_("E513: write error, conversion failed in line %" PRIdLINENR
" (make 'fenc' empty to override)"),
(int64_t)write_info.bw_conv_error_lnum);
write_info.bw_conv_error_lnum);
}
} else if (got_int)
errmsg = (char_u *)_(e_interr);
else
errmsg = (char_u *)_("E514: write error (file system full?)");
} else if (got_int) {
SET_ERRMSG(_(e_interr));
} else {
SET_ERRMSG(_("E514: write error (file system full?)"));
}
}
/*
@ -3518,8 +3526,8 @@ restore_backup:
fname = sfname; /* use shortname now, for the messages */
#endif
if (!filtering) {
msg_add_fname(buf, fname); /* put fname in IObuff with quotes */
c = FALSE;
add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname);
c = false;
if (write_info.bw_conv_error) {
STRCAT(IObuff, _(" CONVERSION ERROR"));
c = TRUE;
@ -3628,7 +3636,7 @@ restore_backup:
close(empty_fd);
}
if (org != NULL) {
os_setperm((char_u *)org, os_getperm(fname) & 0777);
os_setperm(org, os_getperm((const char *)fname) & 0777);
xfree(org);
}
}
@ -3668,33 +3676,32 @@ nofail:
#endif
if (errmsg != NULL) {
int numlen = errnum != NULL ? (int)STRLEN(errnum) : 0;
attr = hl_attr(HLF_E); /* set highlight for error messages */
msg_add_fname(buf,
// - 100 to save some space for further error message
#ifndef UNIX
sfname
add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)sfname);
#else
fname
add_quoted_fname((char *)IObuff, IOSIZE - 100, buf, (const char *)fname);
#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) {
STRMOVE(IObuff + numlen, IObuff);
memmove(IObuff, errnum, (size_t)numlen);
if (errmsgarg != 0) {
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);
emsg(IObuff);
if (errmsg_allocated)
if (errmsg_allocated) {
xfree(errmsg);
}
retval = FAIL;
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"),
attr | MSG_HIST);
attr | MSG_HIST);
MSG_PUTS_ATTR(_(
"don't quit the editor until the file is successfully written!"),
attr | MSG_HIST);
@ -3754,6 +3761,9 @@ nofail:
got_int |= prev_got_int;
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;
}
/*
* Put file name into IObuff with quotes.
*/
void msg_add_fname(buf_T *buf, char_u *fname)
/// Put file name into the specified buffer with quotes
///
/// Replaces home directory at the start with `~`.
///
/// @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)
fname = (char_u *)"-stdin-";
home_replace(buf, fname, IObuff + 1, IOSIZE - 4, TRUE);
IObuff[0] = '"';
STRCAT(IObuff, "\" ");
if (fname == NULL) {
fname = "-stdin-";
}
ret_buf[0] = '"';
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.
@ -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
/// function will (attempts to?) copy the file across if rename fails -- webb
//
///
/// @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_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.
*/
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;
else
} else {
return 0;
}
}
// 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.
*/
perm = os_getperm(from);
perm = os_getperm((const char *)from);
#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);
#endif
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\"");
to = from;
}
#ifndef UNIX /* for Unix os_open() already set the permission */
os_setperm(to, perm);
#ifndef UNIX // For Unix os_open() already set the permission.
os_setperm((const char *)to, perm);
#endif
#ifdef HAVE_ACL
mch_set_acl(to, acl);
@ -5200,7 +5221,7 @@ void forward_slash(char_u *fname)
{
char_u *p;
if (path_with_url(fname)) {
if (path_with_url((const char *)fname)) {
return;
}
for (p = fname; *p != NUL; p++) {
@ -5261,7 +5282,7 @@ static void vim_maketempdir(void)
/// Delete "name" and everything in it, recursively.
/// @param name The path which should be 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;
@ -5275,7 +5296,7 @@ int delete_recursive(char_u *name)
EW_DIR | EW_FILE | EW_SILENT | EW_ALLLINKS
| EW_DODOT | EW_EMPTYOK) == OK) {
for (int i = 0; i < file_count; i++) {
if (delete_recursive(files[i]) != 0) {
if (delete_recursive((const char *)files[i]) != 0) {
result = -1;
}
}
@ -5285,9 +5306,9 @@ int delete_recursive(char_u *name)
}
xfree(exp);
os_rmdir((char *)name);
os_rmdir(name);
} else {
result = os_remove((char *)name) == 0 ? 0 : -1;
result = os_remove(name) == 0 ? 0 : -1;
}
return result;
@ -5299,7 +5320,7 @@ void vim_deltempdir(void)
if (vim_tempdir != NULL) {
// remove the trailing path separator
path_tail(vim_tempdir)[-1] = NUL;
delete_recursive(vim_tempdir);
delete_recursive((const char *)vim_tempdir);
xfree(vim_tempdir);
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
* starts at another line, update nested folds to keep
* their position, compensating for the new fd_top. */
if (fp->fd_top >= startlnum && fp->fd_top != firstlnum) {
if (fp->fd_top > firstlnum)
/* like lines are inserted */
if (fp->fd_top == firstlnum) {
// We have found a fold beginning exactly where we want one.
} 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,
(linenr_T)0, (linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum), 0L);
else
/* like lines are deleted */
(linenr_T)0, (linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum), 0L);
} else {
// Will move fold down, move nested folds relatively up.
foldMarkAdjustRecurse(&fp->fd_nested,
(linenr_T)0,
(long)(firstlnum - fp->fd_top - 1),
(linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum));
(linenr_T)0,
(long)(firstlnum - fp->fd_top - 1),
(linenr_T)MAXLNUM,
(long)(fp->fd_top - firstlnum));
}
fp->fd_len += fp->fd_top - firstlnum;
fp->fd_top = firstlnum;
fold_changed = TRUE;
} else if (flp->start != 0 && lvl == level
&& fp->fd_top != firstlnum) {
/* Existing fold that includes startlnum must stop
* if we find the start of a new fold at the same
* level. Split it. Delete contained folds at
* this point to split them too. */
foldRemove(&fp->fd_nested, flp->lnum - fp->fd_top,
flp->lnum - fp->fd_top);
fold_changed = true;
} else if ((flp->start != 0 && lvl == level)
|| (firstlnum != startlnum)) {
// Before there was a fold spanning from above startlnum to below
// firstlnum. This fold is valid above startlnum (because we are
// not updating that range), but there is now a break in it.
// If the break is because we are now forced to start a new fold
// at the level "level" at line fline->lnum, then we need to
// 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);
foldSplit(gap, i, flp->lnum, flp->lnum - 1);
foldSplit(gap, i, breakstart, breakend - 1);
fp = (fold_T *)gap->ga_data + i + 1;
/* If using the "marker" or "syntax" method, we
* 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)
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;
}
if (fp->fd_top >= startlnum) {

View File

@ -235,19 +235,18 @@ char_u *get_inserted(void)
return get_buffcont(&redobuff, FALSE);
}
/*
* Add string "s" after the current block of buffer "buf".
* K_SPECIAL and CSI should have been escaped already.
*/
static void
add_buff (
buffheader_T *buf,
char_u *s,
ssize_t slen // length of "s" or -1
)
/// Add string after the current block of the given buffer
///
/// K_SPECIAL and CSI should have been escaped already.
///
/// @param[out] buf Buffer to add to.
/// @param[in] s String to add.
/// @param[in] slen String length or -1 for NUL-terminated string.
static void add_buff(buffheader_T *const buf, const char *const s,
ptrdiff_t slen)
{
if (slen < 0) {
slen = (ssize_t)STRLEN(s);
slen = (ptrdiff_t)strlen(s);
}
if (slen == 0) { // don't add empty strings
return;
@ -292,9 +291,8 @@ add_buff (
*/
static void add_num_buff(buffheader_T *buf, long n)
{
char_u number[32];
sprintf((char *)number, "%" PRId64, (int64_t)n);
char number[32];
snprintf(number, sizeof(number), "%ld", n);
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)
{
char_u bytes[MB_MAXBYTES + 1];
char bytes[MB_MAXBYTES + 1];
int len;
int i;
char_u temp[4];
if (IS_SPECIAL(c))
if (IS_SPECIAL(c)) {
len = 1;
else
len = (*mb_char2bytes)(c, bytes);
for (i = 0; i < len; ++i) {
if (!IS_SPECIAL(c))
c = bytes[i];
} else {
len = (*mb_char2bytes)(c, (char_u *)bytes);
}
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) {
/* translate special key code into three byte sequence */
temp[0] = K_SPECIAL;
temp[1] = (char_u)K_SECOND(c);
temp[2] = (char_u)K_THIRD(c);
// Translate special key code into three byte sequence.
temp[0] = (char)K_SPECIAL;
temp[1] = (char)K_SECOND(c);
temp[2] = (char)K_THIRD(c);
temp[3] = NUL;
} else {
temp[0] = (char_u)c;
temp[0] = (char)c;
temp[1] = NUL;
}
add_buff(buf, temp, -1L);
@ -479,16 +479,14 @@ static int save_level = 0;
void saveRedobuff(void)
{
char_u *s;
if (save_level++ == 0) {
save_redobuff = redobuff;
redobuff.bh_first.b_next = NULL;
save_old_redobuff = old_redobuff;
old_redobuff.bh_first.b_next = NULL;
/* Make a copy, so that ":normal ." in a function works. */
s = get_buffcont(&save_redobuff, FALSE);
// Make a copy, so that ":normal ." in a function works.
char *const s = (char *)get_buffcont(&save_redobuff, false);
if (s != NULL) {
add_buff(&redobuff, s, -1L);
xfree(s);
@ -514,10 +512,11 @@ void restoreRedobuff(void)
* Append "s" to the redo buffer.
* K_SPECIAL and CSI should already have been escaped.
*/
void AppendToRedobuff(char_u *s)
void AppendToRedobuff(const char *s)
{
if (!block_redo)
add_buff(&redobuff, s, -1L);
if (!block_redo) {
add_buff(&redobuff, (const char *)s, -1L);
}
}
/*
@ -530,44 +529,47 @@ AppendToRedobuffLit (
int len /* length of "str" or -1 for up to the NUL */
)
{
char_u *s = str;
int c;
char_u *start;
if (block_redo)
if (block_redo) {
return;
}
while (len < 0 ? *s != NUL : s - str < len) {
/* Put a string of normal characters in the redo buffer (that's
* faster). */
start = s;
while (*s >= ' ' && *s < DEL && (len < 0 || s - str < len))
++s;
const char *s = (const char *)str;
while (len < 0 ? *s != NUL : s - (const char *)str < len) {
// Put a string of normal characters in the redo buffer (that's
// faster).
const char *start = 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
* typed next. */
if (*s == NUL && (s[-1] == '0' || s[-1] == '^'))
--s;
if (s > start)
// Don't put '0' or '^' as last character, just in case a CTRL-D is
// typed next.
if (*s == NUL && (s[-1] == '0' || s[-1] == '^')) {
s--;
}
if (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;
}
/* Handle a special or multibyte character. */
if (has_mbyte)
/* Handle composing chars separately. */
c = mb_cptr2char_adv(&s);
else
c = *s++;
if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^')))
// Handle a special or multibyte character.
// Composing chars separately are handled separately.
const int c = (has_mbyte
? mb_cptr2char_adv((const char_u **)&s)
: (uint8_t)(*s++));
if (c < ' ' || c == DEL || (*s == NUL && (c == '0' || c == '^'))) {
add_char_buff(&redobuff, Ctrl_V);
}
/* CTRL-V '0' must be inserted as CTRL-V 048 */
if (*s == NUL && c == '0')
add_buff(&redobuff, (char_u *)"048", 3L);
else
// CTRL-V '0' must be inserted as CTRL-V 048.
if (*s == NUL && c == '0') {
add_buff(&redobuff, "048", 3L);
} else {
add_char_buff(&redobuff, c);
}
}
}
@ -594,19 +596,19 @@ void AppendNumberToRedobuff(long n)
* Append string "s" to the stuff buffer.
* CSI and K_SPECIAL must already have been escaped.
*/
void stuffReadbuff(char_u *s)
void stuffReadbuff(const char *s)
{
add_buff(&readbuf1, s, -1L);
}
/// Append string "s" to the redo stuff buffer.
/// @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);
}
void stuffReadbuffLen(char_u *s, long len)
void stuffReadbuffLen(const char *s, long len)
{
add_buff(&readbuf1, s, len);
}
@ -616,19 +618,18 @@ void stuffReadbuffLen(char_u *s, long len)
* escaping other K_SPECIAL and CSI bytes.
* Change CR, LF and ESC into a space.
*/
void stuffReadbuffSpec(char_u *s)
void stuffReadbuffSpec(const char *s)
{
int c;
while (*s != NUL) {
if (*s == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
/* Insert special key literally. */
stuffReadbuffLen(s, 3L);
if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
// Insert special key literally.
stuffReadbuffLen(s, 3);
s += 3;
} else {
c = mb_ptr2char_adv(&s);
if (c == CAR || c == NL || c == ESC)
int c = mb_ptr2char_adv((const char_u **)&s);
if (c == CAR || c == NL || c == ESC) {
c = ' ';
}
stuffcharReadbuff(c);
}
}
@ -747,8 +748,8 @@ int start_redo(long count, int old_redo)
/* copy the buffer name, if present */
if (c == '"') {
add_buff(&readbuf2, (char_u *)"\"", 1L);
c = read_redo(FALSE, old_redo);
add_buff(&readbuf2, "\"", 1L);
c = read_redo(false, old_redo);
/* if a numbered buffer is used, increment the number */
if (c >= '1' && c < '9')
@ -1091,21 +1092,19 @@ static void gotchars(char_u *chars, size_t len)
{
char_u *s = chars;
int c;
char_u buf[2];
// remember how many chars were last recorded
if (Recording) {
last_recorded_len += len;
}
buf[1] = NUL;
while (len--) {
// Handle one byte at a time; no translation to be done.
c = *s++;
updatescript(c);
if (Recording) {
buf[0] = (char_u)c;
char buf[2] = { (char)c, NUL };
add_buff(&recordbuff, buf, 1L);
}
}
@ -1881,9 +1880,8 @@ static int vgetorpeek(int advance)
(size_t)(mlen - typebuf.tb_maplen));
}
del_typebuf(mlen, 0); /* remove the chars */
set_option_value((char_u *)"paste",
(long)!p_paste, NULL, 0);
del_typebuf(mlen, 0); // Remove the chars.
set_option_value("paste", !p_paste, NULL, 0);
if (!(State & INSERT)) {
msg_col = 0;
msg_row = (int)Rows - 1;
@ -1905,7 +1903,7 @@ static int vgetorpeek(int advance)
}
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
// matches at least what the matching mapping matched
keylen = 0;
@ -3219,82 +3217,99 @@ showmap (
ui_flush(); /* show one line at a time */
}
/*
* 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.
*/
int map_to_exists(char_u *str, char_u *modechars, int abbr)
/// Check if a map exists that has given string in the rhs
///
/// Also checks mappings local to the current buffer.
///
/// @param[in] str String which mapping must have in the rhs. Termcap codes
/// 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;
char_u *rhs;
char_u *buf;
int retval;
rhs = replace_termcodes(str, STRLEN(str), &buf, false, true, false,
CPO_TO_CPO_FLAGS);
char_u *buf;
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)
mode |= NORMAL;
if (vim_strchr(modechars, 'v') != NULL)
mode |= VISUAL + SELECTMODE;
if (vim_strchr(modechars, 'x') != NULL)
mode |= VISUAL;
if (vim_strchr(modechars, 's') != NULL)
mode |= SELECTMODE;
if (vim_strchr(modechars, 'o') != NULL)
mode |= OP_PENDING;
if (vim_strchr(modechars, 'i') != NULL)
mode |= INSERT;
if (vim_strchr(modechars, 'l') != NULL)
mode |= LANGMAP;
if (vim_strchr(modechars, 'c') != NULL)
mode |= CMDLINE;
#define MAPMODE(mode, modechars, chr, modeflags) \
do { \
if (strchr(modechars, chr) != NULL) { \
mode |= modeflags; \
} \
} while (0)
MAPMODE(mode, modechars, 'n', NORMAL);
MAPMODE(mode, modechars, 'v', VISUAL|SELECTMODE);
MAPMODE(mode, modechars, 'x', VISUAL);
MAPMODE(mode, modechars, 's', SELECTMODE);
MAPMODE(mode, modechars, 'o', OP_PENDING);
MAPMODE(mode, modechars, 'i', INSERT);
MAPMODE(mode, modechars, 'l', LANGMAP);
MAPMODE(mode, modechars, 'c', CMDLINE);
#undef MAPMODE
retval = map_to_exists_mode(rhs, mode, abbr);
retval = map_to_exists_mode((const char *)rhs, mode, abbr);
xfree(buf);
return retval;
}
/*
* Return TRUE if a map exists that has "str" in the rhs for mode "mode".
* Also checks mappings local to the current buffer.
*/
int map_to_exists_mode(char_u *rhs, int mode, int abbr)
/// Check if a map exists that has given string in the rhs
///
/// Also checks mappings local to the current buffer.
///
/// @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;
int hash;
int expand_buffer = FALSE;
bool expand_buffer = false;
validate_maphash();
/* Do it twice: once for global maps and once for local maps. */
for (;; ) {
for (hash = 0; hash < 256; ++hash) {
// Do it twice: once for global maps and once for local maps.
for (;;) {
for (hash = 0; hash < 256; hash++) {
if (abbr) {
if (hash > 0) /* there is only one abbr list */
if (hash > 0) { // There is only one abbr list.
break;
if (expand_buffer)
}
if (expand_buffer) {
mp = curbuf->b_first_abbr;
else
} else {
mp = first_abbr;
} else if (expand_buffer)
}
} else if (expand_buffer) {
mp = curbuf->b_maphash[hash];
else
} else {
mp = maphash[hash];
}
for (; mp; mp = mp->m_next) {
if ((mp->m_mode & mode)
&& strstr((char *)mp->m_str, (char *)rhs) != NULL)
return TRUE;
&& strstr((char *)mp->m_str, rhs) != NULL) {
return true;
}
}
}
if (expand_buffer)
if (expand_buffer) {
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/types.h"
#include "nvim/event/loop.h"
#include "nvim/os/os_defs.h"
#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
// 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
# define _PATHSEPSTR "\\"
#else
@ -473,6 +464,7 @@ typedef enum {
, HLF_CUL // 'cursurline'
, HLF_MC // 'colorcolumn'
, HLF_QFL // selected quickfix line
, HLF_0 // Whitespace
, HLF_COUNT // MUST be the last one
} hlf_T;
@ -481,7 +473,7 @@ typedef enum {
#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', \
'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_user[9]; /* User[1-9] attributes */
@ -1208,6 +1200,7 @@ EXTERN char_u e_dirnotf[] INIT(= N_(
"E919: Directory not found in '%s': \"%s\""));
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_float_as_string[] INIT(= N_("E806: using Float as a String"));
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 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
EXTERN bool embedded_mode INIT(= false);
@ -1255,7 +1243,7 @@ typedef enum {
kCdScopeInvalid = -1,
kCdScopeWindow, ///< Affects one window.
kCdScopeTab, ///< Affects one tab page.
kCdScopeGlobal, ///< Affects the entire instance of Neovim.
kCdScopeGlobal, ///< Affects the entire Nvim instance.
} CdScope;
#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;
uint32_t fg_color;
char *color;
pattr->bold = (highlight_has_attr(hl_id, HL_BOLD, 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);
{
color = (char *)highlight_color(hl_id, (char_u *)"fg", modec);
if (color == NULL)
const char *color = highlight_color(hl_id, "fg", modec);
if (color == NULL) {
colorindex = 0;
else
} else {
colorindex = atoi(color);
}
if (colorindex >= 0 && colorindex < t_colors)
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.
/// WARNING: Returned pointer becomes invalid as soon as the hash table
/// 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));
}
@ -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
/// 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));
}
@ -115,7 +116,7 @@ hashitem_T *hash_find_len(hashtab_T *ht, const char *key, const size_t len)
/// used for that key.
/// WARNING: Returned pointer becomes invalid as soon as the hash table
/// 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 hash_T hash)
{

View File

@ -70,6 +70,25 @@ typedef struct hashtable_S {
hashitem_T ht_smallarray[HT_INIT_SIZE]; /// initial array
} 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
# include "hashtab.h.generated.h"
#endif

View File

@ -140,31 +140,30 @@ char_u *get_cscope_name(expand_T *xp, int idx)
/*
* 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_pattern = arg;
expand_what = (cmdidx == CMD_scscope)
? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD;
xp->xp_pattern = (char_u *)arg;
expand_what = ((cmdidx == CMD_scscope)
? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD);
/* (part of) subcommand already typed */
if (*arg != NUL) {
p = skiptowhite(arg);
if (*p != NUL) { /* past first word */
xp->xp_pattern = skipwhite(p);
if (*skiptowhite(xp->xp_pattern) != NUL)
const char *p = (const char *)skiptowhite((const char_u *)arg);
if (*p != NUL) { // Past first word.
xp->xp_pattern = skipwhite((const char_u *)p);
if (*skiptowhite(xp->xp_pattern) != NUL) {
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;
else if (STRNICMP(arg, "kill", p - arg) == 0)
} else if (STRNICMP(arg, "kill", p - arg) == 0) {
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;
else
} else {
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, '(');
if (paren != NULL) {
ptrdiff_t delim_len = paren - delim;
const ptrdiff_t delim_len = paren - delim;
for (p += 3; *p; ++p)
if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0

View File

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

View File

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

View File

@ -62,7 +62,7 @@ int setmark(int c)
/// Free fmark_T item
void free_fmark(fmark_T fm)
{
dict_unref(fm.additional_data);
tv_dict_unref(fm.additional_data);
}
/// Free xfmark_T item
@ -1431,3 +1431,26 @@ void free_all_marks(void)
memset(&namedfm[0], 0, sizeof(namedfm));
}
#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
#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)
#define SET_XFMARK(xfmarkp_, mark_, fnum_, fname_) \

View File

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

View File

@ -50,6 +50,7 @@
#include "nvim/strings.h"
#include "nvim/os/os.h"
#include "nvim/arabic.h"
#include "nvim/mark.h"
typedef struct {
int rangeStart;
@ -375,16 +376,18 @@ void remove_bom(char_u *s)
*/
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 (p[0] == NUL || ascii_iswhite(p[0]))
if (p[0] == NUL || ascii_iswhite(p[0])) {
return 0;
if (vim_iswordc_buf(p[0], buf))
}
if (vim_iswordc_tab(p[0], chartab)) {
return 2;
}
return 1;
}
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
* "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;
@ -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.
* Note: composing characters are skipped!
*/
int mb_ptr2char_adv(char_u **pp)
int mb_ptr2char_adv(const char_u **const pp)
{
int c;
@ -635,7 +638,7 @@ int mb_ptr2char_adv(char_u **pp)
* Get character at **pp and advance *pp to the next character.
* 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;
@ -1230,7 +1233,8 @@ bool utf_isupper(int 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;
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 */
#endif
/// Reassigns `strw` to a new, allocated pointer to a UTF16 string.
int utf8_to_utf16(const char *str, WCHAR **strw)
FUNC_ATTR_NONNULL_ALL
{
@ -1341,40 +1346,40 @@ int utf8_to_utf16(const char *str, WCHAR **strw)
return 0;
}
/// Reassigns `str` to a new, allocated pointer to a UTF8 string.
int utf16_to_utf8(const WCHAR *strw, char **str)
FUNC_ATTR_NONNULL_ALL
{
// Compute the space required to store the string as UTF-8.
ssize_t utf8_len = WideCharToMultiByte(CP_UTF8,
0,
strw,
-1,
NULL,
0,
NULL,
NULL);
DWORD utf8_len = WideCharToMultiByte(CP_UTF8,
0,
strw,
-1,
NULL,
0,
NULL,
NULL);
if (utf8_len == 0) {
return GetLastError();
}
ssize_t buf_sz = utf8_len * sizeof(char);
char *buf = xmalloc(buf_sz);
char *pos = buf;
*str = xmalloc(utf8_len);
// Convert string to UTF-8.
int r = WideCharToMultiByte(CP_UTF8,
0,
strw,
-1,
pos,
utf8_len,
NULL,
NULL);
assert(r == utf8_len);
if (r != utf8_len) {
EMSG2("WideCharToMultiByte failed: %d", r);
// Convert to UTF-8.
utf8_len = WideCharToMultiByte(CP_UTF8,
0,
strw,
-1,
*str,
utf8_len,
NULL,
NULL);
if (utf8_len == 0) {
free(*str);
*str = NULL;
return GetLastError();
}
*str = pos;
(*str)[utf8_len] = '\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
* 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);
}
/* We need to call mb_stricmp() even when we aren't dealing with a multi-byte
* encoding because mb_stricmp() takes care of all ascii and non-ascii
* encodings, including characters with umlauts in latin1, etc., while
* STRICMP() only handles the system locale version, which often does not
* handle non-ascii properly. */
int mb_stricmp(char_u *s1, char_u *s2)
/// Compare strings case-insensitively
///
/// @note We need to call mb_stricmp() even when we aren't dealing with
/// a multi-byte encoding because mb_stricmp() takes care of all ASCII and
/// non-ascii encodings, including characters with umlauts in latin1,
/// 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)
{
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;
}
mark_mb_adjustpos(curbuf, &curwin->w_cursor);
}
/// Checks and adjusts cursor column. Not mode-dependent.
/// @see check_cursor_col_win
///
/// @param win Places cursor on a valid column for this window.
void mb_check_adjust_col(win_T *win)
/// @param win_ Places cursor on a valid column for this window.
void mb_check_adjust_col(void *win_)
{
win_T *win = (win_T *)win_;
colnr_T oldcol = win->w_cursor.col;
// 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.
* 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,
size_t *unconvlenp, size_t *resultlenp)
static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
size_t slen, size_t *unconvlenp, size_t *resultlenp)
{
const char *from;
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.
* 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);
}
@ -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
* 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)
{
char_u *retval = NULL;

View File

@ -2,6 +2,11 @@
#define NVIM_MBYTE_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".
@ -40,7 +45,41 @@
#define mb_ptr2char utf_ptr2char
#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
# include "mbyte.h.generated.h"
#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

View File

@ -992,7 +992,7 @@ void ml_recover(void)
if (b0_ff != 0)
set_fileformat(b0_ff - 1, OPT_LOCAL);
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);
}
unchanged(curbuf, TRUE);

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