aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c10
-rw-r--r--src/nvim/api/window.c4
-rw-r--r--src/nvim/eval.c26
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/ex_docmd.c16
-rw-r--r--src/nvim/if_cscope.c6
-rw-r--r--src/nvim/option.c23
-rw-r--r--src/nvim/os/env.c4
-rw-r--r--src/nvim/testdir/test_alot.vim6
-rw-r--r--src/nvim/testdir/test_glob2regpat.vim4
-rw-r--r--src/nvim/testdir/test_modeline.vim22
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim12
-rw-r--r--src/nvim/testdir/test_window_id.vim20
-rw-r--r--src/nvim/window.c35
14 files changed, 148 insertions, 41 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 9a5ffecad4..06d7c1810c 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -487,7 +487,7 @@ end:
try_end(err);
}
-/// Returns the byte offset for a line.
+/// Returns the byte offset of a line (0-indexed). |api-indexing|
///
/// Line 1 (index=0) has offset 0. UTF-8 bytes are counted. EOL is one byte.
/// 'fileformat' and 'fileencoding' are ignored. The line index just after the
@@ -879,7 +879,9 @@ void buffer_insert(Buffer buffer,
nvim_buf_set_lines(0, buffer, lnum, lnum, true, lines, err);
}
-/// Return a tuple (row,col) representing the position of the named mark
+/// Return a tuple (row,col) representing the position of the named mark.
+///
+/// Marks are (1,0)-indexed. |api-indexing|
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param name Mark name
@@ -993,8 +995,8 @@ Integer nvim_buf_add_highlight(Buffer buffer,
/// Clears namespaced objects, highlights and virtual text, from a line range
///
-/// To clear the namespace in the entire buffer, pass in 0 and -1 to
-/// line_start and line_end respectively.
+/// Lines are 0-indexed. |api-indexing| To clear the namespace in the entire
+/// buffer, specify line_start=0 and line_end=-1.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace to clear, or -1 to clear all namespaces.
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index e1c50cb89d..9fd1818a5c 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -74,7 +74,7 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
restore_win(save_curwin, save_curtab, false);
}
-/// Gets the cursor position in the window
+/// Gets the (1,0)-indexed cursor position in the window. |api-indexing|
///
/// @param window Window handle
/// @param[out] err Error details, if any
@@ -93,7 +93,7 @@ ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err)
return rv;
}
-/// Sets the cursor position in the window
+/// Sets the (1,0)-indexed cursor position in the window. |api-indexing|
///
/// @param window Window handle
/// @param pos (row, col) tuple representing the new position
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 58285a7716..9f56b42fba 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -8868,8 +8868,8 @@ static void f_fnamemodify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else {
len = strlen(fname);
size_t usedlen = 0;
- (void)modify_fname((char_u *)mods, &usedlen, (char_u **)&fname, &fbuf,
- &len);
+ (void)modify_fname((char_u *)mods, false, &usedlen,
+ (char_u **)&fname, &fbuf, &len);
}
rettv->v_type = VAR_STRING;
@@ -17888,6 +17888,25 @@ static void f_winheight(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "winlayout()" function
+static void f_winlayout(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tabpage_T *tp;
+
+ tv_list_alloc_ret(rettv, 2);
+
+ if (argvars[0].v_type == VAR_UNKNOWN) {
+ tp = curtab;
+ } else {
+ tp = find_tabpage((int)tv_get_number(&argvars[0]));
+ if (tp == NULL) {
+ return;
+ }
+ }
+
+ get_framelayout(tp->tp_topframe, rettv->vval.v_list, true);
+}
+
/*
* "winline()" function
*/
@@ -22639,6 +22658,7 @@ void reset_v_option_vars(void)
int
modify_fname(
char_u *src, // string with modifiers
+ bool tilde_file, // "~" is a file name, not $HOME
size_t *usedlen, // characters after src that are used
char_u **fnamep, // file name so far
char_u **bufp, // buffer for allocated file name or NULL
@@ -22668,8 +22688,8 @@ repeat:
|| (*fnamep)[1] == '\\'
# endif
|| (*fnamep)[1] == NUL)
-
#endif
+ && !(tilde_file && (*fnamep)[1] == NUL)
) {
*fnamep = expand_env_save(*fnamep);
xfree(*bufp); /* free any allocated file name */
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index aad2de5d30..dea00c3edd 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -352,6 +352,7 @@ return {
winbufnr={args=1},
wincol={},
winheight={args=1},
+ winlayout={args={0, 1}},
winline={},
winnr={args={0, 1}},
winrestcmd={},
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 979daf24fe..aa76355bad 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8552,6 +8552,7 @@ eval_vars (
size_t resultlen;
buf_T *buf;
int valid = VALID_HEAD | VALID_PATH; // Assume valid result.
+ bool tilde_file = false;
int skip_mod = false;
char strbuf[30];
@@ -8608,9 +8609,11 @@ eval_vars (
case SPEC_PERC: /* '%': current file */
if (curbuf->b_fname == NULL) {
result = (char_u *)"";
- valid = 0; /* Must have ":p:h" to be valid */
- } else
+ valid = 0; // Must have ":p:h" to be valid
+ } else {
result = curbuf->b_fname;
+ tilde_file = STRCMP(result, "~") == 0;
+ }
break;
case SPEC_HASH: /* '#' or "#99": alternate file */
@@ -8659,9 +8662,11 @@ eval_vars (
*lnump = ECMD_LAST;
if (buf->b_fname == NULL) {
result = (char_u *)"";
- valid = 0; /* Must have ":p:h" to be valid */
- } else
+ valid = 0; // Must have ":p:h" to be valid
+ } else {
result = buf->b_fname;
+ tilde_file = STRCMP(result, "~") == 0;
+ }
}
break;
@@ -8746,7 +8751,8 @@ eval_vars (
resultlen = (size_t)(s - result);
}
} else if (!skip_mod) {
- valid |= modify_fname(src, usedlen, &result, &resultbuf, &resultlen);
+ valid |= modify_fname(src, tilde_file, usedlen, &result,
+ &resultbuf, &resultlen);
if (result == NULL) {
*errormsg = (char_u *)"";
return NULL;
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index 4cb0c9a4ae..84721ee96c 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -425,9 +425,11 @@ cs_add_common(
expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL);
size_t len = STRLEN(fname);
fbuf = (char_u *)fname;
- (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&fname, &fbuf, &len);
- if (fname == NULL)
+ (void)modify_fname((char_u *)":p", false, &usedlen,
+ (char_u **)&fname, &fbuf, &len);
+ if (fname == NULL) {
goto add_err;
+ }
fname = (char *)vim_strnsave((char_u *)fname, len);
xfree(fbuf);
FileInfo file_info;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 743f6c8311..43ee6bf451 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -1239,7 +1239,7 @@ int do_set(
}
len++;
if (opt_idx == -1) {
- key = find_key_option(arg + 1);
+ key = find_key_option(arg + 1, true);
}
} else {
len = 0;
@@ -1253,7 +1253,7 @@ int do_set(
}
opt_idx = findoption_len((const char *)arg, (size_t)len);
if (opt_idx == -1) {
- key = find_key_option(arg);
+ key = find_key_option(arg, false);
}
}
@@ -1986,7 +1986,7 @@ static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c)
static int string_to_key(char_u *arg)
{
if (*arg == '<') {
- return find_key_option(arg + 1);
+ return find_key_option(arg + 1, true);
}
if (*arg == '^') {
return Ctrl_chr(arg[1]);
@@ -4957,19 +4957,20 @@ char *set_option_value(const char *const name, const long number,
return NULL;
}
-/*
- * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
- */
-int find_key_option_len(const char_u *arg, size_t len)
+// Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number.
+// When "has_lt" is true there is a '<' before "*arg_arg".
+// Returns 0 when the key is not recognized.
+int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt)
{
- int key;
+ int key = 0;
int modifiers;
+ const char_u *arg = arg_arg;
// Don't use get_special_key_code() for t_xx, we don't want it to call
// add_termcap_entry().
if (len >= 4 && arg[0] == 't' && arg[1] == '_') {
key = TERMCAP2KEY(arg[2], arg[3]);
- } else {
+ } else if (has_lt) {
arg--; // put arg at the '<'
modifiers = 0;
key = find_special_key(&arg, len + 1, &modifiers, true, true, false);
@@ -4980,9 +4981,9 @@ int find_key_option_len(const char_u *arg, size_t len)
return key;
}
-static int find_key_option(const char_u *arg)
+static int find_key_option(const char_u *arg, bool has_lt)
{
- return find_key_option_len(arg, STRLEN(arg));
+ return find_key_option_len(arg, STRLEN(arg), has_lt);
}
/*
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 7d1021962c..b067de608b 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -870,8 +870,8 @@ size_t home_replace(const buf_T *const buf, const char_u *src,
size_t usedlen = 0;
size_t flen = strlen(homedir_env_mod);
char_u *fbuf = NULL;
- (void)modify_fname((char_u *)":p", &usedlen, (char_u **)&homedir_env_mod,
- &fbuf, &flen);
+ (void)modify_fname((char_u *)":p", false, &usedlen,
+ (char_u **)&homedir_env_mod, &fbuf, &flen);
flen = strlen(homedir_env_mod);
assert(homedir_env_mod != homedir_env);
if (vim_ispathsep(homedir_env_mod[flen - 1])) {
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index d5f19057d0..30e29bd05d 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -29,27 +29,25 @@ source test_lambda.vim
source test_mapping.vim
source test_menu.vim
source test_messages.vim
+source test_modeline.vim
source test_move.vim
source test_partial.vim
source test_popup.vim
source test_put.vim
source test_recover.vim
-source test_regexp_utf8.vim
source test_scroll_opt.vim
source test_sort.vim
-source test_source_utf8.vim
source test_sha256.vim
source test_statusline.vim
source test_suspend.vim
source test_syn_attr.vim
source test_tabline.vim
-" source test_tabpage.vim
+source test_tabpage.vim
source test_tagcase.vim
source test_tagjump.vim
source test_taglist.vim
source test_true_false.vim
source test_unlet.vim
-source test_utf8.vim
source test_virtualedit.vim
source test_window_cmd.vim
source test_wnext.vim
diff --git a/src/nvim/testdir/test_glob2regpat.vim b/src/nvim/testdir/test_glob2regpat.vim
index fdf17946b6..e6e41f13e7 100644
--- a/src/nvim/testdir/test_glob2regpat.vim
+++ b/src/nvim/testdir/test_glob2regpat.vim
@@ -1,12 +1,12 @@
" Test glob2regpat()
-func Test_invalid()
+func Test_glob2regpat_invalid()
call assert_fails('call glob2regpat(1.33)', 'E806:')
call assert_fails('call glob2regpat("}")', 'E219:')
call assert_fails('call glob2regpat("{")', 'E220:')
endfunc
-func Test_valid()
+func Test_glob2regpat_valid()
call assert_equal('^foo\.', glob2regpat('foo.*'))
call assert_equal('^foo.$', glob2regpat('foo?'))
call assert_equal('\.vim$', glob2regpat('*.vim'))
diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim
index 75fe1d993c..091a833774 100644
--- a/src/nvim/testdir/test_modeline.vim
+++ b/src/nvim/testdir/test_modeline.vim
@@ -1,11 +1,15 @@
+" Tests for parsing the modeline.
+
func Test_modeline_invalid()
- let modeline = &modeline
- set modeline
- call assert_fails('set Xmodeline', 'E518:')
+ " This was reading allocated memory in the past.
+ call writefile(['vi:0', 'nothing'], 'Xmodeline')
+ let modeline = &modeline
+ set modeline
+ call assert_fails('set Xmodeline', 'E518:')
- let &modeline = modeline
- bwipe!
- call delete('Xmodeline')
+ let &modeline = modeline
+ bwipe!
+ call delete('Xmodeline')
endfunc
func Test_modeline_filetype()
@@ -40,6 +44,9 @@ func Test_modeline_syntax()
endfunc
func Test_modeline_keymap()
+ if !has('keymap')
+ return
+ endif
call writefile(['vim: set keymap=greek :', 'nothing'], 'Xmodeline_keymap')
let modeline = &modeline
set modeline
@@ -80,5 +87,8 @@ func Test_modeline_syntax_fails()
endfunc
func Test_modeline_keymap_fails()
+ if !has('keymap')
+ return
+ endif
call s:modeline_fails('keymap', 'keymap=evil$CMD')
endfunc
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index 0619e9c027..de209fa9ec 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -73,3 +73,15 @@ func Test_backref()
call assert_fails('call search("\\%#=2\\(e\\1\\)")', 'E65:')
bwipe!
endfunc
+
+func Test_multi_failure()
+ set re=1
+ call assert_fails('/a**', 'E61:')
+ call assert_fails('/a*\+', 'E62:')
+ call assert_fails('/a\{a}', 'E554:')
+ set re=2
+ call assert_fails('/a**', 'E871:')
+ call assert_fails('/a*\+', 'E871:')
+ call assert_fails('/a\{a}', 'E870:')
+ set re=0
+endfunc
diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim
index b3b506d04d..d10d831650 100644
--- a/src/nvim/testdir/test_window_id.vim
+++ b/src/nvim/testdir/test_window_id.vim
@@ -101,3 +101,23 @@ func Test_win_getid_curtab()
call assert_equal(win_getid(1), win_getid(1, 1))
tabclose!
endfunc
+
+func Test_winlayout()
+ let w1 = win_getid()
+ call assert_equal(['leaf', w1], winlayout())
+
+ split
+ let w2 = win_getid()
+ call assert_equal(['col', [['leaf', w2], ['leaf', w1]]], winlayout())
+
+ split
+ let w3 = win_getid()
+ call assert_equal(['col', [['leaf', w3], ['leaf', w2], ['leaf', w1]]], winlayout())
+
+ 2wincmd w
+ vsplit
+ let w4 = win_getid()
+ call assert_equal(['col', [['leaf', w3], ['row', [['leaf', w4], ['leaf', w2]]], ['leaf', w1]]], winlayout())
+
+ only!
+endfunc
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 2ce3b7067b..e6b19cf88d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -6658,6 +6658,41 @@ void win_findbuf(typval_T *argvars, list_T *list)
}
}
+// Get the layout of the given tab page for winlayout().
+void get_framelayout(const frame_T *fr, list_T *l, bool outer)
+{
+ list_T *fr_list;
+
+ if (fr == NULL) {
+ return;
+ }
+
+ if (outer) {
+ // outermost call from f_winlayout()
+ fr_list = l;
+ } else {
+ fr_list = tv_list_alloc(2);
+ tv_list_append_list(l, fr_list);
+ }
+
+ if (fr->fr_layout == FR_LEAF) {
+ if (fr->fr_win != NULL) {
+ tv_list_append_string(fr_list, "leaf", -1);
+ tv_list_append_number(fr_list, fr->fr_win->handle);
+ }
+ } else {
+ tv_list_append_string(fr_list, fr->fr_layout == FR_ROW ? "row" : "col", -1);
+
+ list_T *const win_list = tv_list_alloc(kListLenUnknown);
+ tv_list_append_list(fr_list, win_list);
+ const frame_T *child = fr->fr_child;
+ while (child != NULL) {
+ get_framelayout(child, win_list, false);
+ child = child->fr_next;
+ }
+ }
+}
+
void win_ui_flush_positions(void)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {