Merge branch 'master' into rename-execute

This commit is contained in:
ZyX
2017-04-09 19:14:20 +03:00
30 changed files with 341 additions and 493 deletions

View File

@@ -43,11 +43,6 @@ env:
# If this file exists, we know that the cache contains compiled # If this file exists, we know that the cache contains compiled
# dependencies and we can use it. # dependencies and we can use it.
- CACHE_MARKER="$HOME/.cache/nvim-deps/.travis_cache_marker" - CACHE_MARKER="$HOME/.cache/nvim-deps/.travis_cache_marker"
# Test success marker. If this file exists, we know that all tests
# were successful. Required because we only want to update the cache
# if the tests were successful, but don't have this information
# available in before_cache (which is run before after_success).
- SUCCESS_MARKER="$BUILD_DIR/.tests_successful"
# default target name for functional tests # default target name for functional tests
- FUNCTIONALTEST=functionaltest - FUNCTIONALTEST=functionaltest
- CI_TARGET=tests - CI_TARGET=tests

View File

@@ -275,7 +275,6 @@ else()
endif() endif()
add_definitions(-DINCLUDE_GENERATED_DECLARATIONS) add_definitions(-DINCLUDE_GENERATED_DECLARATIONS)
add_definitions(-DHAVE_CONFIG_H)
if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined")

View File

@@ -3,12 +3,15 @@
set -e set -e
set -o pipefail set -o pipefail
CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/suite.sh"
# Don't cache pip's log and selfcheck. # Don't cache pip's log and selfcheck.
rm -rf "${HOME}/.cache/pip/log" rm -rf "${HOME}/.cache/pip/log"
rm -f "${HOME}/.cache/pip/selfcheck.json" rm -f "${HOME}/.cache/pip/selfcheck.json"
# Update the third-party dependency cache only if the build was successful. # Update the third-party dependency cache only if the build was successful.
if [[ -f "${SUCCESS_MARKER}" ]]; then if ended_successfully; then
rm -rf "${HOME}/.cache/nvim-deps" rm -rf "${HOME}/.cache/nvim-deps"
mv "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps" mv "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps"
touch "${CACHE_MARKER}" touch "${CACHE_MARKER}"

View File

