aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/ui.c3
-rw-r--r--src/nvim/digraph.c37
-rw-r--r--src/nvim/eval.c33
-rw-r--r--src/nvim/event/defs.h2
-rw-r--r--src/nvim/fileio.c54
-rw-r--r--src/nvim/move.c29
-rw-r--r--src/nvim/move.h3
-rw-r--r--src/nvim/os_unix.c2
-rw-r--r--src/nvim/quickfix.c209
-rw-r--r--src/nvim/screen.c57
-rw-r--r--src/nvim/testdir/Makefile3
-rw-r--r--src/nvim/testdir/sautest/autoload/foo.vim7
-rw-r--r--src/nvim/testdir/sautest/autoload/globone.vim1
-rw-r--r--src/nvim/testdir/sautest/autoload/globtwo.vim1
-rw-r--r--src/nvim/testdir/sautest/autoload/sourced.vim3
-rw-r--r--src/nvim/testdir/test24.inbin1265 -> 0 bytes
-rw-r--r--src/nvim/testdir/test24.ok32
-rw-r--r--src/nvim/testdir/test_autoload.vim17
-rw-r--r--src/nvim/testdir/test_comparators.vim9
-rw-r--r--src/nvim/testdir/test_escaped_glob.vim33
-rw-r--r--src/nvim/testdir/test_exec_while_if.vim53
-rw-r--r--src/nvim/testdir/test_exists_autocmd.vim26
-rw-r--r--src/nvim/testdir/test_fold.vim40
-rw-r--r--src/nvim/testdir/test_getcwd.vim91
-rw-r--r--src/nvim/testdir/test_largefile.vim2
-rw-r--r--src/nvim/testdir/test_maparg.vim56
-rw-r--r--src/nvim/testdir/test_plus_arg_edit.vim10
-rw-r--r--src/nvim/testdir/test_quickfix.vim147
-rw-r--r--src/nvim/testdir/test_regex_char_classes.vim58
-rw-r--r--src/nvim/tui/tui.c18
-rw-r--r--src/nvim/ui.c39
-rw-r--r--src/nvim/ui.h2
-rw-r--r--src/nvim/ui_bridge.c12
33 files changed, 828 insertions, 261 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 76e3927820..509032892b 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -424,7 +424,8 @@ static void remote_ui_put(UI *ui, const char *cell)
static void remote_ui_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr,
- const schar_T *chunk, const sattr_T *attrs)
+ Boolean wrap, const schar_T *chunk,
+ const sattr_T *attrs)
{
UIData *data = ui->data;
if (ui->ui_ext[kUINewgrid]) {
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 54508018b5..eb28280457 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -1359,6 +1359,12 @@ static digr_T digraphdefault[] =
{ 'f', 't', 0xfb05 },
{ 's', 't', 0xfb06 },
+ // extra alternatives, easier to remember
+ { 'W', '`', 0x1e80 },
+ { 'w', '`', 0x1e81 },
+ { 'Y', '`', 0x1ef2 },
+ { 'y', '`', 0x1ef3 },
+
// Vim 5.x compatible digraphs that don't conflict with the above
{ '~', '!', 161 }, // ¡
{ 'c', '|', 162 }, // ¢
@@ -1520,34 +1526,6 @@ static int getexactdigraph(int char1, int char2, int meta_char)
}
}
- if ((retval != 0) && !enc_utf8) {
- char_u buf[6], *to;
- vimconv_T vc;
-
- // Convert the Unicode digraph to 'encoding'.
- int i = utf_char2bytes(retval, buf);
- retval = 0;
- vc.vc_type = CONV_NONE;
-
- if (convert_setup(&vc, (char_u *)"utf-8", p_enc) == OK) {
- vc.vc_fail = true;
- assert(i >= 0);
- size_t len = (size_t)i;
- to = string_convert(&vc, buf, &len);
-
- if (to != NULL) {
- retval = utf_ptr2char(to);
- xfree(to);
- }
- (void)convert_setup(&vc, NULL, NULL);
- }
- }
-
- // Ignore multi-byte characters when not in multi-byte mode.
- if (!has_mbyte && (retval > 0xff)) {
- retval = 0;
- }
-
if (retval == 0) {
// digraph deleted or not found
if ((char1 == ' ') && meta_char) {
@@ -1654,8 +1632,7 @@ void listdigraphs(void)
tmp.result = getexactdigraph(tmp.char1, tmp.char2, FALSE);
if ((tmp.result != 0)
- && (tmp.result != tmp.char2)
- && (has_mbyte || (tmp.result <= 255))) {
+ && (tmp.result != tmp.char2)) {
printdigraph(&tmp);
}
dp++;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 38a080b1ef..b7f5d93bf3 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2076,7 +2076,11 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
return p;
}
- v = find_var(lp->ll_name, lp->ll_name_len, &ht, flags & GLV_NO_AUTOLOAD);
+ // Only pass &ht when we would write to the variable, it prevents autoload
+ // as well.
+ v = find_var(lp->ll_name, lp->ll_name_len,
+ (flags & GLV_READ_ONLY) ? NULL : &ht,
+ flags & GLV_NO_AUTOLOAD);
if (v == NULL && !quiet) {
emsgf(_("E121: Undefined variable: %.*s"),
(int)lp->ll_name_len, lp->ll_name);
@@ -8873,9 +8877,14 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char_u buf[FOLD_TEXT_LEN];
foldinfo_T foldinfo;
int fold_count;
+ static bool entered = false;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
+ if (entered) {
+ return; // reject recursive use
+ }
+ entered = true;
linenr_T lnum = tv_get_lnum(argvars);
// Treat illegal types and illegal string values for {lnum} the same.
if (lnum < 0) {
@@ -8889,6 +8898,8 @@ static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
rettv->vval.v_string = text;
}
+
+ entered = false;
}
/*
@@ -9943,7 +9954,7 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
if (what_arg->v_type == VAR_UNKNOWN) {
tv_list_alloc_ret(rettv, kListLenMayKnow);
if (is_qf || wp != NULL) {
- (void)get_errorlist(wp, -1, rettv->vval.v_list);
+ (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
}
} else {
tv_dict_alloc_ret(rettv);
@@ -12138,8 +12149,12 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
if (!get_dict) {
// Return a string.
if (rhs != NULL) {
- rettv->vval.v_string = (char_u *)str2special_save(
- (const char *)rhs, false, false);
+ if (*rhs == NUL) {
+ rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
+ } else {
+ rettv->vval.v_string = (char_u *)str2special_save(
+ (char *)rhs, false, false);
+ }
}
} else {
@@ -18315,9 +18330,9 @@ varnumber_T get_vim_var_nr(int idx) FUNC_ATTR_PURE
return vimvars[idx].vv_nr;
}
-/*
- * Get string v: variable value. Uses a static buffer, can only be used once.
- */
+// Get string v: variable value. Uses a static buffer, can only be used once.
+// If the String variable has never been set, return an empty string.
+// Never returns NULL;
char_u *get_vim_var_str(int idx) FUNC_ATTR_PURE FUNC_ATTR_NONNULL_RET
{
return (char_u *)tv_get_string(&vimvars[idx].vv_tv);
@@ -19804,7 +19819,7 @@ void ex_function(exarg_T *eap)
// s:func script-local function name
// g:func global function name, same as "func"
p = eap->arg;
- name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
+ name = trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL);
paren = (vim_strchr(p, '(') != NULL);
if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) {
/*
@@ -20348,7 +20363,7 @@ trans_function_name(
}
// Note that TFN_ flags use the same values as GLV_ flags.
- end = get_lval((char_u *)start, NULL, &lv, false, skip, flags,
+ end = get_lval((char_u *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
lead > 2 ? 0 : FNE_CHECK_START);
if (end == start) {
if (!skip)
diff --git a/src/nvim/event/defs.h b/src/nvim/event/defs.h
index 55b2d277bb..fdd4f17d5c 100644
--- a/src/nvim/event/defs.h
+++ b/src/nvim/event/defs.h
@@ -4,7 +4,7 @@
#include <assert.h>
#include <stdarg.h>
-#define EVENT_HANDLER_MAX_ARGC 9
+#define EVENT_HANDLER_MAX_ARGC 10
typedef void (*argv_callback)(void **argv);
typedef struct message {
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 8b650d0d5b..290de034d7 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -4311,38 +4311,46 @@ static int make_bom(char_u *buf, char_u *name)
return (int)(p - buf);
}
+/// Shorten filename of a buffer.
+/// When "force" is TRUE: Use full path from now on for files currently being
+/// edited, both for file name and swap file name. Try to shorten the file
+/// names a bit, if safe to do so.
+/// When "force" is FALSE: Only try to shorten absolute file names.
+/// For buffers that have buftype "nofile" or "scratch": never change the file
+/// name.
+void shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
+{
+ char_u *p;
+
+ if (buf->b_fname != NULL
+ && !bt_nofile(buf)
+ && !path_with_url((char *)buf->b_fname)
+ && (force
+ || buf->b_sfname == NULL
+ || path_is_absolute(buf->b_sfname))) {
+ xfree(buf->b_sfname);
+ buf->b_sfname = NULL;
+ p = path_shorten_fname(buf->b_ffname, dirname);
+ if (p != NULL) {
+ buf->b_sfname = vim_strsave(p);
+ buf->b_fname = buf->b_sfname;
+ }
+ if (p == NULL || buf->b_fname == NULL) {
+ buf->b_fname = buf->b_ffname;
+ }
+ }
+}
+
/*
* Shorten filenames for all buffers.
- * When "force" is TRUE: Use full path from now on for files currently being
- * edited, both for file name and swap file name. Try to shorten the file
- * names a bit, if safe to do so.
- * When "force" is FALSE: Only try to shorten absolute file names.
- * For buffers that have buftype "nofile" or "scratch": never change the file
- * name.
*/
void shorten_fnames(int force)
{
char_u dirname[MAXPATHL];
- char_u *p;
os_dirname(dirname, MAXPATHL);
FOR_ALL_BUFFERS(buf) {
- if (buf->b_fname != NULL
- && !bt_nofile(buf)
- && !path_with_url((char *)buf->b_fname)
- && (force
- || buf->b_sfname == NULL
- || path_is_absolute(buf->b_sfname))) {
- xfree(buf->b_sfname);
- buf->b_sfname = NULL;
- p = path_shorten_fname(buf->b_ffname, dirname);
- if (p != NULL) {
- buf->b_sfname = vim_strsave(p);
- buf->b_fname = buf->b_sfname;
- }
- if (p == NULL || buf->b_fname == NULL)
- buf->b_fname = buf->b_ffname;
- }
+ shorten_buf_fname(buf, dirname, force);
/* Always make the swap file name a full path, a "nofile" buffer may
* also have a swap file. */
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 41859a489f..1b84628ebc 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -16,7 +16,6 @@
#include <inttypes.h>
#include <stdbool.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/move.h"
#include "nvim/charset.h"
@@ -1726,7 +1725,7 @@ void cursor_correct(void)
*
* return FAIL for failure, OK otherwise
*/
-int onepage(int dir, long count)
+int onepage(Direction dir, long count)
{
long n;
int retval = OK;
@@ -1884,16 +1883,18 @@ int onepage(int dir, long count)
}
curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
- /*
- * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
- * But make sure we scroll at least one line (happens with mix of long
- * wrapping lines and non-wrapping line).
- */
- if (retval == OK && dir == FORWARD && check_top_offset()) {
- scroll_cursor_top(1, false);
- if (curwin->w_topline <= old_topline
- && old_topline < curbuf->b_ml.ml_line_count) {
- curwin->w_topline = old_topline + 1;
+ if (retval == OK && dir == FORWARD) {
+ // Avoid the screen jumping up and down when 'scrolloff' is non-zero.
+ // But make sure we scroll at least one line (happens with mix of long
+ // wrapping lines and non-wrapping line).
+ if (check_top_offset()) {
+ scroll_cursor_top(1, false);
+ if (curwin->w_topline <= old_topline
+ && old_topline < curbuf->b_ml.ml_line_count) {
+ curwin->w_topline = old_topline + 1;
+ (void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+ }
+ } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) {
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
}
}
@@ -2166,9 +2167,7 @@ void do_check_cursorbind(void)
restart_edit = restart_edit_save;
}
// Correct cursor for multi-byte character.
- if (has_mbyte) {
- mb_adjust_cursor();
- }
+ mb_adjust_cursor();
redraw_later(VALID);
// Only scroll when 'scrollbind' hasn't done this.
diff --git a/src/nvim/move.h b/src/nvim/move.h
index 00fbcc580f..3670dc9086 100644
--- a/src/nvim/move.h
+++ b/src/nvim/move.h
@@ -2,8 +2,7 @@
#define NVIM_MOVE_H
#include <stdbool.h>
-#include "nvim/buffer_defs.h"
-#include "nvim/pos.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "move.h.generated.h"
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index a27fee4e90..e52adfa1a9 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -138,8 +138,8 @@ void mch_exit(int r)
{
exiting = true;
- ui_builtin_stop();
ui_flush();
+ ui_builtin_stop();
ml_close_all(true); // remove all memfiles
if (!event_teardown() && r == 0) {
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 263b8b3a77..7c555da1a0 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -82,6 +82,7 @@ struct qfline_S {
/// created using setqflist()/setloclist() with a title and/or user context
/// information and entries can be added later using setqflist()/setloclist().
typedef struct qf_list_S {
+ unsigned qf_id; ///< Unique identifier for this list
qfline_T *qf_start; ///< pointer to the first error
qfline_T *qf_last; ///< pointer to the last error
qfline_T *qf_ptr; ///< pointer to the current error
@@ -116,7 +117,8 @@ struct qf_info_S {
qf_list_T qf_lists[LISTCOUNT];
};
-static qf_info_T ql_info; /* global quickfix list */
+static qf_info_T ql_info; // global quickfix list
+static unsigned last_qf_id = 0; // Last Used quickfix list id
#define FMT_PATTERNS 10 /* maximum number of % recognized */
@@ -1224,6 +1226,7 @@ static void qf_new_list(qf_info_T *qi, char_u *qf_title)
qi->qf_curlist = qi->qf_listcount++;
memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T)));
qf_store_title(qi, qi->qf_curlist, qf_title);
+ qi->qf_lists[qi->qf_curlist].qf_id = ++last_qf_id;
}
/*
@@ -1467,6 +1470,9 @@ void copy_loclist(win_T *from, win_T *to)
to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */
+ // Assign a new ID for the location list
+ to_qfl->qf_id = ++last_qf_id;
+
/* When no valid entries are present in the list, qf_ptr points to
* the first item in the list */
if (to_qfl->qf_nonevalid) {
@@ -2234,8 +2240,12 @@ void qf_list(exarg_T *eap)
}
}
- if (qi->qf_lists[qi->qf_curlist].qf_nonevalid)
- all = TRUE;
+ // Shorten all the file names, so that it is easy to read.
+ shorten_fnames(false);
+
+ if (qi->qf_lists[qi->qf_curlist].qf_nonevalid) {
+ all = true;
+ }
qfp = qi->qf_lists[qi->qf_curlist].qf_start;
for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) {
if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) {
@@ -2414,7 +2424,7 @@ static void qf_free_items(qf_info_T *qi, int idx)
while (qfl->qf_count && qfl->qf_start != NULL) {
qfp = qfl->qf_start;
qfpnext = qfp->qf_next;
- if (qfl->qf_title != NULL && !stop) {
+ if (!stop) {
xfree(qfp->qf_text);
stop = (qfp == qfpnext);
xfree(qfp->qf_pattern);
@@ -2458,6 +2468,7 @@ static void qf_free(qf_info_T *qi, int idx)
qfl->qf_title = NULL;
tv_free(qfl->qf_ctx);
qfl->qf_ctx = NULL;
+ qfl->qf_id = 0;
}
/*
@@ -2937,6 +2948,10 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
/* Check if there is anything to display */
if (qi->qf_curlist < qi->qf_listcount) {
+ char_u dirname[MAXPATHL];
+
+ *dirname = NUL;
+
// Add one line for each error
if (old_last == NULL) {
qfp = qi->qf_lists[qi->qf_curlist].qf_start;
@@ -2952,6 +2967,14 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
if (qfp->qf_type == 1) { // :helpgrep
STRLCPY(IObuff, path_tail(errbuf->b_fname), sizeof(IObuff));
} else {
+ // shorten the file name if not done already
+ if (errbuf->b_sfname == NULL
+ || path_is_absolute(errbuf->b_sfname)) {
+ if (*dirname == NUL) {
+ os_dirname(dirname, MAXPATHL);
+ }
+ shorten_buf_fname(errbuf, dirname, false);
+ }
STRLCPY(IObuff, errbuf->b_fname, sizeof(IObuff));
}
len = (int)STRLEN(IObuff);
@@ -4031,18 +4054,22 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
/// Add each quickfix error to list "list" as a dictionary.
/// If qf_idx is -1, use the current list. Otherwise, use the specified list.
-int get_errorlist(win_T *wp, int qf_idx, list_T *list)
+int get_errorlist(const qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
{
- qf_info_T *qi = &ql_info;
+ const qf_info_T *qi = qi_arg;
char_u buf[2];
qfline_T *qfp;
int i;
int bufnum;
- if (wp != NULL) {
- qi = GET_LOC_LIST(wp);
- if (qi == NULL)
- return FAIL;
+ if (qi == NULL) {
+ qi = &ql_info;
+ if (wp != NULL) {
+ qi = GET_LOC_LIST(wp);
+ if (qi == NULL) {
+ return FAIL;
+ }
+ }
}
if (qf_idx == -1) {
@@ -4106,9 +4133,48 @@ enum {
QF_GETLIST_NR = 0x4,
QF_GETLIST_WINID = 0x8,
QF_GETLIST_CONTEXT = 0x10,
+ QF_GETLIST_ID = 0x20,
QF_GETLIST_ALL = 0xFF
};
+// Parse text from 'di' and return the quickfix list items
+static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
+{
+ int status = FAIL;
+ char_u *errorformat = p_efm;
+ dictitem_T *efm_di;
+
+ // Only a List value is supported
+ if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
+ // If errorformat is supplied then use it, otherwise use the 'efm'
+ // option setting
+ if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
+ if (efm_di->di_tv.v_type != VAR_STRING
+ || efm_di->di_tv.vval.v_string == NULL) {
+ return FAIL;
+ }
+ errorformat = efm_di->di_tv.vval.v_string;
+ }
+
+ list_T *l = tv_list_alloc(kListLenMayKnow);
+ qf_info_T *qi = xmalloc(sizeof(*qi));
+ memset(qi, 0, sizeof(*qi));
+ qi->qf_refcount++;
+
+ if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
+ true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
+ (void)get_errorlist(qi, NULL, 0, l);
+ qf_free(qi, 0);
+ }
+ xfree(qi);
+
+ tv_dict_add_list(retdict, S_LEN("items"), l);
+ status = OK;
+ }
+
+ return status;
+}
+
/// Return quickfix/location list details (title) as a
/// dictionary. 'what' contains the details to return. If 'list_idx' is -1,
/// then current list is used. Otherwise the specified list is used.
@@ -4117,17 +4183,22 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
qf_info_T *qi = &ql_info;
dictitem_T *di;
+ if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
+ return qf_get_list_from_lines(what, di, retdict);
+ }
+
if (wp != NULL) {
qi = GET_LOC_LIST(wp);
- if (qi == NULL) {
- // If querying for the size of the location list, return 0
- if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL)
- && (di->di_tv.v_type == VAR_STRING)
- && strequal((const char *)di->di_tv.vval.v_string, "$")) {
- return tv_dict_add_nr(retdict, S_LEN("nr"), 0);
- }
- return FAIL;
+ }
+ // List is not present or is empty
+ if (qi == NULL || qi->qf_listcount == 0) {
+ // If querying for the size of the list, return 0
+ if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL)
+ && (di->di_tv.v_type == VAR_STRING)
+ && (STRCMP(di->di_tv.vval.v_string, "$") == 0)) {
+ return tv_dict_add_nr(retdict, S_LEN("nr"), 0);
}
+ return FAIL;
}
int status = OK;
@@ -4143,44 +4214,51 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
}
- } else if (qi->qf_listcount == 0) { // stack is empty
- return FAIL;
}
- flags |= QF_GETLIST_NR;
} else if (di->di_tv.v_type == VAR_STRING
&& strequal((const char *)di->di_tv.vval.v_string, "$")) {
// Get the last quickfix list number
- if (qi->qf_listcount > 0) {
- qf_idx = qi->qf_listcount - 1;
- } else {
- qf_idx = -1; // Quickfix stack is empty
- }
- flags |= QF_GETLIST_NR;
+ qf_idx = qi->qf_listcount - 1;
} else {
return FAIL;
}
+ flags |= QF_GETLIST_NR;
}
- if (qf_idx != -1) {
- if (tv_dict_find(what, S_LEN("all")) != NULL) {
- flags |= QF_GETLIST_ALL;
- }
-
- if (tv_dict_find(what, S_LEN("title")) != NULL) {
- flags |= QF_GETLIST_TITLE;
- }
-
- if (tv_dict_find(what, S_LEN("winid")) != NULL) {
- flags |= QF_GETLIST_WINID;
- }
-
- if (tv_dict_find(what, S_LEN("context")) != NULL) {
- flags |= QF_GETLIST_CONTEXT;
+ if ((di = tv_dict_find(what, S_LEN("id"))) != NULL) {
+ // Look for a list with the specified id
+ if (di->di_tv.v_type == VAR_NUMBER) {
+ // For zero, use the current list or the list specifed by 'nr'
+ if (di->di_tv.vval.v_number != 0) {
+ for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) {
+ if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number) {
+ break;
+ }
+ }
+ if (qf_idx == qi->qf_listcount) {
+ return FAIL; // List not found
+ }
+ }
+ flags |= QF_GETLIST_ID;
+ } else {
+ return FAIL;
}
+ }
- if (tv_dict_find(what, S_LEN("items")) != NULL) {
- flags |= QF_GETLIST_ITEMS;
- }
+ if (tv_dict_find(what, S_LEN("all")) != NULL) {
+ flags |= QF_GETLIST_ALL;
+ }
+ if (tv_dict_find(what, S_LEN("title")) != NULL) {
+ flags |= QF_GETLIST_TITLE;
+ }
+ if (tv_dict_find(what, S_LEN("winid")) != NULL) {
+ flags |= QF_GETLIST_WINID;
+ }
+ if (tv_dict_find(what, S_LEN("context")) != NULL) {
+ flags |= QF_GETLIST_CONTEXT;
+ }
+ if (tv_dict_find(what, S_LEN("items")) != NULL) {
+ flags |= QF_GETLIST_ITEMS;
}
if (flags & QF_GETLIST_TITLE) {
@@ -4201,7 +4279,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
}
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
list_T *l = tv_list_alloc(kListLenMayKnow);
- (void)get_errorlist(wp, qf_idx, l);
+ (void)get_errorlist(qi, NULL, qf_idx, l);
tv_dict_add_list(retdict, S_LEN("items"), l);
}
@@ -4218,6 +4296,10 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
}
}
+ if ((status == OK) && (flags & QF_GETLIST_ID)) {
+ status = tv_dict_add_nr(retdict, S_LEN("id"), qi->qf_lists[qf_idx].qf_id);
+ }
+
return status;
}
@@ -4336,6 +4418,7 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
dictitem_T *di;
int retval = FAIL;
int newlist = false;
+ char_u *errorformat = p_efm;
if (action == ' ' || qi->qf_curlist == qi->qf_listcount) {
newlist = true;
@@ -4374,6 +4457,22 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
}
}
+ if (!newlist && (di = tv_dict_find(what, S_LEN("id"))) != NULL) {
+ // Use the quickfix/location list with the specified id
+ if (di->di_tv.v_type == VAR_NUMBER) {
+ for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) {
+ if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number) {
+ break;
+ }
+ }
+ if (qf_idx == qi->qf_listcount) {
+ return FAIL; // List not found
+ }
+ } else {
+ return FAIL;
+ }
+ }
+
if (newlist) {
qi->qf_curlist = qf_idx;
qf_new_list(qi, title);
@@ -4401,16 +4500,20 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
}
}
- if ((di = tv_dict_find(what, S_LEN("text"))) != NULL) {
- // Only string and list values are supported
- if ((di->di_tv.v_type == VAR_STRING
- && di->di_tv.vval.v_string != NULL)
- || (di->di_tv.v_type == VAR_LIST
- && di->di_tv.vval.v_list != NULL)) {
+ if ((di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
+ if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL) {
+ return FAIL;
+ }
+ errorformat = di->di_tv.vval.v_string;
+ }
+
+ if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
+ // Only a List value is supported
+ if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
if (action == 'r') {
qf_free_items(qi, qf_idx);
}
- if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, p_efm,
+ if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
retval = OK;
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 69c3d3067d..8ad2145400 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -2012,7 +2012,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
screen_line(row + wp->w_winrow, wp->w_wincol, wp->w_width,
- wp->w_width, false, wp, wp->w_hl_attr_normal);
+ wp->w_width, false, wp, wp->w_hl_attr_normal, false);
/*
* Update w_cline_height and w_cline_folded if the cursor line was
@@ -2900,7 +2900,7 @@ win_line (
&& filler_todo <= 0
) {
screen_line(screen_row, wp->w_wincol, col, -wp->w_width, wp->w_p_rl, wp,
- wp->w_hl_attr_normal);
+ wp->w_hl_attr_normal, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
@@ -3989,7 +3989,7 @@ win_line (
}
}
screen_line(screen_row, wp->w_wincol, col, wp->w_width, wp->w_p_rl, wp,
- wp->w_hl_attr_normal);
+ wp->w_hl_attr_normal, false);
row++;
/*
@@ -4197,8 +4197,22 @@ win_line (
|| (wp->w_p_list && lcs_eol != NUL && p_extra != at_end_str)
|| (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
) {
+ bool wrap = wp->w_p_wrap // Wrapping enabled.
+ && filler_todo <= 0 // Not drawing diff filler lines.
+ && lcs_eol_one != -1 // Haven't printed the lcs_eol character.
+ && row != endrow - 1 // Not the last line being displayed.
+ && wp->w_width == Columns // Window spans the width of the screen.
+ && !wp->w_p_rl; // Not right-to-left.
screen_line(screen_row, wp->w_wincol, col - boguscols,
- wp->w_width, wp->w_p_rl, wp, wp->w_hl_attr_normal);
+ wp->w_width, wp->w_p_rl, wp, wp->w_hl_attr_normal, wrap);
+ if (wrap) {
+ // Force a redraw of the first column of the next line.
+ ScreenAttrs[LineOffset[screen_row + 1]] = -1;
+
+ // Remember that the line wraps, used for modeless copy.
+ LineWraps[screen_row] = true;
+ }
+
boguscols = 0;
++row;
++screen_row;
@@ -4225,28 +4239,6 @@ win_line (
break;
}
- if (ui_current_row() == screen_row - 1
- && filler_todo <= 0
- && wp->w_width == Columns) {
- /* Remember that the line wraps, used for modeless copy. */
- LineWraps[screen_row - 1] = TRUE;
-
- // Special trick to make copy/paste of wrapped lines work with
- // xterm/screen: write an extra character beyond the end of
- // the line. This will work with all terminal types
- // (regardless of the xn,am settings).
- // Only do this if the cursor is on the current line
- // (something has been written in it).
- // Don't do this for double-width characters.
- // Don't do this for a window not at the right screen border.
- if (utf_off2cells(LineOffset[screen_row],
- LineOffset[screen_row] + screen_Columns) != 2
- && utf_off2cells(LineOffset[screen_row - 1] + (int)Columns - 2,
- LineOffset[screen_row] + screen_Columns) != 2) {
- ui_add_linewrap(screen_row - 1);
- }
- }
-
col = 0;
off = (unsigned)(current_ScreenLine - ScreenLines);
if (wp->w_p_rl) {
@@ -4312,9 +4304,11 @@ static int char_needs_redraw(int off_from, int off_to, int cols)
* "rlflag" is TRUE in a rightleft window:
* When TRUE and "clear_width" > 0, clear columns 0 to "endcol"
* When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
+ * If "wrap" is true, then hint to the UI that "row" contains a line
+ * which has wrapped into the next row.
*/
-static void screen_line(int row, int coloff, int endcol,
- int clear_width, int rlflag, win_T *wp, int bg_attr)
+static void screen_line(int row, int coloff, int endcol, int clear_width,
+ int rlflag, win_T *wp, int bg_attr, bool wrap)
{
unsigned off_from;
unsigned off_to;
@@ -4475,7 +4469,7 @@ static void screen_line(int row, int coloff, int endcol,
}
if (clear_end > start_dirty) {
ui_line(row, coloff+start_dirty, coloff+end_dirty, coloff+clear_end,
- bg_attr);
+ bg_attr, wrap);
}
}
@@ -5435,7 +5429,8 @@ void screen_puts_line_flush(bool set_cursor)
if (set_cursor) {
ui_cursor_goto(put_dirty_row, put_dirty_last);
}
- ui_line(put_dirty_row, put_dirty_first, put_dirty_last, put_dirty_last, 0);
+ ui_line(put_dirty_row, put_dirty_first, put_dirty_last, put_dirty_last, 0,
+ false);
put_dirty_first = -1;
put_dirty_last = 0;
}
@@ -5794,7 +5789,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
put_dirty_last = MAX(put_dirty_last, dirty_last);
} else {
int last = c2 != ' ' ? dirty_last : dirty_first + (c1 != ' ');
- ui_line(row, dirty_first, last, dirty_last, attr);
+ ui_line(row, dirty_first, last, dirty_last, attr, false);
}
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 10cbd91e36..9a83a46add 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -15,7 +15,6 @@ export TMPDIR := $(abspath ../../../Xtest-tmpdir)
SCRIPTS_DEFAULT = \
test14.out \
- test24.out \
test37.out \
test42.out \
test48.out \
@@ -35,7 +34,7 @@ SCRIPTS ?= $(SCRIPTS_DEFAULT)
NEW_TESTS_ALOT := test_alot_utf8 test_alot
NEW_TESTS_IN_ALOT := $(shell sed '/^source/ s/^source //;s/\.vim$$//' test_alot*.vim)
# Ignored tests.
-# test_alot_latin1: Nvim does not allow setting encoding.
+# test_alot_latin: Nvim does not allow setting encoding.
# test_arglist: ported to Lua, but kept for easier merging.
# test_autochdir: ported to Lua, but kept for easier merging.
# test_eval_func: used as include in old-style test (test_eval.in).
diff --git a/src/nvim/testdir/sautest/autoload/foo.vim b/src/nvim/testdir/sautest/autoload/foo.vim
new file mode 100644
index 0000000000..d7dcd5ce3d
--- /dev/null
+++ b/src/nvim/testdir/sautest/autoload/foo.vim
@@ -0,0 +1,7 @@
+let g:loaded_foo_vim += 1
+
+let foo#bar = {}
+
+func foo#bar.echo()
+ let g:called_foo_bar_echo += 1
+endfunc
diff --git a/src/nvim/testdir/sautest/autoload/globone.vim b/src/nvim/testdir/sautest/autoload/globone.vim
new file mode 100644
index 0000000000..98c9a10582
--- /dev/null
+++ b/src/nvim/testdir/sautest/autoload/globone.vim
@@ -0,0 +1 @@
+" used by Test_globpath()
diff --git a/src/nvim/testdir/sautest/autoload/globtwo.vim b/src/nvim/testdir/sautest/autoload/globtwo.vim
new file mode 100644
index 0000000000..98c9a10582
--- /dev/null
+++ b/src/nvim/testdir/sautest/autoload/globtwo.vim
@@ -0,0 +1 @@
+" used by Test_globpath()
diff --git a/src/nvim/testdir/sautest/autoload/sourced.vim b/src/nvim/testdir/sautest/autoload/sourced.vim
new file mode 100644
index 0000000000..f69f00cb53
--- /dev/null
+++ b/src/nvim/testdir/sautest/autoload/sourced.vim
@@ -0,0 +1,3 @@
+let g:loaded_sourced_vim += 1
+func! sourced#something()
+endfunc
diff --git a/src/nvim/testdir/test24.in b/src/nvim/testdir/test24.in
deleted file mode 100644
index 292f403048..0000000000
--- a/src/nvim/testdir/test24.in
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test24.ok b/src/nvim/testdir/test24.ok
deleted file mode 100644
index cd61210968..0000000000
--- a/src/nvim/testdir/test24.ok
+++ /dev/null
@@ -1,32 +0,0 @@
-start
-test text test text
-test text test text
-test text test text
-test text test text
-test text test text
-test text test text
-test text test text x61
-test text test text x60-x64
-test text test text x78 5
-test text test text o143
-test text test text o140-o144
-test text test text o41 7
-test text test text \%x42
-test text test text \%o103
-test text test text [\x00]
-test text test text [\x00-\x10]
-test text test text [\x-z]
-test text test text [\u-z]
-xx xx a
-xx aaaaa xx a
-xx aaaaa xx a
-xx Aaa xx
-xx Aaaa xx
-xx Aaa xx
-xx foobar xA xx
-xx an A xx
-XX 9;
-YY 77;
- xyz
- bcd
- BB
diff --git a/src/nvim/testdir/test_autoload.vim b/src/nvim/testdir/test_autoload.vim
new file mode 100644
index 0000000000..7396c227c9
--- /dev/null
+++ b/src/nvim/testdir/test_autoload.vim
@@ -0,0 +1,17 @@
+" Tests for autoload
+
+set runtimepath=./sautest
+
+func Test_autoload_dict_func()
+ let g:loaded_foo_vim = 0
+ let g:called_foo_bar_echo = 0
+ call g:foo#bar.echo()
+ call assert_equal(1, g:loaded_foo_vim)
+ call assert_equal(1, g:called_foo_bar_echo)
+endfunc
+
+func Test_source_autoload()
+ let g:loaded_sourced_vim = 0
+ source sautest/autoload/sourced.vim
+ call assert_equal(1, g:loaded_sourced_vim)
+endfunc
diff --git a/src/nvim/testdir/test_comparators.vim b/src/nvim/testdir/test_comparators.vim
new file mode 100644
index 0000000000..87be006cf2
--- /dev/null
+++ b/src/nvim/testdir/test_comparators.vim
@@ -0,0 +1,9 @@
+function Test_Comparators()
+ try
+ let oldisident=&isident
+ set isident+=#
+ call assert_equal(1, 1 is#1)
+ finally
+ let &isident=oldisident
+ endtry
+endfunction
diff --git a/src/nvim/testdir/test_escaped_glob.vim b/src/nvim/testdir/test_escaped_glob.vim
new file mode 100644
index 0000000000..eaeac28d61
--- /dev/null
+++ b/src/nvim/testdir/test_escaped_glob.vim
@@ -0,0 +1,33 @@
+" Test whether glob()/globpath() return correct results with certain escaped
+" characters.
+
+function SetUp()
+ " make sure glob() doesn't use the shell
+ set shell=doesnotexist
+ " consistent sorting of file names
+ set nofileignorecase
+endfunction
+
+function Test_glob()
+ if !has('unix')
+ " This test fails on Windows because of the special characters in the
+ " filenames. Disable the test on non-Unix systems for now.
+ return
+ endif
+ call assert_equal("", glob('Xxx\{'))
+ call assert_equal("", glob('Xxx\$'))
+ w! Xxx{
+ " } to fix highlighting
+ w! Xxx\$
+ call assert_equal("Xxx{", glob('Xxx\{'))
+ call assert_equal("Xxx$", glob('Xxx\$'))
+ call delete('Xxx{')
+ call delete('Xxx$')
+endfunction
+
+function Test_globpath()
+ call assert_equal(expand("sautest/autoload/globone.vim\nsautest/autoload/globtwo.vim"),
+ \ globpath('sautest/autoload', 'glob*.vim'))
+ call assert_equal([expand('sautest/autoload/globone.vim'), expand('sautest/autoload/globtwo.vim')],
+ \ globpath('sautest/autoload', 'glob*.vim', 0, 1))
+endfunction
diff --git a/src/nvim/testdir/test_exec_while_if.vim b/src/nvim/testdir/test_exec_while_if.vim
new file mode 100644
index 0000000000..d6afabff45
--- /dev/null
+++ b/src/nvim/testdir/test_exec_while_if.vim
@@ -0,0 +1,53 @@
+" Test for :execute, :while and :if
+
+function Test_exec_while_if()
+ new
+
+ let i = 0
+ while i < 12
+ let i = i + 1
+ if has("ebcdic")
+ execute "normal o" . i . "\047"
+ else
+ execute "normal o" . i . "\033"
+ endif
+ if i % 2
+ normal Ax
+ if i == 9
+ break
+ endif
+ if i == 5
+ continue
+ else
+ let j = 9
+ while j > 0
+ if has("ebcdic")
+ execute "normal" j . "a" . j . "\x27"
+ else
+ execute "normal" j . "a" . j . "\x1b"
+ endif
+ let j = j - 1
+ endwhile
+ endif
+ endif
+ if i == 9
+ if has("ebcdic")
+ execute "normal Az\047"
+ else
+ execute "normal Az\033"
+ endif
+ endif
+ endwhile
+ unlet i j
+
+ call assert_equal(["",
+ \ "1x999999999888888887777777666666555554444333221",
+ \ "2",
+ \ "3x999999999888888887777777666666555554444333221",
+ \ "4",
+ \ "5x",
+ \ "6",
+ \ "7x999999999888888887777777666666555554444333221",
+ \ "8",
+ \ "9x"], getline(1, 10))
+endfunction
diff --git a/src/nvim/testdir/test_exists_autocmd.vim b/src/nvim/testdir/test_exists_autocmd.vim
new file mode 100644
index 0000000000..7e44a72653
--- /dev/null
+++ b/src/nvim/testdir/test_exists_autocmd.vim
@@ -0,0 +1,26 @@
+" Test that groups and patterns are tested correctly when calling exists() for
+" autocommands.
+
+function Test_AutoCommands()
+ let results=[]
+ augroup auexists
+ augroup END
+ call assert_true(exists("##BufEnter"))
+ call assert_false(exists("#BufEnter"))
+ au BufEnter * let g:entered=1
+ call assert_true(exists("#BufEnter"))
+ call assert_false(exists("#auexists#BufEnter"))
+ augroup auexists
+ au BufEnter * let g:entered=1
+ augroup END
+ call assert_true(exists("#auexists#BufEnter"))
+ call assert_false(exists("#BufEnter#*.test"))
+ au BufEnter *.test let g:entered=1
+ call assert_true(exists("#BufEnter#*.test"))
+ edit testfile.test
+ call assert_false(exists("#BufEnter#<buffer>"))
+ au BufEnter <buffer> let g:entered=1
+ call assert_true(exists("#BufEnter#<buffer>"))
+ edit testfile2.test
+ call assert_false(exists("#BufEnter#<buffer>"))
+endfunction
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 6917378890..b6a545f959 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -1,5 +1,7 @@
" Test for folding
+source view_util.vim
+
func PrepIndent(arg)
return [a:arg] + repeat(["\t".a:arg], 5)
endfu
@@ -278,6 +280,7 @@ func Test_move_folds_around_manual()
call assert_equal(0, foldlevel(6))
call assert_equal(9, foldclosedend(7))
call assert_equal([-1, 2, 2, 2, 2, -1, 7, 7, 7, -1], map(range(1, line('$')), 'foldclosed(v:val)'))
+
%d
" Ensure moving around the edges still works.
call setline(1, PrepIndent("a") + repeat(["a"], 3) + ["\ta"])
@@ -634,3 +637,40 @@ func Test_fold_move()
set fdm& sw& fdl&
enew!
endfunc
+
+func Test_foldtext_recursive()
+ new
+ call setline(1, ['{{{', 'some text', '}}}'])
+ setlocal foldenable foldmethod=marker foldtext=foldtextresult(v\:foldstart)
+ " This was crashing because of endless recursion.
+ 2foldclose
+ redraw
+ call assert_equal(1, foldlevel(2))
+ call assert_equal(1, foldclosed(2))
+ call assert_equal(3, foldclosedend(2))
+ bwipe!
+endfunc
+
+func Test_fold_last_line_with_pagedown()
+ enew!
+ set fdm=manual
+
+ let expect = '+-- 11 lines: 9---'
+ let content = range(1,19)
+ call append(0, content)
+ normal dd9G
+ normal zfG
+ normal zt
+ call assert_equal('9', getline(foldclosed('.')))
+ call assert_equal('19', getline(foldclosedend('.')))
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+ call feedkeys("\<C-F>", 'xt')
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+ call feedkeys("\<C-F>", 'xt')
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+ call feedkeys("\<C-B>\<C-F>\<C-F>", 'xt')
+ call assert_equal(expect, ScreenLines(1, len(expect))[0])
+
+ set fdm&
+ enew!
+endfunc
diff --git a/src/nvim/testdir/test_getcwd.vim b/src/nvim/testdir/test_getcwd.vim
new file mode 100644
index 0000000000..15eab2abbb
--- /dev/null
+++ b/src/nvim/testdir/test_getcwd.vim
@@ -0,0 +1,91 @@
+function! GetCwdInfo(win, tab)
+ let tab_changed = 0
+ let mod = ":t"
+ if a:tab > 0 && a:tab != tabpagenr()
+ let tab_changed = 1
+ exec "tabnext " . a:tab
+ endif
+ let bufname = fnamemodify(bufname(winbufnr(a:win)), mod)
+ if tab_changed
+ tabprevious
+ endif
+ if a:win == 0 && a:tab == 0
+ let dirname = fnamemodify(getcwd(), mod)
+ let lflag = haslocaldir()
+ elseif a:tab == 0
+ let dirname = fnamemodify(getcwd(a:win), mod)
+ let lflag = haslocaldir(a:win)
+ else
+ let dirname = fnamemodify(getcwd(a:win, a:tab), mod)
+ let lflag = haslocaldir(a:win, a:tab)
+ endif
+ return bufname . ' ' . dirname . ' ' . lflag
+endfunction
+
+" Do all test in a separate window to avoid E211 when we recursively
+" delete the Xtopdir directory during cleanup
+function SetUp()
+ set visualbell
+ set nocp viminfo+=nviminfo
+
+ " On windows a swapfile in Xtopdir prevents it from being cleaned up.
+ set noswapfile
+
+ " On windows a stale "Xtopdir" directory may exist, remove it so that
+ " we start from a clean state.
+ call delete("Xtopdir", "rf")
+ new
+ call mkdir('Xtopdir')
+ cd Xtopdir
+ call mkdir('Xdir1')
+ call mkdir('Xdir2')
+ call mkdir('Xdir3')
+endfunction
+
+let g:cwd=getcwd()
+function TearDown()
+ q
+ exec "cd " . g:cwd
+ call delete("Xtopdir", "rf")
+endfunction
+
+function Test_GetCwd()
+ new a
+ new b
+ new c
+ 3wincmd w
+ lcd Xdir1
+ call assert_equal("a Xdir1 1", GetCwdInfo(0, 0))
+ wincmd W
+ call assert_equal("b Xtopdir 0", GetCwdInfo(0, 0))
+ wincmd W
+ lcd Xdir3
+ call assert_equal("c Xdir3 1", GetCwdInfo(0, 0))
+ call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), 0))
+ call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), 0))
+ call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), 0))
+ wincmd W
+ call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), tabpagenr()))
+ call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), tabpagenr()))
+ call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), tabpagenr()))
+
+ tabnew x
+ new y
+ new z
+ 3wincmd w
+ call assert_equal("x Xtopdir 0", GetCwdInfo(0, 0))
+ wincmd W
+ lcd Xdir2
+ call assert_equal("y Xdir2 1", GetCwdInfo(0, 0))
+ wincmd W
+ lcd Xdir3
+ call assert_equal("z Xdir3 1", GetCwdInfo(0, 0))
+ call assert_equal("x Xtopdir 0", GetCwdInfo(bufwinnr("x"), 0))
+ call assert_equal("y Xdir2 1", GetCwdInfo(bufwinnr("y"), 0))
+ call assert_equal("z Xdir3 1", GetCwdInfo(bufwinnr("z"), 0))
+ let tp_nr = tabpagenr()
+ tabrewind
+ call assert_equal("x Xtopdir 0", GetCwdInfo(3, tp_nr))
+ call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr))
+ call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr))
+endfunc
diff --git a/src/nvim/testdir/test_largefile.vim b/src/nvim/testdir/test_largefile.vim
index 1b3e02a0c8..3f9c2dc150 100644
--- a/src/nvim/testdir/test_largefile.vim
+++ b/src/nvim/testdir/test_largefile.vim
@@ -1,5 +1,5 @@
" Tests for large files
-" This is only executed manually: "make test_largefile".
+" This is only executed manually: "TEST_FILE=test_largefile.res make oldtest".
" This is not run as part of "make test".
func Test_largefile()
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
new file mode 100644
index 0000000000..0fb878b04a
--- /dev/null
+++ b/src/nvim/testdir/test_maparg.vim
@@ -0,0 +1,56 @@
+" Tests for maparg().
+" Also test utf8 map with a 0x80 byte.
+if !has("multi_byte")
+ finish
+endif
+
+function s:SID()
+ return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$'))
+endfun
+
+function Test_maparg()
+ new
+ set cpo-=<
+ set encoding=utf8
+ " Test maparg() with a string result
+ map foo<C-V> is<F4>foo
+ vnoremap <script> <buffer> <expr> <silent> bar isbar
+ let sid = s:SID()
+ call assert_equal("is<F4>foo", maparg('foo<C-V>'))
+ call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>',
+ \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'rhs': 'is<F4>foo',
+ \ 'buffer': 0}, maparg('foo<C-V>', '', 0, 1))
+ call assert_equal({'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v',
+ \ 'nowait': 0, 'expr': 1, 'sid': sid, 'rhs': 'isbar', 'buffer': 1},
+ \ maparg('bar', '', 0, 1))
+ map <buffer> <nowait> foo bar
+ call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ',
+ \ 'nowait': 1, 'expr': 0, 'sid': sid, 'rhs': 'bar', 'buffer': 1},
+ \ maparg('foo', '', 0, 1))
+
+ map abc x<char-114>x
+ call assert_equal("xrx", maparg('abc'))
+ map abc y<S-char-114>y
+ call assert_equal("yRy", maparg('abc'))
+
+ map abc <Nop>
+ call assert_equal("<Nop>", maparg('abc'))
+ unmap abc
+endfunction
+
+function Test_range_map()
+ new
+ " Outside of the range, minimum
+ inoremap <Char-0x1040> a
+ execute "normal a\u1040\<Esc>"
+ " Inside of the range, minimum
+ inoremap <Char-0x103f> b
+ execute "normal a\u103f\<Esc>"
+ " Inside of the range, maximum
+ inoremap <Char-0xf03f> c
+ execute "normal a\uf03f\<Esc>"
+ " Outside of the range, maximum
+ inoremap <Char-0xf040> d
+ execute "normal a\uf040\<Esc>"
+ call assert_equal("abcd", getline(1))
+endfunction
diff --git a/src/nvim/testdir/test_plus_arg_edit.vim b/src/nvim/testdir/test_plus_arg_edit.vim
new file mode 100644
index 0000000000..71dbea1991
--- /dev/null
+++ b/src/nvim/testdir/test_plus_arg_edit.vim
@@ -0,0 +1,10 @@
+" Tests for complicated + argument to :edit command
+function Test_edit()
+ call writefile(["foo|bar"], "Xfile1")
+ call writefile(["foo/bar"], "Xfile2")
+ edit +1|s/|/PIPE/|w Xfile1| e Xfile2|1 | s/\//SLASH/|w
+ call assert_equal(["fooPIPEbar"], readfile("Xfile1"))
+ call assert_equal(["fooSLASHbar"], readfile("Xfile2"))
+ call delete('Xfile1')
+ call delete('Xfile2')
+endfunction
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index f603f46d63..624e642e7f 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1879,8 +1879,9 @@ func Xproperty_tests(cchar)
call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']})
let l1=g:Xgetlist({'nr':1,'all':1})
let l2=g:Xgetlist({'nr':2,'all':1})
- let l1.nr=2
- let l2.nr=1
+ let save_id = l1.id
+ let l1.id=l2.id
+ let l2.id=save_id
call g:Xsetlist([], 'r', l1)
call g:Xsetlist([], 'r', l2)
let newl1=g:Xgetlist({'nr':1,'all':1})
@@ -2280,27 +2281,39 @@ func Xsetexpr_tests(cchar)
call s:setup_commands(a:cchar)
let t = ["File1:10:Line10", "File1:20:Line20"]
- call g:Xsetlist([], ' ', {'text' : t})
- call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"})
+ call g:Xsetlist([], ' ', {'lines' : t})
+ call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]})
let l = g:Xgetlist()
call assert_equal(3, len(l))
call assert_equal(20, l[1].lnum)
call assert_equal('Line30', l[2].text)
- call g:Xsetlist([], 'r', {'text' : "File2:5:Line5"})
+ call g:Xsetlist([], 'r', {'lines' : ["File2:5:Line5"]})
let l = g:Xgetlist()
call assert_equal(1, len(l))
call assert_equal('Line5', l[0].text)
- call assert_equal(-1, g:Xsetlist([], 'a', {'text' : 10}))
+ call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : 10}))
+ call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : "F1:10:L10"}))
call g:Xsetlist([], 'f')
" Add entries to multiple lists
- call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]})
- call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]})
- call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]})
- call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]})
call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
+
+ " Adding entries using a custom efm
+ set efm&
+ call g:Xsetlist([], ' ', {'efm' : '%f#%l#%m',
+ \ 'lines' : ["F1#10#L10", "F2#20#L20"]})
+ call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
+ call g:Xsetlist([], 'a', {'efm' : '%f#%l#%m', 'lines' : ["F3:30:L30"]})
+ call assert_equal('F3:30:L30', g:Xgetlist({'items':1}).items[2].text)
+ call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
+ call assert_equal(-1, g:Xsetlist([], 'a', {'efm' : [],
+ \ 'lines' : ['F1:10:L10']}))
endfunc
func Test_setexpr()
@@ -2315,16 +2328,16 @@ func Xmultidirstack_tests(cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
- call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"})
- call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"})
- call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"})
- call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
- call assert_equal('Xone/a/one.txt', bufname(l1.items[1].bufnr))
+ call assert_equal(expand('Xone/a/one.txt'), bufname(l1.items[1].bufnr))
call assert_equal(3, l1.items[1].lnum)
- call assert_equal('Xtwo/a/two.txt', bufname(l2.items[1].bufnr))
+ call assert_equal(expand('Xtwo/a/two.txt'), bufname(l2.items[1].bufnr))
call assert_equal(5, l2.items[1].lnum)
endfunc
@@ -2352,10 +2365,10 @@ func Xmultifilestack_tests(cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
- call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"})
- call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"})
- call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"})
- call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]})
+ call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]})
+ call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
@@ -2501,3 +2514,97 @@ func Test_add_qf()
call XaddQf_tests('c')
call XaddQf_tests('l')
endfunc
+
+" Test for getting the quickfix list items from some text without modifying
+" the quickfix stack
+func XgetListFromLines(cchar)
+ call s:setup_commands(a:cchar)
+ call g:Xsetlist([], 'f')
+
+ let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).items
+ call assert_equal(2, len(l))
+ call assert_equal(30, l[1].lnum)
+
+ call assert_equal({}, g:Xgetlist({'lines' : 10}))
+ call assert_equal({}, g:Xgetlist({'lines' : 'File1:10:Line10'}))
+ call assert_equal([], g:Xgetlist({'lines' : []}).items)
+ call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items)
+
+ " Parse text using a custom efm
+ set efm&
+ let l = g:Xgetlist({'lines':['File3#30#Line30'], 'efm' : '%f#%l#%m'}).items
+ call assert_equal('Line30', l[0].text)
+ let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : '%f-%l-%m'}).items
+ call assert_equal('File3:30:Line30', l[0].text)
+ let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : [1,2]})
+ call assert_equal({}, l)
+ call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':'%2'})", 'E376:')
+ call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':''})", 'E378:')
+
+ " Make sure that the quickfix stack is not modified
+ call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
+endfunc
+
+func Test_get_list_from_lines()
+ call XgetListFromLines('c')
+ call XgetListFromLines('l')
+endfunc
+
+" Tests for the quickfix list id
+func Xqfid_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ call g:Xsetlist([], 'f')
+ call assert_equal({}, g:Xgetlist({'id':0}))
+ Xexpr ''
+ let start_id = g:Xgetlist({'id' : 0}).id
+ Xexpr '' | Xexpr ''
+ Xolder
+ call assert_equal(start_id, g:Xgetlist({'id':0, 'nr':1}).id)
+ call assert_equal(start_id + 1, g:Xgetlist({'id':0, 'nr':0}).id)
+ call assert_equal(start_id + 2, g:Xgetlist({'id':0, 'nr':'$'}).id)
+ call assert_equal({}, g:Xgetlist({'id':0, 'nr':99}))
+ call assert_equal(2, g:Xgetlist({'id':start_id + 1, 'nr':0}).nr)
+ call assert_equal({}, g:Xgetlist({'id':99, 'nr':0}))
+ call assert_equal({}, g:Xgetlist({'id':"abc", 'nr':0}))
+
+ call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]})
+ call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context)
+ call g:Xsetlist([], 'a', {'id':start_id+1, 'lines':['F1:10:L10']})
+ call assert_equal('L10', g:Xgetlist({'nr':2, 'items':1}).items[0].text)
+ call assert_equal(-1, g:Xsetlist([], 'a', {'id':999, 'title':'Vim'}))
+ call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'}))
+
+ let qfid = g:Xgetlist({'id':0, 'nr':0})
+ call g:Xsetlist([], 'f')
+ call assert_equal({}, g:Xgetlist({'id':qfid, 'nr':0}))
+endfunc
+
+func Test_qf_id()
+ call Xqfid_tests('c')
+ call Xqfid_tests('l')
+endfunc
+
+" Test for shortening/simplifying the file name when opening the
+" quickfix window or when displaying the quickfix list
+func Test_shorten_fname()
+ if !has('unix')
+ return
+ endif
+ %bwipe
+ " Create a quickfix list with a absolute path filename
+ let fname = getcwd() . '/test_quickfix.vim'
+ call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
+ call assert_equal(fname, bufname('test_quickfix.vim'))
+ " Opening the quickfix window should simplify the file path
+ cwindow
+ call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
+ cclose
+ %bwipe
+ " Create a quickfix list with a absolute path filename
+ call setqflist([], ' ', {'lines':[fname . ":20:Line20"], 'efm':'%f:%l:%m'})
+ call assert_equal(fname, bufname('test_quickfix.vim'))
+ " Displaying the quickfix list should simplify the file path
+ silent! clist
+ call assert_equal('test_quickfix.vim', bufname('test_quickfix.vim'))
+endfunc
diff --git a/src/nvim/testdir/test_regex_char_classes.vim b/src/nvim/testdir/test_regex_char_classes.vim
new file mode 100644
index 0000000000..2192b5e8fc
--- /dev/null
+++ b/src/nvim/testdir/test_regex_char_classes.vim
@@ -0,0 +1,58 @@
+" Tests for regexp with backslash and other special characters inside []
+" Also test backslash for hex/octal numbered character.
+
+function RunSTest(value, calls, expected)
+ new
+ call feedkeys("i" . a:value, "mx")
+ exec a:calls
+ call assert_equal(a:expected, getline(1), printf("wrong result for %s", a:calls))
+ quit!
+endfunction
+
+function RunXTest(value, search_exp, expected)
+ new
+ call feedkeys("i" . a:value, "mx")
+ call feedkeys("gg" . a:search_exp . "\nx", "mx")
+ call assert_equal(a:expected, getline(1), printf("wrong result for %s", a:search_exp))
+ quit!
+endfunction
+
+
+function Test_x_search()
+ let res = "test text test text"
+ call RunXTest("test \\text test text", "/[\\x]", res)
+ call RunXTest("test \ttext test text", "/[\\t\\]]", res)
+ call RunXTest("test text ]test text", "/[]y]", res)
+ call RunXTest("test ]text test text", "/[\\]]", res)
+ call RunXTest("test text te^st text", "/[y^]", res)
+ call RunXTest("test te$xt test text", "/[$y]", res)
+ call RunXTest("test taext test text", "/[\\x61]", res)
+ call RunXTest("test tbext test text","/[\\x60-\\x64]", res)
+ call RunXTest("test 5text test text","/[\\x785]", res)
+ call RunXTest("testc text test text","/[\\o143]", res)
+ call RunXTest("tesdt text test text","/[\\o140-\\o144]", res)
+ call RunXTest("test7 text test text", "/[\\o417]", res)
+ call RunXTest("test text tBest text", "/\\%x42", res)
+ call RunXTest("test text teCst text", "/\\%o103", res)
+ call RunXTest("test text \<C-V>x00test text", "/[\\x00]", res)
+endfunction
+
+function Test_s_search()
+ let res = "test text test text"
+ call RunSTest("test te\<C-V>x00xt t\<C-V>x04est t\<C-V>x10ext", "s/[\\x00-\\x10]//g", res)
+ call RunSTest("test \\xyztext test text", "s/[\\x-z]\\+//", res)
+ call RunSTest("test text tev\\uyst text", "s/[\\u-z]\\{2,}//", res)
+ call RunSTest("xx aaaaa xx a", "s/\\(a\\)\\+//", "xx xx a")
+ call RunSTest("xx aaaaa xx a", "s/\\(a*\\)\\+//", "xx aaaaa xx a")
+ call RunSTest("xx aaaaa xx a", "s/\\(a*\\)*//", "xx aaaaa xx a")
+ call RunSTest("xx aaaaa xx", "s/\\(a\\)\\{2,3}/A/", "xx Aaa xx")
+ call RunSTest("xx aaaaa xx", "s/\\(a\\)\\{-2,3}/A/", "xx Aaaa xx")
+ call RunSTest("xx aaa12aa xx", "s/\\(a\\)*\\(12\\)\\@>/A/", "xx Aaa xx")
+ call RunSTest("xx foobar xbar xx", "s/\\(foo\\)\\@<!bar/A/", "xx foobar xA xx")
+ call RunSTest("xx an file xx", "s/\\(an\\_s\\+\\)\\@<=file/A/", "xx an A xx")
+ call RunSTest("x= 9;", "s/^\\(\\h\\w*\\%(->\\|\\.\\)\\=\\)\\+=/XX/", "XX 9;")
+ call RunSTest("hh= 77;", "s/^\\(\\h\\w*\\%(->\\|\\.\\)\\=\\)\\+=/YY/", "YY 77;")
+ call RunSTest(" aaa ", "s/aaa/xyz/", " xyz ")
+ call RunSTest(" xyz", "s/~/bcd/", " bcd")
+ call RunSTest(" bcdbcdbcd", "s/~\\+/BB/", " BB")
+endfunction
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 0781b03965..841294aaad 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1191,7 +1191,8 @@ static void tui_option_set(UI *ui, String name, Object value)
static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr,
- const schar_T *chunk, const sattr_T *attrs)
+ Boolean wrap, const schar_T *chunk,
+ const sattr_T *attrs)
{
TUIData *data = ui->data;
UGrid *grid = &data->grid;
@@ -1212,6 +1213,21 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
clear_region(ui, (int)linerow, (int)linerow, (int)endcol, (int)clearcol-1,
cl_attrs);
}
+
+ if (wrap && ui->width == grid->width && linerow + 1 < grid->height) {
+ // Only do line wrapping if the grid width is equal to the terminal
+ // width and the line continuation is within the grid.
+
+ if (endcol != grid->width) {
+ // Print the last cell of the row, if we haven't already done so.
+ cursor_goto(ui, (int)linerow, grid->width - 1);
+ print_cell(ui, &grid->cells[linerow][grid->width - 1]);
+ }
+
+ // Wrap the cursor over to the next line. The next line will be
+ // printed immediately without an intervening newline.
+ final_column_wrap(ui);
+ }
}
static void invalidate(UI *ui, int top, int bot, int left, int right)
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 07aa032a50..e291111f82 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -80,7 +80,7 @@ static char uilog_last_event[1024] = { 0 };
#endif
// UI_CALL invokes a function on all registered UI instances. The functions can
-// have 0-5 arguments (configurable by SELECT_NTH).
+// have 0-10 arguments (configurable by SELECT_NTH).
//
// See http://stackoverflow.com/a/11172679 for how it works.
#ifdef _MSC_VER
@@ -102,9 +102,9 @@ static char uilog_last_event[1024] = { 0 };
} \
} while (0)
#endif
-#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, \
- MORE, MORE, MORE, MORE, MORE, ZERO, ignore)
-#define SELECT_NTH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...) a10
+#define CNT(...) SELECT_NTH(__VA_ARGS__, MORE, MORE, MORE, MORE, MORE, \
+ MORE, MORE, MORE, MORE, ZERO, ignore)
+#define SELECT_NTH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
#define UI_CALL_HELPER(c, ...) UI_CALL_HELPER2(c, __VA_ARGS__)
// Resolves to UI_CALL_MORE or UI_CALL_ZERO.
#define UI_CALL_HELPER2(c, ...) UI_CALL_##c(__VA_ARGS__)
@@ -315,10 +315,11 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active)
}
}
-void ui_line(int row, int startcol, int endcol, int clearcol, int clearattr)
+void ui_line(int row, int startcol, int endcol, int clearcol, int clearattr,
+ bool wrap)
{
size_t off = LineOffset[row]+(size_t)startcol;
- UI_CALL(raw_line, 1, row, startcol, endcol, clearcol, clearattr,
+ UI_CALL(raw_line, 1, row, startcol, endcol, clearcol, clearattr, wrap,
(const schar_T *)ScreenLines+off, (const sattr_T *)ScreenAttrs+off);
if (p_wd) { // 'writedelay': flush & delay each time.
int old_row = row, old_col = col;
@@ -341,32 +342,6 @@ void ui_cursor_goto(int new_row, int new_col)
pending_cursor_update = true;
}
-void ui_add_linewrap(int row)
-{
- // TODO(bfredl): check that this actually still works
- // and move to TUI module in that case.
-#if 0
- // First make sure we are at the end of the screen line,
- // then output the same character again to let the
- // terminal know about the wrap. If the terminal doesn't
- // auto-wrap, we overwrite the character.
- if (ui_current_col() != Columns) {
- screen_char(LineOffset[row] + (unsigned)Columns - 1, row,
- (int)(Columns - 1));
- }
-
- // When there is a multi-byte character, just output a
- // space to keep it simple. */
- if (ScreenLines[LineOffset[row] + (Columns - 1)][1] != 0) {
- ui_putc(' ');
- } else {
- ui_puts(ScreenLines[LineOffset[row] + (Columns - 1)]);
- }
- // force a redraw of the first char on the next line
- ScreenAttrs[LineOffset[row+1]] = (sattr_T)-1;
-#endif
-}
-
void ui_mode_info_set(void)
{
pending_mode_info_update = true;
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index 584d8a77c6..df489f569f 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -47,7 +47,7 @@ struct ui_t {
// in to the public grid_line format.
void (*raw_line)(UI *ui, Integer grid, Integer row, Integer startcol,
Integer endcol, Integer clearcol, Integer clearattr,
- const schar_T *chunk, const sattr_T *attrs);
+ Boolean wrap, const schar_T *chunk, const sattr_T *attrs);
void (*event)(UI *ui, char *name, Array args, bool *args_consumed);
void (*stop)(UI *ui);
void (*inspect)(UI *ui, Dictionary *info);
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index a96a24bde7..ebd4651f4d 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -152,24 +152,24 @@ static void ui_bridge_raw_line_event(void **argv)
UI *ui = UI(argv[0]);
ui->raw_line(ui, PTR2INT(argv[1]), PTR2INT(argv[2]), PTR2INT(argv[3]),
PTR2INT(argv[4]), PTR2INT(argv[5]), PTR2INT(argv[6]),
- argv[7], argv[8]);
- xfree(argv[7]);
+ PTR2INT(argv[7]), argv[8], argv[9]);
xfree(argv[8]);
+ xfree(argv[9]);
}
static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row,
Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr,
- const schar_T *chunk, const sattr_T *attrs)
+ Boolean wrap, const schar_T *chunk,
+ const sattr_T *attrs)
{
size_t ncol = (size_t)(endcol-startcol);
schar_T *c = xmemdup(chunk, ncol * sizeof(schar_T));
sattr_T *hl = xmemdup(attrs, ncol * sizeof(sattr_T));
- UI_BRIDGE_CALL(ui, raw_line, 9, ui, INT2PTR(grid), INT2PTR(row),
+ UI_BRIDGE_CALL(ui, raw_line, 10, ui, INT2PTR(grid), INT2PTR(row),
INT2PTR(startcol), INT2PTR(endcol), INT2PTR(clearcol),
- INT2PTR(clearattr), c, hl);
+ INT2PTR(clearattr), INT2PTR(wrap), c, hl);
}
-
static void ui_bridge_suspend(UI *b)
{
UIBridgeData *data = (UIBridgeData *)b;