aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/dist/ft.vim11
-rw-r--r--runtime/doc/ui.txt10
-rw-r--r--runtime/filetype.vim16
-rw-r--r--runtime/lua/vim/lsp/util.lua2
-rw-r--r--src/nvim/api/ui_events.in.h3
-rw-r--r--src/nvim/eval.c55
-rw-r--r--src/nvim/eval/funcs.c31
-rw-r--r--src/nvim/eval/typval.c33
-rw-r--r--src/nvim/eval/userfunc.c8
-rw-r--r--src/nvim/path.c48
-rw-r--r--src/nvim/quickfix.c10
-rw-r--r--src/nvim/screen.c19
-rw-r--r--src/nvim/testdir/test_filetype.vim42
-rw-r--r--src/nvim/testdir/test_let.vim10
-rw-r--r--src/nvim/testdir/test_quickfix.vim62
-rw-r--r--test/functional/autocmd/autocmd_spec.lua11
-rw-r--r--test/functional/ui/tabline_spec.lua43
-rw-r--r--test/unit/eval/typval_spec.lua2
18 files changed, 341 insertions, 75 deletions
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index 1ac74b5785..ac80659113 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -172,6 +172,17 @@ func dist#ft#FTent()
setf dtd
endfunc
+func dist#ft#ExCheck()
+ let lines = getline(1, min([line("$"), 100]))
+ if exists('g:filetype_euphoria')
+ exe 'setf ' . g:filetype_euphoria
+ elseif match(lines, '^--\|^ifdef\>\|^include\>') > -1
+ setf euphoria3
+ else
+ setf elixir
+ endif
+endfunc
+
func dist#ft#EuphoriaCheck()
if exists('g:filetype_euphoria')
exe 'setf ' . g:filetype_euphoria
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index b385cab36f..e7be14e732 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -631,11 +631,13 @@ Tabline Events *ui-tabline*
Activated by the `ext_tabline` |ui-option|.
-["tabline_update", curtab, tabs]
+["tabline_update", curtab, tabs, curbuf, buffers]
Tabline was updated. UIs should present this data in a custom tabline
- widget.
- curtab: Current Tabpage
- tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...]
+ widget. Note: options `curbuf` + `buffers` were added in API7.
+ curtab: Current Tabpage
+ tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...]
+ curbuf: Current buffer handle.
+ buffers: List of Dicts [{ "buffer": buffer handle, "name": String}, ...]
==============================================================================
Cmdline Events *ui-cmdline*
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 09a1d1d0e6..2617d8ffc0 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -389,7 +389,7 @@ au BufNewFile,BufRead *.cfm,*.cfi,*.cfc setf cf
" Configure scripts
au BufNewFile,BufRead configure.in,configure.ac setf config
-" CUDA Cumpute Unified Device Architecture
+" CUDA Compute Unified Device Architecture
au BufNewFile,BufRead *.cu,*.cuh setf cuda
" Dockerfilb; Podman uses the same syntax with name Containerfile
@@ -404,8 +404,15 @@ au BufNewFile,BufRead *enlightenment/*.cfg setf c
" Eterm
au BufNewFile,BufRead *Eterm/*.cfg setf eterm
+" Elixir or Euphoria
+au BufNewFile,BufRead *.ex call dist#ft#ExCheck()
+
+" Elixir
+au BufRead,BufNewFile mix.lock,*.exs setf elixir
+au BufRead,BufNewFile *.eex,*.leex setf eelixir
+
" Euphoria 3 or 4
-au BufNewFile,BufRead *.eu,*.ew,*.ex,*.exu,*.exw call dist#ft#EuphoriaCheck()
+au BufNewFile,BufRead *.eu,*.ew,*.exu,*.exw call dist#ft#EuphoriaCheck()
if has("fname_case")
au BufNewFile,BufRead *.EU,*.EW,*.EX,*.EXU,*.EXW call dist#ft#EuphoriaCheck()
endif
@@ -851,6 +858,9 @@ au BufNewFile,BufRead *.jov,*.j73,*.jovial setf jovial
" JSON
au BufNewFile,BufRead *.json,*.jsonp,*.webmanifest setf json
+" JSON Patch (RFC 6902)
+au BufNewFile,BufRead *.json-patch setf json
+
" Jupyter Notebook is also json
au BufNewFile,BufRead *.ipynb setf json
@@ -1495,7 +1505,7 @@ au BufNewFile,BufRead *.sass setf sass
au BufNewFile,BufRead *.sa setf sather
" Scala
-au BufNewFile,BufRead *.scala setf scala
+au BufNewFile,BufRead *.scala,*.sc setf scala
" SBT - Scala Build Tool
au BufNewFile,BufRead *.sbt setf sbt
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 08437063a3..195e3a0e65 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1153,7 +1153,7 @@ function M.stylize_markdown(bufnr, contents, opts)
table.insert(highlights, {
ft = match.ft;
start = start + 1;
- finish = #stripped + 1 - 1;
+ finish = #stripped;
})
else
table.insert(stripped, line)
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 11e21a88ea..35d39a34d7 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -130,7 +130,8 @@ void popupmenu_hide(void)
void popupmenu_select(Integer selected)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
-void tabline_update(Tabpage current, Array tabs)
+void tabline_update(Tabpage current, Array tabs,
+ Buffer current_buffer, Array buffers)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void cmdline_show(Array content, Integer pos, String firstc, String prompt,
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 1b78147ec2..ff019d1e07 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2340,10 +2340,8 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, true, false) == OK) {
if ((di == NULL
- || (!var_check_ro(di->di_flags, (const char *)lp->ll_name,
- TV_CSTRING)
- && !tv_check_lock(di->di_tv.v_lock, (const char *)lp->ll_name,
- TV_CSTRING)))
+ || (!var_check_ro(di->di_flags, lp->ll_name, TV_CSTRING)
+ && !tv_check_lock(&di->di_tv, lp->ll_name, TV_CSTRING)))
&& eexe_mod_op(&tv, rettv, op) == OK) {
set_var(lp->ll_name, lp->ll_name_len, &tv, false);
}
@@ -2353,10 +2351,10 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
set_var_const(lp->ll_name, lp->ll_name_len, rettv, copy, is_const);
}
*endp = cc;
- } else if (tv_check_lock(lp->ll_newkey == NULL
- ? lp->ll_tv->v_lock
- : lp->ll_tv->vval.v_dict->dv_lock,
- (const char *)lp->ll_name, TV_CSTRING)) {
+ } else if (var_check_lock(lp->ll_newkey == NULL
+ ? lp->ll_tv->v_lock
+ : lp->ll_tv->vval.v_dict->dv_lock,
+ lp->ll_name, TV_CSTRING)) {
} else if (lp->ll_range) {
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
@@ -2369,9 +2367,8 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
// Check whether any of the list items is locked
for (ri = tv_list_first(rettv->vval.v_list);
ri != NULL && ll_li != NULL; ) {
- if (tv_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock,
- (const char *)lp->ll_name,
- TV_CSTRING)) {
+ if (var_check_lock(TV_LIST_ITEM_TV(ll_li)->v_lock, lp->ll_name,
+ TV_CSTRING)) {
return;
}
ri = TV_LIST_ITEM_NEXT(rettv->vval.v_list, ri);
@@ -2795,13 +2792,13 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap,
} else if ((lp->ll_list != NULL
// ll_list is not NULL when lvalue is not in a list, NULL lists
// yield E689.
- && tv_check_lock(tv_list_locked(lp->ll_list),
- (const char *)lp->ll_name,
- lp->ll_name_len))
+ && var_check_lock(tv_list_locked(lp->ll_list),
+ lp->ll_name,
+ lp->ll_name_len))
|| (lp->ll_dict != NULL
- && tv_check_lock(lp->ll_dict->dv_lock,
- (const char *)lp->ll_name,
- lp->ll_name_len))) {
+ && var_check_lock(lp->ll_dict->dv_lock,
+ lp->ll_name,
+ lp->ll_name_len))) {
return FAIL;
} else if (lp->ll_range) {
assert(lp->ll_list != NULL);
@@ -2810,9 +2807,9 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap,
listitem_T *last_li = first_li;
for (;;) {
listitem_T *const li = TV_LIST_ITEM_NEXT(lp->ll_list, lp->ll_li);
- if (tv_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
- (const char *)lp->ll_name,
- lp->ll_name_len)) {
+ if (var_check_lock(TV_LIST_ITEM_TV(lp->ll_li)->v_lock,
+ lp->ll_name,
+ lp->ll_name_len)) {
return false;
}
lp->ll_li = li;
@@ -2897,11 +2894,11 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
dictitem_T *const di = TV_DICT_HI2DI(hi);
if (var_check_fixed(di->di_flags, (const char *)name, TV_CSTRING)
|| var_check_ro(di->di_flags, (const char *)name, TV_CSTRING)
- || tv_check_lock(d->dv_lock, (const char *)name, TV_CSTRING)) {
+ || var_check_lock(d->dv_lock, name, TV_CSTRING)) {
return FAIL;
}
- if (tv_check_lock(d->dv_lock, (const char *)name, TV_CSTRING)) {
+ if (var_check_lock(d->dv_lock, name, TV_CSTRING)) {
return FAIL;
}
@@ -5962,14 +5959,14 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map)
if (argvars[0].v_type == VAR_LIST) {
tv_copy(&argvars[0], rettv);
if ((l = argvars[0].vval.v_list) == NULL
- || (!map && tv_check_lock(tv_list_locked(l), arg_errmsg,
- TV_TRANSLATE))) {
+ || (!map
+ && var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE))) {
return;
}
} else if (argvars[0].v_type == VAR_DICT) {
tv_copy(&argvars[0], rettv);
if ((d = argvars[0].vval.v_dict) == NULL
- || (!map && tv_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) {
+ || (!map && var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE))) {
return;
}
} else {
@@ -6002,7 +5999,7 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map)
di = TV_DICT_HI2DI(hi);
if (map
- && (tv_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE)
+ && (var_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE)
|| var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE))) {
break;
}
@@ -6029,8 +6026,8 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map)
for (listitem_T *li = tv_list_first(l); li != NULL;) {
if (map
- && tv_check_lock(TV_LIST_ITEM_TV(li)->v_lock, arg_errmsg,
- TV_TRANSLATE)) {
+ && var_check_lock(TV_LIST_ITEM_TV(li)->v_lock, arg_errmsg,
+ TV_TRANSLATE)) {
break;
}
vimvars[VV_KEY].vv_nr = idx;
@@ -8947,7 +8944,7 @@ static void set_var_const(const char *name, const size_t name_len,
// existing variable, need to clear the value
if (var_check_ro(v->di_flags, name, name_len)
- || tv_check_lock(v->di_tv.v_lock, name, name_len)) {
+ || var_check_lock(v->di_tv.v_lock, name, name_len)) {
return;
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 4f9a9fcd68..1ba31bfe68 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -268,7 +268,8 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = 1; // Default: failed.
if (argvars[0].v_type == VAR_LIST) {
list_T *const l = argvars[0].vval.v_list;
- if (!tv_check_lock(tv_list_locked(l), N_("add() argument"), TV_TRANSLATE)) {
+ if (!var_check_lock(tv_list_locked(l), N_("add() argument"),
+ TV_TRANSLATE)) {
tv_list_append_tv(l, &argvars[1]);
tv_copy(&argvars[0], rettv);
}
@@ -2277,9 +2278,9 @@ static void f_flatten(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list = argvars[0].vval.v_list;
if (list != NULL
- && !tv_check_lock(tv_list_locked(list),
- N_("flatten() argument"),
- TV_TRANSLATE)
+ && !var_check_lock(tv_list_locked(list),
+ N_("flatten() argument"),
+ TV_TRANSLATE)
&& tv_list_flatten(list, maxdepth) == OK) {
tv_copy(&argvars[0], rettv);
}
@@ -2299,7 +2300,7 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *const l1 = argvars[0].vval.v_list;
list_T *const l2 = argvars[1].vval.v_list;
- if (!tv_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
+ if (!var_check_lock(tv_list_locked(l1), arg_errmsg, TV_TRANSLATE)) {
listitem_T *item;
if (argvars[2].v_type != VAR_UNKNOWN) {
before = (long)tv_get_number_chk(&argvars[2], &error);
@@ -2328,13 +2329,13 @@ static void f_extend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dict_T *const d1 = argvars[0].vval.v_dict;
dict_T *const d2 = argvars[1].vval.v_dict;
if (d1 == NULL) {
- const bool locked = tv_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
+ const bool locked = var_check_lock(VAR_FIXED, arg_errmsg, TV_TRANSLATE);
(void)locked;
assert(locked == true);
} else if (d2 == NULL) {
// Do nothing
tv_copy(&argvars[0], rettv);
- } else if (!tv_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ } else if (!var_check_lock(d1->dv_lock, arg_errmsg, TV_TRANSLATE)) {
const char *action = "force";
// Check the third argument.
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -4845,8 +4846,8 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), "insert()");
- } else if (!tv_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- N_("insert() argument"), TV_TRANSLATE)) {
+ } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ N_("insert() argument"), TV_TRANSLATE)) {
long before = 0;
if (argvars[2].v_type != VAR_UNKNOWN) {
before = tv_get_number_chk(&argvars[2], &error);
@@ -7079,7 +7080,7 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[2].v_type != VAR_UNKNOWN) {
EMSG2(_(e_toomanyarg), "remove()");
} else if ((d = argvars[0].vval.v_dict) != NULL
- && !tv_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
+ && !var_check_lock(d->dv_lock, arg_errmsg, TV_TRANSLATE)) {
const char *key = tv_get_string_chk(&argvars[1]);
if (key != NULL) {
di = tv_dict_find(d, key, -1);
@@ -7098,8 +7099,8 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listdictarg), "remove()");
- } else if (!tv_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- arg_errmsg, TV_TRANSLATE)) {
+ } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ arg_errmsg, TV_TRANSLATE)) {
bool error = false;
idx = tv_get_number_chk(&argvars[1], &error);
@@ -7374,8 +7375,8 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *l;
if (argvars[0].v_type != VAR_LIST) {
EMSG2(_(e_listarg), "reverse()");
- } else if (!tv_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- N_("reverse() argument"), TV_TRANSLATE)) {
+ } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
+ N_("reverse() argument"), TV_TRANSLATE)) {
tv_list_reverse(l);
tv_list_set_ret(rettv, l);
}
@@ -9462,7 +9463,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
EMSG2(_(e_listarg), sort ? "sort()" : "uniq()");
} else {
list_T *const l = argvars[0].vval.v_list;
- if (tv_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
+ if (var_check_lock(tv_list_locked(l), arg_errmsg, TV_TRANSLATE)) {
goto theend;
}
tv_list_set_ret(rettv, l);
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 4275ff7c61..7221dc8bc9 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1994,7 +1994,7 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2,
} else if (*action == 'f' && di2 != di1) {
typval_T oldtv;
- if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
+ if (var_check_lock(di1->di_tv.v_lock, arg_errmsg, arg_errmsg_len)
|| var_check_ro(di1->di_flags, arg_errmsg, arg_errmsg_len)) {
break;
}
@@ -2625,7 +2625,7 @@ bool tv_islocked(const typval_T *const tv)
///
/// Also gives an error message when typval is locked.
///
-/// @param[in] lock Lock status.
+/// @param[in] tv Typval.
/// @param[in] name Variable name, used in the error message.
/// @param[in] name_len Variable name length. Use #TV_TRANSLATE to translate
/// variable name and compute the length. Use #TV_CSTRING
@@ -2639,10 +2639,37 @@ bool tv_islocked(const typval_T *const tv)
/// gettext.
///
/// @return true if variable is locked, false otherwise.
-bool tv_check_lock(const VarLockStatus lock, const char *name,
+bool tv_check_lock(const typval_T *tv, const char *name,
size_t name_len)
FUNC_ATTR_WARN_UNUSED_RESULT
{
+ VarLockStatus lock = VAR_UNLOCKED;
+
+ switch (tv->v_type) {
+ // case VAR_BLOB:
+ // if (tv->vval.v_blob != NULL)
+ // lock = tv->vval.v_blob->bv_lock;
+ // break;
+ case VAR_LIST:
+ if (tv->vval.v_list != NULL) {
+ lock = tv->vval.v_list->lv_lock;
+ }
+ break;
+ case VAR_DICT:
+ if (tv->vval.v_dict != NULL) {
+ lock = tv->vval.v_dict->dv_lock;
+ }
+ break;
+ default:
+ break;
+ }
+ return var_check_lock(tv->v_lock, name, name_len)
+ || (lock != VAR_UNLOCKED && var_check_lock(lock, name, name_len));
+}
+
+/// @return true if variable "name" is locked (immutable)
+bool var_check_lock(VarLockStatus lock, const char *name, size_t name_len)
+{
const char *error_message = NULL;
switch (lock) {
case VAR_UNLOCKED: {
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index f5d1b1e870..5ffc06ec44 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -2455,13 +2455,13 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (fudi.fd_di == NULL) {
- if (tv_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg,
- TV_CSTRING)) {
+ if (var_check_lock(fudi.fd_dict->dv_lock, (const char *)eap->arg,
+ TV_CSTRING)) {
// Can't add a function to a locked dictionary
goto erret;
}
- } else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg,
- TV_CSTRING)) {
+ } else if (var_check_lock(fudi.fd_di->di_tv.v_lock, (const char *)eap->arg,
+ TV_CSTRING)) {
// Can't change an existing function if it is locked
goto erret;
}
diff --git a/src/nvim/path.c b/src/nvim/path.c
index fe50be5ea1..6ac24182cc 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -180,6 +180,34 @@ const char *path_next_component(const char *fname)
return fname;
}
+/// Returns the length of the path head on the current platform.
+/// @return
+/// - 3 on windows
+/// - 1 otherwise
+int path_head_length(void)
+{
+#ifdef WIN32
+ return 3;
+#else
+ return 1;
+#endif
+}
+
+/// Returns true if path begins with characters denoting the head of a path
+/// (e.g. '/' on linux and 'D:' on windows).
+/// @param path The path to be checked.
+/// @return
+/// - True if path begins with a path head
+/// - False otherwise
+bool is_path_head(const char_u *path)
+{
+#ifdef WIN32
+ return isalpha(path[0]) && path[1] == ':';
+#else
+ return vim_ispathsep(*path);
+#endif
+}
+
/// Get a pointer to one character past the head of a path name.
/// Unix: after "/"; Win: after "c:\"
/// If there is no head, path is returned.
@@ -189,7 +217,7 @@ char_u *get_past_head(const char_u *path)
#ifdef WIN32
// May skip "c:"
- if (isalpha(path[0]) && path[1] == ':') {
+ if (is_path_head(path)) {
retval = path + 2;
}
#endif
@@ -1991,10 +2019,24 @@ char_u *path_shorten_fname(char_u *full_path, char_u *dir_name)
assert(dir_name != NULL);
size_t len = strlen((char *)dir_name);
+
+ // If dir_name is a path head, full_path can always be made relative.
+ if (len == (size_t)path_head_length() && is_path_head(dir_name)) {
+ return full_path + len;
+ }
+
+ // If full_path and dir_name do not match, it's impossible to make one
+ // relative to the other.
+ if (fnamencmp(dir_name, full_path, len) != 0) {
+ return NULL;
+ }
+
char_u *p = full_path + len;
- if (fnamencmp(dir_name, full_path, len) != 0
- || !vim_ispathsep(*p)) {
+ // If *p is not pointing to a path separator, this means that full_path's
+ // last directory name is longer than *dir_name's last directory, so they
+ // don't actually match.
+ if (!vim_ispathsep(*p)) {
return NULL;
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 3e8d623ed4..71624baaf4 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -3925,7 +3925,15 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
int qf_winid = 0;
if (IS_LL_STACK(qi)) {
- qf_winid = curwin->handle;
+ if (curwin->w_llist == qi) {
+ win = curwin;
+ } else {
+ win = qf_find_win_with_loclist(qi);
+ if (win == NULL) {
+ return;
+ }
+ }
+ qf_winid = (int)win->handle;
}
if (old_last == NULL) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 04157a0154..3446a944cd 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -7211,7 +7211,24 @@ void ui_ext_tabline_update(void)
ADD(tabs, DICTIONARY_OBJ(tab_info));
}
- ui_call_tabline_update(curtab->handle, tabs);
+
+ Array buffers = ARRAY_DICT_INIT;
+ FOR_ALL_BUFFERS(buf) {
+ // Do not include unlisted buffers
+ if (!buf->b_p_bl) {
+ continue;
+ }
+
+ Dictionary buffer_info = ARRAY_DICT_INIT;
+ PUT(buffer_info, "buffer", BUFFER_OBJ(buf->handle));
+
+ get_trans_bufname(buf);
+ PUT(buffer_info, "name", STRING_OBJ(cstr_to_string((char *)NameBuff)));
+
+ ADD(buffers, DICTIONARY_OBJ(buffer_info));
+ }
+
+ ui_call_tabline_update(curtab->handle, tabs, curbuf->handle, buffers);
}
/*
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 71a7a2cce5..eb6151fbe1 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -161,6 +161,8 @@ let s:filename_checks = {
\ 'ecd': ['file.ecd'],
\ 'edif': ['file.edf', 'file.edif', 'file.edo'],
\ 'elinks': ['elinks.conf'],
+ \ 'elixir': ['file.ex', 'file.exs', 'mix.lock'],
+ \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elm': ['file.elm'],
\ 'elmfilt': ['filter-rules'],
\ 'epuppet': ['file.epp'],
@@ -257,7 +259,7 @@ let s:filename_checks = {
\ 'jgraph': ['file.jgr'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'],
- \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'],
\ 'jsp': ['file.jsp'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'],
\ 'kivy': ['file.kv'],
@@ -422,7 +424,7 @@ let s:filename_checks = {
\ 'sass': ['file.sass'],
\ 'sather': ['file.sa'],
\ 'sbt': ['file.sbt'],
- \ 'scala': ['file.scala'],
+ \ 'scala': ['file.scala', 'file.sc'],
\ 'scheme': ['file.scm', 'file.ss', 'file.rkt'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
@@ -765,5 +767,41 @@ func Test_pp_file()
filetype off
endfunc
+func Test_ex_file()
+ filetype on
+
+ call writefile(['arbitrary content'], 'Xfile.ex')
+ split Xfile.ex
+ call assert_equal('elixir', &filetype)
+ bwipe!
+ let g:filetype_euphoria = 'euphoria4'
+ split Xfile.ex
+ call assert_equal('euphoria4', &filetype)
+ bwipe!
+ unlet g:filetype_euphoria
+
+ call writefile(['-- filetype euphoria comment'], 'Xfile.ex')
+ split Xfile.ex
+ call assert_equal('euphoria3', &filetype)
+ bwipe!
+
+ call writefile(['--filetype euphoria comment'], 'Xfile.ex')
+ split Xfile.ex
+ call assert_equal('euphoria3', &filetype)
+ bwipe!
+
+ call writefile(['ifdef '], 'Xfile.ex')
+ split Xfile.ex
+ call assert_equal('euphoria3', &filetype)
+ bwipe!
+
+ call writefile(['include '], 'Xfile.ex')
+ split Xfile.ex
+ call assert_equal('euphoria3', &filetype)
+ bwipe!
+
+ call delete('Xfile.ex')
+ filetype off
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim
index a5cbd8f6a6..6cb736a38a 100644
--- a/src/nvim/testdir/test_let.vim
+++ b/src/nvim/testdir/test_let.vim
@@ -126,11 +126,16 @@ endfunction
func s:set_varg7(...) abort
let b = a:000
- call add(b, 1)
+ let b += [1]
endfunction
func s:set_varg8(...) abort
let b = a:000
+ call add(b, 1)
+endfunction
+
+func s:set_varg9(...) abort
+ let b = a:000
let b[0][0] = 1
endfunction
@@ -142,7 +147,8 @@ func Test_let_varg_fail()
call s:set_varg5([0])
call assert_fails('call s:set_varg6(1)', 'E742:')
call assert_fails('call s:set_varg7(1)', 'E742:')
- call s:set_varg8([0])
+ call assert_fails('call s:set_varg8(1)', 'E742:')
+ call s:set_varg9([0])
endfunction
func Test_let_utf8_environment()
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index c63613ab1b..6bd64caa6c 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -891,7 +891,7 @@ func Test_efm1()
Xtestfile:9: parse error before `asd'
make: *** [vim] Error 1
in file "Xtestfile" linenr 10: there is an error
-
+
2 returned
"Xtestfile", line 11 col 1; this is an error
"Xtestfile", line 12 col 2; this is another error
@@ -914,7 +914,7 @@ func Test_efm1()
x should be a dot
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20
^
-
+
Does anyone know what is the problem and how to correction it?
"Xtestfile", line 21 col 9: What is the title of the quickfix window?
"Xtestfile", line 22 col 9: What is the title of the quickfix window?
@@ -5138,4 +5138,62 @@ func Test_qftextfunc()
call Xtest_qftextfunc('l')
endfunc
+" Test for updating a location list for some other window and check that
+" 'qftextfunc' uses the correct location list.
+func Test_qftextfunc_other_loclist()
+ %bw!
+ call setloclist(0, [], 'f')
+
+ " create a window and a location list for it and open the location list
+ " window
+ lexpr ['F1:10:12:one', 'F1:20:14:two']
+ let w1_id = win_getid()
+ call setloclist(0, [], ' ',
+ \ {'lines': ['F1:10:12:one', 'F1:20:14:two'],
+ \ 'quickfixtextfunc':
+ \ {d -> map(getloclist(d.winid, {'id' : d.id,
+ \ 'items' : 1}).items[d.start_idx-1:d.end_idx-1],
+ \ "'Line ' .. v:val.lnum .. ', Col ' .. v:val.col")}})
+ lwindow
+ let w2_id = win_getid()
+
+ " create another window and a location list for it and open the location
+ " list window
+ topleft new
+ let w3_id = win_getid()
+ call setloclist(0, [], ' ',
+ \ {'lines': ['F2:30:32:eleven', 'F2:40:34:twelve'],
+ \ 'quickfixtextfunc':
+ \ {d -> map(getloclist(d.winid, {'id' : d.id,
+ \ 'items' : 1}).items[d.start_idx-1:d.end_idx-1],
+ \ "'Ligne ' .. v:val.lnum .. ', Colonne ' .. v:val.col")}})
+ lwindow
+ let w4_id = win_getid()
+
+ topleft new
+ lexpr ['F3:50:52:green', 'F3:60:54:blue']
+ let w5_id = win_getid()
+
+ " change the location list for some other window
+ call setloclist(0, [], 'r', {'lines': ['F3:55:56:aaa', 'F3:57:58:bbb']})
+ call setloclist(w1_id, [], 'r', {'lines': ['F1:62:63:bbb', 'F1:64:65:ccc']})
+ call setloclist(w3_id, [], 'r', {'lines': ['F2:76:77:ddd', 'F2:78:79:eee']})
+ call assert_equal(['Line 62, Col 63', 'Line 64, Col 65'],
+ \ getbufline(winbufnr(w2_id), 1, '$'))
+ call assert_equal(['Ligne 76, Colonne 77', 'Ligne 78, Colonne 79'],
+ \ getbufline(winbufnr(w4_id), 1, '$'))
+ call setloclist(w2_id, [], 'r', {'lines': ['F1:32:33:fff', 'F1:34:35:ggg']})
+ call setloclist(w4_id, [], 'r', {'lines': ['F2:46:47:hhh', 'F2:48:49:jjj']})
+ call assert_equal(['Line 32, Col 33', 'Line 34, Col 35'],
+ \ getbufline(winbufnr(w2_id), 1, '$'))
+ call assert_equal(['Ligne 46, Colonne 47', 'Ligne 48, Colonne 49'],
+ \ getbufline(winbufnr(w4_id), 1, '$'))
+
+ call win_gotoid(w5_id)
+ lwindow
+ call assert_equal(['F3|55 col 56| aaa', 'F3|57 col 58| bbb'],
+ \ getline(1, '$'))
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index e62d3bb66b..93d71a9e45 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -101,6 +101,17 @@ describe('autocmd', function()
}, eval('g:evs'))
end)
+ it('WinClosed from root directory', function()
+ command('cd /')
+ command('let g:evs = []')
+ command('autocmd WinClosed * :call add(g:evs, ["WinClosed", expand("<afile>")])')
+ command('new')
+ command('close')
+ eq({
+ {'WinClosed', '1001'},
+ }, eval('g:evs'))
+ end)
+
it('v:vim_did_enter is 1 after VimEnter', function()
eq(1, eval('v:vim_did_enter'))
end)
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index 23aae81745..ab8d63cda1 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -4,14 +4,17 @@ local clear, command, eq = helpers.clear, helpers.command, helpers.eq
describe('ui/ext_tabline', function()
local screen
- local event_tabs, event_curtab
+ local event_tabs, event_curtab, event_curbuf, event_buffers
before_each(function()
clear()
screen = Screen.new(25, 5)
screen:attach({rgb=true, ext_tabline=true})
- function screen:_handle_tabline_update(curtab, tabs)
- event_curtab, event_tabs = curtab, tabs
+ function screen:_handle_tabline_update(curtab, tabs, curbuf, buffers)
+ event_curtab = curtab
+ event_tabs = tabs
+ event_curbuf = curbuf
+ event_buffers = buffers
end
end)
@@ -45,4 +48,38 @@ describe('ui/ext_tabline', function()
eq(expected_tabs, event_tabs)
end}
end)
+
+ it('buffer UI events', function()
+ local expected_buffers_initial= {
+ {buffer = { id = 1 }, name = '[No Name]'},
+ }
+
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], condition=function()
+ eq({ id = 1}, event_curbuf)
+ eq(expected_buffers_initial, event_buffers)
+ end}
+
+ command("badd another-buffer")
+ command("bnext")
+
+ local expected_buffers = {
+ {buffer = { id = 2 }, name = 'another-buffer'},
+ }
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]], condition=function()
+ eq({ id = 2 }, event_curbuf)
+ eq(expected_buffers, event_buffers)
+ end}
+ end)
end)
diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua
index 7c03005529..d81e272877 100644
--- a/test/unit/eval/typval_spec.lua
+++ b/test/unit/eval/typval_spec.lua
@@ -2623,7 +2623,7 @@ describe('typval.c', function()
describe('check_lock()', function()
local function tv_check_lock(lock, name, name_len, emsg)
return check_emsg(function()
- return lib.tv_check_lock(lock, name, name_len)
+ return lib.var_check_lock(lock, name, name_len)
end, emsg)
end
itp('works', function()