diff options
author | Daniel Carl <danielcarl@gmx.de> | 2013-10-08 00:24:35 +0200 |
---|---|---|
committer | Daniel Carl <danielcarl@gmx.de> | 2013-10-08 00:36:36 +0200 |
commit | ead4d171cd6ace5f9a6aa59ab15d2a8d1bde3fe1 (patch) | |
tree | d1f2f0b063d061c11c1d69da5fede6102e1921bf | |
parent | 9fd3263bfd4ea794dd9eb81b763b5e94dc93ddda (diff) |
Moved show command to normal.c.
We don't generate the show command for non bound mappings. This might save cpu
cycles. The show commands for the normal mode are set from the keypress
handler. So we can handle show commands like vim where an incomplete mapped
command like ':nmap foo 12g', where the '12g' should appear in show command as
incomplete command.
Now the show commands keys are displayed like in vim with <hex> for none
printable keys.
-rw-r--r-- | src/ascii.h | 4 | ||||
-rw-r--r-- | src/config.def.h | 3 | ||||
-rw-r--r-- | src/map.c | 266 | ||||
-rw-r--r-- | src/normal.c | 56 | ||||
-rw-r--r-- | src/normal.h | 1 |
5 files changed, 174 insertions, 156 deletions
diff --git a/src/ascii.h b/src/ascii.h index 8a13349..88ae8b1 100644 --- a/src/ascii.h +++ b/src/ascii.h @@ -22,8 +22,8 @@ /* CSI (control sequence introducer) is the first byte of a control sequence * and is always followed by two bytes. */ -#define CSI 0x9b -#define CSI_STR "\233" +#define CSI 0x80 +#define CSI_STR "\x80" #define IS_SPECIAL(c) (c < 0) diff --git a/src/config.def.h b/src/config.def.h index 0719fa7..3cd5876 100644 --- a/src/config.def.h +++ b/src/config.def.h @@ -33,6 +33,9 @@ * message where only temporary */ #define MESSAGE_TIMEOUT 5 +/* number of chars to be shown for ambiguous commands */ +#define SHOWCMD_LEN 10 + #define SETTING_MAX_CONNS 25 #define SETTING_MAX_CONNS_PER_HOST 5 @@ -20,6 +20,7 @@ #include "config.h" #include "main.h" #include "map.h" +#include "normal.h" #include "ascii.h" #include "mode.h" @@ -39,8 +40,6 @@ static struct { int qlen; /* pointer to last char in queue */ int resolved; /* number of resolved keys (no mapping required) */ guint timout_id; /* source id of the timeout function */ - char transchar[3]; /* buffer used to translate keys to be shown in statusbar */ - char showbuf[10]; /* buffer to shw ambiguous key sequence */ } map; static int keyval_to_string(guint keyval, guint state, guchar *string); @@ -48,12 +47,10 @@ static int utf_char2bytes(guint c, guchar *buf); static char *convert_keys(char *in, int inlen, int *len); static char *convert_keylabel(char *in, int inlen, int *len); static gboolean do_timeout(gpointer data); -static void showcmd(char *keys, int keylen); -static char* transchar(char c); static void free_map(Map *map); static struct { - guint state; + guint state; guint keyval; char one; char two; @@ -132,102 +129,6 @@ gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data) } /** - * Translate a keyvalue to utf-8 encoded and null terminated string. - * Given string must have room for 6 bytes. - */ -static int keyval_to_string(guint keyval, guint state, guchar *string) -{ - int len; - guint32 uc; - - if ((uc = gdk_keyval_to_unicode(keyval))) { - if ((state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80) { - len = 1; - if (uc >= '@') { - string[0] = uc & 0x1f; - } else if (uc == '8') { - string[0] = KEY_BS; - } else { - string[0] = uc; - } - } else { - /* translate a normal key to utf-8 */ - len = utf_char2bytes((guint)uc, string); - } - } else { - /* translate keys which are represented by ascii control codes */ - len = 1; - switch (keyval) { - case GDK_Tab: - case GDK_KP_Tab: - case GDK_ISO_Left_Tab: - string[0] = KEY_TAB; - break; - case GDK_Linefeed: - string[0] = KEY_NL; - break; - case GDK_Return: - case GDK_ISO_Enter: - case GDK_3270_Enter: - string[0] = KEY_CR; - break; - case GDK_Escape: - string[0] = KEY_ESC; - break; - case GDK_BackSpace: - string[0] = KEY_BS; - break; - default: - len = 0; - break; - } - } - - return len; -} - -static int utf_char2bytes(guint c, guchar *buf) -{ - if (c < 0x80) { - buf[0] = c; - return 1; - } - if (c < 0x800) { - buf[0] = 0xc0 + (c >> 6); - buf[1] = 0x80 + (c & 0x3f); - return 2; - } - if (c < 0x10000) { - buf[0] = 0xe0 + (c >> 12); - buf[1] = 0x80 + ((c >> 6) & 0x3f); - buf[2] = 0x80 + (c & 0x3f); - return 3; - } - if (c < 0x200000) { - buf[0] = 0xf0 + (c >> 18); - buf[1] = 0x80 + ((c >> 12) & 0x3f); - buf[2] = 0x80 + ((c >> 6) & 0x3f); - buf[3] = 0x80 + (c & 0x3f); - return 4; - } - if (c < 0x4000000) { - buf[0] = 0xf8 + (c >> 24); - buf[1] = 0x80 + ((c >> 18) & 0x3f); - buf[2] = 0x80 + ((c >> 12) & 0x3f); - buf[3] = 0x80 + ((c >> 6) & 0x3f); - buf[4] = 0x80 + (c & 0x3f); - return 5; - } - buf[0] = 0xfc + (c >> 30); - buf[1] = 0x80 + ((c >> 24) & 0x3f); - buf[2] = 0x80 + ((c >> 18) & 0x3f); - buf[3] = 0x80 + ((c >> 12) & 0x3f); - buf[4] = 0x80 + ((c >> 6) & 0x3f); - buf[5] = 0x80 + (c & 0x3f); - return 6; -} - -/** * Added the given key sequence ot the key queue and precesses the mapping of * chars. The key sequence do not need to be NUL terminated. * Keylen of 0 signalized a key timeout. @@ -293,7 +194,7 @@ MapState map_handle_keys(const guchar *keys, int keylen) /* send the key to the parser */ if (RESULT_MORE != mode_handle_key((int)qk)) { - showcmd(NULL, 0); + normal_showcmd(0); } } @@ -317,7 +218,15 @@ MapState map_handle_keys(const guchar *keys, int keylen) /* find ambiguous matches */ if (!timeout && m->inlen > map.qlen && !strncmp(m->in, map.queue, map.qlen)) { if (ambiguous == 0) { - showcmd(map.queue, map.qlen); + /* show command chars for the ambiguous commands */ + int i = map.qlen > SHOWCMD_LEN ? map.qlen - SHOWCMD_LEN : 0; + /* only appending the last queue char does not work + * with the multi char termcap entries, so we flush + * the show command and put the chars into it again */ + normal_showcmd(0); + while (i < map.qlen) { + normal_showcmd(map.queue[i++]); + } } ambiguous++; } @@ -342,6 +251,10 @@ MapState map_handle_keys(const guchar *keys, int keylen) * is the result of the mapping */ if (match) { int i, j; + /* flush ths show command to make room for possible mapped command + * chars to show for example if :nmap foo 12g is use we want to + * display the incomplete 12g command */ + normal_showcmd(0); if (match->inlen < match->mappedlen) { /* make some space within the queue */ for (i = map.qlen + match->mappedlen - match->inlen, j = map.qlen; j > match->inlen; ) { @@ -365,7 +278,6 @@ MapState map_handle_keys(const guchar *keys, int keylen) } else { /* first char is not mapped but resolved */ map.resolved = 1; - showcmd(map.queue, map.resolved); } } @@ -411,6 +323,102 @@ gboolean map_delete(char *in, char mode) } /** + * Translate a keyvalue to utf-8 encoded and null terminated string. + * Given string must have room for 6 bytes. + */ +static int keyval_to_string(guint keyval, guint state, guchar *string) +{ + int len; + guint32 uc; + + if ((uc = gdk_keyval_to_unicode(keyval))) { + if ((state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80) { + len = 1; + if (uc >= '@') { + string[0] = uc & 0x1f; + } else if (uc == '8') { + string[0] = KEY_BS; + } else { + string[0] = uc; + } + } else { + /* translate a normal key to utf-8 */ + len = utf_char2bytes((guint)uc, string); + } + } else { + /* translate keys which are represented by ascii control codes */ + len = 1; + switch (keyval) { + case GDK_Tab: + case GDK_KP_Tab: + case GDK_ISO_Left_Tab: + string[0] = KEY_TAB; + break; + case GDK_Linefeed: + string[0] = KEY_NL; + break; + case GDK_Return: + case GDK_ISO_Enter: + case GDK_3270_Enter: + string[0] = KEY_CR; + break; + case GDK_Escape: + string[0] = KEY_ESC; + break; + case GDK_BackSpace: + string[0] = KEY_BS; + break; + default: + len = 0; + break; + } + } + + return len; +} + +static int utf_char2bytes(guint c, guchar *buf) +{ + if (c < 0x80) { + buf[0] = c; + return 1; + } + if (c < 0x800) { + buf[0] = 0xc0 + (c >> 6); + buf[1] = 0x80 + (c & 0x3f); + return 2; + } + if (c < 0x10000) { + buf[0] = 0xe0 + (c >> 12); + buf[1] = 0x80 + ((c >> 6) & 0x3f); + buf[2] = 0x80 + (c & 0x3f); + return 3; + } + if (c < 0x200000) { + buf[0] = 0xf0 + (c >> 18); + buf[1] = 0x80 + ((c >> 12) & 0x3f); + buf[2] = 0x80 + ((c >> 6) & 0x3f); + buf[3] = 0x80 + (c & 0x3f); + return 4; + } + if (c < 0x4000000) { + buf[0] = 0xf8 + (c >> 24); + buf[1] = 0x80 + ((c >> 18) & 0x3f); + buf[2] = 0x80 + ((c >> 12) & 0x3f); + buf[3] = 0x80 + ((c >> 6) & 0x3f); + buf[4] = 0x80 + (c & 0x3f); + return 5; + } + buf[0] = 0xfc + (c >> 30); + buf[1] = 0x80 + ((c >> 24) & 0x3f); + buf[2] = 0x80 + ((c >> 18) & 0x3f); + buf[3] = 0x80 + ((c >> 12) & 0x3f); + buf[4] = 0x80 + ((c >> 6) & 0x3f); + buf[5] = 0x80 + (c & 0x3f); + return 6; +} + +/** * Converts a keysequence into a internal raw keysequence. * Returned keyseqence must be freed if not used anymore. */ @@ -547,56 +555,6 @@ static gboolean do_timeout(gpointer data) return false; } -/** - * Add given keys to the show command queue to show them to the user. - * If the keylen of 0 is given, the show command queue is cleared. - */ -static void showcmd(char *keys, int keylen) -{ - char *translated; - int old, extra, overflow; - - /* if we get a keylen > 1 this means we have a better match for a previous - * ambiguous key sequence and have to remove the previous one before */ - if (keylen != 1) { - map.showbuf[0] = '\0'; - } - /* show the most significant last chars in the statusbar if they don't - * fit into the showbuf */ - for (int i = 0; i < keylen; i++) { - translated = transchar(keys[i]); - old = strlen(map.showbuf); - extra = strlen(translated); - overflow = old + extra - LENGTH(map.showbuf); - if (overflow > 0) { - g_memmove(map.showbuf, map.showbuf + overflow, old - overflow + 1); - } - strcat(map.showbuf, translated); - } - /* show the typed keys */ - gtk_label_set_text(GTK_LABEL(vb.gui.statusbar.cmd), map.showbuf); -} - -/** - * Transalte a singe char into a readable representation to be show to the - * user in statu bar. - */ -static char *transchar(char c) -{ - if (IS_CTRL(c)) { - map.transchar[0] = '^'; - map.transchar[1] = CTRL(c); - map.transchar[2] = '\0'; - } else if ((c & 0xff) == CSI) { - map.transchar[0] = '~'; - map.transchar[1] = '\0'; - } else { - map.transchar[0] = c; - map.transchar[1] = '\0'; - } - return map.transchar; -} - static void free_map(Map *map) { g_free(map->in); diff --git a/src/normal.c b/src/normal.c index 6d08ec6..788f351 100644 --- a/src/normal.c +++ b/src/normal.c @@ -30,6 +30,9 @@ #include "history.h" #include "util.h" +/* convert the lower 4 bits of byte n to its hex character */ +#define NR2HEX(n) (n & 0xf) <= 9 ? (n & 0xf) + '0' : (c & 0xf) - 10 + 'a' + typedef enum { PHASE_START, PHASE_KEY2, @@ -45,6 +48,8 @@ struct NormalCmdInfo_s { typedef VbResult (*NormalCommand)(const NormalCmdInfo *info); +static char *transchar(int c); + static VbResult normal_clear_input(const NormalCmdInfo *info); static VbResult normal_descent(const NormalCmdInfo *info); static VbResult normal_ex(const NormalCmdInfo *info); @@ -201,6 +206,7 @@ static struct { extern VbCore vb; +static char showcmd_buf[SHOWCMD_LEN]; /* buffer to show ambiguous key sequence */ /** * Function called when vimb enters the normal mode. @@ -266,10 +272,60 @@ VbResult normal_keypress(int key) /* unset the info */ info.cmd = info.ncmd = info.count = 0; info.phase = PHASE_START; + } else if (res == RESULT_MORE) { + normal_showcmd(key); } return res; } +/** + * Put the given char onto the show command buffer. + */ +void normal_showcmd(int c) +{ + char *translated; + int old, extra, overflow; + + if (c) { + translated = transchar(c); + old = strlen(showcmd_buf); + extra = strlen(translated); + overflow = old + extra - SHOWCMD_LEN + 1; + if (overflow > 0) { + g_memmove(showcmd_buf, showcmd_buf + overflow, old - overflow + 1); + } + strcat(showcmd_buf, translated); + } else { + showcmd_buf[0] = '\0'; + } + /* show the typed keys */ + gtk_label_set_text(GTK_LABEL(vb.gui.statusbar.cmd), showcmd_buf); +} + +/** + * Transalte a singe char into a readable representation to be show to the + * user in status bar. + */ +static char *transchar(int c) +{ + static char trans[5]; + int i = 0; + if (IS_CTRL(c)) { + trans[i++] = '^'; + trans[i++] = CTRL(c); + } else if ((unsigned)c >= 0x80) { + trans[i++] = '<'; + trans[i++] = NR2HEX((unsigned)c >> 4); + trans[i++] = NR2HEX((unsigned)c); + trans[i++] = '>'; + } else { + trans[i++] = c; + } + trans[i++] = '\0'; + + return trans; +} + static VbResult normal_clear_input(const NormalCmdInfo *info) { vb_set_input_text(""); diff --git a/src/normal.h b/src/normal.h index 8060d2c..4da01cc 100644 --- a/src/normal.h +++ b/src/normal.h @@ -28,5 +28,6 @@ typedef struct NormalCmdInfo_s NormalCmdInfo; void normal_enter(void); void normal_leave(void); VbResult normal_keypress(int key); +void normal_showcmd(int c); #endif /* end of include guard: _NORMAL_H */ |