summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ascii.h4
-rw-r--r--src/config.def.h3
-rw-r--r--src/map.c266
-rw-r--r--src/normal.c56
-rw-r--r--src/normal.h1
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
diff --git a/src/map.c b/src/map.c
index f49ba5e..a783024 100644
--- a/src/map.c
+++ b/src/map.c
@@ -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 */