aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2018-03-24 17:45:48 +0100
committerGitHub <noreply@github.com>2018-03-24 17:45:48 +0100
commit6a7c904648827ec145fe02b314768453e2bbf4fe (patch)
tree6b031436f0a2027eaea0f77f1ebbd1fb1751672a /src
parent1b61167373420440535cb975804fd9e728025011 (diff)
parentd407a48665d8f8e1e42eb1060ea245d979419605 (diff)
downloadrneovim-6a7c904648827ec145fe02b314768453e2bbf4fe.tar.gz
rneovim-6a7c904648827ec145fe02b314768453e2bbf4fe.tar.bz2
rneovim-6a7c904648827ec145fe02b314768453e2bbf4fe.zip
Merge #4419 'implement <Cmd> key'
Diffstat (limited to 'src')
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/ex_docmd.c4
-rw-r--r--src/nvim/ex_getln.c8
-rw-r--r--src/nvim/getchar.c67
-rw-r--r--src/nvim/globals.h6
-rw-r--r--src/nvim/keymap.c1
-rw-r--r--src/nvim/keymap.h2
-rw-r--r--src/nvim/normal.c32
-rw-r--r--src/nvim/screen.c14
-rw-r--r--src/nvim/terminal.c4
10 files changed, 119 insertions, 23 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index cf4328fe0a..b772a944f4 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -974,6 +974,10 @@ static int insert_handle_key(InsertState *s)
multiqueue_process_events(main_loop.events);
break;
+ case K_COMMAND: // some command
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ break;
+
case K_HOME: // <Home>
case K_KHOME:
case K_S_HOME:
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index eb6d7ad815..99495aaa61 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -8156,6 +8156,10 @@ static void ex_startinsert(exarg_T *eap)
restart_edit = 'i';
curwin->w_curswant = 0; /* avoid MAXCOL */
}
+
+ if (VIsual_active) {
+ showmode();
+ }
}
/*
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 9601e0f3b2..698419405a 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -512,8 +512,12 @@ static int command_line_execute(VimState *state, int key)
CommandLineState *s = (CommandLineState *)state;
s->c = key;
- if (s->c == K_EVENT) {
- multiqueue_process_events(main_loop.events);
+ if (s->c == K_EVENT || s->c == K_COMMAND) {
+ if (s->c == K_EVENT) {
+ multiqueue_process_events(main_loop.events);
+ } else {
+ do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT);
+ }
redrawcmdline();
return 1;
}
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 7df1bf8429..5d4e61d56a 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -4247,3 +4247,70 @@ mapblock_T *get_maphash(int index, buf_T *buf)
return (buf == NULL) ? maphash[index] : buf->b_maphash[index];
}
+
+/// Get command argument for <Cmd> key
+char_u * getcmdkeycmd(int promptc, void *cookie, int indent)
+{
+ garray_T line_ga;
+ int c1 = -1, c2;
+ int cmod = 0;
+ bool aborted = false;
+
+ ga_init(&line_ga, 1, 32);
+
+ no_mapping++;
+
+ got_int = false;
+ while (c1 != NUL && !aborted) {
+ ga_grow(&line_ga, 32);
+
+ if (vgetorpeek(false) == NUL) {
+ // incomplete <Cmd> is an error, because there is not much the user
+ // could do in this state.
+ EMSG(e_cmdmap_err);
+ aborted = true;
+ break;
+ }
+
+ // Get one character at a time.
+ c1 = vgetorpeek(true);
+ // Get two extra bytes for special keys
+ if (c1 == K_SPECIAL) {
+ c1 = vgetorpeek(true); // no mapping for these chars
+ c2 = vgetorpeek(true);
+ if (c1 == KS_MODIFIER) {
+ cmod = c2;
+ continue;
+ }
+ c1 = TO_SPECIAL(c1, c2);
+ }
+
+
+ if (got_int) {
+ aborted = true;
+ } else if (c1 == '\r' || c1 == '\n') {
+ c1 = NUL; // end the line
+ } else if (c1 == ESC) {
+ aborted = true;
+ } else if (c1 == K_COMMAND) {
+ // special case to give nicer error message
+ EMSG(e_cmdmap_repeated);
+ aborted = true;
+ } else if (IS_SPECIAL(c1)) {
+ EMSG2(e_cmdmap_key, get_special_key_name(c1, cmod));
+ aborted = true;
+ } else {
+ ga_append(&line_ga, (char)c1);
+ }
+
+ cmod = 0;
+ }
+
+ no_mapping--;
+
+ if (aborted) {
+ ga_clear(&line_ga);
+ }
+
+ return (char_u *)line_ga.ga_data;
+}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 2db22f6cbf..e857f5ff5b 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -1154,6 +1154,12 @@ EXTERN char_u e_fnametoolong[] INIT(= N_("E856: Filename too long"));
EXTERN char_u e_float_as_string[] INIT(= N_("E806: using Float as a String"));
EXTERN char_u e_autocmd_err[] INIT(=N_(
"E5500: autocmd has thrown an exception: %s"));
+EXTERN char_u e_cmdmap_err[] INIT(=N_(
+ "E5520: <Cmd> mapping must end with <CR>"));
+EXTERN char_u e_cmdmap_repeated[] INIT(=N_(
+ "E5521: <Cmd> mapping must end with <CR> before second <Cmd>"));
+EXTERN char_u e_cmdmap_key[] INIT(=N_(
+ "E5522: <Cmd> mapping must not include %s key"));
EXTERN char top_bot_msg[] INIT(= N_("search hit TOP, continuing at BOTTOM"));
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 5e56e5f41b..628bfef221 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -285,6 +285,7 @@ static const struct key_name_entry {
{ K_SNR, "SNR" },
{ K_PLUG, "Plug" },
{ K_PASTE, "Paste" },
+ { K_COMMAND, "Cmd" },
{ 0, NULL }
// NOTE: When adding a long name update MAX_KEY_NAME_LEN.
};
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index 04fc93e29e..00e9cf6ed3 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -243,6 +243,7 @@ enum key_extra {
, KE_EVENT // event
, KE_PASTE // special key to toggle the 'paste' option.
// sent only by UIs
+ , KE_COMMAND // special key to execute command in any mode
};
/*
@@ -431,6 +432,7 @@ enum key_extra {
#define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT)
#define K_PASTE TERMCAP2KEY(KS_EXTRA, KE_PASTE)
+#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
/* Bits for modifier mask */
/* 0x01 cannot be used, because the modifier must be 0x02 or higher */
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index fbbc8248e8..e4310de5d8 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -345,6 +345,7 @@ static const struct nv_cmd {
{ K_F8, farsi_f8, 0, 0 },
{ K_F9, farsi_f9, 0, 0 },
{ K_EVENT, nv_event, NV_KEEPREG, 0 },
+ { K_COMMAND, nv_colon, 0, 0 },
};
/* Number of commands in nv_cmds[]. */
@@ -1473,13 +1474,13 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
AppendToRedobuffLit(cap->searchbuf, -1);
}
AppendToRedobuff(NL_STR);
- } else if (cap->cmdchar == ':') {
- /* do_cmdline() has stored the first typed line in
- * "repeat_cmdline". When several lines are typed repeating
- * won't be possible. */
- if (repeat_cmdline == NULL)
+ } else if (cap->cmdchar == ':' || cap->cmdchar == K_COMMAND) {
+ // do_cmdline() has stored the first typed line in
+ // "repeat_cmdline". When several lines are typed repeating
+ // won't be possible.
+ if (repeat_cmdline == NULL) {
ResetRedobuff();
- else {
+ } else {
AppendToRedobuffLit(repeat_cmdline, -1);
AppendToRedobuff(NL_STR);
xfree(repeat_cmdline);
@@ -4524,23 +4525,22 @@ static void nv_exmode(cmdarg_T *cap)
}
}
-/*
- * Handle a ":" command.
- */
+/// Handle a ":" command and <Cmd>.
static void nv_colon(cmdarg_T *cap)
{
int old_p_im;
bool cmd_result;
+ bool is_cmdkey = cap->cmdchar == K_COMMAND;
- if (VIsual_active)
+ if (VIsual_active && !is_cmdkey) {
nv_operator(cap);
- else {
+ } else {
if (cap->oap->op_type != OP_NOP) {
// Using ":" as a movement is characterwise exclusive.
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
- } else if (cap->count0) {
- /* translate "count:" into ":.,.+(count - 1)" */
+ } else if (cap->count0 && !is_cmdkey) {
+ // translate "count:" into ":.,.+(count - 1)"
stuffcharReadbuff('.');
if (cap->count0 > 1) {
stuffReadbuff(",.+");
@@ -4554,9 +4554,9 @@ static void nv_colon(cmdarg_T *cap)
old_p_im = p_im;
- /* get a command line and execute it */
- cmd_result = do_cmdline(NULL, getexline, NULL,
- cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
+ // get a command line and execute it
+ cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
+ cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
/* If 'insertmode' changed, enter or exit Insert mode */
if (p_im != old_p_im) {
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index e624acaed5..22de08041a 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -6748,16 +6748,20 @@ int showmode(void)
if (p_ri)
MSG_PUTS_ATTR(_(" REVERSE"), attr);
MSG_PUTS_ATTR(_(" INSERT"), attr);
- } else if (restart_edit == 'I')
+ } else if (restart_edit == 'I' || restart_edit == 'i'
+ || restart_edit == 'a') {
MSG_PUTS_ATTR(_(" (insert)"), attr);
- else if (restart_edit == 'R')
+ } else if (restart_edit == 'R') {
MSG_PUTS_ATTR(_(" (replace)"), attr);
- else if (restart_edit == 'V')
+ } else if (restart_edit == 'V') {
MSG_PUTS_ATTR(_(" (vreplace)"), attr);
- if (p_hkmap)
+ }
+ if (p_hkmap) {
MSG_PUTS_ATTR(_(" Hebrew"), attr);
- if (p_fkmap)
+ }
+ if (p_fkmap) {
MSG_PUTS_ATTR(farsi_text_5, attr);
+ }
if (State & LANGMAP) {
if (curwin->w_p_arab) {
MSG_PUTS_ATTR(_(" Arabic"), attr);
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index c5beec5a34..276b47536f 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -461,6 +461,10 @@ static int terminal_execute(VimState *state, int key)
}
break;
+ case K_COMMAND:
+ do_cmdline(NULL, getcmdkeycmd, NULL, 0);
+ break;
+
case Ctrl_N:
if (s->got_bsl) {
return 0;