diff options
-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 */ |