aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt33
-rw-r--r--cmake/LuaHelpers.cmake4
-rw-r--r--runtime/autoload/remote/host.vim1
-rw-r--r--runtime/optwin.vim4
-rwxr-xr-xscripts/vim-patch.sh55
-rw-r--r--src/nvim/CMakeLists.txt1
-rw-r--r--src/nvim/globals.h1
-rw-r--r--src/nvim/misc2.c5
-rw-r--r--src/nvim/msgpack_rpc/remote_ui.c12
-rw-r--r--src/nvim/ops.c19
-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.c69
-rw-r--r--src/nvim/syntax_defs.h4
-rw-r--r--src/nvim/testdir/Makefile1
-rw-r--r--src/nvim/testdir/test_breakindent.in123
-rw-r--r--src/nvim/testdir/test_breakindent.ok74
-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.c14
-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
30 files changed, 808 insertions, 326 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1abc05f0da..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})
@@ -477,18 +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}
- ${TEST_TARGET_ARGS})
+ 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}
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/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/globals.h b/src/nvim/globals.h
index 30fe97c8db..dafb75ca87 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -504,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/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/ops.c b/src/nvim/ops.c
index eda963ff77..adfd0424f0 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -5372,11 +5372,10 @@ void cursor_pos_info(dict_T *dict)
}
}
- // Don't shorten this message, the user asked for it.
bom_count = bomb_size();
if (bom_count > 0) {
vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff),
- _("(+%" PRId64 " for BOM)"), (int64_t)byte_count);
+ _("(+%" PRId64 " for BOM)"), (int64_t)bom_count);
}
if (dict == NULL) {
p = p_shm;
@@ -5387,20 +5386,18 @@ void cursor_pos_info(dict_T *dict)
}
if (dict != NULL) {
+ // Don't shorten this message, the user asked for it.
dict_add_nr_str(dict, "words", word_count, NULL);
dict_add_nr_str(dict, "chars", char_count, NULL);
dict_add_nr_str(dict, "bytes", byte_count + bom_count, NULL);
- if (l_VIsual_active) {
- dict_add_nr_str(dict, "visual_bytes", byte_count_cursor, NULL);
- dict_add_nr_str(dict, "visual_chars", char_count_cursor, NULL);
- dict_add_nr_str(dict, "visual_words", word_count_cursor, NULL);
- } else {
- dict_add_nr_str(dict, "cursor_bytes", byte_count_cursor, NULL);
- dict_add_nr_str(dict, "cursor_chars", char_count_cursor, NULL);
- dict_add_nr_str(dict, "cursor_words", word_count_cursor, NULL);
+ dict_add_nr_str(dict, l_VIsual_active ? "visual_bytes" : "cursor_bytes",
+ byte_count_cursor, NULL);
+ dict_add_nr_str(dict, l_VIsual_active ? "visual_chars" : "cursor_chars",
+ char_count_cursor, NULL);
+ dict_add_nr_str(dict, l_VIsual_active ? "visual_words" : "cursor_words",
+ word_count_cursor, NULL);
}
- }
}
/// Check if the default register (used in an unnamed paste) should be a
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 765207928a..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);
@@ -6452,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 {
@@ -6516,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;
@@ -6532,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));
}
@@ -6548,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;
+ }
}
@@ -6597,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;
}
}
@@ -6635,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;
}
@@ -6696,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);
}
@@ -6733,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);
@@ -6847,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)
@@ -6935,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;
}
}
@@ -7271,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 0e3149b912..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 \
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/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 bb03babf5c..23bfca6221 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -623,18 +623,18 @@ static int included_patches[] = {
// 1064,
// 1063 NA
// 1062 NA
- // 1061,
+ 1061,
// 1060 NA
- // 1059,
+ 1059,
// 1058,
- // 1057,
+ 1057,
// 1056,
1055,
1054,
// 1053,
1052,
// 1051,
- // 1050,
+ 1050,
1049,
1048,
1047,
@@ -650,7 +650,7 @@ static int included_patches[] = {
1037,
1036,
1035,
- // 1034,
+ 1034,
// 1033 NA
1032,
// 1031 NA,
@@ -666,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/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)