aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/nvim/CMakeLists.txt12
-rw-r--r--src/nvim/auevents.lua2
-rw-r--r--src/nvim/highlight_group.c26
-rw-r--r--src/nvim/linematch.c3
-rw-r--r--src/nvim/lua/executor.c15
-rw-r--r--src/nvim/main.c6
-rw-r--r--src/nvim/memory.c6
-rw-r--r--src/nvim/normal.c7
-rw-r--r--src/nvim/quickfix.c198
-rw-r--r--src/nvim/testdir/test_normal.vim40
-rw-r--r--src/nvim/testdir/test_options.vim5
-rw-r--r--src/nvim/testdir/test_quickfix.vim60
12 files changed, 254 insertions, 126 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 61530f5a7b..f3344c10de 100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -14,12 +14,8 @@ else()
endif()
find_package(Libluv 1.43.0 REQUIRED)
-target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBLUV_INCLUDE_DIRS})
-# Use "luv" as imported library, to work around CMake using "-lluv" for
-# "luv.so". #10407
-add_library(luv UNKNOWN IMPORTED)
-set_target_properties(luv PROPERTIES IMPORTED_LOCATION ${LIBLUV_LIBRARIES})
-target_link_libraries(main_lib INTERFACE luv)
+target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBLUV_INCLUDE_DIR})
+target_link_libraries(main_lib INTERFACE ${LIBLUV_LIBRARY})
find_package(Iconv REQUIRED)
find_package(Libtermkey 0.22 REQUIRED)
@@ -630,8 +626,8 @@ if(PREFER_LUA)
message(STATUS "luajit not used, skipping unit tests")
else()
glob_wrapper(UNIT_TEST_FIXTURES ${PROJECT_SOURCE_DIR}/test/unit/fixtures/*.c)
- target_sources(nvim PRIVATE $<$<CONFIG:Debug>:${UNIT_TEST_FIXTURES}>)
- target_compile_definitions(nvim PRIVATE $<$<CONFIG:Debug>:UNIT_TESTING>)
+ target_sources(nvim PRIVATE ${UNIT_TEST_FIXTURES})
+ target_compile_definitions(nvim PRIVATE UNIT_TESTING)
endif()
target_sources(main_lib INTERFACE
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index a75ee3bbd5..aef08be820 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -72,6 +72,7 @@ return {
'InsertLeavePre', -- just before leaving Insert mode
'LspAttach', -- after an LSP client attaches to a buffer
'LspDetach', -- after an LSP client detaches from a buffer
+ 'LspTokenUpdate', -- after a visible LSP token is updated
'MenuPopup', -- just before popup menu is displayed
'ModeChanged', -- after changing the mode
'OptionSet', -- after setting any option
@@ -151,6 +152,7 @@ return {
DiagnosticChanged=true,
LspAttach=true,
LspDetach=true,
+ LspTokenUpdate=true,
RecordingEnter=true,
RecordingLeave=true,
Signal=true,
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index d2f5b60dc6..70ee6c757c 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -270,16 +270,22 @@ static const char *highlight_init_both[] = {
"default link @tag Tag",
// LSP semantic tokens
- "default link @class Structure",
- "default link @struct Structure",
- "default link @enum Type",
- "default link @enumMember Constant",
- "default link @event Identifier",
- "default link @interface Identifier",
- "default link @modifier Identifier",
- "default link @regexp SpecialChar",
- "default link @typeParameter Type",
- "default link @decorator Identifier",
+ "default link @lsp.type.class Structure",
+ "default link @lsp.type.decorator Function",
+ "default link @lsp.type.enum Structure",
+ "default link @lsp.type.enumMember Constant",
+ "default link @lsp.type.function Function",
+ "default link @lsp.type.interface Structure",
+ "default link @lsp.type.macro Macro",
+ "default link @lsp.type.method Function",
+ "default link @lsp.type.namespace Structure",
+ "default link @lsp.type.parameter Identifier",
+ "default link @lsp.type.property Identifier",
+ "default link @lsp.type.struct Structure",
+ "default link @lsp.type.type Type",
+ "default link @lsp.type.typeParameter TypeDef",
+ "default link @lsp.type.variable Identifier",
+
NULL
};
diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c
index a9dac40731..a15f41d9a8 100644
--- a/src/nvim/linematch.c
+++ b/src/nvim/linematch.c
@@ -161,6 +161,9 @@ void fastforward_buf_to_lnum(const char **s, long lnum)
{
for (long i = 0; i < lnum - 1; i++) {
*s = strchr(*s, '\n');
+ if (!*s) {
+ return;
+ }
(*s)++;
}
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 8a50c8fe4f..078bc4fea9 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -165,17 +165,6 @@ static int nlua_pcall(lua_State *lstate, int nargs, int nresults)
return status;
}
-/// Gets the version of the current Nvim build.
-///
-/// @param lstate Lua interpreter state.
-static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
-{
- Dictionary version = version_dict();
- nlua_push_Dictionary(lstate, version, true);
- api_free_dictionary(version);
- return 1;
-}
-
static void nlua_luv_error_event(void **argv)
{
char *error = (char *)argv[0];
@@ -739,10 +728,6 @@ static bool nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// vim.types, vim.type_idx, vim.val_idx
nlua_init_types(lstate);
- // neovim version
- lua_pushcfunction(lstate, &nlua_nvim_version);
- lua_setfield(lstate, -2, "version");
-
// schedule
lua_pushcfunction(lstate, &nlua_schedule);
lua_setfield(lstate, -2, "schedule");
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 71c5c2af46..be1714b207 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -184,8 +184,12 @@ void early_init(mparm_T *paramp)
ovi.dwOSVersionInfoSize = sizeof(ovi);
// Disable warning about GetVersionExA being deprecated. There doesn't seem to be a convenient
// replacement that doesn't add a ton of extra code as of writing this.
-# pragma warning(suppress : 4996)
+# ifdef _MSC_VER
+# pragma warning(suppress : 4996)
GetVersionEx(&ovi);
+# else
+ GetVersionEx(&ovi);
+# endif
snprintf(windowsVersion, sizeof(windowsVersion), "%d.%d",
(int)ovi.dwMajorVersion, (int)ovi.dwMinorVersion);
#endif
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 4e799dfd08..ffeafbdf2c 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -755,11 +755,7 @@ void free_all_mem(void)
p_hi = 0;
init_history();
- qf_free_all(NULL);
- // Free all location lists
- FOR_ALL_TAB_WINDOWS(tab, win) {
- qf_free_all(win);
- }
+ free_quickfix();
// Close all script inputs.
close_all_scripts();
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index f7c99d5991..890215e754 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -963,7 +963,8 @@ normal_end:
may_trigger_modechanged();
// Redraw the cursor with another shape, if we were in Operator-pending
// mode or did a replace command.
- if (s->c || s->ca.cmdchar == 'r') {
+ if (s->c || s->ca.cmdchar == 'r'
+ || (s->ca.cmdchar == 'g' && s->ca.nchar == 'r')) {
ui_cursor_shape(); // may show different cursor shape
}
@@ -1162,7 +1163,7 @@ static int normal_execute(VimState *state, int key)
State = MODE_NORMAL;
- if (s->ca.nchar == ESC) {
+ if (s->ca.nchar == ESC || s->ca.extra_char == ESC) {
clearop(&s->oa);
s->command_finished = true;
goto finish;
@@ -4706,7 +4707,7 @@ static void nv_vreplace(cmdarg_T *cap)
return;
}
- if (checkclearopq(cap->oap) || cap->extra_char == ESC) {
+ if (checkclearopq(cap->oap)) {
return;
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 5518fdfa51..9f6181f986 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -245,6 +245,10 @@ typedef struct vgr_args_S {
#endif
static char *e_no_more_items = N_("E553: No more items");
+static char *e_current_quickfix_list_was_changed =
+ N_("E925: Current quickfix list was changed");
+static char *e_current_location_list_was_changed =
+ N_("E926: Current location list was changed");
// Quickfix window check helper macro
#define IS_QF_WINDOW(wp) (bt_quickfix((wp)->w_buffer) && (wp)->w_llist_ref == NULL)
@@ -275,10 +279,38 @@ static char *e_no_more_items = N_("E553: No more items");
static char *qf_last_bufname = NULL;
static bufref_T qf_last_bufref = { NULL, 0, 0 };
-static char *e_current_quickfix_list_was_changed =
- N_("E925: Current quickfix list was changed");
-static char *e_current_location_list_was_changed =
- N_("E926: Current location list was changed");
+static garray_T qfga;
+
+/// Get a growarray to buffer text in. Shared between various commands to avoid
+/// many alloc/free calls.
+static garray_T *qfga_get(void)
+{
+ static bool initialized = false;
+
+ if (!initialized) {
+ initialized = true;
+ ga_init(&qfga, 1, 256);
+ }
+
+ // Reset the length to zero. Retain ga_data from previous use to avoid
+ // many alloc/free calls.
+ qfga.ga_len = 0;
+
+ return &qfga;
+}
+
+/// The "qfga" grow array buffer is reused across multiple quickfix commands as
+/// a temporary buffer to reduce the number of alloc/free calls. But if the
+/// buffer size is large, then to avoid holding on to that memory, clear the
+/// grow array. Otherwise just reset the grow array length.
+static void qfga_clear(void)
+{
+ if (qfga.ga_maxlen > 1000) {
+ ga_clear(&qfga);
+ } else {
+ qfga.ga_len = 0;
+ }
+}
// Counter to prevent autocmds from freeing up location lists when they are
// still being used.
@@ -2799,6 +2831,8 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char
static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf_T *old_curbuf,
linenr_T old_lnum)
{
+ garray_T *const gap = qfga_get();
+
// Update the screen before showing the message, unless the screen
// scrolled up.
if (!msg_scrolled) {
@@ -2807,13 +2841,13 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
update_screen();
}
}
- snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
- qf_get_curlist(qi)->qf_count,
- qf_ptr->qf_cleared ? _(" (line deleted)") : "",
- qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
+ vim_snprintf(IObuff, IOSIZE, _("(%d of %d)%s%s: "), qf_index,
+ qf_get_curlist(qi)->qf_count,
+ qf_ptr->qf_cleared ? _(" (line deleted)") : "",
+ qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
// Add the message, skipping leading whitespace and newlines.
- int len = (int)strlen(IObuff);
- qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
+ ga_concat(gap, IObuff);
+ qf_fmt_text(gap, skipwhite(qf_ptr->qf_text));
// Output the message. Overwrite to avoid scrolling when the 'O'
// flag is present in 'shortmess'; But when not jumping, print the
@@ -2825,8 +2859,10 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf
msg_scroll = false;
}
msg_ext_set_kind("quickfix");
- msg_attr_keep(IObuff, 0, true, false);
+ msg_attr_keep(gap->ga_data, 0, true, false);
msg_scroll = (int)i;
+
+ qfga_clear();
}
/// Find a usable window for opening a file from the quickfix/location list. If
@@ -3086,41 +3122,30 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
if (qfp->qf_lnum != 0) {
msg_puts_attr(":", qfSepAttr);
}
+ garray_T *gap = qfga_get();
if (qfp->qf_lnum == 0) {
- IObuff[0] = NUL;
+ ga_append(gap, NUL);
} else {
- qf_range_text(qfp, IObuff, IOSIZE);
+ qf_range_text(gap, qfp);
}
- vim_snprintf(IObuff + strlen(IObuff), IOSIZE, "%s", qf_types(qfp->qf_type, qfp->qf_nr));
- msg_puts_attr((const char *)IObuff, qfLineAttr);
+ ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
+ ga_append(gap, NUL);
+ msg_puts_attr(gap->ga_data, qfLineAttr);
msg_puts_attr(":", qfSepAttr);
if (qfp->qf_pattern != NULL) {
- qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
- msg_puts((const char *)IObuff);
+ gap = qfga_get();
+ qf_fmt_text(gap, qfp->qf_pattern);
+ msg_puts(gap->ga_data);
msg_puts_attr(":", qfSepAttr);
}
msg_puts(" ");
- char *tbuf = IObuff;
- size_t tbuflen = IOSIZE;
- size_t len = strlen(qfp->qf_text) + 3;
-
- if (len > IOSIZE) {
- tbuf = xmalloc(len);
- tbuflen = len;
- }
-
// Remove newlines and leading whitespace from the text. For an
// unrecognized line keep the indent, the compiler may mark a word
// with ^^^^.
- qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
- ? skipwhite(qfp->qf_text) : qfp->qf_text,
- tbuf, (int)tbuflen);
- msg_prt_line(tbuf, false);
-
- if (tbuf != IObuff) {
- xfree(tbuf);
- }
+ gap = qfga_get();
+ qf_fmt_text(gap, (fname != NULL || qfp->qf_lnum != 0) ? skipwhite(qfp->qf_text) : qfp->qf_text);
+ msg_prt_line(gap->ga_data, false);
}
// ":clist": list all errors
@@ -3195,51 +3220,57 @@ void qf_list(exarg_T *eap)
}
os_breakcheck();
}
+ qfga_clear();
}
-// Remove newlines and leading whitespace from an error message.
-// Put the result in "buf[bufsize]".
-static void qf_fmt_text(const char *restrict text, char *restrict buf, int bufsize)
+/// Remove newlines and leading whitespace from an error message.
+/// Add the result to the grow array "gap".
+static void qf_fmt_text(garray_T *gap, const char *restrict text)
FUNC_ATTR_NONNULL_ALL
{
- int i;
const char *p = (char *)text;
- for (i = 0; *p != NUL && i < bufsize - 1; i++) {
+ while (*p != NUL) {
if (*p == '\n') {
- buf[i] = ' ';
+ ga_append(gap, ' ');
while (*++p != NUL) {
if (!ascii_iswhite(*p) && *p != '\n') {
break;
}
}
} else {
- buf[i] = *p++;
+ ga_append(gap, (uint8_t)(*p++));
}
}
- buf[i] = NUL;
+
+ ga_append(gap, NUL);
}
-// Range information from lnum, col, end_lnum, and end_col.
-// Put the result in "buf[bufsize]".
-static void qf_range_text(const qfline_T *qfp, char *buf, int bufsize)
+/// Add the range information from the lnum, col, end_lnum, and end_col values
+/// of a quickfix entry to the grow array "gap".
+static void qf_range_text(garray_T *gap, const qfline_T *qfp)
{
- vim_snprintf(buf, (size_t)bufsize, "%" PRIdLINENR, qfp->qf_lnum);
- int len = (int)strlen(buf);
+ char *const buf = IObuff;
+ const size_t bufsize = IOSIZE;
+
+ vim_snprintf(buf, bufsize, "%" PRIdLINENR, qfp->qf_lnum);
+ size_t len = strlen(buf);
if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) {
- vim_snprintf(buf + len, (size_t)(bufsize - len), "-%" PRIdLINENR, qfp->qf_end_lnum);
- len += (int)strlen(buf + len);
+ vim_snprintf(buf + len, bufsize - len, "-%" PRIdLINENR, qfp->qf_end_lnum);
+ len += strlen(buf + len);
}
if (qfp->qf_col > 0) {
- vim_snprintf(buf + len, (size_t)(bufsize - len), " col %d", qfp->qf_col);
- len += (int)strlen(buf + len);
+ vim_snprintf(buf + len, bufsize - len, " col %d", qfp->qf_col);
+ len += strlen(buf + len);
if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) {
- vim_snprintf(buf + len, (size_t)(bufsize - len), "-%d", qfp->qf_end_col);
- len += (int)strlen(buf + len);
+ vim_snprintf(buf + len, bufsize - len, "-%d", qfp->qf_end_col);
+ len += strlen(buf + len);
}
}
buf[len] = NUL;
+
+ ga_concat_len(gap, buf, len);
}
/// Display information (list number, list size and the title) about a
@@ -3945,21 +3976,22 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli
char *dirname, char *qftf_str, bool first_bufline)
FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5)
{
+ garray_T *gap = qfga_get();
+
// If the 'quickfixtextfunc' function returned a non-empty custom string
// for this entry, then use it.
if (qftf_str != NULL && *qftf_str != NUL) {
- xstrlcpy(IObuff, qftf_str, IOSIZE);
+ ga_concat(gap, qftf_str);
+ ga_append(gap, NUL);
} else {
buf_T *errbuf;
- int len;
if (qfp->qf_module != NULL) {
- xstrlcpy(IObuff, qfp->qf_module, IOSIZE);
- len = (int)strlen(IObuff);
+ ga_concat(gap, qfp->qf_module);
} else if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL) {
if (qfp->qf_type == 1) { // :helpgrep
- xstrlcpy(IObuff, path_tail(errbuf->b_fname), IOSIZE);
+ ga_concat(gap, path_tail(errbuf->b_fname));
} else {
// Shorten the file name if not done already.
// For optimization, do this only for the first entry in a
@@ -3972,42 +4004,31 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfli
}
shorten_buf_fname(errbuf, dirname, false);
}
- xstrlcpy(IObuff, errbuf->b_fname, IOSIZE);
+ ga_concat(gap, errbuf->b_fname);
}
- len = (int)strlen(IObuff);
- } else {
- len = 0;
}
- if (len < IOSIZE - 1) {
- IObuff[len++] = '|';
- }
- if (qfp->qf_lnum > 0) {
- qf_range_text(qfp, IObuff + len, IOSIZE - len);
- len += (int)strlen(IObuff + len);
- snprintf(IObuff + len, (size_t)(IOSIZE - len), "%s", qf_types(qfp->qf_type,
- qfp->qf_nr));
- len += (int)strlen(IObuff + len);
+ ga_append(gap, '|');
+
+ if (qfp->qf_lnum > 0) {
+ qf_range_text(gap, qfp);
+ ga_concat(gap, qf_types(qfp->qf_type, qfp->qf_nr));
} else if (qfp->qf_pattern != NULL) {
- qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
- len += (int)strlen(IObuff + len);
- }
- if (len < IOSIZE - 2) {
- IObuff[len++] = '|';
- IObuff[len++] = ' ';
+ qf_fmt_text(gap, qfp->qf_pattern);
}
+ ga_append(gap, '|');
+ ga_append(gap, ' ');
// Remove newlines and leading whitespace from the text.
// For an unrecognized line keep the indent, the compiler may
// mark a word with ^^^^.
- qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
- IObuff + len, IOSIZE - len);
+ qf_fmt_text(gap, gap->ga_len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text);
}
- if (ml_append_buf(buf, lnum, IObuff,
- (colnr_T)strlen(IObuff) + 1, false) == FAIL) {
+ if (ml_append_buf(buf, lnum, gap->ga_data, gap->ga_len, false) == FAIL) {
return FAIL;
}
+
return OK;
}
@@ -4142,6 +4163,8 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// Delete the empty line which is now at the end
(void)ml_delete(lnum + 1, false);
}
+
+ qfga_clear();
}
// Correct cursor position.
@@ -7214,6 +7237,19 @@ void ex_helpgrep(exarg_T *eap)
}
}
+#if defined(EXITFREE)
+void free_quickfix(void)
+{
+ qf_free_all(NULL);
+ // Free all location lists
+ FOR_ALL_TAB_WINDOWS(tab, win) {
+ qf_free_all(win);
+ }
+
+ ga_clear(&qfga);
+}
+#endif
+
static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
{
if (what_arg->v_type == VAR_UNKNOWN) {
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 5d8e1913a2..48e6bc5298 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -2540,6 +2540,11 @@ func Test_normal33_g_cmd2()
norm! g'a
call assert_equal('>', a[-1:])
call assert_equal(1, line('.'))
+ let v:errmsg = ''
+ call assert_nobeep("normal! g`\<Esc>")
+ call assert_equal('', v:errmsg)
+ call assert_nobeep("normal! g'\<Esc>")
+ call assert_equal('', v:errmsg)
" Test for g; and g,
norm! g;
@@ -3315,7 +3320,8 @@ func Test_gr_command()
set modifiable&
call assert_nobeep("normal! gr\<Esc>")
- call assert_beeps("normal! cgr\<Esc>")
+ call assert_nobeep("normal! cgr\<Esc>")
+ call assert_beeps("normal! cgrx")
call assert_equal('zxxxx line l', getline(1))
exe "normal! 2|gr\<C-V>\<Esc>"
@@ -3895,4 +3901,36 @@ func Test_mouse_shape_after_failed_change()
call delete('Xmouseshapes')
endfunc
+" Test that mouse shape is restored to Normal mode after cancelling "gr".
+func Test_mouse_shape_after_cancelling_gr()
+ CheckFeature mouseshape
+ CheckCanRunGui
+
+ let lines =<< trim END
+ vim9script
+ var mouse_shapes = []
+
+ feedkeys('gr')
+ timer_start(50, (_) => {
+ mouse_shapes += [getmouseshape()]
+ timer_start(50, (_) => {
+ feedkeys("\<Esc>")
+ timer_start(50, (_) => {
+ mouse_shapes += [getmouseshape()]
+ timer_start(50, (_) => {
+ writefile(mouse_shapes, 'Xmouseshapes')
+ quit
+ })
+ })
+ })
+ })
+ END
+ call writefile(lines, 'Xmouseshape.vim', 'D')
+ call RunVim([], [], "-g -S Xmouseshape.vim")
+ sleep 300m
+ call assert_equal(['beam', 'arrow'], readfile('Xmouseshapes'))
+
+ call delete('Xmouseshapes')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 43cc3632e6..b6b982e92e 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -890,8 +890,9 @@ func Test_debug_option()
exe "normal \<C-c>"
call assert_equal('Beep!', Screenline(&lines))
call assert_equal('line 4:', Screenline(&lines - 1))
- " only match the final colon in the line that shows the source
- call assert_match(':$', Screenline(&lines - 2))
+ " also check a line above, with a certain window width the colon is there
+ call assert_match('Test_debug_option:$',
+ \ Screenline(&lines - 3) .. Screenline(&lines - 2))
set debug&
endfunc
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 8dc4173d60..fedc486e62 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -6220,6 +6220,66 @@ func Test_loclist_replace_autocmd()
call setloclist(0, [], 'f')
endfunc
+" Test for a very long error line and a very long information line
+func Test_very_long_error_line()
+ let msg = repeat('abcdefghijklmn', 146)
+ let emsg = 'Xlonglines.c:1:' . msg
+ call writefile([msg, emsg], 'Xerror', 'D')
+ cfile Xerror
+ cwindow
+ call assert_equal($'|| {msg}', getline(1))
+ call assert_equal($'Xlonglines.c|1| {msg}', getline(2))
+ cclose
+
+ let l = execute('clist!')->split("\n")
+ call assert_equal([$' 1: {msg}', $' 2 Xlonglines.c:1: {msg}'], l)
+
+ let l = execute('cc')->split("\n")
+ call assert_equal([$'(2 of 2): {msg}'], l)
+
+ call setqflist([], 'f')
+endfunc
+
+" The test depends on deferred delete and string interpolation, which haven't
+" been ported, so override it with a rewrite that doesn't use these features.
+func! Test_very_long_error_line()
+ let msg = repeat('abcdefghijklmn', 146)
+ let emsg = 'Xlonglines.c:1:' . msg
+ call writefile([msg, emsg], 'Xerror')
+ cfile Xerror
+ call delete('Xerror')
+ cwindow
+ call assert_equal('|| ' .. msg, getline(1))
+ call assert_equal('Xlonglines.c|1| ' .. msg, getline(2))
+ cclose
+
+ let l = execute('clist!')->split("\n")
+ call assert_equal([' 1: ' .. msg, ' 2 Xlonglines.c:1: ' .. msg], l)
+
+ let l = execute('cc')->split("\n")
+ call assert_equal(['(2 of 2): ' .. msg], l)
+
+ call setqflist([], 'f')
+endfunc
+
+" In the quickfix window, spaces at the beginning of an informational line
+" should not be removed but should be removed from an error line.
+func Test_info_line_with_space()
+ cexpr ["a.c:20:12: error: expected ';' before ':' token",
+ \ ' 20 | Afunc():', '', ' | ^']
+ copen
+ call assert_equal(["a.c|20 col 12| error: expected ';' before ':' token",
+ \ '|| 20 | Afunc():', '|| ',
+ \ '|| | ^'], getline(1, '$'))
+ cclose
+
+ let l = execute('clist!')->split("\n")
+ call assert_equal([" 1 a.c:20 col 12: error: expected ';' before ':' token",
+ \ ' 2: 20 | Afunc():', ' 3: ', ' 4: | ^'], l)
+
+ call setqflist([], 'f')
+endfunc
+
func s:QfTf(_)
endfunc