aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZyX <kp-pav@yandex.ru>2017-10-30 00:49:12 +0300
committerZyX <kp-pav@yandex.ru>2017-10-30 00:49:12 +0300
commitb29a776550dadefefb891d01054ea21eb942bad1 (patch)
tree799bb2c0e926a20ac5b1af262f0849208eae699a /src
parent538af1c90a4ac9928f60e97338869e516def4956 (diff)
parent45296b331fa462eeabb141037ad10a3ad24ab8a6 (diff)
downloadrneovim-b29a776550dadefefb891d01054ea21eb942bad1.tar.gz
rneovim-b29a776550dadefefb891d01054ea21eb942bad1.tar.bz2
rneovim-b29a776550dadefefb891d01054ea21eb942bad1.zip
Merge branch 'master' into expression-parser
Diffstat (limited to 'src')
-rwxr-xr-xsrc/clint.py1
-rw-r--r--src/nvim/CMakeLists.txt7
-rw-r--r--src/nvim/api/buffer.c6
-rw-r--r--src/nvim/api/private/helpers.c33
-rw-r--r--src/nvim/api/ui_events.in.h16
-rw-r--r--src/nvim/buffer.c2
-rw-r--r--src/nvim/cursor.c29
-rw-r--r--src/nvim/eval.c73
-rw-r--r--src/nvim/ex_cmds.lua8
-rw-r--r--src/nvim/ex_docmd.c11
-rw-r--r--src/nvim/ex_getln.c353
-rw-r--r--src/nvim/generators/gen_options.lua1
-rw-r--r--src/nvim/globals.h7
-rw-r--r--src/nvim/lua/executor.c47
-rw-r--r--src/nvim/menu.c12
-rw-r--r--src/nvim/misc1.c4
-rw-r--r--src/nvim/msgpack_rpc/channel.c36
-rw-r--r--src/nvim/normal.c13
-rw-r--r--src/nvim/ops.c2
-rw-r--r--src/nvim/option.c27
-rw-r--r--src/nvim/options.lua5
-rw-r--r--src/nvim/regexp_defs.h46
-rw-r--r--src/nvim/screen.c60
-rw-r--r--src/nvim/syntax_defs.h8
-rw-r--r--src/nvim/terminal.c2
-rw-r--r--src/nvim/terminal.h2
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_options.vim23
-rw-r--r--src/nvim/testdir/test_profile.vim147
-rw-r--r--src/nvim/testdir/test_retab.vim77
-rw-r--r--src/nvim/testdir/test_virtualedit.vim43
-rw-r--r--src/nvim/testdir/test_visual.vim18
-rw-r--r--src/nvim/undo.h1
-rw-r--r--src/nvim/undo_defs.h6
-rw-r--r--src/nvim/version.c66
-rw-r--r--src/nvim/window.c8
37 files changed, 904 insertions, 299 deletions
diff --git a/src/clint.py b/src/clint.py
index 4a41650ec4..e63175a69b 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -2531,6 +2531,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
r'(?<!\bkhash_t)'
r'(?<!\bkbtree_t)'
r'(?<!\bkbitr_t)'
+ r'(?<!\bPMap)'
r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)'
r' +'
r'-?(?:\*+|&)?(?:\w+|\+\+|--|\()', cast_line)
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index e7b9deb152..d3e07326bf 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -166,7 +166,7 @@ if(NOT MSVC)
endif()
endif()
-if(DEFINED MIN_LOG_LEVEL)
+if(NOT "${MIN_LOG_LEVEL}" MATCHES "^$")
add_definitions(-DMIN_LOG_LEVEL=${MIN_LOG_LEVEL})
endif()
@@ -543,11 +543,6 @@ endfunction()
set(NO_SINGLE_CHECK_HEADERS
os/win_defs.h
os/pty_process_win.h
- regexp_defs.h
- syntax_defs.h
- terminal.h
- undo.h
- undo_defs.h
)
foreach(hfile ${NVIM_HEADERS})
get_test_target(test-includes "${hfile}" relative_path texe)
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 82de8fd4a2..c381e92dc7 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -793,7 +793,11 @@ Integer nvim_buf_add_highlight(Buffer buffer,
col_end = MAXCOL;
}
- int hlg_id = syn_name2id((char_u *)(hl_group.data ? hl_group.data : ""));
+ int hlg_id = 0;
+ if (hl_group.size > 0) {
+ hlg_id = syn_check_group((char_u *)hl_group.data, (int)hl_group.size);
+ }
+
src_id = bufhl_add_hl(buf, (int)src_id, hlg_id, (linenr_T)line+1,
(colnr_T)col_start+1, (colnr_T)col_end);
return src_id;
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index e736e29e2d..2944925a9c 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -667,6 +667,22 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err)
return rv;
}
+/// Allocates a String consisting of a single char. Does not support multibyte
+/// characters. The resulting string is also NUL-terminated, to facilitate
+/// interoperating with code using C strings.
+///
+/// @param char the char to convert
+/// @return the resulting String, if the input char was NUL, an
+/// empty String is returned
+String cchar_to_string(char c)
+{
+ char buf[] = { c, NUL };
+ return (String) {
+ .data = xmemdupz(buf, 1),
+ .size = (c != NUL) ? 1 : 0
+ };
+}
+
/// Copies a C string into a String (binary safe string, characters + length).
/// The resulting string is also NUL-terminated, to facilitate interoperating
/// with code using C strings.
@@ -687,6 +703,23 @@ String cstr_to_string(const char *str)
};
}
+/// Copies buffer to an allocated String.
+/// The resulting string is also NUL-terminated, to facilitate interoperating
+/// with code using C strings.
+///
+/// @param buf the buffer to copy
+/// @param size length of the buffer
+/// @return the resulting String, if the input string was NULL, an
+/// empty String is returned
+String cbuf_to_string(const char *buf, size_t size)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return (String) {
+ .data = xmemdupz(buf, size),
+ .size = size
+ };
+}
+
/// Creates a String using the given C string. Unlike
/// cstr_to_string this function DOES NOT copy the C string.
///
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 1b5d17584f..65357d008a 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -68,4 +68,20 @@ void popupmenu_select(Integer selected)
void tabline_update(Tabpage current, Array tabs)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_show(Array content, Integer pos, String firstc, String prompt,
+ Integer indent, Integer level)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_pos(Integer pos, Integer level)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_special_char(String c, Boolean shift, Integer level)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_hide(Integer level)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_block_show(Array lines)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_block_append(Array lines)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+void cmdline_block_hide(void)
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
+
#endif // NVIM_API_UI_EVENTS_IN_H
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index fc5bb90973..9d42fbc1b3 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -1466,7 +1466,7 @@ void enter_buffer(buf_T *buf)
if (buf->terminal) {
terminal_resize(buf->terminal,
- (uint16_t)curwin->w_width,
+ (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))),
(uint16_t)curwin->w_height);
}
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 60002f3cea..0e97e2203f 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -375,17 +375,30 @@ void check_cursor_col_win(win_T *win)
win->w_cursor.col = 0;
}
- /* If virtual editing is on, we can leave the cursor on the old position,
- * only we must set it to virtual. But don't do it when at the end of the
- * line. */
- if (oldcol == MAXCOL)
+ // If virtual editing is on, we can leave the cursor on the old position,
+ // only we must set it to virtual. But don't do it when at the end of the
+ // line.
+ if (oldcol == MAXCOL) {
win->w_cursor.coladd = 0;
- else if (ve_flags == VE_ALL) {
- if (oldcoladd > win->w_cursor.col)
+ } else if (ve_flags == VE_ALL) {
+ if (oldcoladd > win->w_cursor.col) {
win->w_cursor.coladd = oldcoladd - win->w_cursor.col;
- else
- /* avoid weird number when there is a miscalculation or overflow */
+
+ // Make sure that coladd is not more than the char width.
+ // Not for the last character, coladd is then used when the cursor
+ // is actually after the last character.
+ if (win->w_cursor.col + 1 < len && win->w_cursor.coladd > 0) {
+ int cs, ce;
+
+ getvcol(win, &win->w_cursor, &cs, NULL, &ce);
+ if (win->w_cursor.coladd > ce - cs) {
+ win->w_cursor.coladd = ce - cs;
+ }
+ }
+ } else {
+ // avoid weird number when there is a miscalculation or overflow
win->w_cursor.coladd = 0;
+ }
}
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index b2a0d9a767..c7cb51ac29 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -11147,17 +11147,18 @@ void get_user_input(const typval_T *const argvars,
cmd_silent = false; // Want to see the prompt.
// Only the part of the message after the last NL is considered as
- // prompt for the command line.
- const char *p = strrchr(prompt, '\n');
- if (p == NULL) {
- p = prompt;
- } else {
- p++;
- msg_start();
- msg_clr_eos();
- msg_puts_attr_len(prompt, p - prompt, echo_attr);
- msg_didout = false;
- msg_starthere();
+ // prompt for the command line, unlsess cmdline is externalized
+ const char *p = prompt;
+ if (!ui_is_external(kUICmdline)) {
+ const char *lastnl = strrchr(prompt, '\n');
+ if (lastnl != NULL) {
+ p = lastnl+1;
+ msg_start();
+ msg_clr_eos();
+ msg_puts_attr_len(prompt, p - prompt, echo_attr);
+ msg_didout = false;
+ msg_starthere();
+ }
}
cmdline_row = msg_row;
@@ -16723,9 +16724,10 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+ uint16_t term_width = MAX(0, curwin->w_width - win_col_off(curwin));
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
true, false, false, cwd);
- data->proc.pty.width = curwin->w_width;
+ data->proc.pty.width = term_width;
data->proc.pty.height = curwin->w_height;
data->proc.pty.term_name = xstrdup("xterm-256color");
if (!common_job_start(data, rettv)) {
@@ -16733,7 +16735,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
TerminalOptions topts;
topts.data = data;
- topts.width = curwin->w_width;
+ topts.width = term_width;
topts.height = curwin->w_height;
topts.write_cb = term_write;
topts.resize_cb = term_resize;
@@ -19642,6 +19644,7 @@ void ex_function(exarg_T *eap)
int todo;
hashitem_T *hi;
int sourcing_lnum_off;
+ bool show_block = false;
/*
* ":function" without argument: list functions.
@@ -19815,6 +19818,11 @@ void ex_function(exarg_T *eap)
goto errret_2;
}
+ if (KeyTyped && ui_is_external(kUICmdline)) {
+ show_block = true;
+ ui_ext_cmdline_block_append(0, (const char *)eap->cmd);
+ }
+
// find extra arguments "range", "dict", "abort" and "closure"
for (;; ) {
p = skipwhite(p);
@@ -19867,7 +19875,9 @@ void ex_function(exarg_T *eap)
if (!eap->skip && did_emsg)
goto erret;
- msg_putchar('\n'); /* don't overwrite the function name */
+ if (!ui_is_external(kUICmdline)) {
+ msg_putchar('\n'); // don't overwrite the function name
+ }
cmdline_row = msg_row;
}
@@ -19901,6 +19911,9 @@ void ex_function(exarg_T *eap)
EMSG(_("E126: Missing :endfunction"));
goto erret;
}
+ if (show_block) {
+ ui_ext_cmdline_block_append(indent, (const char *)theline);
+ }
/* Detect line continuation: sourcing_lnum increased more than one. */
if (sourcing_lnum > sourcing_lnum_off + 1)
@@ -20193,6 +20206,9 @@ ret_free:
xfree(name);
did_emsg |= saved_did_emsg;
need_wait_return |= saved_wait_return;
+ if (show_block) {
+ ui_ext_cmdline_block_leave();
+ }
}
/// Get a function name, translating "<SID>" and "<SNR>".
@@ -22850,3 +22866,32 @@ void eval_format_source_name_line(char *buf, size_t bufsize)
(sourcing_name ? sourcing_name : (char_u *)"?"),
(sourcing_name ? sourcing_lnum : 0));
}
+
+/// ":checkhealth [plugins]"
+void ex_checkhealth(exarg_T *eap)
+{
+ bool found = !!find_func((char_u *)"health#check");
+ if (!found
+ && script_autoload("health#check", sizeof("health#check") - 1, false)) {
+ found = !!find_func((char_u *)"health#check");
+ }
+ if (!found) {
+ const char *vimruntime_env = os_getenv("VIMRUNTIME");
+ if (vimruntime_env == NULL) {
+ EMSG(_("E5009: $VIMRUNTIME is empty or unset"));
+ return;
+ } else {
+ EMSG2(_("E5009: Invalid $VIMRUNTIME: %s"), os_getenv("VIMRUNTIME"));
+ return;
+ }
+ }
+
+ size_t bufsize = STRLEN(eap->arg) + sizeof("call health#check('')");
+ char *buf = xmalloc(bufsize);
+ snprintf(buf, bufsize, "call health#check('%s')", eap->arg);
+
+ do_cmdline_cmd(buf);
+
+ xfree(buf);
+}
+
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 5a578cd088..e57e662039 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -451,6 +451,12 @@ return {
func='ex_changes',
},
{
+ command='checkhealth',
+ flags=bit.bor(EXTRA, TRLBAR),
+ addr_type=ADDR_LINES,
+ func='ex_checkhealth',
+ },
+ {
command='checkpath',
flags=bit.bor(TRLBAR, BANG, CMDWIN),
addr_type=ADDR_LINES,
@@ -614,7 +620,7 @@ return {
},
{
command='cquit',
- flags=bit.bor(TRLBAR, BANG),
+ flags=bit.bor(RANGE, NOTADR, COUNT, ZEROR, TRLBAR, BANG),
addr_type=ADDR_LINES,
func='ex_cquit',
},
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 664ab69792..3bcea4b666 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -9,6 +9,7 @@
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
#include <inttypes.h>
#include "nvim/vim.h"
@@ -5996,7 +5997,7 @@ static void ex_quit(exarg_T *eap)
*/
static void ex_cquit(exarg_T *eap)
{
- getout(1);
+ getout(eap->addr_count > 0 ? (int)eap->line2 : EXIT_FAILURE);
}
/*
@@ -9883,7 +9884,7 @@ static void ex_terminal(exarg_T *eap)
/// Checks if `cmd` is "previewable" (i.e. supported by 'inccommand').
///
-/// @param[in] cmd Commandline to check. May start with a range.
+/// @param[in] cmd Commandline to check. May start with a range or modifier.
///
/// @return true if `cmd` is previewable
bool cmd_can_preview(char_u *cmd)
@@ -9892,6 +9893,12 @@ bool cmd_can_preview(char_u *cmd)
return false;
}
+ // Ignore any leading modifiers (:keeppatterns, :verbose, etc.)
+ for (int len = modifier_len(cmd); len != 0; len = modifier_len(cmd)) {
+ cmd += len;
+ cmd = skipwhite(cmd);
+ }
+
exarg_T ea;
// parse the command line
ea.cmd = skip_range(cmd, NULL);
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 386e9e81aa..785038f5d6 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -69,6 +69,30 @@
#include "nvim/viml/parser/parser.h"
#include "nvim/viml/parser/expressions.h"
+/// Command-line colors: one chunk
+///
+/// Defines a region which has the same highlighting.
+typedef struct {
+ int start; ///< Colored chunk start.
+ int end; ///< Colored chunk end (exclusive, > start).
+ int attr; ///< Highlight attr.
+} CmdlineColorChunk;
+
+/// Command-line colors
+///
+/// Holds data about all colors.
+typedef kvec_t(CmdlineColorChunk) CmdlineColors;
+
+/// Command-line coloring
+///
+/// Holds both what are the colors and what have been colored. Latter is used to
+/// suppress unnecessary calls to coloring callbacks.
+typedef struct {
+ unsigned prompt_id; ///< ID of the prompt which was colored last.
+ char *cmdbuff; ///< What exactly was colored last time or NULL.
+ CmdlineColors colors; ///< Last colors.
+} ColoredCmdline;
+
/*
* Variables shared between getcmdline(), redrawcmdline() and others.
* These need to be saved when using CTRL-R |, that's why they are in a
@@ -93,6 +117,11 @@ struct cmdline_info {
int input_fn; // when TRUE Invoked for input() function
unsigned prompt_id; ///< Prompt number, used to disable coloring on errors.
Callback highlight_callback; ///< Callback used for coloring user input.
+ ColoredCmdline last_colors; ///< Last cmdline colors
+ int level; // current cmdline level
+ struct cmdline_info *prev_ccline; ///< pointer to saved cmdline state
+ char special_char; ///< last putcmdline char (used for redraws)
+ bool special_shift; ///< shift of last putcmdline char
};
/// Last value of prompt_id, incremented when doing new prompt
static unsigned last_prompt_id = 0;
@@ -145,36 +174,6 @@ typedef struct command_line_state {
struct cmdline_info save_ccline;
} CommandLineState;
-/// Command-line colors: one chunk
-///
-/// Defines a region which has the same highlighting.
-typedef struct {
- int start; ///< Colored chunk start.
- int end; ///< Colored chunk end (exclusive, > start).
- int attr; ///< Highlight attr.
-} CmdlineColorChunk;
-
-/// Command-line colors
-///
-/// Holds data about all colors.
-typedef kvec_t(CmdlineColorChunk) CmdlineColors;
-
-/// Command-line coloring
-///
-/// Holds both what are the colors and what have been colored. Latter is used to
-/// suppress unnecessary calls to coloring callbacks.
-typedef struct {
- unsigned prompt_id; ///< ID of the prompt which was colored last.
- char *cmdbuff; ///< What exactly was colored last time or NULL.
- CmdlineColors colors; ///< Last colors.
-} ColoredCmdline;
-
-/// Last command-line colors.
-ColoredCmdline last_ccline_colors = {
- .cmdbuff = NULL,
- .colors = KV_INITIAL_VALUE
-};
-
typedef struct cmdline_info CmdlineInfo;
/* The current cmdline_info. It is initialized in getcmdline() and after that
@@ -187,6 +186,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */
static int new_cmdpos; /* position set by set_cmdline_pos() */
+static Array cmdline_block; ///< currently displayed block of context
+
/*
* Type used by call_user_expand_func
*/
@@ -241,6 +242,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
}
ccline.prompt_id = last_prompt_id++;
+ ccline.level++;
ccline.overstrike = false; // always start in insert mode
clearpos(&s->match_end);
s->save_cursor = curwin->w_cursor; // may be restored later
@@ -260,6 +262,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
ccline.cmdlen = ccline.cmdpos = 0;
ccline.cmdbuff[0] = NUL;
+ ccline.last_colors = (ColoredCmdline){ .cmdbuff = NULL,
+ .colors = KV_INITIAL_VALUE };
+
// autoindent for :insert and :append
if (s->firstc <= 0) {
memset(ccline.cmdbuff, ' ', s->indent);
@@ -410,12 +415,19 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
setmouse();
ui_cursor_shape(); // may show different cursor shape
xfree(s->save_p_icm);
+ xfree(ccline.last_colors.cmdbuff);
+ kv_destroy(ccline.last_colors.colors);
{
char_u *p = ccline.cmdbuff;
// Make ccline empty, getcmdline() may try to use it.
ccline.cmdbuff = NULL;
+
+ if (ui_is_external(kUICmdline)) {
+ ui_call_cmdline_hide(ccline.level);
+ }
+ ccline.level--;
return p;
}
}
@@ -806,7 +818,9 @@ static int command_line_execute(VimState *state, int key)
}
if (!cmd_silent) {
- ui_cursor_goto(msg_row, 0);
+ if (!ui_is_external(kUICmdline)) {
+ ui_cursor_goto(msg_row, 0);
+ }
ui_flush();
}
return 0;
@@ -1136,7 +1150,7 @@ static int command_line_handle_key(CommandLineState *s)
xfree(ccline.cmdbuff); // no commandline to return
ccline.cmdbuff = NULL;
- if (!cmd_silent) {
+ if (!cmd_silent && !ui_is_external(kUICmdline)) {
if (cmdmsg_rl) {
msg_col = Columns;
} else {
@@ -1588,9 +1602,14 @@ static int command_line_handle_key(CommandLineState *s)
s->do_abbr = false; // don't do abbreviation now
// may need to remove ^ when composing char was typed
if (enc_utf8 && utf_iscomposing(s->c) && !cmd_silent) {
- draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
- msg_putchar(' ');
- cursorcmd();
+ if (ui_is_external(kUICmdline)) {
+ // TODO(bfredl): why not make unputcmdline also work with true?
+ unputcmdline();
+ } else {
+ draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
+ msg_putchar(' ');
+ cursorcmd();
+ }
}
break;
@@ -2404,8 +2423,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
/// Should use built-in command parser or user-specified one. Currently only the
/// latter is supported.
///
-/// @param[in] colored_ccline Command-line to color.
-/// @param[out] ret_ccline_colors What should be colored. Also holds a cache:
+/// @param[in,out] colored_ccline Command-line to color. Also holds a cache:
/// if ->prompt_id and ->cmdbuff values happen
/// to be equal to those from colored_cmdline it
/// will just do nothing, assuming that ->colors
@@ -2415,11 +2433,11 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
///
/// @return true if draw_cmdline may proceed, false if it does not need anything
/// to do.
-static bool color_cmdline(const CmdlineInfo *const colored_ccline,
- ColoredCmdline *const ret_ccline_colors)
+static bool color_cmdline(CmdlineInfo *colored_ccline)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
bool printed_errmsg = false;
+
#define PRINT_ERRMSG(...) \
do { \
msg_putchar('\n'); \
@@ -2428,19 +2446,21 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
} while (0)
bool ret = true;
+ ColoredCmdline *ccline_colors = &colored_ccline->last_colors;
+
// Check whether result of the previous call is still valid.
- if (ret_ccline_colors->prompt_id == colored_ccline->prompt_id
- && ret_ccline_colors->cmdbuff != NULL
- && STRCMP(ret_ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) {
+ if (ccline_colors->prompt_id == colored_ccline->prompt_id
+ && ccline_colors->cmdbuff != NULL
+ && STRCMP(ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) {
return ret;
}
- kv_size(ret_ccline_colors->colors) = 0;
+ kv_size(ccline_colors->colors) = 0;
if (colored_ccline->cmdbuff == NULL || *colored_ccline->cmdbuff == NUL) {
// Nothing to do, exiting.
- xfree(ret_ccline_colors->cmdbuff);
- ret_ccline_colors->cmdbuff = NULL;
+ xfree(ccline_colors->cmdbuff);
+ ccline_colors->cmdbuff = NULL;
return ret;
}
@@ -2453,7 +2473,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
static unsigned prev_prompt_id = UINT_MAX;
static int prev_prompt_errors = 0;
- Callback color_cb = { .type = kCallbackNone };
+ Callback color_cb = CALLBACK_NONE;
bool can_free_cb = false;
TryState tstate;
Error err = ERROR_INIT;
@@ -2557,7 +2577,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
goto color_cmdline_error;
}
if (start != prev_end) {
- kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
+ kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = prev_end,
.end = start,
.attr = 0,
@@ -2586,14 +2606,14 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
}
const int id = syn_name2id((char_u *)group);
const int attr = (id == 0 ? 0 : syn_id2attr(id));
- kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
+ kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = start,
.end = end,
.attr = attr,
}));
}
if (prev_end < colored_ccline->cmdlen) {
- kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
+ kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
.start = prev_end,
.end = colored_ccline->cmdlen,
.attr = 0,
@@ -2605,14 +2625,14 @@ color_cmdline_end:
if (can_free_cb) {
callback_free(&color_cb);
}
- xfree(ret_ccline_colors->cmdbuff);
+ xfree(ccline_colors->cmdbuff);
// Note: errors “output” is cached just as well as regular results.
- ret_ccline_colors->prompt_id = colored_ccline->prompt_id;
+ ccline_colors->prompt_id = colored_ccline->prompt_id;
if (arg_allocated) {
- ret_ccline_colors->cmdbuff = (char *)arg.vval.v_string;
+ ccline_colors->cmdbuff = (char *)arg.vval.v_string;
} else {
- ret_ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff,
- (size_t)colored_ccline->cmdlen);
+ ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff,
+ (size_t)colored_ccline->cmdlen);
}
tv_clear(&tv);
return ret;
@@ -2625,7 +2645,7 @@ color_cmdline_error:
(void)printed_errmsg;
prev_prompt_errors++;
- kv_size(ret_ccline_colors->colors) = 0;
+ kv_size(ccline_colors->colors) = 0;
redrawcmdline();
ret = false;
goto color_cmdline_end;
@@ -2638,7 +2658,13 @@ color_cmdline_error:
*/
static void draw_cmdline(int start, int len)
{
- if (!color_cmdline(&ccline, &last_ccline_colors)) {
+ if (!color_cmdline(&ccline)) {
+ return;
+ }
+
+ if (ui_is_external(kUICmdline)) {
+ ccline.special_char = NUL;
+ ui_ext_cmdline_show(&ccline);
return;
}
@@ -2740,9 +2766,9 @@ static void draw_cmdline(int start, int len)
msg_outtrans_len(arshape_buf, newlen);
} else {
draw_cmdline_no_arabicshape:
- if (kv_size(last_ccline_colors.colors)) {
- for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) {
- CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i);
+ if (kv_size(ccline.last_colors.colors)) {
+ for (size_t i = 0; i < kv_size(ccline.last_colors.colors); i++) {
+ CmdlineColorChunk chunk = kv_A(ccline.last_colors.colors, i);
if (chunk.end <= start) {
continue;
}
@@ -2757,6 +2783,107 @@ draw_cmdline_no_arabicshape:
}
}
+static void ui_ext_cmdline_show(CmdlineInfo *line)
+{
+ Array content = ARRAY_DICT_INIT;
+ if (cmdline_star) {
+ size_t len = 0;
+ for (char_u *p = ccline.cmdbuff; *p; mb_ptr_adv(p)) {
+ len++;
+ }
+ char *buf = xmallocz(len);
+ memset(buf, '*', len);
+ Array item = ARRAY_DICT_INIT;
+ ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ ADD(item, STRING_OBJ(((String) { .data = buf, .size = len })));
+ ADD(content, ARRAY_OBJ(item));
+ } else if (kv_size(line->last_colors.colors)) {
+ for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) {
+ CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i);
+ Array item = ARRAY_DICT_INIT;
+
+ if (chunk.attr) {
+ attrentry_T *aep = syn_cterm_attr2entry(chunk.attr);
+ // TODO(bfredl): this desicion could be delayed by making attr_code a
+ // recognized type
+ HlAttrs rgb_attrs = attrentry2hlattrs(aep, true);
+ ADD(item, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs)));
+ } else {
+ ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ }
+ ADD(item, STRING_OBJ(cbuf_to_string((char *)line->cmdbuff + chunk.start,
+ chunk.end-chunk.start)));
+ ADD(content, ARRAY_OBJ(item));
+ }
+ } else {
+ Array item = ARRAY_DICT_INIT;
+ ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ ADD(item, STRING_OBJ(cstr_to_string((char *)(line->cmdbuff))));
+ ADD(content, ARRAY_OBJ(item));
+ }
+ ui_call_cmdline_show(content, line->cmdpos,
+ cchar_to_string((char)line->cmdfirstc),
+ cstr_to_string((char *)(line->cmdprompt)),
+ line->cmdindent,
+ line->level);
+ if (line->special_char) {
+ ui_call_cmdline_special_char(cchar_to_string((char)(line->special_char)),
+ line->special_shift,
+ line->level);
+ }
+}
+
+void ui_ext_cmdline_block_append(int indent, const char *line)
+{
+ char *buf = xmallocz(indent + strlen(line));
+ memset(buf, ' ', indent);
+ memcpy(buf+indent, line, strlen(line));
+
+ Array item = ARRAY_DICT_INIT;
+ ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ ADD(item, STRING_OBJ(cstr_as_string(buf)));
+ Array content = ARRAY_DICT_INIT;
+ ADD(content, ARRAY_OBJ(item));
+ ADD(cmdline_block, ARRAY_OBJ(content));
+ if (cmdline_block.size > 1) {
+ ui_call_cmdline_block_append(copy_array(content));
+ } else {
+ ui_call_cmdline_block_show(copy_array(cmdline_block));
+ }
+}
+
+void ui_ext_cmdline_block_leave(void)
+{
+ api_free_array(cmdline_block);
+ ui_call_cmdline_block_hide();
+}
+
+/// Extra redrawing needed for redraw! and on ui_attach
+/// assumes "redrawcmdline()" will already be invoked
+void cmdline_screen_cleared(void)
+{
+ if (!ui_is_external(kUICmdline)) {
+ return;
+ }
+
+ if (cmdline_block.size) {
+ ui_call_cmdline_block_show(copy_array(cmdline_block));
+ }
+
+ int prev_level = ccline.level-1;
+ CmdlineInfo *prev_ccline = ccline.prev_ccline;
+ while (prev_level > 0 && prev_ccline) {
+ if (prev_ccline->level == prev_level) {
+ // don't redraw a cmdline already shown in the cmdline window
+ if (prev_level != cmdwin_level) {
+ ui_ext_cmdline_show(prev_ccline);
+ }
+ prev_level--;
+ }
+ prev_ccline = prev_ccline->prev_ccline;
+ }
+}
+
/*
* Put a character on the command line. Shifts the following text to the
* right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
@@ -2764,33 +2891,39 @@ draw_cmdline_no_arabicshape:
*/
void putcmdline(int c, int shift)
{
- if (cmd_silent)
+ if (cmd_silent) {
return;
- msg_no_more = TRUE;
- msg_putchar(c);
- if (shift)
- draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
- msg_no_more = FALSE;
+ }
+ if (!ui_is_external(kUICmdline)) {
+ msg_no_more = true;
+ msg_putchar(c);
+ if (shift) {
+ draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
+ }
+ msg_no_more = false;
+ } else {
+ ccline.special_char = c;
+ ccline.special_shift = shift;
+ ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift,
+ ccline.level);
+ }
cursorcmd();
ui_cursor_shape();
}
-/*
- * Undo a putcmdline(c, FALSE).
- */
+/// Undo a putcmdline(c, FALSE).
void unputcmdline(void)
{
- if (cmd_silent)
+ if (cmd_silent) {
return;
- msg_no_more = TRUE;
- if (ccline.cmdlen == ccline.cmdpos)
+ }
+ msg_no_more = true;
+ if (ccline.cmdlen == ccline.cmdpos && !ui_is_external(kUICmdline)) {
msg_putchar(' ');
- else if (has_mbyte)
- draw_cmdline(ccline.cmdpos,
- (*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos));
- else
- draw_cmdline(ccline.cmdpos, 1);
- msg_no_more = FALSE;
+ } else {
+ draw_cmdline(ccline.cmdpos, mb_ptr2len(ccline.cmdbuff + ccline.cmdpos));
+ }
+ msg_no_more = false;
cursorcmd();
ui_cursor_shape();
}
@@ -2924,9 +3057,6 @@ void put_on_cmdline(char_u *str, int len, int redraw)
msg_check();
}
-static struct cmdline_info prev_ccline;
-static int prev_ccline_used = FALSE;
-
/*
* Save ccline, because obtaining the "=" register may execute "normal :cmd"
* and overwrite it. But get_cmdline_str() may need it, thus make it
@@ -2934,15 +3064,12 @@ static int prev_ccline_used = FALSE;
*/
static void save_cmdline(struct cmdline_info *ccp)
{
- if (!prev_ccline_used) {
- memset(&prev_ccline, 0, sizeof(struct cmdline_info));
- prev_ccline_used = TRUE;
- }
- *ccp = prev_ccline;
- prev_ccline = ccline;
+ *ccp = ccline;
+ ccline.prev_ccline = ccp;
ccline.cmdbuff = NULL;
ccline.cmdprompt = NULL;
ccline.xpc = NULL;
+ ccline.special_char = NUL;
}
/*
@@ -2950,8 +3077,7 @@ static void save_cmdline(struct cmdline_info *ccp)
*/
static void restore_cmdline(struct cmdline_info *ccp)
{
- ccline = prev_ccline;
- prev_ccline = *ccp;
+ ccline = *ccp;
}
/*
@@ -3119,17 +3245,25 @@ static void redrawcmdprompt(void)
if (cmd_silent)
return;
- if (ccline.cmdfirstc != NUL)
+ if (ui_is_external(kUICmdline)) {
+ ui_ext_cmdline_show(&ccline);
+ return;
+ }
+ if (ccline.cmdfirstc != NUL) {
msg_putchar(ccline.cmdfirstc);
+ }
if (ccline.cmdprompt != NULL) {
msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr);
ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
- /* do the reverse of set_cmdspos() */
- if (ccline.cmdfirstc != NUL)
- --ccline.cmdindent;
- } else
- for (i = ccline.cmdindent; i > 0; --i)
+ // do the reverse of set_cmdspos()
+ if (ccline.cmdfirstc != NUL) {
+ ccline.cmdindent--;
+ }
+ } else {
+ for (i = ccline.cmdindent; i > 0; i--) {
msg_putchar(' ');
+ }
+ }
}
/*
@@ -3140,6 +3274,11 @@ void redrawcmd(void)
if (cmd_silent)
return;
+ if (ui_is_external(kUICmdline)) {
+ draw_cmdline(0, ccline.cmdlen);
+ return;
+ }
+
/* when 'incsearch' is set there may be no command line while redrawing */
if (ccline.cmdbuff == NULL) {
ui_cursor_goto(cmdline_row, 0);
@@ -3183,6 +3322,11 @@ static void cursorcmd(void)
if (cmd_silent)
return;
+ if (ui_is_external(kUICmdline)) {
+ ui_call_cmdline_pos(ccline.cmdpos, ccline.level);
+ return;
+ }
+
if (cmdmsg_rl) {
msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
@@ -3200,6 +3344,9 @@ static void cursorcmd(void)
void gotocmdline(int clr)
{
+ if (ui_is_external(kUICmdline)) {
+ return;
+ }
msg_start();
if (cmdmsg_rl)
msg_col = Columns - 1;
@@ -5257,13 +5404,15 @@ int get_history_idx(int histype)
*/
static struct cmdline_info *get_ccline_ptr(void)
{
- if ((State & CMDLINE) == 0)
+ if ((State & CMDLINE) == 0) {
return NULL;
- if (ccline.cmdbuff != NULL)
+ } else if (ccline.cmdbuff != NULL) {
return &ccline;
- if (prev_ccline_used && prev_ccline.cmdbuff != NULL)
- return &prev_ccline;
- return NULL;
+ } else if (ccline.prev_ccline && ccline.prev_ccline->cmdbuff != NULL) {
+ return ccline.prev_ccline;
+ } else {
+ return NULL;
+ }
}
/*
@@ -5699,6 +5848,7 @@ static int ex_window(void)
return K_IGNORE;
}
cmdwin_type = get_cmdline_type();
+ cmdwin_level = ccline.level;
// Create empty command-line buffer.
buf_open_scratch(0, "[Command Line]");
@@ -5751,6 +5901,9 @@ static int ex_window(void)
curwin->w_cursor.col = ccline.cmdpos;
changed_line_abv_curs();
invalidate_botline();
+ if (ui_is_external(kUICmdline)) {
+ ui_call_cmdline_hide(ccline.level);
+ }
redraw_later(SOME_VALID);
// Save the command line info, can be used recursively.
@@ -5793,6 +5946,7 @@ static int ex_window(void)
// Restore the command line info.
restore_cmdline(&save_ccline);
cmdwin_type = 0;
+ cmdwin_level = 0;
exmode_active = save_exmode;
@@ -6027,3 +6181,4 @@ static void set_search_match(pos_T *t)
coladvance((colnr_T)MAXCOL);
}
}
+
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index ca0134043c..36562c0be9 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -74,6 +74,7 @@ local get_flags = function(o)
{'gettext'},
{'noglob'},
{'normal_fname_chars', 'P_NFNAME'},
+ {'normal_dname_chars', 'P_NDNAME'},
{'pri_mkrc'},
{'deny_in_modelines', 'P_NO_ML'},
{'deny_duplicates', 'P_NODUP'},
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index c5d26aa2ce..2a041177d4 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -958,9 +958,10 @@ EXTERN int fill_diff INIT(= '-');
EXTERN int km_stopsel INIT(= FALSE);
EXTERN int km_startsel INIT(= FALSE);
-EXTERN int cedit_key INIT(= -1); /* key value of 'cedit' option */
-EXTERN int cmdwin_type INIT(= 0); /* type of cmdline window or 0 */
-EXTERN int cmdwin_result INIT(= 0); /* result of cmdline window or 0 */
+EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option
+EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0
+EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0
+EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level
EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--"));
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index eb821f7831..16bb4169c4 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -124,9 +124,40 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
/// omitted.
static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
- const char *s1 = luaL_checklstring(lstate, 1, NULL);
- const char *s2 = luaL_checklstring(lstate, 2, NULL);
- const int ret = STRICMP(s1, s2);
+ size_t s1_len;
+ size_t s2_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ const char *s2 = luaL_checklstring(lstate, 2, &s2_len);
+ char *nul1;
+ char *nul2;
+ int ret = 0;
+ assert(s1[s1_len] == NUL);
+ assert(s2[s2_len] == NUL);
+ do {
+ nul1 = memchr(s1, NUL, s1_len);
+ nul2 = memchr(s2, NUL, s2_len);
+ ret = STRICMP(s1, s2);
+ if (ret == 0) {
+ // Compare "a\0" greater then "a".
+ if ((nul1 == NULL) != (nul2 == NULL)) {
+ ret = ((nul1 != NULL) - (nul2 != NULL));
+ break;
+ }
+ if (nul1 != NULL) {
+ assert(nul2 != NULL);
+ // Can't shift both strings by the same amount of bytes: lowercase
+ // letter may have different byte-length than uppercase.
+ s1_len -= (size_t)(nul1 - s1) + 1;
+ s2_len -= (size_t)(nul2 - s2) + 1;
+ s1 = nul1 + 1;
+ s2 = nul2 + 1;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ } while (true);
lua_pop(lstate, 2);
lua_pushnumber(lstate, (lua_Number)((ret > 0) - (ret < 0)));
return 1;
@@ -254,10 +285,6 @@ static int nlua_exec_lua_file(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
/// Called by lua interpreter itself to initialize state.
static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
- // stricmp
- lua_pushcfunction(lstate, &nlua_stricmp);
- lua_setglobal(lstate, "stricmp");
-
// print
lua_pushcfunction(lstate, &nlua_print);
lua_setglobal(lstate, "print");
@@ -277,13 +304,17 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
nlua_add_api_functions(lstate);
// vim.types, vim.type_idx, vim.val_idx
nlua_init_types(lstate);
+ // stricmp
+ lua_pushcfunction(lstate, &nlua_stricmp);
+ lua_setfield(lstate, -2, "stricmp");
+
lua_setglobal(lstate, "vim");
return 0;
}
/// Initialize lua interpreter
///
-/// Crashes NeoVim if initialization fails. Should be called once per lua
+/// Crashes Nvim if initialization fails. Should be called once per lua
/// interpreter instance.
///
/// @return New lua interpreter instance.
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 0db250d111..88d968704b 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -682,6 +682,10 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
tv_dict_add_str(dict, S_LEN("shortcut"), buf);
}
+ if (menu->actext) {
+ tv_dict_add_str(dict, S_LEN("actext"), (char *)menu->actext);
+ }
+
if (menu->modes & MENU_TIP_MODE && menu->strings[MENU_INDEX_TIP]) {
tv_dict_add_str(dict, S_LEN("tooltip"),
(char *)menu->strings[MENU_INDEX_TIP]);
@@ -695,11 +699,9 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
for (int bit = 0; bit < MENU_MODES; bit++) {
if ((menu->modes & modes & (1 << bit)) != 0) {
dict_T *impl = tv_dict_alloc();
- if (*menu->strings[bit] == NUL) {
- tv_dict_add_str(impl, S_LEN("rhs"), (char *)"<Nop>");
- } else {
- tv_dict_add_str(impl, S_LEN("rhs"), (char *)menu->strings[bit]);
- }
+ tv_dict_add_allocated_str(impl, S_LEN("rhs"),
+ str2special_save((char *)menu->strings[bit],
+ false, false));
tv_dict_add_nr(impl, S_LEN("silent"), menu->silent[bit]);
tv_dict_add_nr(impl, S_LEN("enabled"),
(menu->enabled & (1 << bit)) ? 1 : 0);
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 5270687a4d..137de84953 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -1273,8 +1273,8 @@ int plines_win_nofold(win_T *wp, linenr_T lnum)
* Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
*/
width = wp->w_width - win_col_off(wp);
- if (width <= 0) {
- return 32000; // bigger than the number of lines of the screen
+ if (width <= 0 || col > 32000) {
+ return 32000; // bigger than the number of screen columns
}
if (col <= (unsigned int)width) {
return 1;
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 88232a55de..5efdb9a194 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -56,7 +56,6 @@ typedef struct {
typedef struct {
uint64_t id;
size_t refcount;
- size_t pending_requests;
PMap(cstr_t) *subscribed_events;
bool closed;
ChannelType type;
@@ -71,7 +70,6 @@ typedef struct {
} data;
uint64_t next_request_id;
kvec_t(ChannelCallFrame *) call_stack;
- kvec_t(WBuffer *) delayed_notifications;
MultiQueue *events;
} Channel;
@@ -205,14 +203,7 @@ bool channel_send_event(uint64_t id, const char *name, Array args)
}
if (channel) {
- if (channel->pending_requests) {
- // Pending request, queue the notification for later sending.
- const String method = cstr_as_string((char *)name);
- WBuffer *buffer = serialize_request(id, 0, method, args, &out_buffer, 1);
- kv_push(channel->delayed_notifications, buffer);
- } else {
- send_event(channel, name, args);
- }
+ send_event(channel, name, args);
} else {
broadcast_event(name, args);
}
@@ -248,10 +239,8 @@ Object channel_send_call(uint64_t id,
// Push the frame
ChannelCallFrame frame = { request_id, false, false, NIL };
kv_push(channel->call_stack, &frame);
- channel->pending_requests++;
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1, frame.returned);
(void)kv_pop(channel->call_stack);
- channel->pending_requests--;
if (frame.errored) {
if (frame.result.type == kObjectTypeString) {
@@ -276,10 +265,6 @@ Object channel_send_call(uint64_t id,
api_free_object(frame.result);
}
- if (!channel->pending_requests) {
- send_delayed_notifications(channel);
- }
-
decref(channel);
return frame.errored ? NIL : frame.result;
@@ -704,11 +689,7 @@ static void broadcast_event(const char *name, Array args)
for (size_t i = 0; i < kv_size(subscribed); i++) {
Channel *channel = kv_A(subscribed, i);
- if (channel->pending_requests) {
- kv_push(channel->delayed_notifications, buffer);
- } else {
- channel_write(channel, buffer);
- }
+ channel_write(channel, buffer);
}
end:
@@ -786,7 +767,6 @@ static void free_channel(Channel *channel)
pmap_free(cstr_t)(channel->subscribed_events);
kv_destroy(channel->call_stack);
- kv_destroy(channel->delayed_notifications);
if (channel->type != kChannelTypeProc) {
multiqueue_free(channel->events);
}
@@ -811,11 +791,9 @@ static Channel *register_channel(ChannelType type, uint64_t id,
rv->closed = false;
rv->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
rv->id = id > 0 ? id : next_chan_id++;
- rv->pending_requests = 0;
rv->subscribed_events = pmap_new(cstr_t)();
rv->next_request_id = 1;
kv_init(rv->call_stack);
- kv_init(rv->delayed_notifications);
pmap_put(uint64_t)(channels, rv->id, rv);
ILOG("new channel %" PRIu64 " (%s): %s", rv->id,
@@ -912,16 +890,6 @@ static WBuffer *serialize_response(uint64_t channel_id,
return rv;
}
-static void send_delayed_notifications(Channel* channel)
-{
- for (size_t i = 0; i < kv_size(channel->delayed_notifications); i++) {
- WBuffer *buffer = kv_A(channel->delayed_notifications, i);
- channel_write(channel, buffer);
- }
-
- kv_size(channel->delayed_notifications) = 0;
-}
-
static void incref(Channel *channel)
{
channel->refcount++;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index c40ed58550..1103fe15d2 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1548,8 +1548,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
}
oap->start = VIsual;
- if (VIsual_mode == 'V')
+ if (VIsual_mode == 'V') {
oap->start.col = 0;
+ oap->start.coladd = 0;
+ }
}
/*
@@ -6260,15 +6262,18 @@ static void nv_gomark(cmdarg_T *cap)
} else
nv_cursormark(cap, cap->arg, pos);
- /* May need to clear the coladd that a mark includes. */
- if (!virtual_active())
+ // May need to clear the coladd that a mark includes.
+ if (!virtual_active()) {
curwin->w_cursor.coladd = 0;
+ }
+ check_cursor_col();
if (cap->oap->op_type == OP_NOP
&& pos != NULL
&& (pos == (pos_T *)-1 || !equalpos(old_cursor, *pos))
&& (fdo_flags & FDO_MARK)
- && old_KeyTyped)
+ && old_KeyTyped) {
foldOpenCursor();
+ }
}
/*
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index e7bc20698b..c6df71ea46 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -5535,7 +5535,7 @@ int get_default_register_name(void)
static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing)
{
#define MSG_NO_CLIP "clipboard: No provider. " \
- "Try \":CheckHealth\" or \":h clipboard\"."
+ "Try \":checkhealth\" or \":h clipboard\"."
yankreg_T *target = NULL;
bool explicit_cb_reg = (*name == '*' || *name == '+');
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 13aadb71bb..f6f334f432 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -242,6 +242,7 @@ typedef struct vimoption {
#define P_NO_DEF_EXP 0x8000000U ///< Do not expand default value.
#define P_RWINONLY 0x10000000U ///< only redraw current window
+#define P_NDNAME 0x20000000U ///< only normal dir name chars allowed
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \
@@ -2454,11 +2455,14 @@ did_set_string_option (
if ((secure || sandbox != 0)
&& (options[opt_idx].flags & P_SECURE)) {
errmsg = e_secure;
- } else if ((options[opt_idx].flags & P_NFNAME)
- && vim_strpbrk(*varp, (char_u *)"/\\*?[|;&<>\r\n") != NULL) {
- // Check for a "normal" file name in some options. Disallow a path
- // separator (slash and/or backslash), wildcards and characters that are
- // often illegal in a file name.
+ } else if (((options[opt_idx].flags & P_NFNAME)
+ && vim_strpbrk(*varp, (char_u *)(secure ? "/\\*?[|;&<>\r\n"
+ : "/\\*?[<>\r\n")) != NULL)
+ || ((options[opt_idx].flags & P_NDNAME)
+ && vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL)) {
+ // Check for a "normal" directory or file name in some options. Disallow a
+ // path separator (slash and/or backslash), wildcards and characters that
+ // are often illegal in a file name. Be more permissive if "secure" is off.
errmsg = e_invarg;
}
/* 'backupcopy' */
@@ -3173,17 +3177,18 @@ did_set_string_option (
} else {
// Options that are a list of flags.
p = NULL;
- if (varp == &p_ww)
+ if (varp == &p_ww) { // 'whichwrap'
p = (char_u *)WW_ALL;
- if (varp == &p_shm)
+ }
+ if (varp == &p_shm) { // 'shortmess'
p = (char_u *)SHM_ALL;
- else if (varp == &(p_cpo))
+ } else if (varp == &(p_cpo)) { // 'cpoptions'
p = (char_u *)CPO_VI;
- else if (varp == &(curbuf->b_p_fo))
+ } else if (varp == &(curbuf->b_p_fo)) { // 'formatoptions'
p = (char_u *)FO_ALL;
- else if (varp == &curwin->w_p_cocu)
+ } else if (varp == &curwin->w_p_cocu) { // 'concealcursor'
p = (char_u *)COCU_ALL;
- else if (varp == &p_mouse) {
+ } else if (varp == &p_mouse) { // 'mouse'
p = (char_u *)MOUSE_ALL;
}
if (p != NULL) {
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 84ccb2e28d..7cecb16686 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -7,7 +7,7 @@
-- enable_if=nil,
-- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil},
-- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil,
--- pri_mkrc=nil, deny_in_modelines=nil,
+-- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil,
-- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true,
-- alloced=nil,
-- save_pv_indir=nil,
@@ -575,6 +575,7 @@ return {
full_name='dictionary', abbreviation='dict',
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
+ normal_dname_chars=true,
vi_def=true,
expand=true,
varname='p_dict',
@@ -1750,6 +1751,7 @@ return {
{
full_name='printexpr', abbreviation='pexpr',
type='string', scope={'global'},
+ secure=true,
vi_def=true,
varname='p_pexpr',
defaults={if_true={vi=""}}
@@ -2449,6 +2451,7 @@ return {
full_name='thesaurus', abbreviation='tsr',
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
+ normal_dname_chars=true,
vi_def=true,
expand=true,
varname='p_tsr',
diff --git a/src/nvim/regexp_defs.h b/src/nvim/regexp_defs.h
index 6426ee441b..b5d56e07fc 100644
--- a/src/nvim/regexp_defs.h
+++ b/src/nvim/regexp_defs.h
@@ -15,6 +15,8 @@
#include <stdbool.h>
#include "nvim/pos.h"
+#include "nvim/types.h"
+#include "nvim/profile.h"
/*
* The number of sub-matches is limited to 10.
@@ -41,18 +43,36 @@
#define NFA_ENGINE 2
typedef struct regengine regengine_T;
+typedef struct regprog regprog_T;
+typedef struct reg_extmatch reg_extmatch_T;
+
+/// Structure to be used for multi-line matching.
+/// Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col"
+/// and ends in line "endpos[no].lnum" just before column "endpos[no].col".
+/// The line numbers are relative to the first line, thus startpos[0].lnum is
+/// always 0.
+/// When there is no match, the line number is -1.
+typedef struct {
+ regprog_T *regprog;
+ lpos_T startpos[NSUBEXP];
+ lpos_T endpos[NSUBEXP];
+ int rmm_ic;
+ colnr_T rmm_maxcol; /// when not zero: maximum column
+} regmmatch_T;
+
+#include "nvim/buffer_defs.h"
/*
* Structure returned by vim_regcomp() to pass on to vim_regexec().
* This is the general structure. For the actual matcher, two specific
* structures are used. See code below.
*/
-typedef struct regprog {
+struct regprog {
regengine_T *engine;
unsigned regflags;
unsigned re_engine; ///< Automatic, backtracking or NFA engine.
unsigned re_flags; ///< Second argument for vim_regcomp().
-} regprog_T;
+};
/*
* Structure used by the back track matcher.
@@ -126,30 +146,14 @@ typedef struct {
} regmatch_T;
/*
- * Structure to be used for multi-line matching.
- * Sub-match "no" starts in line "startpos[no].lnum" column "startpos[no].col"
- * and ends in line "endpos[no].lnum" just before column "endpos[no].col".
- * The line numbers are relative to the first line, thus startpos[0].lnum is
- * always 0.
- * When there is no match, the line number is -1.
- */
-typedef struct {
- regprog_T *regprog;
- lpos_T startpos[NSUBEXP];
- lpos_T endpos[NSUBEXP];
- int rmm_ic;
- colnr_T rmm_maxcol; /* when not zero: maximum column */
-} regmmatch_T;
-
-/*
* Structure used to store external references: "\z\(\)" to "\z\1".
* Use a reference count to avoid the need to copy this around. When it goes
* from 1 to zero the matches need to be freed.
*/
-typedef struct {
- short refcnt;
+struct reg_extmatch {
+ int16_t refcnt;
char_u *matches[NSUBEXP];
-} reg_extmatch_T;
+};
struct regengine {
regprog_T *(*regcomp)(char_u*, int);
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 5659f30f64..41e900eb4c 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -345,8 +345,9 @@ void update_screen(int type)
if (need_highlight_changed)
highlight_changed();
- if (type == CLEAR) { /* first clear screen */
- screenclear(); /* will reset clear_cmdline */
+ if (type == CLEAR) { // first clear screen
+ screenclear(); // will reset clear_cmdline
+ cmdline_screen_cleared(); // clear external cmdline state
type = NOT_VALID;
}
@@ -692,12 +693,18 @@ static void win_update(win_T *wp)
if (wp->w_nrwidth != i) {
type = NOT_VALID;
wp->w_nrwidth = i;
- } else if (buf->b_mod_set && buf->b_mod_xlines != 0 && wp->w_redraw_top != 0) {
- /*
- * When there are both inserted/deleted lines and specific lines to be
- * redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
- * everything (only happens when redrawing is off for while).
- */
+
+ if (buf->terminal) {
+ terminal_resize(buf->terminal,
+ (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))),
+ (uint16_t)curwin->w_height);
+ }
+ } else if (buf->b_mod_set
+ && buf->b_mod_xlines != 0
+ && wp->w_redraw_top != 0) {
+ // When there are both inserted/deleted lines and specific lines to be
+ // redrawn, w_redraw_top and w_redraw_bot may be invalid, just redraw
+ // everything (only happens when redrawing is off for while).
type = NOT_VALID;
} else {
/*
@@ -2202,7 +2209,6 @@ win_line (
colnr_T trailcol = MAXCOL; /* start of trailing spaces */
int need_showbreak = false; // overlong line, skip first x chars
int line_attr = 0; // attribute for the whole line
- int line_attr_low_priority = 0; // current line, lowest priority
matchitem_T *cur; // points to the match list
match_T *shl; // points to search_hl or a match
int shl_flag; // flag to indicate whether search_hl
@@ -2428,13 +2434,7 @@ win_line (
filler_lines = wp->w_topfill;
filler_todo = filler_lines;
- // 'cursorline' highlighting for the current window. Not when Visual mode is
- // active, because it's not clear what is selected then.
- if (wp->w_p_cul && lnum == wp->w_cursor.lnum
- && !(wp == curwin && VIsual_active)) {
- line_attr_low_priority = win_hl_attr(wp, HLF_CUL);
- }
-
+ // If this line has a sign with line highlighting set line_attr.
v = buf_getsigntype(wp->w_buffer, lnum, SIGN_LINEHL);
if (v != 0) {
line_attr = sign_get_attr((int)v, true);
@@ -2449,7 +2449,7 @@ win_line (
line_attr = hl_combine_attr(wp->w_hl_attr_normal, line_attr);
}
- if (line_attr_low_priority || line_attr) {
+ if (line_attr != 0) {
area_highlighting = true;
}
@@ -2671,6 +2671,20 @@ win_line (
cur = cur->next;
}
+ // Cursor line highlighting for 'cursorline' in the current window. Not
+ // when Visual mode is active, because it's not clear what is selected
+ // then.
+ if (wp->w_p_cul && lnum == wp->w_cursor.lnum
+ && !(wp == curwin && VIsual_active)) {
+ if (line_attr != 0 && !(State & INSERT) && bt_quickfix(wp->w_buffer)
+ && qf_current_entry(wp) == lnum) {
+ line_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), line_attr);
+ } else {
+ line_attr = win_hl_attr(wp, HLF_CUL);
+ }
+ area_highlighting = true;
+ }
+
off = (unsigned)(current_ScreenLine - ScreenLines);
col = 0;
if (wp->w_p_rl) {
@@ -3589,9 +3603,7 @@ win_line (
// Display a '$' after the line or highlight an extra
// character if the line break is included.
// For a diff line the highlighting continues after the "$".
- if (diff_hlf == (hlf_T)0
- && line_attr == 0
- && line_attr_low_priority == 0) {
+ if (diff_hlf == (hlf_T)0 && line_attr == 0) {
// In virtualedit, visual selections may extend beyond end of line.
if (area_highlighting && virtual_active()
&& tocol != MAXCOL && vcol < tocol) {
@@ -3655,7 +3667,7 @@ win_line (
(col < wp->w_width))) {
c = ' ';
ptr--; // put it back at the NUL
- } else if ((diff_hlf != (hlf_T)0 || line_attr_low_priority || line_attr)
+ } else if ((diff_hlf != (hlf_T)0 || line_attr != 0)
&& (wp->w_p_rl
? (col >= 0)
: (col - boguscols < wp->w_width))) {
@@ -3667,8 +3679,7 @@ win_line (
did_line_attr++;
// don't do search HL for the rest of the line
- if ((line_attr_low_priority || line_attr)
- && char_attr == search_attr && col > 0) {
+ if (line_attr != 0 && char_attr == search_attr && col > 0) {
char_attr = line_attr;
}
if (diff_hlf == HLF_TXD) {
@@ -4037,9 +4048,6 @@ win_line (
}
}
- // Apply `line_attr_low_priority` now, so that everthing can override it.
- char_attr = hl_combine_attr(line_attr_low_priority, char_attr);
-
/*
* Store character to be displayed.
* Skip characters that are left of the screen for 'nowrap'.
diff --git a/src/nvim/syntax_defs.h b/src/nvim/syntax_defs.h
index 56fadbe7f6..7260853703 100644
--- a/src/nvim/syntax_defs.h
+++ b/src/nvim/syntax_defs.h
@@ -2,7 +2,6 @@
#define NVIM_SYNTAX_DEFS_H
#include "nvim/highlight_defs.h"
-#include "nvim/regexp_defs.h"
# define SST_MIN_ENTRIES 150 /* minimal size for state stack array */
# define SST_MAX_ENTRIES 1000 /* maximal size for state stack array */
@@ -10,6 +9,11 @@
# define SST_DIST 16 /* normal distance between entries */
# define SST_INVALID (synstate_T *)-1 /* invalid syn_state pointer */
+typedef struct syn_state synstate_T;
+
+#include "nvim/buffer_defs.h"
+#include "nvim/regexp_defs.h"
+
typedef unsigned short disptick_T; /* display tick type */
/* struct passed to in_id_list() */
@@ -48,8 +52,6 @@ typedef struct buf_state {
* syn_state contains the syntax state stack for the start of one line.
* Used by b_sst_array[].
*/
-typedef struct syn_state synstate_T;
-
struct syn_state {
synstate_T *sst_next; /* next entry in used or free list */
linenr_T sst_lnum; /* line number for this state */
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 4a9acf2559..1dac9c69bd 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -552,7 +552,7 @@ void terminal_receive(Terminal *term, char *data, size_t len)
}
void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
- int *term_attrs)
+ int *term_attrs)
{
int height, width;
vterm_get_size(term->vt, &height, &width);
diff --git a/src/nvim/terminal.h b/src/nvim/terminal.h
index 25e609fb68..f2b0e232c3 100644
--- a/src/nvim/terminal.h
+++ b/src/nvim/terminal.h
@@ -10,6 +10,8 @@ typedef void (*terminal_write_cb)(char *buffer, size_t size, void *data);
typedef void (*terminal_resize_cb)(uint16_t width, uint16_t height, void *data);
typedef void (*terminal_close_cb)(void *data);
+#include "nvim/buffer_defs.h"
+
typedef struct {
void *data;
uint16_t width, height;
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 38caa8815d..ccf999c7ee 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -62,7 +62,9 @@ NEW_TESTS ?= \
test_mksession_utf8.res \
test_nested_function.res \
test_normal.res \
+ test_profile.res \
test_quickfix.res \
+ test_retab.res \
test_search.res \
test_signs.res \
test_smartindent.res \
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index d55170c27c..535e290a34 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -34,4 +34,5 @@ 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
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 8a9d793a2e..08ee00e352 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -104,6 +104,29 @@ func Test_keymap_valid()
call assert_fails(":set kmp=trunc\x00name", "trunc")
endfunc
+func Check_dir_option(name)
+ " Check that it's possible to set the option.
+ exe 'set ' . a:name . '=/usr/share/dict/words'
+ call assert_equal('/usr/share/dict/words', eval('&' . a:name))
+ exe 'set ' . a:name . '=/usr/share/dict/words,/and/there'
+ call assert_equal('/usr/share/dict/words,/and/there', eval('&' . a:name))
+ exe 'set ' . a:name . '=/usr/share/dict\ words'
+ call assert_equal('/usr/share/dict words', eval('&' . a:name))
+
+ " Check rejecting weird characters.
+ call assert_fails("set " . a:name . "=/not&there", "E474:")
+ call assert_fails("set " . a:name . "=/not>there", "E474:")
+ call assert_fails("set " . a:name . "=/not.*there", "E474:")
+endfunc
+
+func Test_dictionary()
+ call Check_dir_option('dictionary')
+endfunc
+
+func Test_thesaurus()
+ call Check_dir_option('thesaurus')
+endfunc
+
func Test_complete()
" Trailing single backslash used to cause invalid memory access.
set complete=s\
diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim
new file mode 100644
index 0000000000..183f52b8ac
--- /dev/null
+++ b/src/nvim/testdir/test_profile.vim
@@ -0,0 +1,147 @@
+" Test Vim profiler
+if !has('profile')
+ finish
+endif
+
+func Test_profile_func()
+ let lines = [
+ \ "func! Foo1()",
+ \ "endfunc",
+ \ "func! Foo2()",
+ \ " let l:count = 100",
+ \ " while l:count > 0",
+ \ " let l:count = l:count - 1",
+ \ " endwhile",
+ \ "endfunc",
+ \ "func! Foo3()",
+ \ "endfunc",
+ \ "func! Bar()",
+ \ "endfunc",
+ \ "call Foo1()",
+ \ "call Foo1()",
+ \ "profile pause",
+ \ "call Foo1()",
+ \ "profile continue",
+ \ "call Foo2()",
+ \ "call Foo3()",
+ \ "call Bar()",
+ \ "if !v:profiling",
+ \ " delfunc Foo2",
+ \ "endif",
+ \ "delfunc Foo3",
+ \ ]
+
+ call writefile(lines, 'Xprofile_func.vim')
+ call system(v:progpath
+ \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ \ . ' -c "profile start Xprofile_func.log"'
+ \ . ' -c "profile func Foo*"'
+ \ . ' -c "so Xprofile_func.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_func.log')
+
+ " - Foo1() is called 3 times but should be reported as called twice
+ " since one call is in between "profile pause" .. "profile continue".
+ " - Foo2() should come before Foo1() since Foo1() does much more work.
+ " - Foo3() is not reported because function is deleted.
+ " - Unlike Foo3(), Foo2() should not be deleted since there is a check
+ " for v:profiling.
+ " - Bar() is not reported since it does not match "profile func Foo*".
+ call assert_equal(28, len(lines))
+
+ call assert_equal('FUNCTION Foo1()', lines[0])
+ call assert_equal('Called 2 times', lines[1])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_equal('', lines[4])
+ call assert_equal('count total (s) self (s)', lines[5])
+ call assert_equal('', lines[6])
+ call assert_equal('FUNCTION Foo2()', lines[7])
+ call assert_equal('Called 1 time', lines[8])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[9])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[10])
+ call assert_equal('', lines[11])
+ call assert_equal('count total (s) self (s)', lines[12])
+ call assert_match('^\s*1\s\+.*\slet l:count = 100$', lines[13])
+ call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[14])
+ call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[15])
+ call assert_match('^\s*100\s\+.*\sendwhile$', lines[16])
+ call assert_equal('', lines[17])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[18])
+ call assert_equal('count total (s) self (s) function', lines[19])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[20])
+ call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[21])
+ call assert_equal('', lines[22])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[23])
+ call assert_equal('count total (s) self (s) function', lines[24])
+ call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[25])
+ call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[26])
+ call assert_equal('', lines[27])
+
+ call delete('Xprofile_func.vim')
+ call delete('Xprofile_func.log')
+endfunc
+
+func Test_profile_file()
+ let lines = [
+ \ 'func! Foo()',
+ \ 'endfunc',
+ \ 'for i in range(10)',
+ \ ' " a comment',
+ \ ' call Foo()',
+ \ 'endfor',
+ \ 'call Foo()',
+ \ ]
+
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath
+ \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ \ . ' -c "profile start Xprofile_file.log"'
+ \ . ' -c "profile file Xprofile_file.vim"'
+ \ . ' -c "so Xprofile_file.vim"'
+ \ . ' -c "so Xprofile_file.vim"'
+ \ . ' -c "qall!"')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+
+ call assert_equal(14, len(lines))
+
+ call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0])
+ call assert_equal('Sourced 2 times', lines[1])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_equal('', lines[4])
+ call assert_equal('count total (s) self (s)', lines[5])
+ call assert_equal(' func! Foo()', lines[6])
+ call assert_equal(' endfunc', lines[7])
+ " Loop iterates 10 times. Since script runs twice, body executes 20 times.
+ " First line of loop executes one more time than body to detect end of loop.
+ call assert_match('^\s*22\s\+\d\+\.\d\+\s\+for i in range(10)$', lines[8])
+ call assert_equal(' " a comment', lines[9])
+ " if self and total are equal we only get one number
+ call assert_match('^\s*20\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[10])
+ call assert_match('^\s*20\s\+\d\+\.\d\+\s\+endfor$', lines[11])
+ " if self and total are equal we only get one number
+ call assert_match('^\s*2\s\+\(\d\+\.\d\+\s\+\)\=\d\+\.\d\+\s\+call Foo()$', lines[12])
+ call assert_equal('', lines[13])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
+
+func Test_profile_completion()
+ call feedkeys(":profile \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profile continue dump file func pause start stop', @:)
+
+ call feedkeys(":profile start test_prof\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"profile start.* test_profile\.vim', @:)
+endfunc
+
+func Test_profile_errors()
+ call assert_fails("profile func Foo", 'E750:')
+ call assert_fails("profile pause", 'E750:')
+ call assert_fails("profile continue", 'E750:')
+endfunc
diff --git a/src/nvim/testdir/test_retab.vim b/src/nvim/testdir/test_retab.vim
new file mode 100644
index 0000000000..f11a32bade
--- /dev/null
+++ b/src/nvim/testdir/test_retab.vim
@@ -0,0 +1,77 @@
+" Test :retab
+func SetUp()
+ new
+ call setline(1, "\ta \t b c ")
+endfunc
+
+func TearDown()
+ bwipe!
+endfunc
+
+func Retab(bang, n)
+ let l:old_tabstop = &tabstop
+ let l:old_line = getline(1)
+ exe "retab" . a:bang . a:n
+ let l:line = getline(1)
+ call setline(1, l:old_line)
+ if a:n > 0
+ " :retab changes 'tabstop' to n with argument n > 0.
+ call assert_equal(a:n, &tabstop)
+ exe 'set tabstop=' . l:old_tabstop
+ else
+ " :retab does not change 'tabstop' with empty or n <= 0.
+ call assert_equal(l:old_tabstop, &tabstop)
+ endif
+ return l:line
+endfunc
+
+func Test_retab()
+ set tabstop=8 noexpandtab
+ call assert_equal("\ta\t b c ", Retab('', ''))
+ call assert_equal("\ta\t b c ", Retab('', 0))
+ call assert_equal("\ta\t b c ", Retab('', 8))
+ call assert_equal("\ta\t b\t c\t ", Retab('!', ''))
+ call assert_equal("\ta\t b\t c\t ", Retab('!', 0))
+ call assert_equal("\ta\t b\t c\t ", Retab('!', 8))
+
+ call assert_equal("\t\ta\t\t\tb c ", Retab('', 4))
+ call assert_equal("\t\ta\t\t\tb\t\t c\t ", Retab('!', 4))
+
+ call assert_equal(" a\t\tb c ", Retab('', 10))
+ call assert_equal(" a\t\tb c ", Retab('!', 10))
+
+ set tabstop=8 expandtab
+ call assert_equal(" a b c ", Retab('', ''))
+ call assert_equal(" a b c ", Retab('', 0))
+ call assert_equal(" a b c ", Retab('', 8))
+ call assert_equal(" a b c ", Retab('!', ''))
+ call assert_equal(" a b c ", Retab('!', 0))
+ call assert_equal(" a b c ", Retab('!', 8))
+
+ call assert_equal(" a b c ", Retab(' ', 4))
+ call assert_equal(" a b c ", Retab('!', 4))
+
+ call assert_equal(" a b c ", Retab(' ', 10))
+ call assert_equal(" a b c ", Retab('!', 10))
+
+ set tabstop=4 noexpandtab
+ call assert_equal("\ta\t\tb c ", Retab('', ''))
+ call assert_equal("\ta\t\tb\t\t c\t ", Retab('!', ''))
+ call assert_equal("\t a\t\t\tb c ", Retab('', 3))
+ call assert_equal("\t a\t\t\tb\t\t\tc\t ", Retab('!', 3))
+ call assert_equal(" a\t b c ", Retab('', 5))
+ call assert_equal(" a\t b\t\t c\t ", Retab('!', 5))
+
+ set tabstop=4 expandtab
+ call assert_equal(" a b c ", Retab('', ''))
+ call assert_equal(" a b c ", Retab('!', ''))
+ call assert_equal(" a b c ", Retab('', 3))
+ call assert_equal(" a b c ", Retab('!', 3))
+ call assert_equal(" a b c ", Retab('', 5))
+ call assert_equal(" a b c ", Retab('!', 5))
+endfunc
+
+func Test_retab_error()
+ call assert_fails('retab -1', 'E487:')
+ call assert_fails('retab! -1', 'E487:')
+endfunc
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
new file mode 100644
index 0000000000..2b8849f488
--- /dev/null
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -0,0 +1,43 @@
+" Tests for 'virtualedit'.
+
+func Test_yank_move_change()
+ new
+ call setline(1, [
+ \ "func foo() error {",
+ \ "\tif n, err := bar();",
+ \ "\terr != nil {",
+ \ "\t\treturn err",
+ \ "\t}",
+ \ "\tn = n * n",
+ \ ])
+ set virtualedit=all
+ set ts=4
+ function! MoveSelectionDown(count) abort
+ normal! m`
+ silent! exe "'<,'>move'>+".a:count
+ norm! ``
+ endfunction
+
+ xmap ]e :<C-U>call MoveSelectionDown(v:count1)<CR>
+ 2
+ normal 2gg
+ normal J
+ normal jVj
+ normal ]e
+ normal ce
+ bwipe!
+ set virtualedit=
+ set ts=8
+endfunc
+
+func Test_paste_end_of_line()
+ new
+ set virtualedit=all
+ call setline(1, ['456', '123'])
+ normal! gg0"ay$
+ exe "normal! 2G$lllA\<C-O>:normal! \"agP\r"
+ call assert_equal('123456', getline(2))
+
+ bwipe!
+ set virtualedit=
+endfunc
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 8cb59ca32a..1694adbd32 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -1,13 +1,13 @@
-" Tests for Visual mode
-if !has('multi_byte')
- finish
-endif
-
+" Tests for various Visual mode.
if !has('visual')
finish
endif
func Test_block_shift_multibyte()
+ " Uses double-wide character.
+ if !has('multi_byte')
+ return
+ endif
split
call setline(1, ['xヹxxx', 'ヹxxx'])
exe "normal 1G0l\<C-V>jl>"
@@ -35,3 +35,11 @@ func Test_Visual_vapo()
normal vapo
bwipe!
endfunc
+
+func Test_dotregister_paste()
+ new
+ exe "norm! ihello world\<esc>"
+ norm! 0ve".p
+ call assert_equal('hello world world', getline(1))
+ q!
+endfunc
diff --git a/src/nvim/undo.h b/src/nvim/undo.h
index ab8584fbb2..802cdc5583 100644
--- a/src/nvim/undo.h
+++ b/src/nvim/undo.h
@@ -2,6 +2,7 @@
#define NVIM_UNDO_H
#include "nvim/undo_defs.h"
+#include "nvim/ex_cmds_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "undo.h.generated.h"
diff --git a/src/nvim/undo_defs.h b/src/nvim/undo_defs.h
index d841210815..6c7e2bba41 100644
--- a/src/nvim/undo_defs.h
+++ b/src/nvim/undo_defs.h
@@ -4,9 +4,10 @@
#include <time.h> // for time_t
#include "nvim/pos.h"
-#include "nvim/buffer_defs.h"
#include "nvim/mark_defs.h"
+typedef struct u_header u_header_T;
+
/* Structure to store info about the Visual area. */
typedef struct {
pos_T vi_start; /* start pos of last VIsual */
@@ -15,8 +16,9 @@ typedef struct {
colnr_T vi_curswant; /* MAXCOL from w_curswant */
} visualinfo_T;
+#include "nvim/buffer_defs.h"
+
typedef struct u_entry u_entry_T;
-typedef struct u_header u_header_T;
struct u_entry {
u_entry_T *ue_next; /* pointer to next entry in list */
linenr_T ue_top; /* number of line above undo block */
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 3382e394f8..17f60f309c 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -22,6 +22,7 @@
#include "nvim/message.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
+#include "nvim/lua/executor.h"
// version info generated by the build system
#include "auto/versiondef.h"
@@ -161,7 +162,7 @@ static const int included_patches[] = {
// 947,
// 946,
// 945,
- // 944,
+ 944,
// 943,
// 942,
// 941,
@@ -899,7 +900,7 @@ static const int included_patches[] = {
209,
208,
// 207,
- // 206,
+ 206,
205,
// 204,
// 203 NA
@@ -909,20 +910,20 @@ static const int included_patches[] = {
// 199 NA
// 198,
// 197,
- // 196,
+ 196,
195,
- // 194,
+ 194,
// 193 NA
// 192 NA
// 191 NA
190,
- // 189,
+ 189,
188,
// 187 NA
186,
// 185,
// 184,
- // 183,
+ // 183 NA
182,
181,
// 180,
@@ -965,7 +966,7 @@ static const int included_patches[] = {
143,
142,
// 141,
- // 140,
+ 140,
// 139 NA
// 138 NA
137,
@@ -987,7 +988,7 @@ static const int included_patches[] = {
121,
// 120 NA
119,
- // 118,
+ 118,
// 117 NA
116,
// 115 NA
@@ -999,12 +1000,12 @@ static const int included_patches[] = {
// 109 NA
// 108 NA
// 107 NA
- // 106,
+ 106,
// 105 NA
- // 104,
+ 104,
// 103 NA
- // 102,
- // 101,
+ 102,
+ 101,
100,
99,
// 98 NA
@@ -1109,16 +1110,6 @@ static const int included_patches[] = {
};
// clang-format on
-/// Place to put a short description when adding a feature with a patch.
-/// Keep it short, e.g.,: "relative numbers", "persistent undo".
-/// Also add a comment marker to separate the lines.
-/// See the official Vim patches for the diff format: It must use a context of
-/// one line only. Create it by hand or use "diff -C2" and edit the patch.
-static char *(extra_patches[]) = {
- // Add your patch description below this line
- NULL
-};
-
/// Compares a version string to the current Nvim version.
///
/// @param version Version string like "1.3.42"
@@ -1253,27 +1244,24 @@ static void list_features(void)
MSG_PUTS("See \":help feature-compile\"\n\n");
}
+void list_lua_version(void)
+{
+ typval_T luaver_tv;
+ typval_T arg = { .v_type = VAR_UNKNOWN }; // No args.
+ char *luaver_expr = "((jit and jit.version) and jit.version or _VERSION)";
+ executor_eval_lua(cstr_as_string(luaver_expr), &arg, &luaver_tv);
+ assert(luaver_tv.v_type == VAR_STRING);
+ MSG(luaver_tv.vval.v_string);
+ xfree(luaver_tv.vval.v_string);
+}
+
void list_version(void)
{
- // When adding features here, don't forget to update the list of
- // internal variables in eval.c!
MSG(longVersion);
MSG(version_buildtype);
+ list_lua_version();
MSG(version_cflags);
- // Print the list of extra patch descriptions if there is at least one.
- char *s = "";
- if (extra_patches[0] != NULL) {
- MSG_PUTS(_("\nExtra patches: "));
- s = "";
-
- for (int i = 0; extra_patches[i] != NULL; ++i) {
- MSG_PUTS(s);
- s = ", ";
- MSG_PUTS(extra_patches[i]);
- }
- }
-
#ifdef HAVE_PATHDEF
if ((*compiled_user != NUL) || (*compiled_sys != NUL)) {
@@ -1314,6 +1302,8 @@ void list_version(void)
version_msg("\"\n");
}
#endif // ifdef HAVE_PATHDEF
+
+ version_msg("\nRun :checkhealth for more info");
}
/// Output a string for the version message. If it's going to wrap, output a
@@ -1367,7 +1357,7 @@ void intro_message(int colon)
N_("https://neovim.io/community"),
"",
N_("type :help nvim<Enter> if you are new! "),
- N_("type :CheckHealth<Enter> to optimize Nvim"),
+ N_("type :checkhealth<Enter> to optimize Nvim"),
N_("type :q<Enter> to exit "),
N_("type :help<Enter> for help "),
"",
diff --git a/src/nvim/window.c b/src/nvim/window.c
index c2d0a9b3b1..2d64409a1c 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -3747,7 +3747,9 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
do_autochdir();
if (curbuf->terminal) {
- terminal_resize(curbuf->terminal, curwin->w_width, curwin->w_height);
+ terminal_resize(curbuf->terminal,
+ (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))),
+ (uint16_t)curwin->w_height);
}
}
@@ -4946,7 +4948,9 @@ void win_new_width(win_T *wp, int width)
if (wp->w_buffer->terminal) {
if (wp->w_height != 0) {
- terminal_resize(wp->w_buffer->terminal, wp->w_width, 0);
+ terminal_resize(wp->w_buffer->terminal,
+ (uint16_t)(MAX(0, curwin->w_width - win_col_off(curwin))),
+ 0);
}
}
}