aboutsummaryrefslogtreecommitdiff
path: root/src/nvim
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim')
-rw-r--r--src/nvim/api/vim.c8
-rw-r--r--src/nvim/arglist.c167
-rw-r--r--src/nvim/ex_docmd.c39
-rw-r--r--src/nvim/memory.c18
-rw-r--r--src/nvim/option_defs.h1
-rw-r--r--src/nvim/options.lua8
-rw-r--r--src/nvim/os/input.c6
-rw-r--r--src/nvim/popupmenu.c7
-rw-r--r--src/nvim/tui/input.c7
-rw-r--r--src/nvim/tui/tui.c27
10 files changed, 172 insertions, 116 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 83d6ba8dc7..95c9919522 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -336,9 +336,9 @@ Integer nvim_input(String keys)
/// mouse input in a GUI. The deprecated pseudokey form
/// ("<LeftMouse><col,row>") of |nvim_input()| has the same limitation.
///
-/// @param button Mouse button: one of "left", "right", "middle", "wheel".
+/// @param button Mouse button: one of "left", "right", "middle", "wheel", "move".
/// @param action For ordinary buttons, one of "press", "drag", "release".
-/// For the wheel, one of "up", "down", "left", "right".
+/// For the wheel, one of "up", "down", "left", "right". Ignored for "move".
/// @param modifier String of modifiers each represented by a single char.
/// The same specifiers are used as for a key press, except
/// that the "-" separator is optional, so "C-A-", "c-a"
@@ -365,6 +365,8 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri
code = KE_RIGHTMOUSE;
} else if (strequal(button.data, "wheel")) {
code = KE_MOUSEDOWN;
+ } else if (strequal(button.data, "move")) {
+ code = KE_MOUSEMOVE;
} else {
goto error;
}
@@ -381,7 +383,7 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri
} else {
goto error;
}
- } else {
+ } else if (code != KE_MOUSEMOVE) {
if (strequal(action.data, "press")) {
// pass
} else if (strequal(action.data, "drag")) {
diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c
index 70b2e71949..e6ac1f6247 100644
--- a/src/nvim/arglist.c
+++ b/src/nvim/arglist.c
@@ -79,11 +79,12 @@ void alist_expand(int *fnum_list, int fnum_len)
{
char *save_p_su = p_su;
+ char **old_arg_files = xmalloc(sizeof(*old_arg_files) * GARGCOUNT);
+
// Don't use 'suffixes' here. This should work like the shell did the
// expansion. Also, the vimrc file isn't read yet, thus the user
// can't set the options.
p_su = empty_option;
- char **old_arg_files = xmalloc(sizeof(*old_arg_files) * GARGCOUNT);
for (int i = 0; i < GARGCOUNT; i++) {
old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname);
}
@@ -308,6 +309,50 @@ static void alist_add_list(int count, char **files, int after, bool will_edit)
}
}
+/// Delete the file names in "alist_ga" from the argument list.
+static void arglist_del_files(garray_T *alist_ga)
+{
+ regmatch_T regmatch;
+
+ // Delete the items: use each item as a regexp and find a match in the
+ // argument list.
+ regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set
+ for (int i = 0; i < alist_ga->ga_len && !got_int; i++) {
+ char *p = ((char **)alist_ga->ga_data)[i];
+ p = file_pat_to_reg_pat(p, NULL, NULL, false);
+ if (p == NULL) {
+ break;
+ }
+ regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
+ if (regmatch.regprog == NULL) {
+ xfree(p);
+ break;
+ }
+
+ bool didone = false;
+ for (int match = 0; match < ARGCOUNT; match++) {
+ if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]), (colnr_T)0)) {
+ didone = true;
+ xfree(ARGLIST[match].ae_fname);
+ memmove(ARGLIST + match, ARGLIST + match + 1,
+ (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T));
+ ALIST(curwin)->al_ga.ga_len--;
+ if (curwin->w_arg_idx > match) {
+ curwin->w_arg_idx--;
+ }
+ match--;
+ }
+ }
+
+ vim_regfree(regmatch.regprog);
+ xfree(p);
+ if (!didone) {
+ semsg(_(e_nomatch2), ((char **)alist_ga->ga_data)[i]);
+ }
+ }
+ ga_clear(alist_ga);
+}
+
/// @param str
/// @param what
/// AL_SET: Redefine the argument list to 'str'.
@@ -324,8 +369,6 @@ static int do_arglist(char *str, int what, int after, bool will_edit)
garray_T new_ga;
int exp_count;
char **exp_files;
- char *p;
- int match;
int arg_escaped = true;
// Set default argument for ":argadd" command.
@@ -341,46 +384,7 @@ static int do_arglist(char *str, int what, int after, bool will_edit)
get_arglist(&new_ga, str, arg_escaped);
if (what == AL_DEL) {
- regmatch_T regmatch;
- bool didone;
-
- // Delete the items: use each item as a regexp and find a match in the
- // argument list.
- regmatch.rm_ic = p_fic; // ignore case when 'fileignorecase' is set
- for (int i = 0; i < new_ga.ga_len && !got_int; i++) {
- p = ((char **)new_ga.ga_data)[i];
- p = file_pat_to_reg_pat(p, NULL, NULL, false);
- if (p == NULL) {
- break;
- }
- regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
- if (regmatch.regprog == NULL) {
- xfree(p);
- break;
- }
-
- didone = false;
- for (match = 0; match < ARGCOUNT; match++) {
- if (vim_regexec(&regmatch, alist_name(&ARGLIST[match]), (colnr_T)0)) {
- didone = true;
- xfree(ARGLIST[match].ae_fname);
- memmove(ARGLIST + match, ARGLIST + match + 1,
- (size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T));
- ALIST(curwin)->al_ga.ga_len--;
- if (curwin->w_arg_idx > match) {
- curwin->w_arg_idx--;
- }
- match--;
- }
- }
-
- vim_regfree(regmatch.regprog);
- xfree(p);
- if (!didone) {
- semsg(_(e_nomatch2), ((char **)new_ga.ga_data)[i]);
- }
- }
- ga_clear(&new_ga);
+ arglist_del_files(&new_ga);
} else {
int i = expand_wildcards(new_ga.ga_len, new_ga.ga_data,
&exp_count, &exp_files,
@@ -471,22 +475,27 @@ void ex_args(exarg_T *eap)
ex_next(eap);
} else if (eap->cmdidx == CMD_args) {
// ":args": list arguments.
- if (ARGCOUNT > 0) {
- char **items = xmalloc(sizeof(char *) * (size_t)ARGCOUNT);
- // Overwrite the command, for a short list there is no scrolling
- // required and no wait_return().
- gotocmdline(true);
- for (int i = 0; i < ARGCOUNT; i++) {
- items[i] = alist_name(&ARGLIST[i]);
- }
- list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
- xfree(items);
+ if (ARGCOUNT <= 0) {
+ return;
}
+
+ char **items = xmalloc(sizeof(char *) * (size_t)ARGCOUNT);
+
+ // Overwrite the command, for a short list there is no scrolling
+ // required and no wait_return().
+ gotocmdline(true);
+
+ for (int i = 0; i < ARGCOUNT; i++) {
+ items[i] = alist_name(&ARGLIST[i]);
+ }
+ list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
+ xfree(items);
} else if (eap->cmdidx == CMD_arglocal) {
garray_T *gap = &curwin->w_alist->al_ga;
// ":argslocal": make a local copy of the global argument list.
ga_grow(gap, GARGCOUNT);
+
for (int i = 0; i < GARGCOUNT; i++) {
if (GARGLIST[i].ae_fname != NULL) {
AARGLIST(curwin->w_alist)[gap->ga_len].ae_fname = xstrdup(GARGLIST[i].ae_fname);
@@ -1126,31 +1135,33 @@ void f_argv(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
aentry_T *arglist = NULL;
int argcount = -1;
- if (argvars[0].v_type != VAR_UNKNOWN) {
- if (argvars[1].v_type == VAR_UNKNOWN) {
- arglist = ARGLIST;
- argcount = ARGCOUNT;
- } else if (argvars[1].v_type == VAR_NUMBER
- && tv_get_number(&argvars[1]) == -1) {
- arglist = GARGLIST;
- argcount = GARGCOUNT;
- } else {
- win_T *wp = find_win_by_nr_or_id(&argvars[1]);
- if (wp != NULL) {
- // Use the argument list of the specified window
- arglist = WARGLIST(wp);
- argcount = WARGCOUNT(wp);
- }
- }
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- int idx = (int)tv_get_number_chk(&argvars[0], NULL);
- if (arglist != NULL && idx >= 0 && idx < argcount) {
- rettv->vval.v_string = xstrdup((const char *)alist_name(&arglist[idx]));
- } else if (idx == -1) {
- get_arglist_as_rettv(arglist, argcount, rettv);
- }
- } else {
+ if (argvars[0].v_type == VAR_UNKNOWN) {
get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
+ return;
+ }
+
+ if (argvars[1].v_type == VAR_UNKNOWN) {
+ arglist = ARGLIST;
+ argcount = ARGCOUNT;
+ } else if (argvars[1].v_type == VAR_NUMBER
+ && tv_get_number(&argvars[1]) == -1) {
+ arglist = GARGLIST;
+ argcount = GARGCOUNT;
+ } else {
+ win_T *wp = find_win_by_nr_or_id(&argvars[1]);
+ if (wp != NULL) {
+ // Use the argument list of the specified window
+ arglist = WARGLIST(wp);
+ argcount = WARGCOUNT(wp);
+ }
+ }
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ int idx = (int)tv_get_number_chk(&argvars[0], NULL);
+ if (arglist != NULL && idx >= 0 && idx < argcount) {
+ rettv->vval.v_string = xstrdup((const char *)alist_name(&arglist[idx]));
+ } else if (idx == -1) {
+ get_arglist_as_rettv(arglist, argcount, rettv);
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 6517ebd081..8fb166d2c9 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5544,27 +5544,26 @@ void ex_cd(exarg_T *eap)
// for non-UNIX ":cd" means: print current directory unless 'cdhome' is set
if (*new_dir == NUL && !p_cdh) {
ex_pwd(NULL);
- } else
+ return;
+ }
#endif
- {
- CdScope scope = kCdScopeGlobal;
- switch (eap->cmdidx) {
- case CMD_tcd:
- case CMD_tchdir:
- scope = kCdScopeTabpage;
- break;
- case CMD_lcd:
- case CMD_lchdir:
- scope = kCdScopeWindow;
- break;
- default:
- break;
- }
- if (changedir_func(new_dir, scope)) {
- // Echo the new current directory if the command was typed.
- if (KeyTyped || p_verbose >= 5) {
- ex_pwd(eap);
- }
+ CdScope scope = kCdScopeGlobal;
+ switch (eap->cmdidx) {
+ case CMD_tcd:
+ case CMD_tchdir:
+ scope = kCdScopeTabpage;
+ break;
+ case CMD_lcd:
+ case CMD_lchdir:
+ scope = kCdScopeWindow;
+ break;
+ default:
+ break;
+ }
+ if (changedir_func(new_dir, scope)) {
+ // Echo the new current directory if the command was typed.
+ if (KeyTyped || p_verbose >= 5) {
+ ex_pwd(eap);
}
}
}
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index e5fea027cb..03cfde6160 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -506,16 +506,18 @@ bool striequal(const char *a, const char *b)
// Did_outofmem_msg is reset when a character is read.
void do_outofmem_msg(size_t size)
{
- if (!did_outofmem_msg) {
- // Don't hide this message
- emsg_silent = 0;
+ if (did_outofmem_msg) {
+ return;
+ }
- /* Must come first to avoid coming back here when printing the error
- * message fails, e.g. when setting v:errmsg. */
- did_outofmem_msg = true;
+ // Don't hide this message
+ emsg_silent = 0;
- semsg(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), (uint64_t)size);
- }
+ // Must come first to avoid coming back here when printing the error
+ // message fails, e.g. when setting v:errmsg.
+ did_outofmem_msg = true;
+
+ semsg(_("E342: Out of memory! (allocating %" PRIu64 " bytes)"), (uint64_t)size);
}
/// Writes time_t to "buf[8]".
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index bfac0cff87..64b3f69df4 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -616,6 +616,7 @@ EXTERN int p_ma; ///< 'modifiable'
EXTERN int p_mod; ///< 'modified'
EXTERN char *p_mouse; // 'mouse'
EXTERN char *p_mousem; // 'mousemodel'
+EXTERN int p_mousemev; ///< 'mousemoveevent'
EXTERN int p_mousef; // 'mousefocus'
EXTERN char *p_mousescroll; // 'mousescroll'
EXTERN long p_mousescroll_vert INIT(= MOUSESCROLL_VERT_DFLT);
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 2f941f5d0c..717ca6747b 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1622,6 +1622,14 @@ return {
defaults={if_true="popup_setpos"}
},
{
+ full_name='mousemoveevent', abbreviation='mousemev',
+ short_desc=N_("deliver mouse move events to input queue"),
+ type='bool', scope={'global'},
+ redraw={'ui_option'},
+ varname='p_mousemev',
+ defaults={if_true=false}
+ },
+ {
full_name='mousescroll',
short_desc=N_("amount to scroll by when scrolling with a mouse"),
type='string', list='comma', scope={'global'},
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index bfe6d59dc6..ea9f31d776 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -293,7 +293,8 @@ static uint8_t check_multiclick(int code, int grid, int row, int col)
|| code == KE_MOUSEDOWN
|| code == KE_MOUSEUP
|| code == KE_MOUSELEFT
- || code == KE_MOUSERIGHT) {
+ || code == KE_MOUSERIGHT
+ || code == KE_MOUSEMOVE) {
return 0;
}
uint64_t mouse_time = os_hrtime(); // time of current mouse click (ns)
@@ -347,7 +348,8 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bu
if (type != KS_EXTRA
|| !((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE)
- || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) {
+ || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT)
+ || mouse_code == KE_MOUSEMOVE)) {
return bufsize;
}
diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c
index 0d9080ceb7..4de3713f4f 100644
--- a/src/nvim/popupmenu.c
+++ b/src/nvim/popupmenu.c
@@ -1045,6 +1045,10 @@ void pum_show_popupmenu(vimmenu_T *menu)
pum_selected = -1;
pum_first = 0;
+ if (!p_mousemev) {
+ // Pretend 'mousemoveevent' is set.
+ ui_call_option_set(STATIC_CSTR_AS_STRING("mousemoveevent"), BOOLEAN_OBJ(true));
+ }
for (;;) {
pum_is_visible = true;
@@ -1102,6 +1106,9 @@ void pum_show_popupmenu(vimmenu_T *menu)
xfree(array);
pum_undisplay(true);
+ if (!p_mousemev) {
+ ui_call_option_set(STATIC_CSTR_AS_STRING("mousemoveevent"), BOOLEAN_OBJ(false));
+ }
}
void pum_make_popup(const char *path_name, int use_mouse_pos)
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index d269878f46..728520c20c 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -406,8 +406,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
}
}
- if (button == 0 || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG
- && ev != TERMKEY_MOUSE_RELEASE)) {
+ if ((button == 0 && ev != TERMKEY_MOUSE_RELEASE)
+ || (ev != TERMKEY_MOUSE_PRESS && ev != TERMKEY_MOUSE_DRAG && ev != TERMKEY_MOUSE_RELEASE)) {
return;
}
@@ -453,7 +453,8 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag");
break;
case TERMKEY_MOUSE_RELEASE:
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release");
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, button ? "Release" : "MouseMove");
+ last_pressed_button = 0;
break;
case TERMKEY_MOUSE_UNKNOWN:
abort();
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 38e8c15762..471a3fb859 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -103,6 +103,7 @@ struct TUIData {
bool immediate_wrap_after_last_column;
bool bce;
bool mouse_enabled;
+ bool mouse_move_enabled;
bool busy, is_invisible, want_invisible;
bool cork, overflow;
bool cursor_color_changed;
@@ -117,6 +118,7 @@ struct TUIData {
ModeShape showing_mode;
struct {
int enable_mouse, disable_mouse;
+ int enable_mouse_move, disable_mouse_move;
int enable_bracketed_paste, disable_bracketed_paste;
int enable_lr_margin, disable_lr_margin;
int enter_strikethrough_mode;
@@ -236,6 +238,8 @@ static void terminfo_start(UI *ui)
data->showing_mode = SHAPE_IDX_N;
data->unibi_ext.enable_mouse = -1;
data->unibi_ext.disable_mouse = -1;
+ data->unibi_ext.enable_mouse_move = -1;
+ data->unibi_ext.disable_mouse_move = -1;
data->unibi_ext.set_cursor_color = -1;
data->unibi_ext.reset_cursor_color = -1;
data->unibi_ext.enable_bracketed_paste = -1;
@@ -1138,6 +1142,9 @@ static void tui_mouse_on(UI *ui)
TUIData *data = ui->data;
if (!data->mouse_enabled) {
unibi_out_ext(ui, data->unibi_ext.enable_mouse);
+ if (data->mouse_move_enabled) {
+ unibi_out_ext(ui, data->unibi_ext.enable_mouse_move);
+ }
data->mouse_enabled = true;
}
}
@@ -1146,6 +1153,9 @@ static void tui_mouse_off(UI *ui)
{
TUIData *data = ui->data;
if (data->mouse_enabled) {
+ if (data->mouse_move_enabled) {
+ unibi_out_ext(ui, data->unibi_ext.disable_mouse_move);
+ }
unibi_out_ext(ui, data->unibi_ext.disable_mouse);
data->mouse_enabled = false;
}
@@ -1457,9 +1467,18 @@ static void tui_screenshot(UI *ui, String path)
static void tui_option_set(UI *ui, String name, Object value)
{
TUIData *data = ui->data;
- if (strequal(name.data, "termguicolors")) {
+ if (strequal(name.data, "mousemoveevent")) {
+ if (data->mouse_move_enabled != value.data.boolean) {
+ if (data->mouse_enabled) {
+ tui_mouse_off(ui);
+ data->mouse_move_enabled = value.data.boolean;
+ tui_mouse_on(ui);
+ } else {
+ data->mouse_move_enabled = value.data.boolean;
+ }
+ }
+ } else if (strequal(name.data, "termguicolors")) {
ui->rgb = value.data.boolean;
-
data->print_attr_id = -1;
invalidate(ui, 0, data->grid.height, 0, data->grid.width);
} else if (strequal(name.data, "ttimeout")) {
@@ -2135,6 +2154,10 @@ static void augment_terminfo(TUIData *data, const char *term, long vte_version,
"\x1b[?1002h\x1b[?1006h");
data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, "ext.disable_mouse",
"\x1b[?1002l\x1b[?1006l");
+ data->unibi_ext.enable_mouse_move = (int)unibi_add_ext_str(ut, "ext.enable_mouse_move",
+ "\x1b[?1003h");
+ data->unibi_ext.disable_mouse_move = (int)unibi_add_ext_str(ut, "ext.disable_mouse_move",
+ "\x1b[?1003l");
// Extended underline.
// terminfo will have Smulx for this (but no support for colors yet).