diff options
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 ? ¤t_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 = ¤t_funccal->l_avars; + *d = &get_funccal()->l_avars; } else if (*name == 'l' && current_funccal != NULL) { // local variable - *d = ¤t_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) |