aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt49
-rw-r--r--cmake/LuaHelpers.cmake4
-rw-r--r--runtime/autoload/remote/host.vim1
-rw-r--r--runtime/doc/repeat.txt32
-rw-r--r--runtime/optwin.vim4
-rwxr-xr-xscripts/vim-patch.sh55
-rw-r--r--src/nvim/CMakeLists.txt1
-rw-r--r--src/nvim/assert.h9
-rw-r--r--src/nvim/eval.c29
-rw-r--r--src/nvim/ex_cmds.c15
-rw-r--r--src/nvim/ex_cmds2.c135
-rw-r--r--src/nvim/globals.h10
-rw-r--r--src/nvim/message.c107
-rw-r--r--src/nvim/misc2.c5
-rw-r--r--src/nvim/msgpack_rpc/remote_ui.c12
-rw-r--r--src/nvim/option.c19
-rw-r--r--src/nvim/quickfix.c3
-rw-r--r--src/nvim/screen.c54
-rw-r--r--src/nvim/syntax.c89
-rw-r--r--src/nvim/syntax_defs.h4
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/test_breakindent.in123
-rw-r--r--src/nvim/testdir/test_breakindent.ok74
-rw-r--r--src/nvim/testdir/test_menu.vim9
-rw-r--r--src/nvim/tui/tui.c6
-rw-r--r--src/nvim/ugrid.h2
-rw-r--r--src/nvim/ui.c7
-rw-r--r--src/nvim/ui.h3
-rw-r--r--src/nvim/ui_bridge.c11
-rw-r--r--src/nvim/version.c21
-rw-r--r--test/functional/legacy/108_backtrace_debug_commands_spec.lua177
-rw-r--r--test/functional/legacy/breakindent_spec.lua211
-rw-r--r--test/functional/legacy/set_spec.lua15
-rw-r--r--test/functional/terminal/highlight_spec.lua6
-rw-r--r--test/functional/ui/highlight_spec.lua351
-rw-r--r--test/functional/ui/mouse_spec.lua17
-rw-r--r--test/functional/ui/screen.lua9
37 files changed, 1270 insertions, 411 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 98ffc77b15..317d2a1a5b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -300,9 +300,6 @@ include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS})
find_package(Msgpack 1.0.0 REQUIRED)
include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS})
-find_package(LuaJit REQUIRED)
-include_directories(SYSTEM ${LUAJIT_INCLUDE_DIRS})
-
find_package(Unibilium REQUIRED)
include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS})
@@ -451,6 +448,14 @@ if(BUSTED_PRG)
get_target_property(TEST_LIBNVIM_PATH nvim-test LOCATION)
endif()
+ # When running tests from 'ninja' we need to use the
+ # console pool: to do so we need to use the USES_TERMINAL
+ # option, but this is only available in CMake 3.2
+ set(TEST_TARGET_ARGS)
+ if(NOT (${CMAKE_VERSION} VERSION_LESS 3.2.0))
+ list(APPEND TEST_TARGET_ARGS "USES_TERMINAL")
+ endif()
+
configure_file(
test/config/paths.lua.in
${CMAKE_BINARY_DIR}/test/config/paths.lua)
@@ -469,17 +474,24 @@ if(BUSTED_PRG)
add_custom_target(benchmark-prereqs
DEPENDS ${BENCHMARK_PREREQS})
- add_custom_target(unittest
- COMMAND ${CMAKE_COMMAND}
- -DBUSTED_PRG=${BUSTED_PRG}
- -DLUA_PRG=${LUA_PRG}
- -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR}
- -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
- -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
- -DBUILD_DIR=${CMAKE_BINARY_DIR}
- -DTEST_TYPE=unit
- -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
- DEPENDS ${UNITTEST_PREREQS})
+ check_lua_module(${LUA_PRG} "ffi" LUA_HAS_FFI)
+ if(LUA_HAS_FFI)
+ add_custom_target(unittest
+ COMMAND ${CMAKE_COMMAND}
+ -DBUSTED_PRG=${BUSTED_PRG}
+ -DLUA_PRG=${LUA_PRG}
+ -DWORKING_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -DBUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE}
+ -DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
+ -DBUILD_DIR=${CMAKE_BINARY_DIR}
+ -DTEST_TYPE=unit
+ -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
+ DEPENDS ${UNITTEST_PREREQS}
+ ${TEST_TARGET_ARGS})
+ else()
+ message(WARNING "The Luajit ffi is not available in ${LUA_PRG}"
+ ", disabling unit tests")
+ endif()
add_custom_target(functionaltest
COMMAND ${CMAKE_COMMAND}
@@ -491,7 +503,8 @@ if(BUSTED_PRG)
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=functional
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
- DEPENDS ${FUNCTIONALTEST_PREREQS})
+ DEPENDS ${FUNCTIONALTEST_PREREQS}
+ ${TEST_TARGET_ARGS})
add_custom_target(benchmark
COMMAND ${CMAKE_COMMAND}
@@ -503,7 +516,8 @@ if(BUSTED_PRG)
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=benchmark
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
- DEPENDS ${BENCHMARK_PREREQS})
+ DEPENDS ${BENCHMARK_PREREQS}
+ ${TEST_TARGET_ARGS})
endif()
if(BUSTED_LUA_PRG)
@@ -517,7 +531,8 @@ if(BUSTED_LUA_PRG)
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=functional
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
- DEPENDS ${FUNCTIONALTEST_PREREQS})
+ DEPENDS ${FUNCTIONALTEST_PREREQS}
+ ${TEST_TARGET_ARGS})
endif()
if(LUACHECK_PRG)
diff --git a/cmake/LuaHelpers.cmake b/cmake/LuaHelpers.cmake
index b1e67e0ca7..32f7e46a57 100644
--- a/cmake/LuaHelpers.cmake
+++ b/cmake/LuaHelpers.cmake
@@ -8,8 +8,6 @@ function(check_lua_module LUA_PRG_PATH MODULE RESULT_VAR)
RESULT_VARIABLE module_missing
ERROR_QUIET)
if(module_missing)
- message(STATUS
- "[${LUA_PRG_PATH}] The '${MODULE}' lua package is required for building Neovim")
set(${RESULT_VAR} False PARENT_SCOPE)
else()
set(${RESULT_VAR} True PARENT_SCOPE)
@@ -29,6 +27,8 @@ function(check_lua_deps LUA_PRG_PATH MODULES RESULT_VAR)
foreach(module ${MODULES})
check_lua_module(${LUA_PRG_PATH} ${module} has_module)
if(NOT has_module)
+ message(STATUS
+ "[${LUA_PRG_PATH}] The '${module}' lua package is required for building Neovim")
set(${RESULT_VAR} False PARENT_SCOPE)
return()
endif()
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index 8faeaed2ea..a63c6a923b 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -140,6 +140,7 @@ function! s:RegistrationCommands(host) abort
call remote#host#RegisterClone(host_id, a:host)
let pattern = s:plugin_patterns[a:host]
let paths = globpath(&rtp, 'rplugin/'.a:host.'/'.pattern, 0, 1)
+ let paths = map(paths, 'tr(v:val,"\\","/")') " Normalize slashes #4795
if empty(paths)
return []
endif
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index b2e935eb3f..343d3e62cf 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -1,4 +1,4 @@
-*repeat.txt* For Vim version 7.4. Last change: 2015 Apr 13
+*repeat.txt* For Vim version 7.4. Last change: 2016 Jan 16
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -467,16 +467,44 @@ Additionally, these commands can be used:
finish Finish the current script or user function and come
back to debug mode for the command after the one that
sourced or called it.
+ *>bt*
+ *>backtrace*
+ *>where*
+ backtrace Show the call stacktrace for current debugging session.
+ bt
+ where
+ *>frame*
+ frame N Goes to N backtrace level. + and - signs make movement
+ relative. E.g., ":frame +3" goes three frames up.
+ *>up*
+ up Goes one level up from call stacktrace.
+ *>down*
+ down Goes one level down from call stacktrace.
About the additional commands in debug mode:
- There is no command-line completion for them, you get the completion for the
normal Ex commands only.
-- You can shorten them, up to a single character: "c", "n", "s" and "f".
+- You can shorten them, up to a single character, unless more then one command
+ starts with the same letter. "f" stands for "finish", use "fr" for "frame".
- Hitting <CR> will repeat the previous one. When doing another command, this
is reset (because it's not clear what you want to repeat).
- When you want to use the Ex command with the same name, prepend a colon:
":cont", ":next", ":finish" (or shorter).
+The backtrace shows the hierarchy of function calls, e.g.:
+ >bt ~
+ 3 function One[3] ~
+ 2 Two[3] ~
+ ->1 Three[3] ~
+ 0 Four ~
+ line 1: let four = 4 ~
+
+The "->" points to the current frame. Use "up", "down" and "frame N" to
+select another frame.
+
+In the current frame you can evaluate the local function variables. There is
+no way to see the command at the current line yet.
+
DEFINING BREAKPOINTS
*:breaka* *:breakadd*
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 07dcd31b1b..68444dde01 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -766,7 +766,7 @@ call append("$", "infercase\tadjust case of a keyword completion match")
call append("$", "\t(local to buffer)")
call <SID>BinOptionL("inf")
if has("digraphs")
- call append("$", "digraph\tenable entering digraps with c1 <BS> c2")
+ call append("$", "digraph\tenable entering digraphs with c1 <BS> c2")
call <SID>BinOptionG("dg", &dg)
endif
call append("$", "tildeop\tthe \"~\" command behaves like an operator")
@@ -1142,7 +1142,7 @@ if has("arabic")
call <SID>BinOptionG("tbidi", &tbidi)
endif
if has("keymap")
- call append("$", "keymap\tname of a keyboard mappping")
+ call append("$", "keymap\tname of a keyboard mapping")
call <SID>OptionL("kmp")
endif
if has("langmap")
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 751f50d290..7a0001769a 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -33,7 +33,11 @@ usage() {
# Checks if a program is in the user's PATH, and is executable.
check_executable() {
- if [[ ! -x $(command -v "${1}") ]]; then
+ test -x "$(command -v "${1}")"
+}
+
+require_executable() {
+ if ! check_executable "${1}"; then
>&2 echo "${BASENAME}: '${1}' not found in PATH or not executable."
exit 1
fi
@@ -61,7 +65,7 @@ clean_files() {
}
get_vim_sources() {
- check_executable git
+ require_executable git
if [[ ! -d ${VIM_SOURCE_DIR} ]]; then
echo "Cloning Vim sources into '${VIM_SOURCE_DIR}'."
@@ -194,9 +198,28 @@ get_vim_patch() {
echo " for more information."
}
+hub_pr() {
+ hub pull-request -m "$1"
+}
+
+git_hub_pr() {
+ git hub pull new -m "$1"
+}
+
submit_pr() {
- check_executable git
- check_executable hub
+ require_executable git
+ local push_first
+ push_first=1
+ local submit_fn
+ if check_executable hub; then
+ submit_fn="hub_pr"
+ elif check_executable git-hub; then
+ push_first=0
+ submit_fn="git_hub_pr"
+ else
+ >&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable."
+ exit 1
+ fi
cd "${NEOVIM_SOURCE_DIR}"
local checked_out_branch
@@ -219,14 +242,17 @@ submit_pr() {
local pr_message
pr_message="$(printf '[RFC] vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")"
- echo "Pushing to 'origin/${checked_out_branch}'."
- output="$(git push origin "${checked_out_branch}" 2>&1)" &&
- echo "✔ ${output}" ||
- (echo "✘ ${output}"; git reset --soft HEAD^1; false)
+ if [[ $push_first -ne 0 ]]; then
+ echo "Pushing to 'origin/${checked_out_branch}'."
+ output="$(git push origin "${checked_out_branch}" 2>&1)" &&
+ echo "✔ ${output}" ||
+ (echo "✘ ${output}"; git reset --soft HEAD^1; false)
+
+ echo
+ fi
- echo
echo "Creating pull request."
- output="$(hub pull-request -F - 2>&1 <<< "${pr_message}")" &&
+ output="$(${submit_fn} "${pr_message}" 2>&1)" &&
echo "✔ ${output}" ||
(echo "✘ ${output}"; false)
@@ -264,6 +290,9 @@ list_vim_patches() {
is_missing="$(sed -n '/static int included_patches/,/}/p' "${NEOVIM_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 show --name-only "v${vim_commit}" 2>/dev/null) | grep -q ^runtime; then
+ vim_commit="${vim_commit} (+runtime)"
+ fi
else
# Untagged Vim patch (e.g. runtime updates), check the Neovim git log:
is_missing="$(cd "${NEOVIM_SOURCE_DIR}" &&
@@ -346,9 +375,9 @@ review_commit() {
}
review_pr() {
- check_executable curl
- check_executable nvim
- check_executable jq
+ require_executable curl
+ require_executable nvim
+ require_executable jq
get_vim_sources
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 6b2ce08d36..172643091a 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -231,7 +231,6 @@ endif()
list(APPEND NVIM_LINK_LIBRARIES
${LIBUV_LIBRARIES}
${MSGPACK_LIBRARIES}
- ${LUAJIT_LIBRARIES}
${LIBVTERM_LIBRARIES}
${LIBTERMKEY_LIBRARIES}
${UNIBILIUM_LIBRARIES}
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
index 2c43777858..761636305e 100644
--- a/src/nvim/assert.h
+++ b/src/nvim/assert.h
@@ -65,9 +65,16 @@
# define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
# undef STATIC_ASSERT_PRAGMA_START
+
+#if __GNUC__ >= 6
# define STATIC_ASSERT_PRAGMA_START \
_Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-pedantic\"") \
+ _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
+#else
+# define STATIC_ASSERT_PRAGMA_START \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-pedantic\"")
+#endif
# undef STATIC_ASSERT_PRAGMA_END
# define STATIC_ASSERT_PRAGMA_END \
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 712ee06b85..201a71facb 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -18123,6 +18123,25 @@ static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, in
return HI2DI(hi);
}
+// Get function call environment based on backtrace debug level
+static funccall_T *get_funccal(void)
+{
+ funccall_T *funccal = current_funccal;
+ if (debug_backtrace_level > 0) {
+ for (int i = 0; i < debug_backtrace_level; i++) {
+ funccall_T *temp_funccal = funccal->caller;
+ if (temp_funccal) {
+ funccal = temp_funccal;
+ } else {
+ // backtrace level overflow. reset to max
+ debug_backtrace_level = i;
+ }
+ }
+ }
+
+ return funccal;
+}
+
// Find the dict and hashtable used for a variable name. Set "varname" to the
// start of name without ':'.
static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
@@ -18147,7 +18166,11 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
return &compat_hashtab;
}
- *d = current_funccal ? &current_funccal->l_vars : &globvardict;
+ if (current_funccal == NULL) {
+ *d = &globvardict;
+ } else {
+ *d = &get_funccal()->l_vars; // l: variable
+ }
goto end;
}
@@ -18169,9 +18192,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)
} else if (*name == 'v') { // v: variable
*d = &vimvardict;
} else if (*name == 'a' && current_funccal != NULL) { // function argument
- *d = &current_funccal->l_avars;
+ *d = &get_funccal()->l_avars;
} else if (*name == 'l' && current_funccal != NULL) { // local variable
- *d = &current_funccal->l_vars;
+ *d = &get_funccal()->l_vars;
} else if (*name == 's' // script variable
&& current_SID > 0 && current_SID <= ga_scripts.ga_len) {
*d = &SCRIPT_SV(current_SID)->sv_dict;
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 415d6ee460..86f1a16216 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3816,16 +3816,17 @@ skip:
EMSG2(_(e_patnotf2), get_search_pat());
}
- if (do_ask && hasAnyFolding(curwin))
- /* Cursor position may require updating */
+ if (do_ask && hasAnyFolding(curwin)) {
+ // Cursor position may require updating
changed_window_setting();
+ }
- vim_regfree(regmatch.regprog);
+ vim_regfree(regmatch.regprog);
- // Restore the flag values, they can be used for ":&&".
- do_all = save_do_all;
- do_ask = save_do_ask;
- }
+ // Restore the flag values, they can be used for ":&&".
+ do_all = save_do_all;
+ do_ask = save_do_ask;
+}
/*
* Give message for number of substitutions.
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index df387f9a60..5fe6209a0a 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -144,6 +144,10 @@ void do_debug(char_u *cmd)
#define CMD_FINISH 4
#define CMD_QUIT 5
#define CMD_INTERRUPT 6
+#define CMD_BACKTRACE 7
+#define CMD_FRAME 8
+#define CMD_UP 9
+#define CMD_DOWN 10
++RedrawingDisabled; /* don't redisplay the window */
@@ -185,6 +189,7 @@ void do_debug(char_u *cmd)
ignore_script = TRUE;
}
+ xfree(cmdline);
cmdline = getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL);
if (typeahead_saved) {
@@ -194,6 +199,7 @@ void do_debug(char_u *cmd)
ex_normal_busy = save_ex_normal_busy;
cmdline_row = msg_row;
+ msg_starthere();
if (cmdline != NULL) {
/* If this is a debug command, set "last_cmd".
* If not, reset "last_cmd".
@@ -210,8 +216,15 @@ void do_debug(char_u *cmd)
case 's': last_cmd = CMD_STEP;
tail = "tep";
break;
- case 'f': last_cmd = CMD_FINISH;
- tail = "inish";
+ case 'f':
+ last_cmd = 0;
+ if (p[1] == 'r') {
+ last_cmd = CMD_FRAME;
+ tail = "rame";
+ } else {
+ last_cmd = CMD_FINISH;
+ tail = "inish";
+ }
break;
case 'q': last_cmd = CMD_QUIT;
tail = "uit";
@@ -219,6 +232,26 @@ void do_debug(char_u *cmd)
case 'i': last_cmd = CMD_INTERRUPT;
tail = "nterrupt";
break;
+ case 'b':
+ last_cmd = CMD_BACKTRACE;
+ if (p[1] == 't') {
+ tail = "t";
+ } else {
+ tail = "acktrace";
+ }
+ break;
+ case 'w':
+ last_cmd = CMD_BACKTRACE;
+ tail = "here";
+ break;
+ case 'u':
+ last_cmd = CMD_UP;
+ tail = "p";
+ break;
+ case 'd':
+ last_cmd = CMD_DOWN;
+ tail = "own";
+ break;
default: last_cmd = 0;
}
if (last_cmd != 0) {
@@ -228,8 +261,9 @@ void do_debug(char_u *cmd)
++p;
++tail;
}
- if (ASCII_ISALPHA(*p))
+ if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) {
last_cmd = 0;
+ }
}
}
@@ -259,7 +293,28 @@ void do_debug(char_u *cmd)
/* Do not repeat ">interrupt" cmd, continue stepping. */
last_cmd = CMD_STEP;
break;
+ case CMD_BACKTRACE:
+ do_showbacktrace(cmd);
+ continue;
+ case CMD_FRAME:
+ if (*p == NUL) {
+ do_showbacktrace(cmd);
+ } else {
+ p = skipwhite(p);
+ do_setdebugtracelevel(p);
+ }
+ continue;
+ case CMD_UP:
+ debug_backtrace_level++;
+ do_checkbacktracelevel();
+ continue;
+ case CMD_DOWN:
+ debug_backtrace_level--;
+ do_checkbacktracelevel();
+ continue;
}
+ // Going out reset backtrace_level
+ debug_backtrace_level = 0;
break;
}
@@ -269,8 +324,6 @@ void do_debug(char_u *cmd)
(void)do_cmdline(cmdline, getexline, NULL,
DOCMD_VERBOSE|DOCMD_EXCRESET);
debug_break_level = n;
-
- xfree(cmdline);
}
lines_left = (int)(Rows - 1);
}
@@ -294,6 +347,78 @@ void do_debug(char_u *cmd)
debug_did_msg = TRUE;
}
+static int get_maxbacktrace_level(void)
+{
+ int maxbacktrace = 0;
+
+ if (sourcing_name != NULL) {
+ char *p = (char *)sourcing_name;
+ char *q;
+ while ((q = strstr(p, "..")) != NULL) {
+ p = q + 2;
+ maxbacktrace++;
+ }
+ }
+ return maxbacktrace;
+}
+
+static void do_setdebugtracelevel(char_u *arg)
+{
+ int level = atoi((char *)arg);
+ if (*arg == '+' || level < 0) {
+ debug_backtrace_level += level;
+ } else {
+ debug_backtrace_level = level;
+ }
+
+ do_checkbacktracelevel();
+}
+
+static void do_checkbacktracelevel(void)
+{
+ if (debug_backtrace_level < 0) {
+ debug_backtrace_level = 0;
+ MSG(_("frame is zero"));
+ } else {
+ int max = get_maxbacktrace_level();
+ if (debug_backtrace_level > max) {
+ debug_backtrace_level = max;
+ smsg(_("frame at highest level: %d"), max);
+ }
+ }
+}
+
+static void do_showbacktrace(char_u *cmd)
+{
+ if (sourcing_name != NULL) {
+ int i = 0;
+ int max = get_maxbacktrace_level();
+ char *cur = (char *)sourcing_name;
+ while (!got_int) {
+ char *next = strstr(cur, "..");
+ if (next != NULL) {
+ *next = NUL;
+ }
+ if (i == max - debug_backtrace_level) {
+ smsg("->%d %s", max - i, cur);
+ } else {
+ smsg(" %d %s", max - i, cur);
+ }
+ i++;
+ if (next == NULL) {
+ break;
+ }
+ *next = '.';
+ cur = next + 2;
+ }
+ }
+ if (sourcing_lnum != 0) {
+ smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
+ } else {
+ smsg(_("cmd: %s"), cmd);
+ }
+}
+
/*
* ":debug".
*/
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 49d1de21d9..dafb75ca87 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -293,10 +293,11 @@ EXTERN int msg_no_more INIT(= FALSE); /* don't use more prompt, truncate
EXTERN char_u *sourcing_name INIT( = NULL); /* name of error message source */
EXTERN linenr_T sourcing_lnum INIT(= 0); /* line number of the source file */
-EXTERN int ex_nesting_level INIT(= 0); /* nesting level */
-EXTERN int debug_break_level INIT(= -1); /* break below this level */
-EXTERN int debug_did_msg INIT(= FALSE); /* did "debug mode" message */
-EXTERN int debug_tick INIT(= 0); /* breakpoint change count */
+EXTERN int ex_nesting_level INIT(= 0); // nesting level
+EXTERN int debug_break_level INIT(= -1); // break below this level
+EXTERN int debug_did_msg INIT(= false); // did "debug mode" message
+EXTERN int debug_tick INIT(= 0); // breakpoint change count
+EXTERN int debug_backtrace_level INIT(= 0); // breakpoint backtrace level
/* Values for "do_profiling". */
#define PROF_NONE 0 /* profiling not started */
@@ -503,6 +504,7 @@ EXTERN int cterm_normal_fg_bold INIT(= 0);
EXTERN int cterm_normal_bg_color INIT(= 0);
EXTERN RgbValue normal_fg INIT(= -1);
EXTERN RgbValue normal_bg INIT(= -1);
+EXTERN RgbValue normal_sp INIT(= -1);
EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */
EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 265f8c00c0..47f246fc76 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1508,51 +1508,44 @@ void msg_puts_attr(char_u *s, int attr)
msg_puts_attr_len(s, -1, attr);
}
-/*
- * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
- * When "maxlen" is -1 there is no maximum length.
- * When "maxlen" is >= 0 the message is not put in the history.
- */
+/// Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
+/// When "maxlen" is -1 there is no maximum length.
+/// When "maxlen" is >= 0 the message is not put in the history.
static void msg_puts_attr_len(char_u *str, int maxlen, int attr)
{
- /*
- * If redirection is on, also write to the redirection file.
- */
+ // If redirection is on, also write to the redirection file.
redir_write(str, maxlen);
- /*
- * Don't print anything when using ":silent cmd".
- */
- if (msg_silent != 0)
+ // Don't print anything when using ":silent cmd".
+ if (msg_silent != 0) {
return;
+ }
- /* if MSG_HIST flag set, add message to history */
+ // if MSG_HIST flag set, add message to history
if ((attr & MSG_HIST) && maxlen < 0) {
add_msg_hist(str, -1, attr);
attr &= ~MSG_HIST;
}
- /*
- * When writing something to the screen after it has scrolled, requires a
- * wait-return prompt later. Needed when scrolling, resetting
- * need_wait_return after some prompt, and then outputting something
- * without scrolling
- */
- if (msg_scrolled != 0 && !msg_scrolled_ign)
- need_wait_return = TRUE;
- msg_didany = TRUE; /* remember that something was outputted */
+ // When writing something to the screen after it has scrolled, requires a
+ // wait-return prompt later. Needed when scrolling, resetting
+ // need_wait_return after some prompt, and then outputting something
+ // without scrolling
+ if (msg_scrolled != 0 && !msg_scrolled_ign) {
+ need_wait_return = true;
+ }
+ msg_didany = true; // remember that something was outputted
- /*
- * If there is no valid screen, use fprintf so we can see error messages.
- * If termcap is not active, we may be writing in an alternate console
- * window, cursor positioning may not work correctly (window size may be
- * different, e.g. for Win32 console) or we just don't know where the
- * cursor is.
- */
- if (msg_use_printf())
- msg_puts_printf(str, maxlen);
- else
- msg_puts_display(str, maxlen, attr, FALSE);
+ // If there is no valid screen, use fprintf so we can see error messages.
+ // If termcap is not active, we may be writing in an alternate console
+ // window, cursor positioning may not work correctly (window size may be
+ // different, e.g. for Win32 console) or we just don't know where the
+ // cursor is.
+ if (msg_use_printf()) {
+ msg_puts_printf((char *)str, maxlen);
+ } else {
+ msg_puts_display(str, maxlen, attr, false);
+ }
}
/*
@@ -1926,46 +1919,46 @@ int msg_use_printf(void)
return !embedded_mode && !ui_active();
}
-/*
- * Print a message when there is no valid screen.
- */
-static void msg_puts_printf(char_u *str, int maxlen)
+/// Print a message when there is no valid screen.
+static void msg_puts_printf(char *str, int maxlen)
{
- char_u *s = str;
- char_u buf[4];
- char_u *p;
+ char *s = str;
+ char buf[4];
+ char *p;
while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) {
if (!(silent_mode && p_verbose == 0)) {
- /* NL --> CR NL translation (for Unix, not for "--version") */
- /* NL --> CR translation (for Mac) */
+ // NL --> CR NL translation (for Unix, not for "--version")
p = &buf[0];
- if (*s == '\n' && !info_message)
+ if (*s == '\n' && !info_message) {
*p++ = '\r';
+ }
*p++ = *s;
*p = '\0';
- if (info_message) /* informative message, not an error */
- mch_msg((char *)buf);
- else
- mch_errmsg((char *)buf);
+ if (info_message) {
+ mch_msg(buf);
+ } else {
+ mch_errmsg(buf);
+ }
}
- /* primitive way to compute the current column */
+ // primitive way to compute the current column
if (cmdmsg_rl) {
- if (*s == '\r' || *s == '\n')
+ if (*s == '\r' || *s == '\n') {
msg_col = Columns - 1;
- else
- --msg_col;
+ } else {
+ msg_col--;
+ }
} else {
- if (*s == '\r' || *s == '\n')
+ if (*s == '\r' || *s == '\n') {
msg_col = 0;
- else
- ++msg_col;
+ } else {
+ msg_col++;
+ }
}
- ++s;
+ s++;
}
- msg_didout = TRUE; /* assume that line is not empty */
-
+ msg_didout = true; // assume that line is not empty
}
/*
diff --git a/src/nvim/misc2.c b/src/nvim/misc2.c
index 4b64de1be0..368f83cfb5 100644
--- a/src/nvim/misc2.c
+++ b/src/nvim/misc2.c
@@ -467,11 +467,12 @@ bool put_bytes(FILE *fd, uintmax_t number, size_t len)
}
/// Writes time_t to file "fd" in 8 bytes.
-void put_time(FILE *fd, time_t time_)
+/// @returns FAIL when the write failed.
+int put_time(FILE *fd, time_t time_)
{
uint8_t buf[8];
time_to_bytes(time_, buf);
- (void)fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd);
+ return fwrite(buf, sizeof(uint8_t), ARRAY_SIZE(buf), fd) == 1 ? OK : FAIL;
}
/// Writes time_t to "buf[8]".
diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c
index f0d92b52a0..6ffcffe2e1 100644
--- a/src/nvim/msgpack_rpc/remote_ui.c
+++ b/src/nvim/msgpack_rpc/remote_ui.c
@@ -96,6 +96,7 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id,
ui->visual_bell = remote_ui_visual_bell;
ui->update_fg = remote_ui_update_fg;
ui->update_bg = remote_ui_update_bg;
+ ui->update_sp = remote_ui_update_sp;
ui->flush = remote_ui_flush;
ui->suspend = remote_ui_suspend;
ui->set_title = remote_ui_set_title;
@@ -285,6 +286,10 @@ static void remote_ui_highlight_set(UI *ui, HlAttrs attrs)
PUT(hl, "background", INTEGER_OBJ(attrs.background));
}
+ if (attrs.special != -1) {
+ PUT(hl, "special", INTEGER_OBJ(attrs.special));
+ }
+
ADD(args, DICTIONARY_OBJ(hl));
push_call(ui, "highlight_set", args);
}
@@ -323,6 +328,13 @@ static void remote_ui_update_bg(UI *ui, int bg)
push_call(ui, "update_bg", args);
}
+static void remote_ui_update_sp(UI *ui, int sp)
+{
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, INTEGER_OBJ(sp));
+ push_call(ui, "update_sp", args);
+}
+
static void remote_ui_flush(UI *ui)
{
UIData *data = ui->data;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 2f22c245dd..45ebb4fa4c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1639,18 +1639,21 @@ do_set (
&& STRNCMP(s, newval, i) == 0
&& (!(flags & P_COMMA)
|| s[i] == ','
- || s[i] == NUL))
+ || s[i] == NUL)) {
break;
- /* Count backslashes. Only a comma with an
- * even number of backslashes before it is
- * recognized as a separator */
- if (s > origval && s[-1] == '\\')
- ++bs;
- else
+ }
+ // Count backslashes. Only a comma with an even number of
+ // backslashes or a single backslash preceded by a comma
+ // before it is recognized as a separator
+ if ((s > origval + 1 && s[-1] == '\\' && s[-2] != ',')
+ || (s == origval + 1 && s[-1] == '\\')) {
+ bs++;
+ } else {
bs = 0;
+ }
}
- /* do not add if already there */
+ // do not add if already there
if ((adding || prepending) && *s) {
prepending = FALSE;
adding = FALSE;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 17cb8a86aa..151b9d3790 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -160,9 +160,6 @@ qf_init (
{
qf_info_T *qi = &ql_info;
- if (efile == NULL)
- return FAIL;
-
if (wp != NULL) {
qi = ll_get_or_alloc_list(wp);
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 10b5b6bba4..34eef83164 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -3385,11 +3385,9 @@ win_line (
&& lcs_nbsp)
|| (c == ' ' && lcs_space && ptr - line <= trailcol))) {
c = (c == ' ') ? lcs_space : lcs_nbsp;
- if (area_attr == 0 && search_attr == 0) {
- n_attr = 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; // save current attr
- }
+ n_attr = 1;
+ extra_attr = hl_attr(HLF_8);
+ saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
mb_utf8 = true;
@@ -3402,11 +3400,9 @@ win_line (
if (trailcol != MAXCOL && ptr > line + trailcol && c == ' ') {
c = lcs_trail;
- if (!attr_pri) {
- n_attr = 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; /* save current attr */
- }
+ n_attr = 1;
+ extra_attr = hl_attr(HLF_8);
+ saved_attr2 = char_attr; // save current attr
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
mb_utf8 = TRUE;
@@ -3554,11 +3550,9 @@ win_line (
c = ' ';
}
lcs_eol_one = -1;
- --ptr; /* put it back at the NUL */
- if (!attr_pri) {
- extra_attr = hl_attr(HLF_AT);
- n_attr = 1;
- }
+ ptr--; // put it back at the NUL
+ extra_attr = hl_attr(HLF_AT);
+ n_attr = 1;
mb_c = c;
if (enc_utf8 && (*mb_char2len)(c) > 1) {
mb_utf8 = TRUE;
@@ -3587,12 +3581,10 @@ win_line (
n_extra = byte2cells(c) - 1;
c = *p_extra++;
}
- if (!attr_pri) {
- n_attr = n_extra + 1;
- extra_attr = hl_attr(HLF_8);
- saved_attr2 = char_attr; /* save current attr */
- }
- mb_utf8 = FALSE; /* don't draw as UTF-8 */
+ n_attr = n_extra + 1;
+ extra_attr = hl_attr(HLF_8);
+ saved_attr2 = char_attr; // save current attr
+ mb_utf8 = false; // don't draw as UTF-8
} else if (VIsual_active
&& (VIsual_mode == Ctrl_V
|| VIsual_mode == 'v')
@@ -3702,11 +3694,10 @@ win_line (
did_wcol = true;
}
- /* Don't override visual selection highlighting. */
- if (n_attr > 0
- && draw_state == WL_LINE
- && !attr_pri)
- char_attr = extra_attr;
+ // Don't override visual selection highlighting.
+ if (n_attr > 0 && draw_state == WL_LINE) {
+ char_attr = hl_combine_attr(char_attr, extra_attr);
+ }
/*
* Handle the case where we are in column 0 but not on the first
@@ -3734,13 +3725,12 @@ win_line (
mb_utf8 = TRUE;
u8cc[0] = 0;
c = 0xc0;
- } else
- mb_utf8 = FALSE; /* don't draw as UTF-8 */
- if (!attr_pri) {
- saved_attr3 = char_attr; /* save current attr */
- char_attr = hl_attr(HLF_AT); /* later copied to char_attr */
- n_attr3 = 1;
+ } else {
+ mb_utf8 = false; // don't draw as UTF-8
}
+ saved_attr3 = char_attr; // save current attr
+ char_attr = hl_attr(HLF_AT); // later copied to char_attr
+ n_attr3 = 1;
}
/*
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index b04180ad1c..1f9dbd8228 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -62,8 +62,10 @@ struct hl_group {
int sg_gui; // "gui=" highlighting attributes
RgbValue sg_rgb_fg; // RGB foreground color
RgbValue sg_rgb_bg; // RGB background color
+ RgbValue sg_rgb_sp; // RGB special color
uint8_t *sg_rgb_fg_name; // RGB foreground color name
uint8_t *sg_rgb_bg_name; // RGB background color name
+ uint8_t *sg_rgb_sp_name; // RGB special color name
};
#define SG_CTERM 2 // cterm has been set
@@ -6169,12 +6171,11 @@ do_highlight (
break;
}
- /*
- * Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg" or
- * "guibg").
- */
- while (*linep && !ascii_iswhite(*linep) && *linep != '=')
- ++linep;
+ // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg",
+ // "guibg" or "guisp").
+ while (*linep && !ascii_iswhite(*linep) && *linep != '=') {
+ linep++;
+ }
xfree(key);
key = vim_strnsave_up(key_start, (int)(linep - key_start));
linep = skipwhite(linep);
@@ -6370,18 +6371,14 @@ do_highlight (
} else
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
}
- color &= 7; /* truncate to 8 colors */
- } else if (t_colors == 16 || t_colors == 88 || t_colors == 256) {
- switch (t_colors) {
- case 16:
- color = color_numbers_8[i];
- break;
- case 88:
- color = color_numbers_88[i];
- break;
- case 256:
- color = color_numbers_256[i];
- break;
+ color &= 7; // truncate to 8 colors
+ } else if (t_colors == 16 || t_colors == 88 || t_colors >= 256) {
+ if (t_colors == 88) {
+ color = color_numbers_88[i];
+ } else if (t_colors >= 256) {
+ color = color_numbers_256[i];
+ } else {
+ color = color_numbers_8[i];
}
}
}
@@ -6456,7 +6453,23 @@ do_highlight (
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
}
} else if (STRCMP(key, "GUISP") == 0) {
- // Ignored for now
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init)
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+
+ xfree(HL_TABLE()[idx].sg_rgb_sp_name);
+ if (STRCMP(arg, "NONE") != 0) {
+ HL_TABLE()[idx].sg_rgb_sp_name = (uint8_t *)xstrdup((char *)arg);
+ HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg);
+ } else {
+ HL_TABLE()[idx].sg_rgb_sp_name = NULL;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
+ }
+ }
+
+ if (is_normal_group) {
+ normal_sp = HL_TABLE()[idx].sg_rgb_sp;
+ }
} else if (STRCMP(key, "START") == 0 || STRCMP(key, "STOP") == 0) {
// Ignored for now
} else {
@@ -6520,6 +6533,7 @@ void restore_cterm_colors(void)
{
normal_fg = -1;
normal_bg = -1;
+ normal_sp = -1;
cterm_normal_fg_color = 0;
cterm_normal_fg_bold = 0;
cterm_normal_bg_color = 0;
@@ -6536,6 +6550,7 @@ static int hl_has_settings(int idx, int check_link)
|| HL_TABLE()[idx].sg_cterm_bg != 0
|| HL_TABLE()[idx].sg_rgb_fg_name != NULL
|| HL_TABLE()[idx].sg_rgb_bg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_sp_name != NULL
|| (check_link && (HL_TABLE()[idx].sg_set & SG_LINK));
}
@@ -6552,14 +6567,18 @@ static void highlight_clear(int idx)
HL_TABLE()[idx].sg_gui = 0;
HL_TABLE()[idx].sg_rgb_fg = -1;
HL_TABLE()[idx].sg_rgb_bg = -1;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
xfree(HL_TABLE()[idx].sg_rgb_fg_name);
HL_TABLE()[idx].sg_rgb_fg_name = NULL;
xfree(HL_TABLE()[idx].sg_rgb_bg_name);
HL_TABLE()[idx].sg_rgb_bg_name = NULL;
- /* Clear the script ID only when there is no link, since that is not
- * cleared. */
- if (HL_TABLE()[idx].sg_link == 0)
+ xfree(HL_TABLE()[idx].sg_rgb_sp_name);
+ HL_TABLE()[idx].sg_rgb_sp_name = NULL;
+ // Clear the script ID only when there is no link, since that is not
+ // cleared.
+ if (HL_TABLE()[idx].sg_link == 0) {
HL_TABLE()[idx].sg_scriptID = 0;
+ }
}
@@ -6601,7 +6620,8 @@ int get_attr_entry(attrentry_T *aep)
&& aep->cterm_bg_color == taep->cterm_bg_color
&& aep->rgb_ae_attr == taep->rgb_ae_attr
&& aep->rgb_fg_color == taep->rgb_fg_color
- && aep->rgb_bg_color == taep->rgb_bg_color) {
+ && aep->rgb_bg_color == taep->rgb_bg_color
+ && aep->rgb_sp_color == taep->rgb_sp_color) {
return i + ATTR_OFF;
}
}
@@ -6639,6 +6659,7 @@ int get_attr_entry(attrentry_T *aep)
taep->rgb_ae_attr = aep->rgb_ae_attr;
taep->rgb_fg_color = aep->rgb_fg_color;
taep->rgb_bg_color = aep->rgb_bg_color;
+ taep->rgb_sp_color = aep->rgb_sp_color;
return table->ga_len - 1 + ATTR_OFF;
}
@@ -6700,6 +6721,10 @@ int hl_combine_attr(int char_attr, int prim_attr)
if (spell_aep->rgb_bg_color >= 0) {
new_en.rgb_bg_color = spell_aep->rgb_bg_color;
}
+
+ if (spell_aep->rgb_sp_color >= 0) {
+ new_en.rgb_sp_color = spell_aep->rgb_sp_color;
+ }
}
return get_attr_entry(&new_en);
}
@@ -6737,7 +6762,7 @@ static void highlight_list_one(int id)
didh = highlight_list_arg(id, didh, LIST_STRING,
0, sgp->sg_rgb_bg_name, "guibg");
didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, NULL, "guisp");
+ 0, sgp->sg_rgb_sp_name, "guisp");
if (sgp->sg_link && !got_int) {
(void)syn_list_header(didh, 9999, id);
@@ -6851,8 +6876,9 @@ highlight_color (
if (modec == 'g') {
if (fg)
return HL_TABLE()[id - 1].sg_rgb_fg_name;
- if (sp)
- return NULL;
+ if (sp) {
+ return HL_TABLE()[id - 1].sg_rgb_sp_name;
+ }
return HL_TABLE()[id - 1].sg_rgb_bg_name;
}
if (font || sp)
@@ -6939,11 +6965,16 @@ set_hl_attr (
// before setting attr_entry->{f,g}g_color to a other than -1
at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
+ at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
if (at_en.cterm_fg_color != 0 || at_en.cterm_bg_color != 0
|| at_en.rgb_fg_color != -1 || at_en.rgb_bg_color != -1
- || at_en.cterm_ae_attr != 0 || at_en.rgb_ae_attr != 0) {
+ || at_en.rgb_sp_color != -1 || at_en.cterm_ae_attr != 0
+ || at_en.rgb_ae_attr != 0) {
sgp->sg_attr = get_attr_entry(&at_en);
+ } else {
+ // If all the fields are cleared, clear the attr field back to default value
+ sgp->sg_attr = 0;
}
}
@@ -7275,6 +7306,10 @@ int highlight_changed(void)
hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg;
}
+ if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) {
+ hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp;
+ }
+
highlight_ga.ga_len = hlcnt + i + 1;
set_hl_attr(hlcnt + i); /* At long last we can apply */
highlight_stlnc[i] = syn_id2attr(hlcnt + i + 1);
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 67cf672ef2..8d207e6286 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -69,8 +69,8 @@ struct syn_state {
// Structure shared between syntax.c, screen.c
typedef struct attr_entry {
- short rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
- RgbValue rgb_fg_color, rgb_bg_color;
+ int16_t rgb_ae_attr, cterm_ae_attr; // HL_BOLD, etc.
+ RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
int cterm_fg_color, cterm_bg_color;
} attrentry_T;
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 7195c7e632..90542a6a6c 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -32,7 +32,6 @@ SCRIPTS := \
test73.out \
test79.out \
test_listlbr.out \
- test_breakindent.out \
test_close_count.out \
test_marks.out \
@@ -41,6 +40,7 @@ SCRIPTS := \
NEW_TESTS = \
test_cursor_func.res \
test_help_tagjump.res \
+ test_menu.res \
test_viml.res \
test_alot.res
diff --git a/src/nvim/testdir/test_breakindent.in b/src/nvim/testdir/test_breakindent.in
deleted file mode 100644
index 5a8e580c4a..0000000000
--- a/src/nvim/testdir/test_breakindent.in
+++ /dev/null
@@ -1,123 +0,0 @@
-Test for breakindent
-
-STARTTEST
-:so small.vim
-:if !exists("+breakindent") | e! test.ok | w! test.out | qa! | endif
-:set wildchar=^E
-:10new|:vsp|:vert resize 20
-:put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\"
-:set ts=4 sw=4 sts=4 breakindent
-:fu! ScreenChar(line, width)
-: let c=''
-: for i in range(1,a:width)
-: let c.=nr2char(screenchar(a:line, i))
-: endfor
-: let c.="\n"
-: for i in range(1,a:width)
-: let c.=nr2char(screenchar(a:line+1, i))
-: endfor
-: let c.="\n"
-: for i in range(1,a:width)
-: let c.=nr2char(screenchar(a:line+2, i))
-: endfor
-: return c
-:endfu
-:fu DoRecordScreen()
-: wincmd l
-: $put =printf(\"\n%s\", g:test)
-: $put =g:line1
-: wincmd p
-:endfu
-:set briopt=min:0
-:let g:test="Test 1: Simple breakindent"
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test="Test 2: Simple breakindent + sbr=>>"
-:set sbr=>>
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test ="Test 3: Simple breakindent + briopt:sbr"
-:set briopt=sbr,min:0 sbr=++
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test ="Test 4: Simple breakindent + min width: 18"
-:set sbr= briopt=min:18
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test =" Test 5: Simple breakindent + shift by 2"
-:set briopt=shift:2,min:0
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test=" Test 6: Simple breakindent + shift by -1"
-:set briopt=shift:-1,min:0
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr"
-:set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr"
-:set briopt=shift:1,sbr,min:0 nu sbr=# list lcs&vi
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list"
-:set briopt-=sbr
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n"
-:set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0
-:let line1=ScreenChar(line('.'),10)
-:call DoRecordScreen()
-:wincmd p
-:let g:test="\n Test 11: strdisplaywidth when breakindent is on"
-:set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4
-:let text=getline(2) "skip leading tab when calculating text width
-:let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3 " text wraps 3 times
-:$put =g:test
-:$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width)
-:let g:str="\t\t\t\t\t{"
-:let g:test=" Test 12: breakindent + long indent"
-:wincmd p
-:set all& breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4
-:$put =g:str
-zt:let line1=ScreenChar(1,10)
-:wincmd p
-:call DoRecordScreen()
-:"
-:" Test, that the string " a\tb\tc\td\te" is correctly
-:" displayed in a 20 column wide window (see bug report
-:" https://groups.google.com/d/msg/vim_dev/ZOdg2mc9c9Y/TT8EhFjEy0IJ
-:only
-:vert 20new
-:set all& breakindent briopt=min:10
-:call setline(1, [" a\tb\tc\td\te", " z y x w v"])
-:/^\s*a
-fbgjyl:let line1 = @0
-:?^\s*z
-fygjyl:let line2 = @0
-:quit!
-:$put ='Test 13: breakindent with wrapping Tab'
-:$put =line1
-:$put =line2
-:"
-:let g:test="Test 14: breakindent + visual blockwise delete #1"
-:set all& breakindent shada+=nX-test-breakindent.shada
-:30vnew
-:normal! 3a1234567890
-:normal! a abcde
-:exec "normal! 0\<C-V>tex"
-:let line1=ScreenChar(line('.'),8)
-:call DoRecordScreen()
-:"
-:let g:test="Test 15: breakindent + visual blockwise delete #2"
-:%d
-:normal! 4a1234567890
-:exec "normal! >>\<C-V>3f0x"
-:let line1=ScreenChar(line('.'),20)
-:call DoRecordScreen()
-:quit!
-:"
-:%w! test.out
-:qa!
-ENDTEST
-dummy text
diff --git a/src/nvim/testdir/test_breakindent.ok b/src/nvim/testdir/test_breakindent.ok
deleted file mode 100644
index 995bd5f29c..0000000000
--- a/src/nvim/testdir/test_breakindent.ok
+++ /dev/null
@@ -1,74 +0,0 @@
-
- abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
-
-Test 1: Simple breakindent
- abcd
- qrst
- GHIJ
-
-Test 2: Simple breakindent + sbr=>>
- abcd
- >>qr
- >>EF
-
-Test 3: Simple breakindent + briopt:sbr
- abcd
-++ qrst
-++ GHIJ
-
-Test 4: Simple breakindent + min width: 18
- abcd
- qrstuv
- IJKLMN
-
- Test 5: Simple breakindent + shift by 2
- abcd
- qr
- EF
-
- Test 6: Simple breakindent + shift by -1
- abcd
- qrstu
- HIJKL
-
- Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr
- 2 ab
- ? m
- ? x
-
- Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr
- 2 ^Iabcd
- # opq
- # BCD
-
- Test 9: breakindent + shift by +1 + 'nu' + sbr=# list
- 2 ^Iabcd
- #op
- #AB
-
- Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n
- 2 ab
-~ mn
-~ yz
-
- Test 11: strdisplaywidth when breakindent is on
-strdisplaywidth: 46 == calculated: 64
- {
-
- Test 12: breakindent + long indent
-56
-
-~
-Test 13: breakindent with wrapping Tab
-d
-w
-
-Test 14: breakindent + visual blockwise delete #1
-e
-~
-~
-
-Test 15: breakindent + visual blockwise delete #2
- 1234567890
-~
-~
diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim
new file mode 100644
index 0000000000..be559467c8
--- /dev/null
+++ b/src/nvim/testdir/test_menu.vim
@@ -0,0 +1,9 @@
+" Test that the system menu can be loaded.
+
+func Test_load_menu()
+ try
+ source $VIMRUNTIME/menu.vim
+ catch
+ call assert_false(1, 'error while loading menus: ' . v:exception)
+ endtry
+endfunc
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 202c5666a1..62bc81ba64 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -100,6 +100,7 @@ UI *tui_start(void)
ui->visual_bell = tui_visual_bell;
ui->update_fg = tui_update_fg;
ui->update_bg = tui_update_bg;
+ ui->update_sp = tui_update_sp;
ui->flush = tui_flush;
ui->suspend = tui_suspend;
ui->set_title = tui_set_title;
@@ -573,6 +574,11 @@ static void tui_update_bg(UI *ui, int bg)
((TUIData *)ui->data)->grid.bg = bg;
}
+static void tui_update_sp(UI *ui, int sp)
+{
+ // Do nothing; 'special' color is for GUI only
+}
+
static void tui_flush(UI *ui)
{
TUIData *data = ui->data;
diff --git a/src/nvim/ugrid.h b/src/nvim/ugrid.h
index df51e1fced..ad6d96a168 100644
--- a/src/nvim/ugrid.h
+++ b/src/nvim/ugrid.h
@@ -21,7 +21,7 @@ struct ugrid {
UCell **cells;
};
-#define EMPTY_ATTRS ((HlAttrs){false, false, false, false, false, -1, -1})
+#define EMPTY_ATTRS ((HlAttrs){ false, false, false, false, false, -1, -1, -1 })
#define UGRID_FOREACH_CELL(grid, top, bot, left, right, code) \
do { \
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index d32969f149..05322a6f64 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -155,6 +155,7 @@ void ui_resize(int new_width, int new_height)
UI_CALL(update_fg, (ui->rgb ? normal_fg : cterm_normal_fg_color - 1));
UI_CALL(update_bg, (ui->rgb ? normal_bg : cterm_normal_bg_color - 1));
+ UI_CALL(update_sp, (ui->rgb ? normal_sp : -1));
sr.top = 0;
sr.bot = height - 1;
@@ -388,7 +389,7 @@ static void parse_control_character(uint8_t c)
static void set_highlight_args(int attr_code)
{
- HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1 };
+ HlAttrs rgb_attrs = { false, false, false, false, false, -1, -1, -1 };
HlAttrs cterm_attrs = rgb_attrs;
if (attr_code == HL_NORMAL) {
@@ -425,6 +426,10 @@ static void set_highlight_args(int attr_code)
rgb_attrs.background = aep->rgb_bg_color;
}
+ if (aep->rgb_sp_color != normal_sp) {
+ rgb_attrs.special = aep->rgb_sp_color;
+ }
+
if (cterm_normal_fg_color != aep->cterm_fg_color) {
cterm_attrs.foreground = aep->cterm_fg_color - 1;
}
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 4c051fcfbf..5934d2fee9 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -7,7 +7,7 @@
typedef struct {
bool bold, underline, undercurl, italic, reverse;
- int foreground, background;
+ int foreground, background, special;
} HlAttrs;
typedef struct ui_t UI;
@@ -35,6 +35,7 @@ struct ui_t {
void (*flush)(UI *ui);
void (*update_fg)(UI *ui, int fg);
void (*update_bg)(UI *ui, int bg);
+ void (*update_sp)(UI *ui, int sp);
void (*suspend)(UI *ui);
void (*set_title)(UI *ui, char *title);
void (*set_icon)(UI *ui, char *icon);
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 359fffe3bf..fd9d4671e3 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -49,6 +49,7 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
rv->bridge.visual_bell = ui_bridge_visual_bell;
rv->bridge.update_fg = ui_bridge_update_fg;
rv->bridge.update_bg = ui_bridge_update_bg;
+ rv->bridge.update_sp = ui_bridge_update_sp;
rv->bridge.flush = ui_bridge_flush;
rv->bridge.suspend = ui_bridge_suspend;
rv->bridge.set_title = ui_bridge_set_title;
@@ -305,6 +306,16 @@ static void ui_bridge_update_bg_event(void **argv)
ui->update_bg(ui, PTR2INT(argv[1]));
}
+static void ui_bridge_update_sp(UI *b, int sp)
+{
+ UI_CALL(b, update_sp, 2, b, INT2PTR(sp));
+}
+static void ui_bridge_update_sp_event(void **argv)
+{
+ UI *ui = UI(argv[0]);
+ ui->update_sp(ui, PTR2INT(argv[1]));
+}
+
static void ui_bridge_flush(UI *b)
{
UI_CALL(b, flush, 1, b);
diff --git a/src/nvim/version.c b/src/nvim/version.c
index af8b3b3fde..3134b10108 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -69,6 +69,7 @@ static char *features[] = {
// clang-format off
static int included_patches[] = {
+ 1832,
1809,
1808,
1806,
@@ -573,7 +574,7 @@ static int included_patches[] = {
1113,
1112,
// 1111,
- // 1110,
+ 1110,
// 1109 NA
// 1108,
1107,
@@ -581,7 +582,7 @@ static int included_patches[] = {
1105,
// 1104 NA
// 1103 NA
- // 1102,
+ 1102,
1101,
// 1100 NA
// 1099 NA
@@ -622,11 +623,11 @@ static int included_patches[] = {
// 1064,
// 1063 NA
// 1062 NA
- // 1061,
+ 1061,
// 1060 NA
- // 1059,
+ 1059,
// 1058,
- // 1057,
+ 1057,
// 1056,
1055,
1054,
@@ -637,7 +638,7 @@ static int included_patches[] = {
1049,
1048,
1047,
- // 1046,
+ 1046,
// 1045 NA
// 1044 NA
// 1043 NA
@@ -647,9 +648,9 @@ static int included_patches[] = {
// 1039,
// 1038 NA
1037,
- // 1036,
+ 1036,
1035,
- // 1034,
+ 1034,
// 1033 NA
1032,
// 1031 NA,
@@ -665,8 +666,8 @@ static int included_patches[] = {
// 1021 NA
// 1020 NA
// 1019 NA
- // 1018,
- // 1017,
+ 1018,
+ 1017,
// 1016 NA
1015,
// 1014 NA
diff --git a/test/functional/legacy/108_backtrace_debug_commands_spec.lua b/test/functional/legacy/108_backtrace_debug_commands_spec.lua
new file mode 100644
index 0000000000..6df645d255
--- /dev/null
+++ b/test/functional/legacy/108_backtrace_debug_commands_spec.lua
@@ -0,0 +1,177 @@
+-- Tests for backtrace debug commands.
+
+local helpers = require('test.functional.helpers')
+local feed, clear = helpers.feed, helpers.clear
+local execute, expect = helpers.execute, helpers.expect
+
+describe('108', function()
+ before_each(clear)
+
+ it('is working', function()
+ execute('lang mess C')
+ execute('function! Foo()')
+ execute(' let var1 = 1')
+ execute(' let var2 = Bar(var1) + 9')
+ execute(' return var2')
+ execute('endfunction')
+ execute('function! Bar(var)')
+ execute(' let var1 = 2 + a:var')
+ execute(' let var2 = Bazz(var1) + 4')
+ execute(' return var2')
+ execute('endfunction')
+ execute('function! Bazz(var)')
+ execute(' let var1 = 3 + a:var')
+ execute(' let var3 = "another var"')
+ execute(' return var1')
+ execute('endfunction')
+ execute('new')
+ execute('debuggreedy')
+ execute('redir => out')
+ execute('debug echo Foo()')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed([[echo "- show backtrace:\n"<cr>]])
+ feed('backtrace<cr>')
+ feed([[echo "\nshow variables on different levels:\n"<cr>]])
+ feed('echo var1<cr>')
+ feed('up<cr>')
+ feed('back<cr>')
+ feed('echo var1<cr>')
+ feed('u<cr>')
+ feed('bt<cr>')
+ feed('echo var1<cr>')
+ feed([[echo "\n- undefined vars:\n"<cr>]])
+ feed('step<cr>')
+ feed('frame 2<cr>')
+ feed('echo "undefined var3 on former level:"<cr>')
+ feed('echo var3<cr>')
+ feed('fr 0<cr>')
+ feed([[echo "here var3 is defined with \"another var\":"<cr>]])
+ feed('echo var3<cr>')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed('step<cr>')
+ feed('up<cr>')
+ feed([[echo "\nundefined var2 on former level"<cr>]])
+ feed('echo var2<cr>')
+ feed('down<cr>')
+ feed('echo "here var2 is defined with 10:"<cr>')
+ feed('echo var2<cr>')
+ feed([[echo "\n- backtrace movements:\n"<cr>]])
+ feed('b<cr>')
+ feed([[echo "\nnext command cannot go down, we are on bottom\n"<cr>]])
+ feed('down<cr>')
+ feed('up<cr>')
+ feed([[echo "\nnext command cannot go up, we are on top\n"<cr>]])
+ feed('up<cr>')
+ feed('b<cr>')
+ feed('echo "fil is not frame or finish, it is file"<cr>')
+ feed('fil<cr>')
+ feed([[echo "\n- relative backtrace movement\n"<cr>]])
+ feed('fr -1<cr>')
+ feed('frame<cr>')
+ feed('fra +1<cr>')
+ feed('fram<cr>')
+ feed([[echo "\n- go beyond limits does not crash\n"<cr>]])
+ feed('fr 100<cr>')
+ feed('fra<cr>')
+ feed('frame -40<cr>')
+ feed('fram<cr>')
+ feed([[echo "\n- final result 19:"<cr>]])
+ feed('cont<cr>')
+ execute('0debuggreedy')
+ execute('redir END')
+ execute('$put =out')
+
+ -- Assert buffer contents.
+ expect([=[
+
+
+
+ - show backtrace:
+
+ 2 function Foo[2]
+ 1 Bar[2]
+ ->0 Bazz
+ line 2: let var3 = "another var"
+
+ show variables on different levels:
+
+ 6
+ 2 function Foo[2]
+ ->1 Bar[2]
+ 0 Bazz
+ line 2: let var3 = "another var"
+ 3
+ ->2 function Foo[2]
+ 1 Bar[2]
+ 0 Bazz
+ line 2: let var3 = "another var"
+ 1
+
+ - undefined vars:
+
+ undefined var3 on former level:
+ Error detected while processing function Foo[2]..Bar[2]..Bazz:
+ line 3:
+ E121: Undefined variable: var3
+ E15: Invalid expression: var3
+ here var3 is defined with "another var":
+ another var
+
+ undefined var2 on former level
+ Error detected while processing function Foo[2]..Bar:
+ line 3:
+ E121: Undefined variable: var2
+ E15: Invalid expression: var2
+ here var2 is defined with 10:
+ 10
+
+ - backtrace movements:
+
+ 1 function Foo[2]
+ ->0 Bar
+ line 3: End of function
+
+ next command cannot go down, we are on bottom
+
+ frame is zero
+
+ next command cannot go up, we are on top
+
+ frame at highest level: 1
+ ->1 function Foo[2]
+ 0 Bar
+ line 3: End of function
+ fil is not frame or finish, it is file
+ "[No Name]" --No lines in buffer--
+
+ - relative backtrace movement
+
+ 1 function Foo[2]
+ ->0 Bar
+ line 3: End of function
+ ->1 function Foo[2]
+ 0 Bar
+ line 3: End of function
+
+ - go beyond limits does not crash
+
+ frame at highest level: 1
+ ->1 function Foo[2]
+ 0 Bar
+ line 3: End of function
+ frame is zero
+ 1 function Foo[2]
+ ->0 Bar
+ line 3: End of function
+
+ - final result 19:
+ 19
+ ]=])
+ end)
+end)
diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua
new file mode 100644
index 0000000000..a12d4add10
--- /dev/null
+++ b/test/functional/legacy/breakindent_spec.lua
@@ -0,0 +1,211 @@
+-- Test for breakindent
+
+local helpers = require('test.functional.helpers')
+local feed, insert = helpers.feed, helpers.insert
+local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect
+
+describe('breakindent', function()
+ setup(clear)
+
+ it('is working', function()
+ insert('dummy text')
+
+ execute('set wildchar=^E')
+ execute('10new')
+ execute('vsp')
+ execute('vert resize 20')
+ execute([[put =\"\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP\"]])
+ execute('set ts=4 sw=4 sts=4 breakindent')
+ execute('fu! ScreenChar(line, width)')
+ execute(' let c=""')
+ execute(' for i in range(1,a:width)')
+ execute(' let c.=nr2char(screenchar(a:line, i))')
+ execute(' endfor')
+ execute([[ let c.="\n"]])
+ execute(' for i in range(1,a:width)')
+ execute(' let c.=nr2char(screenchar(a:line+1, i))')
+ execute(' endfor')
+ execute([[ let c.="\n"]])
+ execute(' for i in range(1,a:width)')
+ execute(' let c.=nr2char(screenchar(a:line+2, i))')
+ execute(' endfor')
+ execute(' return c')
+ execute('endfu')
+ execute('fu DoRecordScreen()')
+ execute(' wincmd l')
+ execute([[ $put =printf(\"\n%s\", g:test)]])
+ execute(' $put =g:line1')
+ execute(' wincmd p')
+ execute('endfu')
+ execute('set briopt=min:0')
+ execute('let g:test="Test 1: Simple breakindent"')
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+ execute('let g:test="Test 2: Simple breakindent + sbr=>>"')
+ execute('set sbr=>>')
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+ execute('let g:test ="Test 3: Simple breakindent + briopt:sbr"')
+ execute('set briopt=sbr,min:0 sbr=++')
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+ execute('let g:test ="Test 4: Simple breakindent + min width: 18"')
+ execute('set sbr= briopt=min:18')
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+ execute('let g:test =" Test 5: Simple breakindent + shift by 2"')
+ execute('set briopt=shift:2,min:0')
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+ execute('let g:test=" Test 6: Simple breakindent + shift by -1"')
+ execute('set briopt=shift:-1,min:0')
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+ execute('let g:test=" Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr"')
+ execute('set briopt=shift:1,sbr,min:0 nu sbr=? nuw=4')
+ execute('let line1=ScreenChar(line("."),10)')
+ execute('call DoRecordScreen()')
+ execute('let g:test=" Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr"')
+ execute('set briopt=shift:1,sbr,min:0 nu sbr=# list lcs&vi')
+ execute('let line1=ScreenChar(line("."),10)')
+ execute('call DoRecordScreen()')
+ execute([[let g:test=" Test 9: breakindent + shift by +1 + 'nu' + sbr=# list"]])
+ execute('set briopt-=sbr')
+ execute('let line1=ScreenChar(line("."),10)')
+ execute('call DoRecordScreen()')
+ execute([[let g:test=" Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n"]])
+ execute('set cpo+=n sbr=~ nu nuw=4 nolist briopt=sbr,min:0')
+ execute('let line1=ScreenChar(line("."),10)')
+ execute('call DoRecordScreen()')
+ execute('wincmd p')
+ execute([[let g:test="\n Test 11: strdisplaywidth when breakindent is on"]])
+ execute('set cpo-=n sbr=>> nu nuw=4 nolist briopt= ts=4')
+ -- Skip leading tab when calculating text width.
+ execute('let text=getline(2)')
+ -- Text wraps 3 times.
+ execute('let width = strlen(text[1:])+indent(2)*4+strlen(&sbr)*3')
+ execute('$put =g:test')
+ execute([[$put =printf(\"strdisplaywidth: %d == calculated: %d\", strdisplaywidth(text), width)]])
+ execute([[let g:str="\t\t\t\t\t{"]])
+ execute('let g:test=" Test 12: breakindent + long indent"')
+ execute('wincmd p')
+ execute('set all& breakindent linebreak briopt=min:10 nu numberwidth=3 ts=4')
+ execute('$put =g:str')
+ feed('zt')
+ execute('let line1=ScreenChar(1,10)')
+ execute('wincmd p')
+ execute('call DoRecordScreen()')
+
+ -- Test, that the string " a\tb\tc\td\te" is correctly displayed in a
+ -- 20 column wide window (see bug report
+ -- https://groups.google.com/d/msg/vim_dev/ZOdg2mc9c9Y/TT8EhFjEy0IJ ).
+ execute('only')
+ execute('vert 20new')
+ execute('set all& breakindent briopt=min:10')
+ execute([[call setline(1, [" a\tb\tc\td\te", " z y x w v"])]])
+ execute([[/^\s*a]])
+ feed('fbgjyl')
+ execute('let line1 = @0')
+ execute([[?^\s*z]])
+ feed('fygjyl')
+ execute('let line2 = @0')
+ execute('quit!')
+ execute([[$put ='Test 13: breakindent with wrapping Tab']])
+ execute('$put =line1')
+ execute('$put =line2')
+
+ execute('let g:test="Test 14: breakindent + visual blockwise delete #1"')
+ execute('set all& breakindent shada+=nX-test-breakindent.shada')
+ execute('30vnew')
+ execute('normal! 3a1234567890')
+ execute('normal! a abcde')
+ execute([[exec "normal! 0\<C-V>tex"]])
+ execute('let line1=ScreenChar(line("."),8)')
+ execute('call DoRecordScreen()')
+
+ execute('let g:test="Test 15: breakindent + visual blockwise delete #2"')
+ execute('%d')
+ execute('normal! 4a1234567890')
+ execute([[exec "normal! >>\<C-V>3f0x"]])
+ execute('let line1=ScreenChar(line("."),20)')
+ execute('call DoRecordScreen()')
+ execute('quit!')
+
+ -- Assert buffer contents.
+ expect([[
+
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
+
+ Test 1: Simple breakindent
+ abcd
+ qrst
+ GHIJ
+
+ Test 2: Simple breakindent + sbr=>>
+ abcd
+ >>qr
+ >>EF
+
+ Test 3: Simple breakindent + briopt:sbr
+ abcd
+ ++ qrst
+ ++ GHIJ
+
+ Test 4: Simple breakindent + min width: 18
+ abcd
+ qrstuv
+ IJKLMN
+
+ Test 5: Simple breakindent + shift by 2
+ abcd
+ qr
+ EF
+
+ Test 6: Simple breakindent + shift by -1
+ abcd
+ qrstu
+ HIJKL
+
+ Test 7: breakindent + shift by +1 + nu + sbr=? briopt:sbr
+ 2 ab
+ ? m
+ ? x
+
+ Test 8: breakindent + shift:1 + nu + sbr=# list briopt:sbr
+ 2 ^Iabcd
+ # opq
+ # BCD
+
+ Test 9: breakindent + shift by +1 + 'nu' + sbr=# list
+ 2 ^Iabcd
+ #op
+ #AB
+
+ Test 10: breakindent + shift by +1 + 'nu' + sbr=~ cpo+=n
+ 2 ab
+ ~ mn
+ ~ yz
+
+ Test 11: strdisplaywidth when breakindent is on
+ strdisplaywidth: 46 == calculated: 64
+ {
+
+ Test 12: breakindent + long indent
+ 56
+
+ ~
+ Test 13: breakindent with wrapping Tab
+ d
+ w
+
+ Test 14: breakindent + visual blockwise delete #1
+ e
+ ~
+ ~
+
+ Test 15: breakindent + visual blockwise delete #2
+ 1234567890
+ ~
+ ~ ]])
+ end)
+end)
diff --git a/test/functional/legacy/set_spec.lua b/test/functional/legacy/set_spec.lua
index f81fcd3700..f2c907084e 100644
--- a/test/functional/legacy/set_spec.lua
+++ b/test/functional/legacy/set_spec.lua
@@ -7,6 +7,21 @@ local clear, execute, eval, eq =
describe(':set', function()
before_each(clear)
+ it('handles backslash properly', function()
+ execute('set iskeyword=a,b,c')
+ execute('set iskeyword+=d')
+ eq('a,b,c,d', eval('&iskeyword'))
+
+ execute([[set iskeyword+=\\,e]])
+ eq([[a,b,c,d,\,e]], eval('&iskeyword'))
+
+ execute('set iskeyword-=e')
+ eq([[a,b,c,d,\]], eval('&iskeyword'))
+
+ execute([[set iskeyword-=\]])
+ eq('a,b,c,d', eval('&iskeyword'))
+ end)
+
it('recognizes a trailing comma with +=', function()
execute('set wildignore=*.png,')
execute('set wildignore+=*.jpg')
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 045f5aa42f..97875c5147 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -25,7 +25,7 @@ describe('terminal window highlighting', function()
[5] = {background = 11},
[6] = {foreground = 130},
[7] = {reverse = true},
- [8] = {background = 11}
+ [8] = {background = 11},
})
screen:attach(false)
execute('enew | call termopen(["'..nvim_dir..'/tty-test"]) | startinsert')
@@ -121,7 +121,7 @@ describe('terminal window highlighting with custom palette', function()
clear()
screen = Screen.new(50, 7)
screen:set_default_attr_ids({
- [1] = {foreground = 1193046}
+ [1] = {foreground = 1193046, special = Screen.colors.Black}
})
screen:set_default_attr_ignore({
[1] = {bold = true},
@@ -130,7 +130,7 @@ describe('terminal window highlighting with custom palette', function()
[5] = {background = 11},
[6] = {foreground = 130},
[7] = {reverse = true},
- [8] = {background = 11}
+ [8] = {background = 11},
})
screen:attach(true)
nvim('set_var', 'terminal_color_3', '#123456')
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 06139277b2..85fca4d7ca 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -1,7 +1,7 @@
local helpers = require('test.functional.helpers')
local Screen = require('test.functional.ui.screen')
local os = require('os')
-local clear, feed = helpers.clear, helpers.feed
+local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local execute, request, eq = helpers.execute, helpers.request, helpers.eq
@@ -302,4 +302,353 @@ describe('Default highlight groups', function()
{1:-- INSERT --} |
]], {[1] = {foreground = Screen.colors.Red, background = Screen.colors.Green}})
end)
+ it('can be cleared by assigning NONE', function()
+ execute('syn keyword TmpKeyword neovim')
+ execute('hi link TmpKeyword ErrorMsg')
+ insert('neovim')
+ screen:expect([[
+ {1:neovi^m} |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], {
+ [1] = {foreground = Screen.colors.White, background = Screen.colors.Red}
+ })
+ execute("hi ErrorMsg term=NONE cterm=NONE ctermfg=NONE ctermbg=NONE"
+ .. " gui=NONE guifg=NONE guibg=NONE guisp=NONE")
+ screen:expect([[
+ neovi^m |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], {})
+ end)
+end)
+
+describe('guisp (special/undercurl)', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25,10)
+ screen:attach()
+ screen:set_default_attr_ignore({
+ [1] = {bold = true, foreground = Screen.colors.Blue},
+ [2] = {bold = true}
+ })
+ end)
+
+ it('can be set and is applied like foreground or background', function()
+ execute('syntax on')
+ execute('syn keyword TmpKeyword neovim')
+ execute('syn keyword TmpKeyword1 special')
+ execute('syn keyword TmpKeyword2 specialwithbg')
+ execute('syn keyword TmpKeyword3 specialwithfg')
+ execute('hi! Awesome guifg=red guibg=yellow guisp=red')
+ execute('hi! Awesome1 guisp=red')
+ execute('hi! Awesome2 guibg=yellow guisp=red')
+ execute('hi! Awesome3 guifg=red guisp=red')
+ execute('hi link TmpKeyword Awesome')
+ execute('hi link TmpKeyword1 Awesome1')
+ execute('hi link TmpKeyword2 Awesome2')
+ execute('hi link TmpKeyword3 Awesome3')
+ insert([[
+ neovim
+ awesome neovim
+ wordcontainingneovim
+ special
+ specialwithbg
+ specialwithfg
+ ]])
+ feed('Go<tab>neovim tabbed')
+ screen:expect([[
+ {1:neovim} |
+ awesome {1:neovim} |
+ wordcontainingneovim |
+ {2:special} |
+ {3:specialwithbg} |
+ {4:specialwithfg} |
+ |
+ {1:neovim} tabbed^ |
+ ~ |
+ -- INSERT -- |
+ ]],{
+ [1] = {background = Screen.colors.Yellow, foreground = Screen.colors.Red,
+ special = Screen.colors.Red},
+ [2] = {special = Screen.colors.Red},
+ [3] = {special = Screen.colors.Red, background = Screen.colors.Yellow},
+ [4] = {foreground = Screen.colors.Red, special = Screen.colors.Red},
+ })
+
+ end)
+end)
+
+describe("'cursorline' with 'listchars'", function()
+ local screen
+
+ local hlgroup_colors = {
+ NonText = Screen.colors.Blue,
+ Cursorline = Screen.colors.Grey90,
+ SpecialKey = Screen.colors.Red,
+ Visual = Screen.colors.LightGrey,
+ }
+
+ before_each(function()
+ clear()
+ screen = Screen.new(20,5)
+ screen:attach()
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ it("'cursorline' and 'cursorcolumn'", function()
+ screen:set_default_attr_ids({[1] = {background=hlgroup_colors.Cursorline}})
+ screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} )
+ execute('highlight clear ModeMsg')
+ execute('set cursorline')
+ feed('i')
+ screen:expect([[
+ {1:^ }|
+ ~ |
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ feed('abcdefg<cr>kkasdf')
+ screen:expect([[
+ abcdefg |
+ {1:kkasdf^ }|
+ ~ |
+ ~ |
+ -- INSERT -- |
+ ]])
+ feed('<esc>')
+ screen:expect([[
+ abcdefg |
+ {1:kkasd^f }|
+ ~ |
+ ~ |
+ |
+ ]])
+ execute('set nocursorline')
+ screen:expect([[
+ abcdefg |
+ kkasd^f |
+ ~ |
+ ~ |
+ :set nocursorline |
+ ]])
+ feed('k')
+ screen:expect([[
+ abcde^fg |
+ kkasdf |
+ ~ |
+ ~ |
+ :set nocursorline |
+ ]])
+ feed('jjji<cr><cr><cr><esc>')
+ screen:expect([[
+ kkasd |
+ |
+ |
+ ^f |
+ |
+ ]])
+ execute('set cursorline')
+ execute('set cursorcolumn')
+ feed('kkiabcdefghijk<esc>hh')
+ screen:expect([[
+ kkasd {1: } |
+ {1:abcdefgh^ijk }|
+ {1: } |
+ f {1: } |
+ |
+ ]])
+ feed('khh')
+ screen:expect([[
+ {1:kk^asd }|
+ ab{1:c}defghijk |
+ {1: } |
+ f {1: } |
+ |
+ ]])
+ end)
+
+ it("'cursorline' and with 'listchar' option: space, eol, tab, and trail", function()
+ screen:set_default_attr_ids({
+ [1] = {background=hlgroup_colors.Cursorline},
+ [2] = {
+ foreground=hlgroup_colors.SpecialKey,
+ background=hlgroup_colors.Cursorline,
+ },
+ [3] = {
+ background=hlgroup_colors.Cursorline,
+ foreground=hlgroup_colors.NonText,
+ bold=true,
+ },
+ [4] = {
+ foreground=hlgroup_colors.NonText,
+ bold=true,
+ },
+ [5] = {
+ foreground=hlgroup_colors.SpecialKey,
+ },
+ })
+ execute('highlight clear ModeMsg')
+ execute('highlight SpecialKey guifg=#FF0000')
+ execute('set cursorline')
+ execute('set tabstop=8')
+ execute('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
+ feed('i\t abcd <cr>\t abcd <cr><esc>k')
+ screen:expect([[
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }|
+ {4:¬} |
+ {4:~ }|
+ |
+ ]])
+ feed('k')
+ screen:expect([[
+ {2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }|
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {4:¬} |
+ {4:~ }|
+ |
+ ]])
+ execute('set nocursorline')
+ screen:expect([[
+ {5:^>-------.}abcd{5:*}{4:¬} |
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {4:¬} |
+ {4:~ }|
+ :set nocursorline |
+ ]])
+ execute('set nowrap')
+ feed('ALorem ipsum dolor sit amet<ESC>0')
+ screen:expect([[
+ {5:^>-------.}abcd{5:.}Lorem{4:>}|
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {4:¬} |
+ {4:~ }|
+ |
+ ]])
+ execute('set cursorline')
+ screen:expect([[
+ {2:^>-------.}{1:abcd}{2:.}{1:Lorem}{4:>}|
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {4:¬} |
+ {4:~ }|
+ :set cursorline |
+ ]])
+ feed('$')
+ screen:expect([[
+ {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }|
+ {4:<} |
+ {4:<} |
+ {4:~ }|
+ :set cursorline |
+ ]])
+ feed('G')
+ screen:expect([[
+ {5:>-------.}abcd{5:.}Lorem{4:>}|
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {3:^¬}{1: }|
+ {4:~ }|
+ :set cursorline |
+ ]])
+ end)
+
+ it("'listchar' in visual mode", function()
+ screen:set_default_attr_ids({
+ [1] = {background=hlgroup_colors.Cursorline},
+ [2] = {
+ foreground=hlgroup_colors.SpecialKey,
+ background=hlgroup_colors.Cursorline,
+ },
+ [3] = {
+ background=hlgroup_colors.Cursorline,
+ foreground=hlgroup_colors.NonText,
+ bold=true,
+ },
+ [4] = {
+ foreground=hlgroup_colors.NonText,
+ bold=true,
+ },
+ [5] = {
+ foreground=hlgroup_colors.SpecialKey,
+ },
+ [6] = {
+ background=hlgroup_colors.Visual,
+ },
+ [7] = {
+ background=hlgroup_colors.Visual,
+ foreground=hlgroup_colors.SpecialKey,
+ },
+ [8] = {
+ background=hlgroup_colors.Visual,
+ foreground=hlgroup_colors.NonText,
+ bold=true,
+ },
+ })
+ execute('highlight clear ModeMsg')
+ execute('highlight SpecialKey guifg=#FF0000')
+ execute('set cursorline')
+ execute('set tabstop=8')
+ execute('set nowrap')
+ execute('set listchars=space:.,eol:¬,tab:>-,extends:>,precedes:<,trail:* list')
+ feed('i\t abcd <cr>\t abcd Lorem ipsum dolor sit amet<cr><esc>kkk0')
+ screen:expect([[
+ {2:^>-------.}{1:abcd}{2:*}{3:¬}{1: }|
+ {5:>-------.}abcd{5:.}Lorem{4:>}|
+ {4:¬} |
+ {4:~ }|
+ |
+ ]])
+ feed('lllvj')
+ screen:expect([[
+ {5:>-------.}a{6:bcd}{7:*}{8:¬} |
+ {7:>-------.}{6:a}^bcd{5:.}Lorem{4:>}|
+ {4:¬} |
+ {4:~ }|
+ -- VISUAL -- |
+ ]])
+ feed('<esc>V')
+ screen:expect([[
+ {5:>-------.}abcd{5:*}{4:¬} |
+ {7:>-------.}{6:a}^b{6:cd}{7:.}{6:Lorem}{4:>}|
+ {4:¬} |
+ {4:~ }|
+ -- VISUAL LINE -- |
+ ]])
+ feed('<esc>$')
+ screen:expect([[
+ {4:<} |
+ {4:<}{1:r}{2:.}{1:sit}{2:.}{1:ame^t}{3:¬}{1: }|
+ {4:<} |
+ {4:~ }|
+ |
+ ]])
+ end)
end)
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index d0d791308b..993bbd5b0e 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -23,7 +23,12 @@ describe('Mouse input', function()
screen:attach()
screen:set_default_attr_ids({
[1] = {background = hlgroup_colors.Visual},
- [2] = {bold = true}
+ [2] = {bold = true},
+ [3] = {
+ foreground = hlgroup_colors.NonText,
+ background = hlgroup_colors.Visual,
+ bold = true,
+ },
})
screen:set_default_attr_ignore( {{bold=true, foreground=hlgroup_colors.NonText}} )
feed('itesting<cr>mouse<cr>support and selection<esc>')
@@ -225,14 +230,14 @@ describe('Mouse input', function()
feed('<LeftDrag><2,2>')
screen:expect([[
testing |
- mo{1:use } |
+ mo{1:use}{3: } |
{1:su}^pport and selection |
~ |
{2:-- VISUAL --} |
]])
feed('<LeftDrag><0,0>')
screen:expect([[
- ^t{1:esting } |
+ ^t{1:esting}{3: } |
{1:mou}se |
support and selection |
~ |
@@ -293,7 +298,7 @@ describe('Mouse input', function()
screen:expect([[
testing |
mouse |
- {1:su}^p{1:port and selection } |
+ {1:su}^p{1:port and selection}{3: } |
~ |
{2:-- VISUAL LINE --} |
]])
@@ -321,8 +326,8 @@ describe('Mouse input', function()
]])
feed('<RightMouse><2,2>')
screen:expect([[
- {1:testing } |
- {1:mouse } |
+ {1:testing}{3: } |
+ {1:mouse}{3: } |
{1:su}^pport and selection |
~ |
{2:-- VISUAL --} |
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index a11fab18a2..6372cbe081 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -425,6 +425,10 @@ function Screen:_handle_update_bg(bg)
self._bg = bg
end
+function Screen:_handle_update_sp(sp)
+ self._sp = sp
+end
+
function Screen:_handle_suspend()
self.suspended = true
end
@@ -573,7 +577,7 @@ function Screen:_pprint_attrs(attrs)
local items = {}
for f, v in pairs(attrs) do
local desc = tostring(v)
- if f == "foreground" or f == "background" then
+ if f == "foreground" or f == "background" or f == "special" then
if Screen.colornames[v] ~= nil then
desc = "Screen.colors."..Screen.colornames[v]
end
@@ -614,7 +618,8 @@ function Screen:_equal_attrs(a, b)
a.underline == b.underline and a.undercurl == b.undercurl and
a.italic == b.italic and a.reverse == b.reverse and
a.foreground == b.foreground and
- a.background == b.background
+ a.background == b.background and
+ a.special == b.special
end
function Screen:_attr_index(attrs, attr)