@@ -2,11 +2,18 @@
NL="$(printf '\nE')" NL="$(printf '\nE')"
NL="${NL%E}" NL="${NL%E}"
FAILED=0
FAIL_SUMMARY="" FAIL_SUMMARY=""
# Test success marker. If END_MARKER file exists, we know that all tests
# finished. If FAIL_SUMMARY_FILE exists we know that some tests failed, this
# file will contain information about failed tests. Build is considered
# successful if tests ended without any of them failing.
END_MARKER="$BUILD_DIR/.tests_finished"
FAIL_SUMMARY_FILE="$BUILD_DIR/.test_errors"
enter_suite() { enter_suite() {
FAILED=0
rm -f "${END_MARKER}"
local suite_name="$1" local suite_name="$1"
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE}/$suite_name" export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE}/$suite_name"
} }
@@ -19,17 +26,16 @@ exit_suite() {
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE%/*}" export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE%/*}"
if test "x$1" != "x--continue" ; then if test "x$1" != "x--continue" ; then
exit $FAILED exit $FAILED
else
local saved_failed=$FAILED
FAILED=0
return $saved_failed
fi fi
} }
fail() { fail() {
local allow_failure=
if test "x$1" = "x--allow-failure" ; then
shift
allow_failure=A
fi
local test_name="$1" local test_name="$1"
local fail_char="$allow_failure$2" local fail_char="$2"
local message="$3" local message="$3"
: ${fail_char:=F} : ${fail_char:=F}
@@ -37,10 +43,9 @@ fail() {
local full_msg="$fail_char $NVIM_TEST_CURRENT_SUITE|$test_name :: $message" local full_msg="$fail_char $NVIM_TEST_CURRENT_SUITE|$test_name :: $message"
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}" FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}"
echo "${full_msg}" >> "${FAIL_SUMMARY_FILE}"
echo "Failed: $full_msg" echo "Failed: $full_msg"
if test "x$allow_failure" = "x" ; then FAILED=1
FAILED=1
fi
} }
run_test() { run_test() {
@@ -55,6 +60,12 @@ run_test() {
} }
run_test_wd() { run_test_wd() {
local hang_ok=
if test "x$1" = "x--allow-hang" ; then
hang_ok=1
shift
fi
local timeout="$1" local timeout="$1"
test $# -gt 0 && shift test $# -gt 0 && shift
@@ -77,14 +88,13 @@ run_test_wd() {
while test $restarts -gt 0 ; do while test $restarts -gt 0 ; do
: > "${status_file}" : > "${status_file}"
( (
FAILED=0 set -o pipefail
if ! ( ret=0
set -o pipefail if ! eval "$cmd" 2>&1 | tee -a "$output_file" ; then
eval "$cmd" 2>&1 | tee -a "$output_file" ret=1
) ; then
fail "${test_name}" "$@"
fi fi
echo "$FAILED" > "$status_file" echo "$ret" > "$status_file"
exit $ret
) & ) &
local pid=$! local pid=$!
while test "$(stat -c "%s" "$status_file")" -eq 0 ; do while test "$(stat -c "%s" "$status_file")" -eq 0 ; do
@@ -101,7 +111,9 @@ run_test_wd() {
# status file not updated, assuming hang # status file not updated, assuming hang
kill -KILL $pid kill -KILL $pid
if test $restarts -eq 0 ; then if test $restarts -eq 0 ; then
fail "${test_name}" E "Test hang up" if test "x$hang_ok" = "x" ; then
fail "${test_name}" E "Test hang up"
fi
else else
echo "Test ${test_name} hang up, restarting" echo "Test ${test_name} hang up, restarting"
eval "$restart_cmd" eval "$restart_cmd"
@@ -116,6 +128,20 @@ run_test_wd() {
done done
} }
succeeded() { ended_successfully() {
return $FAILED if [[ -f "${FAIL_SUMMARY_FILE}" ]]; then
echo 'Test failed, complete summary:'
cat "${FAIL_SUMMARY_FILE}"
return 1
fi
if ! [[ -f "${END_MARKER}" ]] ; then
echo 'ended_successfully called before end marker was touched'
return 1
fi
return 0
}
end_tests() {
touch "${END_MARKER}"
ended_successfully
} }

View File

@@ -1,4 +1,5 @@
source "${CI_DIR}/common/build.sh" source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/suite.sh"
print_core() { print_core() {
local app="$1" local app="$1"
@@ -40,10 +41,9 @@ check_core_dumps() {
print_core "$app" "$core" print_core "$app" "$core"
fi fi
done done
if test "$app" = quiet ; then if test "$app" != quiet ; then
return 0 fail 'cores' E 'Core dumps found'
fi fi
exit 1
} }
check_logs() { check_logs() {
@@ -62,8 +62,7 @@ check_logs() {
err=1 err=1
done done
if [[ -n "${err}" ]]; then if [[ -n "${err}" ]]; then
echo "Runtime errors detected." fail 'logs' E 'Runtime errors detected.'
exit 1
fi fi
} }
@@ -75,50 +74,53 @@ asan_check() {
check_logs "${1}" "*san.*" check_logs "${1}" "*san.*"
} }
run_unittests() { run_unittests() {(
enter_suite unittests
ulimit -c unlimited ulimit -c unlimited
if ! build_make unittest ; then if ! build_make unittest ; then
check_core_dumps "$(which luajit)" fail 'unittests' F 'Unit tests failed'
exit 1
fi fi
check_core_dumps "$(which luajit)" check_core_dumps "$(which luajit)"
} exit_suite
)}
run_functionaltests() { run_functionaltests() {(
enter_suite functionaltests
ulimit -c unlimited ulimit -c unlimited
if ! build_make ${FUNCTIONALTEST}; then if ! build_make ${FUNCTIONALTEST}; then
asan_check "${LOG_DIR}" fail 'functionaltests' F 'Functional tests failed'
valgrind_check "${LOG_DIR}"
check_core_dumps
exit 1
fi fi
asan_check "${LOG_DIR}" asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}" valgrind_check "${LOG_DIR}"
check_core_dumps check_core_dumps
} exit_suite
)}
run_oldtests() { run_oldtests() {(
enter_suite oldtests
ulimit -c unlimited ulimit -c unlimited
if ! make -C "${TRAVIS_BUILD_DIR}/src/nvim/testdir"; then if ! make -C "${TRAVIS_BUILD_DIR}/src/nvim/testdir"; then
reset reset
asan_check "${LOG_DIR}" fail 'oldtests' F 'Legacy tests failed'
valgrind_check "${LOG_DIR}"
check_core_dumps
exit 1
fi fi
asan_check "${LOG_DIR}" asan_check "${LOG_DIR}"
valgrind_check "${LOG_DIR}" valgrind_check "${LOG_DIR}"
check_core_dumps check_core_dumps
} exit_suite
)}
install_nvim() { install_nvim() {(
build_make install enter_suite 'install_nvim'
if ! build_make install ; then
fail 'install' E 'make install failed'
exit_suite
fi
"${INSTALL_PREFIX}/bin/nvim" --version "${INSTALL_PREFIX}/bin/nvim" --version
"${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' || { "${INSTALL_PREFIX}/bin/nvim" -u NONE -e -c ':help' -c ':qall' || {
echo "Running ':help' in the installed nvim failed." echo "Running ':help' in the installed nvim failed."
echo "Maybe the helptags have not been generated properly." echo "Maybe the helptags have not been generated properly."
exit 1 fail 'help' F 'Failed running :help'
} }
local genvimsynf=syntax/vim/generated.vim local genvimsynf=syntax/vim/generated.vim
@@ -127,24 +129,22 @@ install_nvim() {
cd runtime ; git ls-files | grep -e '.vim$' -e '.ps$' -e '.dict$' -e '.py$' -e '.tutor$' cd runtime ; git ls-files | grep -e '.vim$' -e '.ps$' -e '.dict$' -e '.py$' -e '.tutor$'
) ; do ) ; do
if ! test -e "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then if ! test -e "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then
echo "It appears that $file is not installed." fail 'runtime-install' F "It appears that $file is not installed."
exit 1
fi fi
done done
# Check that generated syntax file has function names, #5060. # Check that generated syntax file has function names, #5060.
local gpat='syn keyword vimFuncName .*eval' local gpat='syn keyword vimFuncName .*eval'
if ! grep -q "$gpat" "${INSTALL_PREFIX}/share/nvim/runtime/$genvimsynf"; then if ! grep -q "$gpat" "${INSTALL_PREFIX}/share/nvim/runtime/$genvimsynf"; then
echo "It appears that $genvimsynf does not contain $gpat." fail 'funcnames' F "It appears that $genvimsynf does not contain $gpat."
exit 1
fi fi
for file in $( for file in $(
cd runtime ; git ls-files | grep -e '.awk$' -e '.sh$' -e '.bat$' cd runtime ; git ls-files | grep -e '.awk$' -e '.sh$' -e '.bat$'
) ; do ) ; do
if ! test -x "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then if ! test -x "${INSTALL_PREFIX}/share/nvim/runtime/$file" ; then
echo "It appears that $file is not installed or is not executable." fail 'not-exe' F "It appears that $file is not installed or is not executable."
exit 1
fi fi
done done
} exit_suite
)}

View File

@@ -20,9 +20,10 @@ csi_clean() {
run_test 'top_make clint-full' clint run_test 'top_make clint-full' clint
run_test 'top_make testlint' testlint run_test 'top_make testlint' testlint
CLICOLOR_FORCE=1 run_test_wd \ CLICOLOR_FORCE=1 run_test_wd \
5s \ --allow-hang \
10s \
'top_make check-single-includes' \ 'top_make check-single-includes' \
'csi_clean' \ 'csi_clean' \
single-includes single-includes
exit_suite end_tests

View File

@@ -27,8 +27,4 @@ run_test run_oldtests
run_test install_nvim run_test install_nvim
if succeeded ; then end_tests
touch "${SUCCESS_MARKER}"
fi
exit_suite

View File

@@ -0,0 +1,2 @@
file(GLOB_RECURSE JSON_FILES *.json)
file(COPY ${JSON_FILES} DESTINATION "${TARGET}")

View File

@@ -4944,8 +4944,8 @@ json_decode({expr}) *json_decode()*
json_encode({expr}) *json_encode()* json_encode({expr}) *json_encode()*
Convert {expr} into a JSON string. Accepts Convert {expr} into a JSON string. Accepts
|msgpack-special-dict| as the input. Will not convert |Funcref|s, |msgpack-special-dict| as the input. Will not convert
mappings with non-string keys (can be created as |Funcref|s, mappings with non-string keys (can be created as
|msgpack-special-dict|), values with self-referencing |msgpack-special-dict|), values with self-referencing
containers, strings which contain non-UTF-8 characters, containers, strings which contain non-UTF-8 characters,
pseudo-UTF-8 strings which contain codepoints reserved for pseudo-UTF-8 strings which contain codepoints reserved for

View File

@@ -5151,8 +5151,8 @@ A jump table for the options with a short description can be found at |Q_op|.
saved. When not included, the value of 'history' is used. saved. When not included, the value of 'history' is used.
*shada-c* *shada-c*
c Dummy option, kept for compatibility reasons. Has no actual c Dummy option, kept for compatibility reasons. Has no actual
effect. Current encoding state is described in effect: ShaDa always uses UTF-8 and 'encoding' value is fixed
|shada-encoding|. to UTF-8 as well.
*shada-f* *shada-f*
f Whether file marks need to be stored. If zero, file marks ('0 f Whether file marks need to be stored. If zero, file marks ('0
to '9, 'A to 'Z) are not stored. When not present or when to '9, 'A to 'Z) are not stored. When not present or when

View File

@@ -1097,23 +1097,6 @@ SHADA FILE NAME *shada-file-name*
default and the name given with 'shada' or "-i" (unless it's NONE). default and the name given with 'shada' or "-i" (unless it's NONE).
CHARACTER ENCODING *shada-encoding*
The text in the ShaDa file is UTF-8-encoded. Normally you will always work
with the same 'encoding' value, and this works just fine. However, if you
read the ShaDa file with value for 'encoding' different from utf-8 and
'encoding' used when writing ShaDa file, some of the text (non-ASCII
characters) may be invalid as Neovim always attempts to convert the text in
the ShaDa file from the UTF-8 to the current 'encoding' value. Filenames are
never converted, affected elements are:
- history strings;
- variable values;
- register values;
- last used search and substitute patterns;
- last used substitute replacement string.
MANUALLY READING AND WRITING *shada-read-write* MANUALLY READING AND WRITING *shada-read-write*
Two commands can be used to read and write the ShaDa file manually. This Two commands can be used to read and write the ShaDa file manually. This
@@ -1221,8 +1204,11 @@ exactly four MessagePack objects:
3. Third goes the length of the fourth entry. Unsigned integer as well, used 3. Third goes the length of the fourth entry. Unsigned integer as well, used
for fast skipping without parsing. for fast skipping without parsing.
4. Fourth is actual entry data. All currently used ShaDa entries use 4. Fourth is actual entry data. All currently used ShaDa entries use
containers to hold data: either map or array. Exact format depends on the containers to hold data: either map or array. All string values in those
entry type: containers are either binary (applies to filenames) or UTF-8, yet parser
needs to expect that invalid bytes may be present in a UTF-8 string.
Exact format depends on the entry type:
Entry type (name) Entry data ~ Entry type (name) Entry data ~
1 (Header) Map containing data that describes the generator 1 (Header) Map containing data that describes the generator

View File

@@ -41,7 +41,10 @@ set(LINT_SUPPRESS_URL "${LINT_SUPPRESS_URL_BASE}/errors.json")
set(LINT_PRG ${PROJECT_SOURCE_DIR}/src/clint.py) set(LINT_PRG ${PROJECT_SOURCE_DIR}/src/clint.py)
set(DOWNLOAD_SCRIPT ${PROJECT_SOURCE_DIR}/cmake/Download.cmake) set(DOWNLOAD_SCRIPT ${PROJECT_SOURCE_DIR}/cmake/Download.cmake)
set(LINT_SUPPRESSES_ROOT ${PROJECT_BINARY_DIR}/errors) 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") set(LINT_SUPPRESSES_URL "${LINT_SUPPRESS_URL_BASE}/errors.tar.gz")
set(LINT_SUPPRESSES_ARCHIVE ${LINT_SUPPRESSES_ROOT}/errors.tar.gz)
set(LINT_SUPPRESSES_TOUCH_FILE "${TOUCHES_DIR}/unpacked-clint-errors-archive")
set(LINT_SUPPRESSES_INSTALL_SCRIPT "${PROJECT_SOURCE_DIR}/cmake/InstallClintErrors.cmake")
include_directories(${GENERATED_DIR}) include_directories(${GENERATED_DIR})
include_directories(${CACHED_GENERATED_DIR}) include_directories(${CACHED_GENERATED_DIR})
@@ -50,6 +53,8 @@ include_directories(${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${TOUCHES_DIR}) file(MAKE_DIRECTORY ${TOUCHES_DIR})
file(MAKE_DIRECTORY ${GENERATED_DIR}) file(MAKE_DIRECTORY ${GENERATED_DIR})
file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR}) file(MAKE_DIRECTORY ${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${LINT_SUPPRESSES_ROOT})
file(MAKE_DIRECTORY ${LINT_SUPPRESSES_ROOT}/src)
file(GLOB NVIM_SOURCES *.c) file(GLOB NVIM_SOURCES *.c)
file(GLOB NVIM_HEADERS *.h) file(GLOB NVIM_HEADERS *.h)
@@ -486,6 +491,20 @@ function(add_download output url allow_failure)
) )
endfunction() endfunction()
add_download(${LINT_SUPPRESSES_ARCHIVE} ${LINT_SUPPRESSES_URL} off)
add_custom_command(
OUTPUT ${LINT_SUPPRESSES_TOUCH_FILE}
WORKING_DIRECTORY ${LINT_SUPPRESSES_ROOT}/src
COMMAND ${CMAKE_COMMAND} -E tar xfz ${LINT_SUPPRESSES_ARCHIVE}
COMMAND
${CMAKE_COMMAND}
-DTARGET=${LINT_SUPPRESSES_ROOT}
-P ${LINT_SUPPRESSES_INSTALL_SCRIPT}
DEPENDS
${LINT_SUPPRESSES_ARCHIVE} ${LINT_SUPPRESSES_INSTALL_SCRIPT}
)
add_download(${LINT_SUPPRESS_FILE} ${LINT_SUPPRESS_URL} off) add_download(${LINT_SUPPRESS_FILE} ${LINT_SUPPRESS_URL} off)
set(LINT_NVIM_REL_SOURCES) set(LINT_NVIM_REL_SOURCES)
@@ -494,14 +513,13 @@ foreach(sfile ${LINT_NVIM_SOURCES})
set(suppress_file ${LINT_SUPPRESSES_ROOT}/${suffix}.json) set(suppress_file ${LINT_SUPPRESSES_ROOT}/${suffix}.json)
set(suppress_url "${LINT_SUPPRESS_URL_BASE}/${suffix}.json") set(suppress_url "${LINT_SUPPRESS_URL_BASE}/${suffix}.json")
set(rsfile src/nvim/${r}) set(rsfile src/nvim/${r})
add_download(${suppress_file} ${suppress_url} on)
set(touch_file "${TOUCHES_DIR}/ran-clint-${suffix}") set(touch_file "${TOUCHES_DIR}/ran-clint-${suffix}")
add_custom_command( add_custom_command(
OUTPUT ${touch_file} OUTPUT ${touch_file}
COMMAND ${LINT_PRG} --suppress-errors=${suppress_file} ${rsfile} COMMAND ${LINT_PRG} --suppress-errors=${suppress_file} ${rsfile}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND} -E touch ${touch_file} COMMAND ${CMAKE_COMMAND} -E touch ${touch_file}
DEPENDS ${LINT_PRG} ${sfile} ${suppress_file} DEPENDS ${LINT_PRG} ${sfile} ${LINT_SUPPRESSES_TOUCH_FILE}
) )
list(APPEND LINT_TARGETS ${touch_file}) list(APPEND LINT_TARGETS ${touch_file})
list(APPEND LINT_NVIM_REL_SOURCES ${rsfile}) list(APPEND LINT_NVIM_REL_SOURCES ${rsfile})

View File

@@ -1,8 +1,8 @@
#ifndef NVIM_DIGRAPH_H #ifndef NVIM_DIGRAPH_H
#define NVIM_DIGRAPH_H #define NVIM_DIGRAPH_H
#include "nvim/types.h" // for char_u #include "nvim/types.h"
#include "nvim/ex_cmds_defs.h" // for exarg_T #include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "digraph.h.generated.h" # include "digraph.h.generated.h"

View File

@@ -222,8 +222,6 @@ static inline int json_decoder_pop(ValuesStackItem obj,
/// Parse JSON double-quoted string /// Parse JSON double-quoted string
/// ///
/// @param[in] conv Defines conversion necessary to convert UTF-8 string to
/// &encoding.
/// @param[in] buf Buffer being converted. /// @param[in] buf Buffer being converted.
/// @param[in] buf_len Length of the buffer. /// @param[in] buf_len Length of the buffer.
/// @param[in,out] pp Pointer to the start of the string. Must point to '"'. /// @param[in,out] pp Pointer to the start of the string. Must point to '"'.
@@ -240,8 +238,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
/// value when decoder is restarted, otherwise unused. /// value when decoder is restarted, otherwise unused.
/// ///
/// @return OK in case of success, FAIL in case of error. /// @return OK in case of success, FAIL in case of error.
static inline int parse_json_string(vimconv_T *const conv, static inline int parse_json_string(const char *const buf, const size_t buf_len,
const char *const buf, const size_t buf_len,
const char **const pp, const char **const pp,
ValuesStack *const stack, ValuesStack *const stack,
ContainerStack *const container_stack, ContainerStack *const container_stack,
@@ -416,20 +413,6 @@ static inline int parse_json_string(vimconv_T *const conv,
} }
PUT_FST_IN_PAIR(fst_in_pair, str_end); PUT_FST_IN_PAIR(fst_in_pair, str_end);
#undef PUT_FST_IN_PAIR #undef PUT_FST_IN_PAIR
if (conv->vc_type != CONV_NONE) {
size_t str_len = (size_t) (str_end - str);
char *const new_str = (char *) string_convert(conv, (char_u *) str,
&str_len);
if (new_str == NULL) {
emsgf(_("E474: Failed to convert string \"%.*s\" from UTF-8"),
(int) str_len, str);
xfree(str);
goto parse_json_string_fail;
}
xfree(str);
str = new_str;
str_end = new_str + str_len;
}
if (hasnul) { if (hasnul) {
typval_T obj; typval_T obj;
list_T *const list = tv_list_alloc(); list_T *const list = tv_list_alloc();
@@ -626,9 +609,6 @@ int json_decode_string(const char *const buf, const size_t buf_len,
EMSG(_("E474: Attempt to decode a blank string")); EMSG(_("E474: Attempt to decode a blank string"));
return FAIL; return FAIL;
} }
vimconv_T conv = { .vc_type = CONV_NONE };
convert_setup(&conv, (char_u *) "utf-8", p_enc);
conv.vc_fail = true;
int ret = OK; int ret = OK;
ValuesStack stack = KV_INITIAL_VALUE; ValuesStack stack = KV_INITIAL_VALUE;
ContainerStack container_stack = KV_INITIAL_VALUE; ContainerStack container_stack = KV_INITIAL_VALUE;
@@ -774,7 +754,7 @@ json_decode_string_cycle_start:
break; break;
} }
case '"': { case '"': {
if (parse_json_string(&conv, buf, buf_len, &p, &stack, &container_stack, if (parse_json_string(buf, buf_len, &p, &stack, &container_stack,
&next_map_special, &didcomma, &didcolon) &next_map_special, &didcomma, &didcolon)
== FAIL) { == FAIL) {
// Error message was already given // Error message was already given

View File

@@ -11,7 +11,7 @@
#include <math.h> #include <math.h>
#include "nvim/eval/encode.h" #include "nvim/eval/encode.h"
#include "nvim/buffer_defs.h" // vimconv_T #include "nvim/buffer_defs.h"
#include "nvim/eval.h" #include "nvim/eval.h"
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"
#include "nvim/garray.h" #include "nvim/garray.h"
@@ -29,10 +29,6 @@
#define utf_ptr2char(b) utf_ptr2char((char_u *)b) #define utf_ptr2char(b) utf_ptr2char((char_u *)b)
#define utf_ptr2len(b) ((size_t)utf_ptr2len((char_u *)b)) #define utf_ptr2len(b) ((size_t)utf_ptr2len((char_u *)b))
#define utf_char2len(b) ((size_t)utf_char2len(b)) #define utf_char2len(b) ((size_t)utf_char2len(b))
#define string_convert(a, b, c) \
((char *)string_convert((vimconv_T *)a, (char_u *)b, c))
#define convert_setup(vcp, from, to) \
(convert_setup(vcp, (char_u *)from, (char_u *)to))
const char *const encode_special_var_names[] = { const char *const encode_special_var_names[] = {
[kSpecialVarNull] = "null", [kSpecialVarNull] = "null",
@@ -537,17 +533,6 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
} \ } \
} while (0) } while (0)
/// Last used p_enc value
///
/// Generic pointer: it is not used as a string, only pointer comparisons are
/// performed. Must not be freed.
static const void *last_p_enc = NULL;
/// Conversion setup for converting from last_p_enc to UTF-8
static vimconv_T p_enc_conv = {
.vc_type = CONV_NONE,
};
/// Escape sequences used in JSON /// Escape sequences used in JSON
static const char escapes[][3] = { static const char escapes[][3] = {
[BS] = "\\b", [BS] = "\\b",
@@ -579,33 +564,15 @@ static inline int convert_to_json_string(garray_T *const gap,
} else { } else {
size_t utf_len = len; size_t utf_len = len;
char *tofree = NULL; char *tofree = NULL;
if (last_p_enc != (const void *) p_enc) {
p_enc_conv.vc_type = CONV_NONE;
convert_setup(&p_enc_conv, p_enc, "utf-8");
p_enc_conv.vc_fail = true;
last_p_enc = p_enc;
}
if (p_enc_conv.vc_type != CONV_NONE) {
tofree = string_convert(&p_enc_conv, buf, &utf_len);
if (tofree == NULL) {
emsgf(_("E474: Failed to convert string \"%.*s\" to UTF-8"),
utf_len, utf_buf);
return FAIL;
}
utf_buf = tofree;
}
size_t str_len = 0; size_t str_len = 0;
// Encode character as \u0000 if // Encode character as \uNNNN if
// 1. It is an ASCII control character (0x0 .. 0x1F, 0x7F). // 1. It is an ASCII control character (0x0 .. 0x1F; 0x7F not
// 2. &encoding is not UTF-8 and code point is above 0x7F. // utf_printable and thus not checked specially).
// 3. &encoding is UTF-8 and code point is not printable according to // 2. Code point is not printable according to utf_printable().
// utf_printable(). // This is done to make resulting values displayable on screen also not from
// This is done to make it possible to :echo values when &encoding is not // Neovim.
// UTF-8. #define ENCODE_RAW(ch) \
#define ENCODE_RAW(p_enc_conv, ch) \ (ch >= 0x20 && utf_printable(ch))
(ch >= 0x20 && (p_enc_conv.vc_type == CONV_NONE \
? utf_printable(ch) \
: ch < 0x7F))
for (size_t i = 0; i < utf_len;) { for (size_t i = 0; i < utf_len;) {
const int ch = utf_ptr2char(utf_buf + i); const int ch = utf_ptr2char(utf_buf + i);
const size_t shift = (ch == 0? 1: utf_ptr2len(utf_buf + i)); const size_t shift = (ch == 0? 1: utf_ptr2len(utf_buf + i));
@@ -636,7 +603,7 @@ static inline int convert_to_json_string(garray_T *const gap,
utf_len - (i - shift), utf_buf + i - shift); utf_len - (i - shift), utf_buf + i - shift);
xfree(tofree); xfree(tofree);
return FAIL; return FAIL;
} else if (ENCODE_RAW(p_enc_conv, ch)) { } else if (ENCODE_RAW(ch)) {
str_len += shift; str_len += shift;
} else { } else {
str_len += ((sizeof("\\u1234") - 1) str_len += ((sizeof("\\u1234") - 1)
@@ -666,7 +633,7 @@ static inline int convert_to_json_string(garray_T *const gap,
break; break;
} }
default: { default: {
if (ENCODE_RAW(p_enc_conv, ch)) { if (ENCODE_RAW(ch)) {
ga_concat_len(gap, utf_buf + i, shift); ga_concat_len(gap, utf_buf + i, shift);
} else if (ch < SURROGATE_FIRST_CHAR) { } else if (ch < SURROGATE_FIRST_CHAR) {
ga_concat_len(gap, ((const char[]) { ga_concat_len(gap, ((const char[]) {

View File

@@ -6,8 +6,8 @@
#include "nvim/os/time.h" #include "nvim/os/time.h"
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"
#include "nvim/buffer_defs.h" // for buf_T and win_T #include "nvim/buffer_defs.h"
#include "nvim/ex_cmds_defs.h" // for exarg_T #include "nvim/ex_cmds_defs.h"
// flags for do_ecmd() // flags for do_ecmd()
#define ECMD_HIDE 0x01 // don't free the current buffer #define ECMD_HIDE 0x01 // don't free the current buffer

View File

@@ -3,9 +3,9 @@
#include "nvim/eval/typval.h" #include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h" #include "nvim/ex_cmds.h"
#include "nvim/ex_cmds_defs.h" // for exarg_T #include "nvim/ex_cmds_defs.h"
#include "nvim/os/time.h" // for Timestamp #include "nvim/os/time.h"
#include "nvim/regexp_defs.h" // for regmatch_T #include "nvim/regexp_defs.h"
/* Values for nextwild() and ExpandOne(). See ExpandOne() for meaning. */ /* Values for nextwild() and ExpandOne(). See ExpandOne() for meaning. */
#define WILD_FREE 1 #define WILD_FREE 1

View File

@@ -1,12 +1,12 @@
#ifndef NVIM_FOLD_H #ifndef NVIM_FOLD_H
#define NVIM_FOLD_H #define NVIM_FOLD_H
#include <stdio.h> // for FILE #include <stdio.h>
#include "nvim/pos.h" #include "nvim/pos.h"
#include "nvim/garray.h" // for garray_T #include "nvim/garray.h"
#include "nvim/types.h" // for char_u #include "nvim/types.h"
#include "nvim/buffer_defs.h" // for win_T #include "nvim/buffer_defs.h"
/* /*
* Info used to pass info about a fold from the fold-detection code to the * Info used to pass info about a fold from the fold-detection code to the

View File

@@ -10,9 +10,7 @@
// USE_ICONV, or to put the USE_ICONV definition in config.h.in directly. As // USE_ICONV, or to put the USE_ICONV definition in config.h.in directly. As
// it stands, globals.h needs to be included alongside iconv.h. // it stands, globals.h needs to be included alongside iconv.h.
#ifdef HAVE_CONFIG_H #include "auto/config.h"
# include "auto/config.h"
#endif
// Use iconv() when it's available, either by linking to the library at // Use iconv() when it's available, either by linking to the library at
// compile time or by loading it at runtime. // compile time or by loading it at runtime.

View File

@@ -3,10 +3,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> // for size_t #include <stdlib.h>
#include "nvim/types.h" #include "nvim/types.h"
#include "nvim/pos.h" // for linenr_T #include "nvim/pos.h"
/// A block number. /// A block number.
/// ///

View File

@@ -2,8 +2,8 @@
#define NVIM_MOVE_H #define NVIM_MOVE_H
#include <stdbool.h> #include <stdbool.h>
#include "nvim/buffer_defs.h" // for win_T #include "nvim/buffer_defs.h"
#include "nvim/pos.h" // for linenr_T #include "nvim/pos.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "move.h.generated.h" # include "move.h.generated.h"

View File

@@ -73,15 +73,10 @@ KHASH_SET_INIT_STR(strset)
(vim_rename((char_u *)a, (char_u *)b)) (vim_rename((char_u *)a, (char_u *)b))
#define mb_strnicmp(a, b, c) \ #define mb_strnicmp(a, b, c) \
(mb_strnicmp((char_u *)a, (char_u *)b, c)) (mb_strnicmp((char_u *)a, (char_u *)b, c))
#define has_non_ascii(a) (has_non_ascii((char_u *)a))
#define string_convert(a, b, c) \
((char *)string_convert((vimconv_T *)a, (char_u *)b, c))
#define path_shorten_fname_if_possible(b) \ #define path_shorten_fname_if_possible(b) \
((char *)path_shorten_fname_if_possible((char_u *)b)) ((char *)path_shorten_fname_if_possible((char_u *)b))
#define buflist_new(ffname, sfname, ...) \ #define buflist_new(ffname, sfname, ...) \
(buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__)) (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
#define convert_setup(vcp, from, to) \
(convert_setup(vcp, (char_u *)from, (char_u *)to))
#define os_isdir(f) (os_isdir((char_u *) f)) #define os_isdir(f) (os_isdir((char_u *) f))
#define regtilde(s, m) ((char *) regtilde((char_u *) s, m)) #define regtilde(s, m) ((char *) regtilde((char_u *) s, m))
#define path_tail_with_sep(f) ((char *) path_tail_with_sep((char_u *)f)) #define path_tail_with_sep(f) ((char *) path_tail_with_sep((char_u *)f))
@@ -413,8 +408,6 @@ typedef struct sd_read_def {
const char *error; ///< Error message in case of error. const char *error; ///< Error message in case of error.
uintmax_t fpos; ///< Current position (amount of bytes read since uintmax_t fpos; ///< Current position (amount of bytes read since
///< reader structure initialization). May overflow. ///< reader structure initialization). May overflow.
vimconv_T sd_conv; ///< Structure used for converting encodings of some
///< items.
} ShaDaReadDef; } ShaDaReadDef;
struct sd_write_def; struct sd_write_def;
@@ -435,8 +428,6 @@ typedef struct sd_write_def {
ShaDaWriteCloser close; ///< Close function. ShaDaWriteCloser close; ///< Close function.
void *cookie; ///< Data describing object written to. void *cookie; ///< Data describing object written to.
const char *error; ///< Error message in case of error. const char *error; ///< Error message in case of error.
vimconv_T sd_conv; ///< Structure used for converting encodings of some
///< items.
} ShaDaWriteDef; } ShaDaWriteDef;
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -803,7 +794,7 @@ static int open_shada_file_for_reading(const char *const fname,
return error; return error;
} }
convert_setup(&sd_reader->sd_conv, "utf-8", p_enc); assert(STRCMP(p_enc, "utf-8") == 0);
return 0; return 0;
} }
@@ -1899,127 +1890,24 @@ shada_pack_entry_error:
} }
#undef PACK_STRING #undef PACK_STRING
/// Write single ShaDa entry, converting it if needed /// Write single ShaDa entry and free it afterwards
/// ///
/// @warning Frees entry after packing. /// Will not free if entry could not be freed.
/// ///
/// @param[in] packer Packer used to write entry. /// @param[in] packer Packer used to write entry.
/// @param[in] sd_conv Conversion definitions. /// @param[in] entry Entry written.
/// @param[in] entry Entry written. If entry.can_free_entry is false then
/// it assumes that entry was not converted, otherwise it
/// is assumed that entry was already converted.
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no /// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
/// restrictions. /// restrictions.
static ShaDaWriteResult shada_pack_encoded_entry(msgpack_packer *const packer, static inline ShaDaWriteResult shada_pack_pfreed_entry(
const vimconv_T *const sd_conv, msgpack_packer *const packer, PossiblyFreedShadaEntry entry,
PossiblyFreedShadaEntry entry, const size_t max_kbyte)
const size_t max_kbyte) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
FUNC_ATTR_NONNULL_ALL
{ {
ShaDaWriteResult ret = kSDWriteSuccessfull; ShaDaWriteResult ret = kSDWriteSuccessfull;
ret = shada_pack_entry(packer, entry.data, max_kbyte);
if (entry.can_free_entry) { if (entry.can_free_entry) {
ret = shada_pack_entry(packer, entry.data, max_kbyte);
shada_free_shada_entry(&entry.data); shada_free_shada_entry(&entry.data);
return ret;
} }
#define RUN_WITH_CONVERTED_STRING(cstr, code) \
do { \
bool did_convert = false; \
if (sd_conv->vc_type != CONV_NONE && has_non_ascii((cstr))) { \
char *const converted_string = string_convert(sd_conv, (cstr), NULL); \
if (converted_string != NULL) { \
(cstr) = converted_string; \
did_convert = true; \
} \
} \
code \
if (did_convert) { \
xfree((cstr)); \
} \
} while (0)
switch (entry.data.type) {
case kSDItemUnknown:
case kSDItemMissing: {
assert(false);
}
case kSDItemSearchPattern: {
RUN_WITH_CONVERTED_STRING(entry.data.data.search_pattern.pat, {
ret = shada_pack_entry(packer, entry.data, max_kbyte);
});
break;
}
case kSDItemHistoryEntry: {
RUN_WITH_CONVERTED_STRING(entry.data.data.history_item.string, {
ret = shada_pack_entry(packer, entry.data, max_kbyte);
});
break;
}
case kSDItemSubString: {
RUN_WITH_CONVERTED_STRING(entry.data.data.sub_string.sub, {
ret = shada_pack_entry(packer, entry.data, max_kbyte);
});
break;
}
case kSDItemVariable: {
if (sd_conv->vc_type != CONV_NONE) {
typval_T tgttv;
var_item_copy(sd_conv, &entry.data.data.global_var.value, &tgttv,
true, 0);
tv_clear(&entry.data.data.global_var.value);
entry.data.data.global_var.value = tgttv;
}
ret = shada_pack_entry(packer, entry.data, max_kbyte);
break;
}
case kSDItemRegister: {
bool did_convert = false;
if (sd_conv->vc_type != CONV_NONE) {
size_t first_non_ascii = 0;
for (size_t i = 0; i < entry.data.data.reg.contents_size; i++) {
if (has_non_ascii(entry.data.data.reg.contents[i])) {
first_non_ascii = i;
did_convert = true;
break;
}
}
if (did_convert) {
entry.data.data.reg.contents =
xmemdup(entry.data.data.reg.contents,
(entry.data.data.reg.contents_size
* sizeof(entry.data.data.reg.contents[0])));
for (size_t i = 0; i < entry.data.data.reg.contents_size; i++) {
if (i >= first_non_ascii) {
entry.data.data.reg.contents[i] = get_converted_string(
sd_conv,
entry.data.data.reg.contents[i],
strlen(entry.data.data.reg.contents[i]));
} else {
entry.data.data.reg.contents[i] =
xstrdup(entry.data.data.reg.contents[i]);
}
}
}
}
ret = shada_pack_entry(packer, entry.data, max_kbyte);
if (did_convert) {
for (size_t i = 0; i < entry.data.data.reg.contents_size; i++) {
xfree(entry.data.data.reg.contents[i]);
}
xfree(entry.data.data.reg.contents);
}
break;
}
case kSDItemHeader:
case kSDItemGlobalMark:
case kSDItemJump:
case kSDItemBufferList:
case kSDItemLocalMark:
case kSDItemChange: {
ret = shada_pack_entry(packer, entry.data, max_kbyte);
break;
}
}
#undef RUN_WITH_CONVERTED_STRING
return ret; return ret;
} }
@@ -2556,11 +2444,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
break; break;
} }
typval_T tgttv; typval_T tgttv;
if (sd_writer->sd_conv.vc_type != CONV_NONE) { tv_copy(&vartv, &tgttv);
var_item_copy(&sd_writer->sd_conv, &vartv, &tgttv, true, 0);
} else {
tv_copy(&vartv, &tgttv);
}
ShaDaWriteResult spe_ret; ShaDaWriteResult spe_ret;
if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) { if ((spe_ret = shada_pack_entry(packer, (ShadaEntry) {
.type = kSDItemVariable, .type = kSDItemVariable,
@@ -2811,9 +2695,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
do { \ do { \
for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \ for (size_t i_ = 0; i_ < ARRAY_SIZE(wms_array); i_++) { \
if (wms_array[i_].data.type != kSDItemMissing) { \ if (wms_array[i_].data.type != kSDItemMissing) { \
if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, \ if (shada_pack_pfreed_entry(packer, wms_array[i_], max_kbyte) \
wms_array[i_], \ == kSDWriteFailed) { \
max_kbyte) == kSDWriteFailed) { \
ret = kSDWriteFailed; \ ret = kSDWriteFailed; \
goto shada_write_exit; \ goto shada_write_exit; \
} \ } \
@@ -2823,8 +2706,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
PACK_WMS_ARRAY(wms->global_marks); PACK_WMS_ARRAY(wms->global_marks);
PACK_WMS_ARRAY(wms->registers); PACK_WMS_ARRAY(wms->registers);
for (size_t i = 0; i < wms->jumps_size; i++) { for (size_t i = 0; i < wms->jumps_size; i++) {
if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms->jumps[i], if (shada_pack_pfreed_entry(packer, wms->jumps[i], max_kbyte)
max_kbyte) == kSDWriteFailed) { == kSDWriteFailed) {
ret = kSDWriteFailed; ret = kSDWriteFailed;
goto shada_write_exit; goto shada_write_exit;
} }
@@ -2832,8 +2715,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
#define PACK_WMS_ENTRY(wms_entry) \ #define PACK_WMS_ENTRY(wms_entry) \
do { \ do { \
if (wms_entry.data.type != kSDItemMissing) { \ if (wms_entry.data.type != kSDItemMissing) { \
if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, wms_entry, \ if (shada_pack_pfreed_entry(packer, wms_entry, max_kbyte) \
max_kbyte) == kSDWriteFailed) { \ == kSDWriteFailed) { \
ret = kSDWriteFailed; \ ret = kSDWriteFailed; \
goto shada_write_exit; \ goto shada_write_exit; \
} \ } \
@@ -2860,9 +2743,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
for (size_t i = 0; i < file_markss_to_dump; i++) { for (size_t i = 0; i < file_markss_to_dump; i++) {
PACK_WMS_ARRAY(all_file_markss[i]->marks); PACK_WMS_ARRAY(all_file_markss[i]->marks);
for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) { for (size_t j = 0; j < all_file_markss[i]->changes_size; j++) {
if (shada_pack_encoded_entry(packer, &sd_writer->sd_conv, if (shada_pack_pfreed_entry(packer, all_file_markss[i]->changes[j],
all_file_markss[i]->changes[j], max_kbyte) == kSDWriteFailed) {
max_kbyte) == kSDWriteFailed) {
ret = kSDWriteFailed; ret = kSDWriteFailed;
goto shada_write_exit; goto shada_write_exit;
} }
@@ -2886,8 +2768,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (dump_one_history[i]) { if (dump_one_history[i]) {
hms_insert_whole_neovim_history(&wms->hms[i]); hms_insert_whole_neovim_history(&wms->hms[i]);
HMS_ITER(&wms->hms[i], cur_entry, { HMS_ITER(&wms->hms[i], cur_entry, {
if (shada_pack_encoded_entry( if (shada_pack_pfreed_entry(
packer, &sd_writer->sd_conv, (PossiblyFreedShadaEntry) { packer, (PossiblyFreedShadaEntry) {
.data = cur_entry->data, .data = cur_entry->data,
.can_free_entry = cur_entry->can_free_entry, .can_free_entry = cur_entry->can_free_entry,
}, max_kbyte) == kSDWriteFailed) { }, max_kbyte) == kSDWriteFailed) {
@@ -3038,8 +2920,6 @@ shada_write_file_nomerge: {}
verbose_leave(); verbose_leave();
} }
convert_setup(&sd_writer.sd_conv, p_enc, "utf-8");
const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge
? NULL ? NULL
: &sd_reader)); : &sd_reader));
@@ -3327,29 +3207,6 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
return kSDReadStatusSuccess; return kSDReadStatusSuccess;
} }
/// Convert or copy and return a string
///
/// @param[in] sd_conv Conversion definition.
/// @param[in] str String to convert.
/// @param[in] len String length.
///
/// @return [allocated] converted string or copy of the original string.
static inline char *get_converted_string(const vimconv_T *const sd_conv,
const char *const str,
const size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
{
if (!has_non_ascii_len(str, len)) {
return xmemdupz(str, len);
}
size_t new_len = len;
char *const new_str = string_convert(sd_conv, str, &new_len);
if (new_str == NULL) {
return xmemdupz(str, len);
}
return new_str;
}
#define READERR(entry_name, error_desc) \ #define READERR(entry_name, error_desc) \
RERR "Error while reading ShaDa file: " \ RERR "Error while reading ShaDa file: " \
entry_name " entry at position %" PRIu64 " " \ entry_name " entry at position %" PRIu64 " " \
@@ -3427,10 +3284,7 @@ static inline char *get_converted_string(const vimconv_T *const sd_conv,
sizeof(*unpacked.data.via.map.ptr)); \ sizeof(*unpacked.data.via.map.ptr)); \
ad_ga.ga_len++; \ ad_ga.ga_len++; \
} }
#define CONVERTED(str, len) ( \ #define CONVERTED(str, len) (xmemdupz((str), (len)))
sd_reader->sd_conv.vc_type != CONV_NONE \
? get_converted_string(&sd_reader->sd_conv, (str), (len)) \
: xmemdupz((str), (len)))
#define BIN_CONVERTED(b) CONVERTED(b.ptr, b.size) #define BIN_CONVERTED(b) CONVERTED(b.ptr, b.size)
#define SET_ADDITIONAL_DATA(tgt, name) \ #define SET_ADDITIONAL_DATA(tgt, name) \
do { \ do { \
@@ -3803,30 +3657,14 @@ shada_read_next_item_start:
(char) unpacked.data.via.array.ptr[2].via.u64; (char) unpacked.data.via.array.ptr[2].via.u64;
} }
size_t strsize; size_t strsize;
if (sd_reader->sd_conv.vc_type == CONV_NONE strsize = (
|| !has_non_ascii_len(unpacked.data.via.array.ptr[1].via.bin.ptr, unpacked.data.via.array.ptr[1].via.bin.size
unpacked.data.via.array.ptr[1].via.bin.size)) { + 1 // Zero byte
shada_read_next_item_hist_no_conv: + 1); // Separator character
strsize = ( entry->data.history_item.string = xmalloc(strsize);
unpacked.data.via.array.ptr[1].via.bin.size memcpy(entry->data.history_item.string,
+ 1 // Zero byte unpacked.data.via.array.ptr[1].via.bin.ptr,
+ 1); // Separator character unpacked.data.via.array.ptr[1].via.bin.size);
entry->data.history_item.string = xmalloc(strsize);
memcpy(entry->data.history_item.string,
unpacked.data.via.array.ptr[1].via.bin.ptr,
unpacked.data.via.array.ptr[1].via.bin.size);
} else {
size_t len = unpacked.data.via.array.ptr[1].via.bin.size;
char *const converted = string_convert(
&sd_reader->sd_conv, unpacked.data.via.array.ptr[1].via.bin.ptr,
&len);
if (converted != NULL) {
strsize = len + 2;
entry->data.history_item.string = xrealloc(converted, strsize);
} else {
goto shada_read_next_item_hist_no_conv;
}
}
entry->data.history_item.string[strsize - 2] = 0; entry->data.history_item.string[strsize - 2] = 0;
entry->data.history_item.string[strsize - 1] = entry->data.history_item.string[strsize - 1] =
entry->data.history_item.sep; entry->data.history_item.sep;
@@ -3859,16 +3697,6 @@ shada_read_next_item_hist_no_conv:
"be converted to the VimL value")), initial_fpos); "be converted to the VimL value")), initial_fpos);
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
if (sd_reader->sd_conv.vc_type != CONV_NONE) {
typval_T tgttv;
var_item_copy(&sd_reader->sd_conv,
&entry->data.global_var.value,
&tgttv,
true,
0);
tv_clear(&entry->data.global_var.value);
entry->data.global_var.value = tgttv;
}
SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2, SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
entry->data.global_var.additional_elements, entry->data.global_var.additional_elements,
"variable"); "variable");

View File

@@ -11,20 +11,16 @@
#define RUNTIME_DIRNAME "runtime" #define RUNTIME_DIRNAME "runtime"
/* end */ /* end */
/* ============ the header file puzzle (ca. 50-100 pieces) ========= */ #include "auto/config.h"
#define HAVE_PATHDEF
#ifdef HAVE_CONFIG_H /* GNU autoconf (or something else) was here */
# include "auto/config.h"
# define HAVE_PATHDEF
/* /*
* Check if configure correctly managed to find sizeof(int). If this failed, * Check if configure correctly managed to find sizeof(int). If this failed,
* it becomes zero. This is likely a problem of not being able to run the * it becomes zero. This is likely a problem of not being able to run the
* test program. Other items from configure may also be wrong then! * test program. Other items from configure may also be wrong then!
*/ */
# if (SIZEOF_INT == 0) #if (SIZEOF_INT == 0)
Error: configure did not run properly.Check auto/config.log. # error Configure did not run properly.
# endif
#endif #endif
#include "nvim/os/os_defs.h" /* bring lots of system header files */ #include "nvim/os/os_defs.h" /* bring lots of system header files */
@@ -46,11 +42,6 @@ enum { NUMBUFLEN = 65 };
#include "nvim/keymap.h" #include "nvim/keymap.h"
#include "nvim/macros.h" #include "nvim/macros.h"
/* ================ end of the header file puzzle =============== */
#include "nvim/gettext.h" #include "nvim/gettext.h"
/* special attribute addition: Put message in history */ /* special attribute addition: Put message in history */

View File

@@ -251,12 +251,13 @@ local function retry(max, max_ms, fn)
return result return result
end end
if (max and tries >= max) or (luv.now() - start_time > timeout) then if (max and tries >= max) or (luv.now() - start_time > timeout) then
break if type(result) == "string" then
result = "\nretry() attempts: "..tostring(tries).."\n"..result
end
error(result)
end end
tries = tries + 1 tries = tries + 1
end end
-- Do not use pcall() for the final attempt, let the failure bubble up.
return fn()
end end
local function clear(...) local function clear(...)

View File

@@ -2,9 +2,10 @@
-- as a simple way to send keys and assert screen state. -- as a simple way to send keys and assert screen state.
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers') local thelpers = require('test.functional.terminal.helpers')
local feed = thelpers.feed_data local feed_data = thelpers.feed_data
local feed_command = helpers.feed_command local feed_command = helpers.feed_command
local nvim_dir = helpers.nvim_dir local nvim_dir = helpers.nvim_dir
local retry = helpers.retry
if helpers.pending_win32(pending) then return end if helpers.pending_win32(pending) then return end
@@ -34,7 +35,7 @@ describe('tui', function()
end) end)
it('accepts basic utf-8 input', function() it('accepts basic utf-8 input', function()
feed('iabc\ntest1\ntest2') feed_data('iabc\ntest1\ntest2')
screen:expect([[ screen:expect([[
abc | abc |
test1 | test1 |
@@ -44,7 +45,7 @@ describe('tui', function()
{3:-- INSERT --} | {3:-- INSERT --} |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('\027') feed_data('\027')
screen:expect([[ screen:expect([[
abc | abc |
test1 | test1 |
@@ -60,7 +61,7 @@ describe('tui', function()
local keys = 'dfghjkl' local keys = 'dfghjkl'
for c in keys:gmatch('.') do for c in keys:gmatch('.') do
feed_command('nnoremap <a-'..c..'> ialt-'..c..'<cr><esc>') feed_command('nnoremap <a-'..c..'> ialt-'..c..'<cr><esc>')
feed('\027'..c) feed_data('\027'..c)
end end
screen:expect([[ screen:expect([[
alt-j | alt-j |
@@ -71,7 +72,7 @@ describe('tui', function()
| |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('gg') feed_data('gg')
screen:expect([[ screen:expect([[
{1:a}lt-d | {1:a}lt-d |
alt-f | alt-f |
@@ -90,7 +91,7 @@ describe('tui', function()
-- Example: for input ALT+j: -- Example: for input ALT+j:
-- * Vim (Nvim prior to #3982) sets high-bit, inserts "ê". -- * Vim (Nvim prior to #3982) sets high-bit, inserts "ê".
-- * Nvim (after #3982) inserts "j". -- * Nvim (after #3982) inserts "j".
feed('i\027j') feed_data('i\027j')
screen:expect([[ screen:expect([[
j{1: } | j{1: } |
{4:~ }| {4:~ }|
@@ -103,10 +104,10 @@ describe('tui', function()
end) end)
it('accepts ascii control sequences', function() it('accepts ascii control sequences', function()
feed('i') feed_data('i')
feed('\022\007') -- ctrl+g feed_data('\022\007') -- ctrl+g
feed('\022\022') -- ctrl+v feed_data('\022\022') -- ctrl+v
feed('\022\013') -- ctrl+m feed_data('\022\013') -- ctrl+m
screen:expect([[ screen:expect([[
{9:^G^V^M}{1: } | {9:^G^V^M}{1: } |
{4:~ }| {4:~ }|
@@ -119,7 +120,7 @@ describe('tui', function()
end) end)
it('automatically sends <Paste> for bracketed paste sequences', function() it('automatically sends <Paste> for bracketed paste sequences', function()
feed('i\027[200~') feed_data('i\027[200~')
screen:expect([[ screen:expect([[
{1: } | {1: } |
{4:~ }| {4:~ }|
@@ -129,7 +130,7 @@ describe('tui', function()
{3:-- INSERT (paste) --} | {3:-- INSERT (paste) --} |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('pasted from terminal') feed_data('pasted from terminal')
screen:expect([[ screen:expect([[
pasted from terminal{1: } | pasted from terminal{1: } |
{4:~ }| {4:~ }|
@@ -139,7 +140,7 @@ describe('tui', function()
{3:-- INSERT (paste) --} | {3:-- INSERT (paste) --} |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('\027[201~') feed_data('\027[201~')
screen:expect([[ screen:expect([[
pasted from terminal{1: } | pasted from terminal{1: } |
{4:~ }| {4:~ }|
@@ -157,7 +158,7 @@ describe('tui', function()
for i = 1, 3000 do for i = 1, 3000 do
t[i] = 'item ' .. tostring(i) t[i] = 'item ' .. tostring(i)
end end
feed('i\027[200~'..table.concat(t, '\n')..'\027[201~') feed_data('i\027[200~'..table.concat(t, '\n')..'\027[201~')
screen:expect([[ screen:expect([[
item 2997 | item 2997 |
item 2998 | item 2998 |
@@ -180,7 +181,7 @@ describe('tui with non-tty file descriptors', function()
it('can handle pipes as stdout and stderr', function() it('can handle pipes as stdout and stderr', function()
local screen = thelpers.screen_setup(0, '"'..helpers.nvim_prog local screen = thelpers.screen_setup(0, '"'..helpers.nvim_prog
..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"') ..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"')
feed(':w testF\n:q\n') feed_data(':w testF\n:q\n')
screen:expect([[ screen:expect([[
:w testF | :w testF |
:q | :q |
@@ -200,12 +201,13 @@ describe('tui focus event handling', function()
helpers.clear() helpers.clear()
screen = thelpers.screen_setup(0, '["'..helpers.nvim_prog screen = thelpers.screen_setup(0, '["'..helpers.nvim_prog
..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]') ..'", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile noshowcmd noruler"]')
feed_command('autocmd FocusGained * echo "gained"') feed_data(":autocmd FocusGained * echo 'gained'\n")
feed_command('autocmd FocusLost * echo "lost"') feed_data(":autocmd FocusLost * echo 'lost'\n")
feed_data("\034\016") -- CTRL-\ CTRL-N
end) end)
it('can handle focus events in normal mode', function() it('can handle focus events in normal mode', function()
feed('\027[I') feed_data('\027[I')
screen:expect([[ screen:expect([[
{1: } | {1: } |
{4:~ }| {4:~ }|
@@ -216,7 +218,7 @@ describe('tui focus event handling', function()
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('\027[O') feed_data('\027[O')
screen:expect([[ screen:expect([[
{1: } | {1: } |
{4:~ }| {4:~ }|
@@ -230,8 +232,8 @@ describe('tui focus event handling', function()
it('can handle focus events in insert mode', function() it('can handle focus events in insert mode', function()
feed_command('set noshowmode') feed_command('set noshowmode')
feed('i') feed_data('i')
feed('\027[I') feed_data('\027[I')
screen:expect([[ screen:expect([[
{1: } | {1: } |
{4:~ }| {4:~ }|
@@ -241,7 +243,7 @@ describe('tui focus event handling', function()
gained | gained |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('\027[O') feed_data('\027[O')
screen:expect([[ screen:expect([[
{1: } | {1: } |
{4:~ }| {4:~ }|
@@ -254,8 +256,8 @@ describe('tui focus event handling', function()
end) end)
it('can handle focus events in cmdline mode', function() it('can handle focus events in cmdline mode', function()
feed(':') feed_data(':')
feed('\027[I') feed_data('\027[I')
screen:expect([[ screen:expect([[
| |
{4:~ }| {4:~ }|
@@ -265,7 +267,7 @@ describe('tui focus event handling', function()
g{1:a}ined | g{1:a}ined |
{3:-- TERMINAL --} | {3:-- TERMINAL --} |
]]) ]])
feed('\027[O') feed_data('\027[O')
screen:expect([[ screen:expect([[
| |
{4:~ }| {4:~ }|
@@ -278,30 +280,36 @@ describe('tui focus event handling', function()
end) end)
it('can handle focus events in terminal mode', function() it('can handle focus events in terminal mode', function()
feed_command('set shell='..nvim_dir..'/shell-test') feed_data(':set shell='..nvim_dir..'/shell-test\n')
feed_command('set laststatus=0') feed_data(':set noshowmode laststatus=0\n')
feed_command('set noshowmode')
feed_command('terminal') retry(2, 3 * screen.timeout, function()
feed('\027[I') feed_data(':terminal\n')
screen:expect([[ feed_data('\027[I')
ready $ | screen:expect([[
[Process exited 0]{1: } | ready $ |
| [Process exited 0]{1: } |
| |
| |
gained | |
{3:-- TERMINAL --} | gained |
]]) {3:-- TERMINAL --} |
feed('\027[O') ]])
screen:expect([[ feed_data('\027[O')
ready $ | screen:expect([[
[Process exited 0]{1: } | ready $ |
| [Process exited 0]{1: } |
| |
| |
lost | |
{3:-- TERMINAL --} | lost |
]]) {3:-- TERMINAL --} |
]])
-- If retry is needed...
feed_data("\034\016") -- CTRL-\ CTRL-N
feed_data(':bwipeout!\n')
end)
end) end)
end) end)

View File

@@ -17,18 +17,28 @@ local ok = function(res)
return assert.is_true(res) return assert.is_true(res)
end end
-- initial_path: directory to recurse into
-- re: include pattern (string)
-- exc_re: exclude pattern(s) (string or table)
local function glob(initial_path, re, exc_re) local function glob(initial_path, re, exc_re)
exc_re = type(exc_re) == 'table' and exc_re or { exc_re }
local paths_to_check = {initial_path} local paths_to_check = {initial_path}
local ret = {} local ret = {}
local checked_files = {} local checked_files = {}
local function is_excluded(path)
for _, pat in pairs(exc_re) do
if path:match(pat) then return true end
end
return false
end
while #paths_to_check > 0 do while #paths_to_check > 0 do
local cur_path = paths_to_check[#paths_to_check] local cur_path = paths_to_check[#paths_to_check]
paths_to_check[#paths_to_check] = nil paths_to_check[#paths_to_check] = nil
for e in lfs.dir(cur_path) do for e in lfs.dir(cur_path) do
local full_path = cur_path .. '/' .. e local full_path = cur_path .. '/' .. e
local checked_path = full_path:sub(#initial_path + 1) local checked_path = full_path:sub(#initial_path + 1)
if ((not exc_re or not checked_path:match(exc_re)) if (not is_excluded(checked_path)) and e:sub(1, 1) ~= '.' then
and e:sub(1, 1) ~= '.') then
local attrs = lfs.attributes(full_path) local attrs = lfs.attributes(full_path)
if attrs then if attrs then
local check_key = attrs.dev .. ':' .. tostring(attrs.ino) local check_key = attrs.dev .. ':' .. tostring(attrs.ino)
@@ -106,13 +116,20 @@ local uname = (function()
end) end)
end)() end)()
local function tmpdir_get()
return os.getenv('TMPDIR') and os.getenv('TMPDIR') or os.getenv('TEMP')
end
-- Is temp directory `dir` defined local to the project workspace?
local function tmpdir_is_local(dir)
return not not (dir and string.find(dir, 'Xtest'))
end
local tmpname = (function() local tmpname = (function()
local seq = 0 local seq = 0
local tmpdir = os.getenv('TMPDIR') and os.getenv('TMPDIR') or os.getenv('TEMP') local tmpdir = tmpdir_get()
-- Is $TMPDIR defined local to the project workspace?
local in_workspace = not not (tmpdir and string.find(tmpdir, 'Xtest'))
return (function() return (function()
if in_workspace then if tmpdir_is_local(tmpdir) then
-- Cannot control os.tmpname() dir, so hack our own tmpname() impl. -- Cannot control os.tmpname() dir, so hack our own tmpname() impl.
seq = seq + 1 seq = seq + 1
local fname = tmpdir..'/nvim-test-lua-'..seq local fname = tmpdir..'/nvim-test-lua-'..seq
@@ -162,33 +179,34 @@ end
local tests_skipped = 0 local tests_skipped = 0
local function check_cores(app) local function check_cores(app, force)
app = app or 'build/bin/nvim' app = app or 'build/bin/nvim'
local initial_path, re, exc_re local initial_path, re, exc_re
local gdb_db_cmd = 'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"' local gdb_db_cmd = 'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
local lldb_db_cmd = 'lldb -Q -o "bt all" -f "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"' local lldb_db_cmd = 'lldb -Q -o "bt all" -f "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
local random_skip = false local random_skip = false
local local_tmpdir = tmpdir_is_local(tmpdir_get()) and tmpdir_get() or nil
local db_cmd local db_cmd
if hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then if hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY') initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
re = os.getenv('NVIM_TEST_CORE_GLOB_RE') re = os.getenv('NVIM_TEST_CORE_GLOB_RE')
exc_re = os.getenv('NVIM_TEST_CORE_EXC_RE') exc_re = { os.getenv('NVIM_TEST_CORE_EXC_RE'), local_tmpdir }
db_cmd = os.getenv('NVIM_TEST_CORE_DB_CMD') or gdb_db_cmd db_cmd = os.getenv('NVIM_TEST_CORE_DB_CMD') or gdb_db_cmd
random_skip = os.getenv('NVIM_TEST_CORE_RANDOM_SKIP') random_skip = os.getenv('NVIM_TEST_CORE_RANDOM_SKIP')
elseif os.getenv('TRAVIS_OS_NAME') == 'osx' then elseif os.getenv('TRAVIS_OS_NAME') == 'osx' then
initial_path = '/cores' initial_path = '/cores'
re = nil re = nil
exc_re = nil exc_re = { local_tmpdir }
db_cmd = lldb_db_cmd db_cmd = lldb_db_cmd
else else
initial_path = '.' initial_path = '.'
re = '/core[^/]*$' re = '/core[^/]*$'
exc_re = '^/%.deps$' exc_re = { '^/%.deps$', local_tmpdir }
db_cmd = gdb_db_cmd db_cmd = gdb_db_cmd
random_skip = true random_skip = true
end end
-- Finding cores takes too much time on linux -- Finding cores takes too much time on linux
if random_skip and math.random() < 0.9 then if not force and random_skip and math.random() < 0.9 then
tests_skipped = tests_skipped + 1 tests_skipped = tests_skipped + 1
return return
end end

View File

@@ -2,7 +2,6 @@ local helpers = require('test.unit.helpers')(after_each)
local itp = helpers.gen_itp(it) local itp = helpers.gen_itp(it)
local cimport = helpers.cimport local cimport = helpers.cimport
local to_cstr = helpers.to_cstr
local eq = helpers.eq local eq = helpers.eq
local neq = helpers.neq local neq = helpers.neq
local ffi = helpers.ffi local ffi = helpers.ffi
@@ -72,7 +71,7 @@ describe('json_decode_string()', function()
end end
itp('does not overflow in error messages', function() itp('does not overflow in error messages', function()
local saved_p_enc = decode.p_enc collectgarbage('restart')
check_failure(']test', 1, 'E474: No container to close: ]') check_failure(']test', 1, 'E474: No container to close: ]')
check_failure('[}test', 2, 'E474: Closing list with curly bracket: }') check_failure('[}test', 2, 'E474: Closing list with curly bracket: }')
check_failure('{]test', 2, check_failure('{]test', 2,
@@ -105,10 +104,6 @@ describe('json_decode_string()', function()
check_failure('"\194"test', 3, 'E474: Only UTF-8 strings allowed: \194"') check_failure('"\194"test', 3, 'E474: Only UTF-8 strings allowed: \194"')
check_failure('"\252\144\128\128\128\128"test', 8, 'E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"') check_failure('"\252\144\128\128\128\128"test', 8, 'E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"')
check_failure('"test', 1, 'E474: Expected string end: "') check_failure('"test', 1, 'E474: Expected string end: "')
decode.p_enc = to_cstr('latin1')
check_failure('"\\uABCD"test', 8,
'E474: Failed to convert string "ꯍ" from UTF-8')
decode.p_enc = saved_p_enc
check_failure('-test', 1, 'E474: Missing number after minus sign: -') check_failure('-test', 1, 'E474: Missing number after minus sign: -')
check_failure('-1.test', 3, 'E474: Missing number after decimal dot: -1.') check_failure('-1.test', 3, 'E474: Missing number after decimal dot: -1.')
check_failure('-1.0etest', 5, 'E474: Missing exponent: -1.0e') check_failure('-1.0etest', 5, 'E474: Missing exponent: -1.0e')

View File

@@ -468,7 +468,7 @@ local function tbl2callback(tbl)
data={funcref=eval.xstrdup(tbl.fref)}}}) data={funcref=eval.xstrdup(tbl.fref)}}})
elseif tbl.type == 'pt' then elseif tbl.type == 'pt' then
local pt = ffi.gc(ffi.cast('partial_T*', local pt = ffi.gc(ffi.cast('partial_T*',
eval.xcalloc(1, ffi.sizeof('partial_T'))), eval.partial_unref) eval.xcalloc(1, ffi.sizeof('partial_T'))), nil)
ret = ffi.new('Callback[1]', {{type=eval.kCallbackPartial, ret = ffi.new('Callback[1]', {{type=eval.kCallbackPartial,
data={partial=populate_partial(pt, tbl.pt, {})}}}) data={partial=populate_partial(pt, tbl.pt, {})}}})
else else

View File

@@ -47,6 +47,15 @@ local lib = cimport('./src/nvim/eval/typval.h', './src/nvim/memory.h',
'./src/nvim/eval.h', './src/nvim/vim.h', './src/nvim/eval.h', './src/nvim/vim.h',
'./src/nvim/globals.h') './src/nvim/globals.h')
local function vimconv_alloc()
return ffi.gc(
ffi.cast('vimconv_T*', lib.xcalloc(1, ffi.sizeof('vimconv_T'))),
function(vc)
lib.convert_setup(vc, nil, nil)
lib.xfree(vc)
end)
end
local function list_watch_alloc(li) local function list_watch_alloc(li)
return ffi.cast('listwatch_T*', ffi.new('listwatch_T[1]', {{lw_item=li}})) return ffi.cast('listwatch_T*', ffi.new('listwatch_T[1]', {{lw_item=li}}))
end end
@@ -237,24 +246,33 @@ describe('typval.c', function()
list_watch(l, lis[4]), list_watch(l, lis[4]),
list_watch(l, lis[7]), list_watch(l, lis[7]),
} }
alloc_log:check({
a.list(l),
a.li(lis[1]),
a.li(lis[2]),
a.li(lis[3]),
a.li(lis[4]),
a.li(lis[5]),
a.li(lis[6]),
a.li(lis[7]),
})
lib.tv_list_item_remove(l, lis[4]) lib.tv_list_item_remove(l, lis[4])
ffi.gc(lis[4], lib.tv_list_item_free) alloc_log:check({a.freed(lis[4])})
eq({lis[1], lis[5], lis[7]}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item}) eq({lis[1], lis[5], lis[7]}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item})
lib.tv_list_item_remove(l, lis[2]) lib.tv_list_item_remove(l, lis[2])
ffi.gc(lis[2], lib.tv_list_item_free) alloc_log:check({a.freed(lis[2])})
eq({lis[1], lis[5], lis[7]}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item}) eq({lis[1], lis[5], lis[7]}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item})
lib.tv_list_item_remove(l, lis[7]) lib.tv_list_item_remove(l, lis[7])
ffi.gc(lis[7], lib.tv_list_item_free) alloc_log:check({a.freed(lis[7])})
eq({lis[1], lis[5], nil}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item == nil and nil}) eq({lis[1], lis[5], nil}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item == nil and nil})
lib.tv_list_item_remove(l, lis[1]) lib.tv_list_item_remove(l, lis[1])
ffi.gc(lis[1], lib.tv_list_item_free) alloc_log:check({a.freed(lis[1])})
eq({lis[3], lis[5], nil}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item == nil and nil}) eq({lis[3], lis[5], nil}, {lws[1].lw_item, lws[2].lw_item, lws[3].lw_item == nil and nil})
alloc_log:clear()
lib.tv_list_watch_remove(l, lws[2]) lib.tv_list_watch_remove(l, lws[2])
lib.tv_list_watch_remove(l, lws[3]) lib.tv_list_watch_remove(l, lws[3])
lib.tv_list_watch_remove(l, lws[1]) lib.tv_list_watch_remove(l, lws[1])
@@ -460,6 +478,10 @@ describe('typval.c', function()
eq(empty_list, typvalt2lua(l_tv)) eq(empty_list, typvalt2lua(l_tv))
eq({true, true, true}, {lws[1].lw_item == nil, lws[2].lw_item == nil, lws[3].lw_item == nil}) eq({true, true, true}, {lws[1].lw_item == nil, lws[2].lw_item == nil, lws[3].lw_item == nil})
lib.tv_list_watch_remove(l, lws[1])
lib.tv_list_watch_remove(l, lws[2])
lib.tv_list_watch_remove(l, lws[3])
alloc_log:check({}) alloc_log:check({})
end) end)
end) end)
@@ -730,10 +752,8 @@ describe('typval.c', function()
collectgarbage() collectgarbage()
end) end)
itp('copies list correctly and converts items', function() itp('copies list correctly and converts items', function()
local vc = ffi.gc(ffi.new('vimconv_T[1]'), function(vc) local vc = vimconv_alloc()
lib.convert_setup(vc, nil, nil) -- UTF-8 ↔ latin1 conversions needs no iconv
end)
-- UTF-8 ↔ latin1 conversions need no iconv
eq(OK, lib.convert_setup(vc, to_cstr('utf-8'), to_cstr('latin1'))) eq(OK, lib.convert_setup(vc, to_cstr('utf-8'), to_cstr('latin1')))
local v = {{['«']='»'}, {''}, 1, '', null_string, null_list, null_dict} local v = {{['«']='»'}, {''}, 1, '', null_string, null_list, null_dict}
@@ -1087,12 +1107,16 @@ describe('typval.c', function()
end) end)
end) end)
describe('join()', function() describe('join()', function()
local function list_join(l, sep, ret) local function list_join(l, sep, join_ret)
local ga = ga_alloc() local ga = ga_alloc()
eq(ret or OK, lib.tv_list_join(ga, l, sep)) eq(join_ret or OK, lib.tv_list_join(ga, l, sep))
if ga.ga_data == nil then return '' local ret = ''
else return ffi.string(ga.ga_data) if ga.ga_data ~= nil then
ret = ffi.string(ga.ga_data)
end end
-- For some reason this is not working well in GC
lib.ga_clear(ffi.gc(ga, nil))
return ret
end end
itp('works', function() itp('works', function()
local l local l
@@ -1508,7 +1532,7 @@ describe('typval.c', function()
eq(s:sub(1, len), ffi.string(di.di_key)) eq(s:sub(1, len), ffi.string(di.di_key))
alloc_log:check({a.di(di, len)}) alloc_log:check({a.di(di, len)})
if tv then if tv then
di.di_tv = tv di.di_tv = ffi.gc(tv, nil)
else else
di.di_tv.v_type = lib.VAR_UNKNOWN di.di_tv.v_type = lib.VAR_UNKNOWN
end end
@@ -1539,7 +1563,7 @@ describe('typval.c', function()
alloc_log:check({a.dict(d)}) alloc_log:check({a.dict(d)})
local di = ffi.gc(lib.tv_dict_item_alloc(''), nil) local di = ffi.gc(lib.tv_dict_item_alloc(''), nil)
local tv = lua2typvalt('test') local tv = lua2typvalt('test')
di.di_tv = tv di.di_tv = ffi.gc(tv, nil)
alloc_log:check({a.di(di, ''), a.str(tv.vval.v_string, 'test')}) alloc_log:check({a.di(di, ''), a.str(tv.vval.v_string, 'test')})
eq(OK, lib.tv_dict_add(d, di)) eq(OK, lib.tv_dict_add(d, di))
alloc_log:check({}) alloc_log:check({})
@@ -2131,9 +2155,7 @@ describe('typval.c', function()
collectgarbage() collectgarbage()
end) end)
itp('copies dict correctly and converts items', function() itp('copies dict correctly and converts items', function()
local vc = ffi.gc(ffi.new('vimconv_T[1]'), function(vc) local vc = vimconv_alloc()
lib.convert_setup(vc, nil, nil)
end)
-- UTF-8 ↔ latin1 conversions need no iconv -- UTF-8 ↔ latin1 conversions need no iconv
eq(OK, lib.convert_setup(vc, to_cstr('utf-8'), to_cstr('latin1'))) eq(OK, lib.convert_setup(vc, to_cstr('utf-8'), to_cstr('latin1')))
@@ -2659,7 +2681,8 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0},
{lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', 0},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]
@@ -2687,7 +2710,8 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 0},
{lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', 0},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = {v[4], not not emsg} local ret = {v[4], not not emsg}
@@ -2721,7 +2745,8 @@ describe('typval.c', function()
{lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', -1}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_number(UNKNOWN)', -1},
}) do }) do
lib.curwin.w_cursor.lnum = 46 lib.curwin.w_cursor.lnum = 46
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]
@@ -2749,7 +2774,8 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, 'E907: Using a special value as a Float', 0}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, 'E907: Using a special value as a Float', 0},
{lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_float(UNKNOWN)', 0}, {lib.VAR_UNKNOWN, nil, 'E685: Internal error: tv_get_float(UNKNOWN)', 0},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]
@@ -2780,7 +2806,9 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'},
{lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr in place of Neovim allocated string, cannot
-- tv_clear() that.
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]
@@ -2821,7 +2849,8 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'},
{lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]
@@ -2861,7 +2890,8 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'},
{lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', ''},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]
@@ -2902,7 +2932,8 @@ describe('typval.c', function()
{lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'}, {lib.VAR_SPECIAL, {v_special=lib.kSpecialVarFalse}, nil, 'false'},
{lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil}, {lib.VAR_UNKNOWN, nil, 'E908: using an invalid value as a String', nil},
}) do }) do
local tv = typvalt(v[1], v[2]) -- Using to_cstr, cannot free with tv_clear
local tv = ffi.gc(typvalt(v[1], v[2]), nil)
alloc_log:check({}) alloc_log:check({})
local emsg = v[3] local emsg = v[3]
local ret = v[4] local ret = v[4]

View File

@@ -632,8 +632,9 @@ local function itp_child(wr, func)
collectgarbage('stop') collectgarbage('stop')
child_sethook(wr) child_sethook(wr)
local err, emsg = pcall(func) local err, emsg = pcall(func)
debug.sethook()
collectgarbage('restart') collectgarbage('restart')
collectgarbage()
debug.sethook()
emsg = tostring(emsg) emsg = tostring(emsg)
sc.write(wr, trace_end_msg) sc.write(wr, trace_end_msg)
if not err then if not err then
@@ -654,6 +655,7 @@ end
local function check_child_err(rd) local function check_child_err(rd)
local trace = {} local trace = {}
local did_traceline = false
while true do while true do
local traceline = sc.read(rd, hook_msglen) local traceline = sc.read(rd, hook_msglen)
if #traceline ~= hook_msglen then if #traceline ~= hook_msglen then
@@ -664,6 +666,7 @@ local function check_child_err(rd)
end end
end end
if traceline == trace_end_msg then if traceline == trace_end_msg then
did_traceline = true
break break
end end
trace[#trace + 1] = traceline trace[#trace + 1] = traceline
@@ -679,6 +682,13 @@ local function check_child_err(rd)
error = error .. trace[i] error = error .. trace[i]
end end
end end
if not did_traceline then
error = error .. '\nNo end of trace occurred'
end
local cc_err, cc_emsg = pcall(check_cores, Paths.test_luajit_prg, true)
if not cc_err then
error = error .. '\ncheck_cores failed: ' .. cc_emsg
end
assert.just_fail(error) assert.just_fail(error)
end end
if res == '+\n' then if res == '+\n' then
@@ -764,11 +774,6 @@ local module = {
child_cleanup_once = child_cleanup_once, child_cleanup_once = child_cleanup_once,
sc = sc, sc = sc,
} }
return function(after_each) return function()
if after_each then
after_each(function()
check_cores(Paths.test_luajit_prg)
end)
end
return module return module
end end