aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/CMakeLists.txt9
-rw-r--r--src/nvim/eval.c15
-rw-r--r--src/nvim/ex_cmds.c29
-rw-r--r--src/nvim/ex_cmds2.c34
-rw-r--r--src/nvim/ex_docmd.c46
-rw-r--r--src/nvim/os/env.c117
-rw-r--r--src/nvim/testdir/Makefile3
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim40
-rw-r--r--src/nvim/version.c7
9 files changed, 201 insertions, 99 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 0711642868..6b2ce08d36 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -1,4 +1,5 @@
include(CheckLibraryExists)
+include(CheckCCompilerFlag)
option(USE_GCOV "Enable gcov support" OFF)
@@ -258,8 +259,14 @@ install_helper(TARGETS nvim)
if(CLANG_ASAN_UBSAN)
message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.")
+ check_c_compiler_flag(-fno-sanitize-recover=all SANITIZE_RECOVER_ALL)
+ if(SANITIZE_RECOVER_ALL)
+ set(SANITIZE_RECOVER -fno-sanitize-recover=all) # Clang 3.6+
+ else()
+ set(SANITIZE_RECOVER -fno-sanitize-recover) # Clang 3.5-
+ endif()
set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-DEXITFREE ")
- set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "-fno-sanitize-recover -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist")
+ set_property(TARGET nvim APPEND_STRING PROPERTY COMPILE_FLAGS "${SANITIZE_RECOVER} -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address -fsanitize=undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/.asan-blacklist")
set_property(TARGET nvim APPEND_STRING PROPERTY LINK_FLAGS "-fsanitize=address -fsanitize=undefined ")
elseif(CLANG_MSAN)
message(STATUS "Enabling Clang memory sanitizer for nvim.")
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 8c8881b398..712ee06b85 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -21701,6 +21701,18 @@ static void term_resize(uint16_t width, uint16_t height, void *d)
pty_process_resize(&data->proc.pty, width, height);
}
+static inline void term_delayed_free(void **argv)
+{
+ TerminalJobData *j = argv[0];
+ if (j->in.pending_reqs || j->out.pending_reqs || j->err.pending_reqs) {
+ queue_put(j->events, term_delayed_free, 1, j);
+ return;
+ }
+
+ terminal_destroy(j->term);
+ term_job_data_decref(j);
+}
+
static void term_close(void *d)
{
TerminalJobData *data = d;
@@ -21708,8 +21720,7 @@ static void term_close(void *d)
data->exited = true;
process_stop((Process *)&data->proc);
}
- terminal_destroy(data->term);
- term_job_data_decref(d);
+ queue_put(data->events, term_delayed_free, 1, data);
}
static void term_job_data_decref(TerminalJobData *data)
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index e8314e02e0..415d6ee460 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -4413,17 +4413,20 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
|| (arg[0] == '\\' && arg[1] == '{'))
*d++ = '\\';
- for (s = arg; *s; ++s) {
- /*
- * Replace "|" with "bar" and '"' with "quote" to match the name of
- * the tags for these commands.
- * Replace "*" with ".*" and "?" with "." to match command line
- * completion.
- * Insert a backslash before '~', '$' and '.' to avoid their
- * special meaning.
- */
- if (d - IObuff > IOSIZE - 10) /* getting too long!? */
+ // If tag starts with "('", skip the "(". Fixes CTRL-] on ('option'.
+ if (*arg == '(' && arg[1] == '\'') {
+ arg++;
+ }
+ for (s = arg; *s; s++) {
+ // Replace "|" with "bar" and '"' with "quote" to match the name of
+ // the tags for these commands.
+ // Replace "*" with ".*" and "?" with "." to match command line
+ // completion.
+ // Insert a backslash before '~', '$' and '.' to avoid their
+ // special meaning.
+ if (d - IObuff > IOSIZE - 10) { // getting too long!?
break;
+ }
switch (*s) {
case '|': STRCPY(d, "bar");
d += 3;
@@ -4484,6 +4487,12 @@ int find_help_tags(char_u *arg, int *num_matches, char_u ***matches, int keep_la
*d++ = *s;
+ // If tag contains "({" or "([", tag terminates at the "(".
+ // This is for help on functions, e.g.: abs({expr}).
+ if (*s == '(' && (s[1] == '{' || s[1] =='[')) {
+ break;
+ }
+
/*
* If tag starts with ', toss everything after a second '. Fixes
* CTRL-] on 'option'. (would include the trailing '.').
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 12efddc205..df387f9a60 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1241,16 +1241,18 @@ static void add_bufnum(int *bufnrs, int *bufnump, int nr)
*bufnump = *bufnump + 1;
}
-/*
- * Return TRUE if any buffer was changed and cannot be abandoned.
- * That changed buffer becomes the current buffer.
- */
-int
-check_changed_any (
- int hidden /* Only check hidden buffers */
-)
-{
- int ret = FALSE;
+/// Check if any buffer was changed and cannot be abandoned.
+/// That changed buffer becomes the current buffer.
+/// When "unload" is true the current buffer is unloaded instead of making it
+/// hidden. This is used for ":q!".
+///
+/// @param[in] hidden specifies whether to check only hidden buffers.
+/// @param[in] unload specifies whether to unload, instead of hide, the buffer.
+///
+/// @returns true if any buffer is changed and cannot be abandoned
+int check_changed_any(bool hidden, bool unload)
+{
+ bool ret = false;
int save;
int i;
int bufnum = 0;
@@ -1261,8 +1263,9 @@ check_changed_any (
++bufcount;
}
- if (bufcount == 0)
- return FALSE;
+ if (bufcount == 0) {
+ return false;
+ }
bufnrs = xmalloc(sizeof(*bufnrs) * bufcount);
@@ -1346,9 +1349,10 @@ check_changed_any (
}
buf_found:
- /* Open the changed buffer in the current window. */
- if (buf != curbuf)
- set_curbuf(buf, DOBUF_GOTO);
+ // Open the changed buffer in the current window.
+ if (buf != curbuf) {
+ set_curbuf(buf, unload ? DOBUF_UNLOAD : DOBUF_GOTO);
+ }
theend:
xfree(bufnrs);
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 89c35a3c45..870284a0f7 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5671,10 +5671,10 @@ static void ex_quit(exarg_T *eap)
exiting = TRUE;
if ((!P_HID(curbuf)
&& check_changed(curbuf, (p_awa ? CCGD_AW : 0)
- | (eap->forceit ? CCGD_FORCEIT : 0)
- | CCGD_EXCMD))
- || check_more(TRUE, eap->forceit) == FAIL
- || (only_one_window() && check_changed_any(eap->forceit))) {
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD))
+ || check_more(true, eap->forceit) == FAIL
+ || (only_one_window() && check_changed_any(eap->forceit, true))) {
not_exiting();
} else {
// quit last window
@@ -5723,9 +5723,10 @@ static void ex_quit_all(exarg_T *eap)
if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
return;
- exiting = TRUE;
- if (eap->forceit || !check_changed_any(FALSE))
+ exiting = true;
+ if (eap->forceit || !check_changed_any(false, false)) {
getout(0);
+ }
not_exiting();
}
@@ -6010,21 +6011,22 @@ static void ex_exit(exarg_T *eap)
if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing))
return;
- /*
- * if more files or windows we won't exit
- */
- if (check_more(FALSE, eap->forceit) == OK && only_one_window())
- exiting = TRUE;
- if ( ((eap->cmdidx == CMD_wq
- || curbufIsChanged())
- && do_write(eap) == FAIL)
- || check_more(TRUE, eap->forceit) == FAIL
- || (only_one_window() && check_changed_any(eap->forceit))) {
+ // if more files or windows we won't exit
+ if (check_more(false, eap->forceit) == OK && only_one_window()) {
+ exiting = true;
+ }
+ if (((eap->cmdidx == CMD_wq
+ || curbufIsChanged())
+ && do_write(eap) == FAIL)
+ || check_more(true, eap->forceit) == FAIL
+ || (only_one_window() && check_changed_any(eap->forceit, false))) {
not_exiting();
} else {
- if (only_one_window()) /* quit last window, exit Vim */
+ if (only_one_window()) {
+ // quit last window, exit Vim
getout(0);
- /* Quit current window, may free the buffer. */
+ }
+ // Quit current window, may free the buffer.
win_close(curwin, !P_HID(curwin->w_buffer));
}
}
@@ -9497,12 +9499,14 @@ static void ex_folddo(exarg_T *eap)
static void ex_terminal(exarg_T *eap)
{
- // We will call termopen() with ['shell'] if not given a {cmd}.
- char *name = (char *)p_sh;
+ char *name = (char *)p_sh; // Default to 'shell' if {cmd} is not given.
+ bool mustfree = false;
char *lquote = "['";
char *rquote = "']";
+
if (*eap->arg != NUL) {
name = (char *)vim_strsave_escaped(eap->arg, (char_u *)"\"\\");
+ mustfree = true;
lquote = rquote = "\"";
}
@@ -9512,7 +9516,7 @@ static void ex_terminal(exarg_T *eap)
eap->forceit==TRUE ? "!" : "", lquote, name, rquote);
do_cmdline_cmd(ex_cmd);
- if (name != (char *)p_sh) {
+ if (mustfree) {
xfree(name);
}
}
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 384a17004e..edc430410c 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -147,7 +147,7 @@ static char_u *homedir = NULL;
void init_homedir(void)
{
- /* In case we are called a second time (when 'encoding' changes). */
+ // In case we are called a second time (when 'encoding' changes).
xfree(homedir);
homedir = NULL;
@@ -176,16 +176,16 @@ void init_homedir(void)
if (var != NULL) {
#ifdef UNIX
- /*
- * Change to the directory and get the actual path. This resolves
- * links. Don't do it when we can't return.
- */
+ // Change to the directory and get the actual path. This resolves
+ // links. Don't do it when we can't return.
if (os_dirname(NameBuff, MAXPATHL) == OK
&& os_chdir((char *)NameBuff) == 0) {
- if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK)
+ if (!os_chdir((char *)var) && os_dirname(IObuff, IOSIZE) == OK) {
var = IObuff;
- if (os_chdir((char *)NameBuff) != 0)
+ }
+ if (os_chdir((char *)NameBuff) != 0) {
EMSG(_(e_prev_dir));
+ }
}
#endif
homedir = vim_strsave(var);
@@ -239,29 +239,29 @@ void expand_env(char_u *src, char_u *dst, int dstlen)
/// "~/" is also expanded, using $HOME. For Unix "~user/" is expanded.
/// Skips over "\ ", "\~" and "\$" (not for Win32 though).
/// If anything fails no expansion is done and dst equals src.
-/// startstr recognize the start of a new name, for '~' expansion.
+/// prefix recognize the start of a new name, for '~' expansion.
/// @param srcp Input string e.g. "$HOME/vim.hlp"
/// @param dst Where to put the result
/// @param dstlen Maximum length of the result
/// @param esc Should we escape spaces in expanded variables?
/// @param one Should we expand more than one '~'?
-/// @param startstr Common prefix for paths, can be NULL
-void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
- char_u *startstr)
+/// @param prefix Common prefix for paths, can be NULL
+void expand_env_esc(char_u *restrict srcp,
+ char_u *restrict dst,
+ int dstlen,
+ bool esc,
+ bool one,
+ char_u *prefix)
{
- char_u *src;
char_u *tail;
- int c;
char_u *var;
bool copy_char;
bool mustfree; // var was allocated, need to free it later
bool at_start = true; // at start of a name
- int startstr_len = 0;
- if (startstr != NULL)
- startstr_len = (int)STRLEN(startstr);
+ int prefix_len = (prefix == NULL) ? 0 : (int)STRLEN(prefix);
- src = skipwhite(srcp);
+ char_u *src = skipwhite(srcp);
dstlen--; // leave one char space for "\,"
while (*src && dstlen > 0) {
// Skip over `=expr`.
@@ -281,6 +281,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
dstlen -= (int)len;
continue;
}
+
copy_char = true;
if ((*src == '$') || (*src == '~' && at_start)) {
mustfree = false;
@@ -290,14 +291,15 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
if (*src != '~') { // environment var
tail = src + 1;
var = dst;
- c = dstlen - 1;
+ int c = dstlen - 1;
#ifdef UNIX
// Unix has ${var-name} type environment vars
if (*tail == '{' && !vim_isIDc('{')) {
- tail++; /* ignore '{' */
- while (c-- > 0 && *tail && *tail != '}')
+ tail++; // ignore '{'
+ while (c-- > 0 && *tail != NUL && *tail != '}') {
*var++ = *tail++;
+ }
} else // NOLINT
#endif
{
@@ -321,7 +323,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
#if defined(UNIX)
}
#endif
- } else if ( src[1] == NUL /* home directory */
+ } else if (src[1] == NUL // home directory
|| vim_ispathsep(src[1])
|| vim_strchr((char_u *)" ,\t\n", src[1]) != NULL) {
var = homedir;
@@ -331,12 +333,13 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
// Copy ~user to dst[], so we can put a NUL after it.
tail = src;
var = dst;
- c = dstlen - 1;
- while ( c-- > 0
- && *tail
- && vim_isfilec(*tail)
- && !vim_ispathsep(*tail))
+ int c = dstlen - 1;
+ while (c-- > 0
+ && *tail
+ && vim_isfilec(*tail)
+ && !vim_ispathsep(*tail)) {
*var++ = *tail++;
+ }
*var = NUL;
// Use os_get_user_directory() to get the user directory.
// If this function fails, the shell is used to
@@ -344,8 +347,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
// does not support ~user (old versions of /bin/sh).
var = (char_u *)os_get_user_directory((char *)dst + 1);
mustfree = true;
- if (var == NULL)
- {
+ if (var == NULL) {
expand_T xpc;
ExpandInit(&xpc);
@@ -381,8 +383,9 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) {
char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
- if (mustfree)
+ if (mustfree) {
xfree(var);
+ }
var = p;
mustfree = true;
}
@@ -391,7 +394,7 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
&& (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen)) {
STRCPY(dst, var);
dstlen -= (int)STRLEN(var);
- c = (int)STRLEN(var);
+ int c = (int)STRLEN(var);
// if var[] ends in a path separator and tail[] starts
// with it, skip a character
if (*var != NUL && after_pathsep((char *)dst, (char *)dst + c)
@@ -404,8 +407,9 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
src = tail;
copy_char = false;
}
- if (mustfree)
+ if (mustfree) {
xfree(var);
+ }
}
if (copy_char) { // copy at least one char
@@ -422,9 +426,10 @@ void expand_env_esc(char_u *srcp, char_u *dst, int dstlen, bool esc, bool one,
*dst++ = *src++;
--dstlen;
- if (startstr != NULL && src - startstr_len >= srcp
- && STRNCMP(src - startstr_len, startstr, startstr_len) == 0)
+ if (prefix != NULL && src - prefix_len >= srcp
+ && STRNCMP(src - prefix_len, prefix, prefix_len) == 0) {
at_start = true;
+ }
}
}
*dst = NUL;
@@ -451,17 +456,37 @@ static char *vim_version_dir(const char *vimdir)
return NULL;
}
-/// If the string between "p" and "pend" ends in "name/", return "pend" minus
-/// the length of "name/". Otherwise return "pend".
-static char *remove_tail(char *p, char *pend, char *name)
+/// If `dirname + "/"` precedes `pend` in the path, return the pointer to
+/// `dirname + "/" + pend`. Otherwise return `pend`.
+///
+/// Examples (path = /usr/local/share/nvim/runtime/doc/help.txt):
+///
+/// pend = help.txt
+/// dirname = doc
+/// -> doc/help.txt
+///
+/// pend = doc/help.txt
+/// dirname = runtime
+/// -> runtime/doc/help.txt
+///
+/// pend = runtime/doc/help.txt
+/// dirname = vim74
+/// -> runtime/doc/help.txt
+///
+/// @param path Path to a file
+/// @param pend A suffix of the path
+/// @param dirname The immediate path fragment before the pend
+/// @return The new pend including dirname or just pend
+static char *remove_tail(char *path, char *pend, char *dirname)
{
- size_t len = STRLEN(name) + 1;
- char *newend = pend - len;
+ size_t len = STRLEN(dirname);
+ char *new_tail = pend - len - 1;
- if (newend >= p
- && fnamencmp((char_u *)newend, (char_u *)name, len - 1) == 0
- && (newend == p || after_pathsep(p, newend)))
- return newend;
+ if (new_tail >= path
+ && fnamencmp((char_u *)new_tail, (char_u *)dirname, len) == 0
+ && (new_tail == path || after_pathsep(path, new_tail))) {
+ return new_tail;
+ }
return pend;
}
@@ -745,9 +770,10 @@ void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, bool one)
/// @param src Input file name
char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
{
- size_t len = 3; /* space for "~/" and trailing NUL */
- if (src != NULL) /* just in case */
+ size_t len = 3; // space for "~/" and trailing NUL
+ if (src != NULL) { // just in case
len += STRLEN(src);
+ }
char_u *dst = xmalloc(len);
home_replace(buf, src, dst, (int)len, true);
return dst;
@@ -783,8 +809,7 @@ char_u *get_env_name(expand_T *xp, int idx)
STRLCPY(name, envname, ENVNAMELEN);
xfree(envname);
return name;
- } else {
- return NULL;
}
+ return NULL;
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index b763a67347..7195c7e632 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -39,8 +39,9 @@ SCRIPTS := \
# Tests using runtest.vim.vim.
# Keep test_alot*.res as the last one, sort the others.
NEW_TESTS = \
- test_viml.res \
test_cursor_func.res \
+ test_help_tagjump.res \
+ test_viml.res \
test_alot.res
SCRIPTS_GUI := test16.out
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
new file mode 100644
index 0000000000..9f9207d27d
--- /dev/null
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -0,0 +1,40 @@
+" Tests for :help! {subject}
+
+func SetUp()
+ " v:progpath is …/build/bin/nvim and we need …/build/runtime
+ " to be added to &rtp
+ let builddir = fnamemodify(exepath(v:progpath), ':h:h')
+ let s:rtp = &rtp
+ let &rtp .= printf(',%s/runtime', builddir)
+endfunc
+
+func TearDown()
+ let &rtp = s:rtp
+endfunc
+
+func Test_help_tagjump()
+ help
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*help.txt\*')
+ helpclose
+
+ exec "help! ('textwidth'"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'textwidth'\\*")
+ helpclose
+
+ exec "help! ('buflisted'),"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ "\\*'buflisted'\\*")
+ helpclose
+
+ exec "help! abs({expr})"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*abs()\*')
+ helpclose
+
+ exec "help! arglistid([{winnr})"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*arglistid()\*')
+ helpclose
+endfunc
diff --git a/src/nvim/version.c b/src/nvim/version.c
index d7eae84c1b..3746f53e1f 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -76,6 +76,7 @@ static int included_patches[] = {
1757,
1755,
1753,
+ 1728,
1654,
1652,
1643,
@@ -111,10 +112,10 @@ static int included_patches[] = {
1574,
// 1573,
// 1572 NA
- // 1571,
+ 1571,
1570,
1569,
- // 1568,
+ 1568,
// 1567,
// 1566 NA
// 1565,
@@ -645,7 +646,7 @@ static int included_patches[] = {
// 1040 NA
// 1039,
// 1038 NA
- // 1037,
+ 1037,
// 1036,
1035,
// 1034,