Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: Preliminary-ish hacky implementation of custom correction keymaps



The name of the parameter is totally up for bikeshedding if anyone feels
like we've decided on an appropriate namespace for new parameters of
this kind. Note that this isn't actually in the zle module, though.

As you can probably guess, I got a bit tired of fiddling around with
pointers so for now the final newline has to be included. I can fix that
to be a bit more ergonomic if everyone agrees this is a good idea
overall.

This doesn't expose the weird layout of the internal keymap variables,
so you can just set 8 lines of up to 12 characters each, and all the
tabs and newline characters are filled in as appropriate (I hope). I
changed a couple of the newlines in the hardcoded strings to tabs, so
that echoing the parameter actually shows you 8 lines. If this affects
the algorithm noticably, I guess that's too bad, I didn't even try to
understand how it works :).

I guess this line implies they should be fairly interchangeable?
    if (!(z = strchr(keymap, p[0])) || *z == '\n' || *z == '\t')

Anyway, if you set the parameter to an empty value, it restores the
default according to the option, and you can also do things like
CORRECT_KEYMAP[4,6]=xyz if you want. If the range includes a newline
and you don't, that's still an error though.

---
 Src/params.c |   4 ++
 Src/utils.c  | 104 ++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 87 insertions(+), 21 deletions(-)

diff --git a/Src/params.c b/Src/params.c
index aabfc31206..e4d596a74c 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -248,6 +248,9 @@ static const struct gsu_scalar underscore_gsu =
 { underscoregetfn, nullstrsetfn, stdunsetfn };
 static const struct gsu_scalar keyboard_hack_gsu =
 { keyboardhackgetfn, keyboardhacksetfn, stdunsetfn };
+static const struct gsu_scalar correct_gsu =
+{ get_correct_keymap, set_correct_keymap, stdunsetfn };
+
 #ifdef USE_LOCALE
 static const struct gsu_scalar lc_blah_gsu =
 { strgetfn, lcsetfn, stdunsetfn };
@@ -322,6 +325,7 @@ IPDEF2("WORDCHARS", wordchars_gsu, 0),
 IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
 IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
 IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
+IPDEF2("CORRECT_KEYMAP", correct_gsu, PM_DONTIMPORT),
 IPDEF2("0", argzero_gsu, 0),
 
 #ifdef USE_LOCALE
diff --git a/Src/utils.c b/Src/utils.c
index 13752e7569..1dec76a3d1 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4694,44 +4694,106 @@ mindist(char *dir, char *mindistguess, char *mindistbest, int wantdir)
     return mindistd;
 }
 
-/**/
-static int
-spdist(char *s, char *t, int thresh)
-{
-    /* TODO: Correction for non-ASCII and multibyte-input keyboards. */
-    char *p, *q;
-    const char qwertykeymap[] =
-    "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+char qwertykeymap[] =
+"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
 \t1234567890-=\t\
 \tqwertyuiop[]\t\
-\tasdfghjkl;'\n\t\
+\tasdfghjkl;'\t\t\
 \tzxcvbnm,./\t\t\t\
 \n\n\n\n\n\n\n\n\n\n\n\n\n\n\
 \t!@#$%^&*()_+\t\
 \tQWERTYUIOP{}\t\
-\tASDFGHJKL:\"\n\t\
-\tZXCVBNM<>?\n\n\t\
+\tASDFGHJKL:\"\t\t\
+\tZXCVBNM<>?\t\t\t\
 \n\n\n\n\n\n\n\n\n\n\n\n\n\n";
-    const char dvorakkeymap[] =
-    "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+char dvorakkeymap[] =
+"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
 \t1234567890[]\t\
 \t',.pyfgcrl/=\t\
-\taoeuidhtns-\n\t\
+\taoeuidhtns-\t\t\
 \t;qjkxbmwvz\t\t\t\
 \n\n\n\n\n\n\n\n\n\n\n\n\n\n\
 \t!@#$%^&*(){}\t\
 \t\"<>PYFGCRL?+\t\
-\tAOEUIDHTNS_\n\t\
-\t:QJKXBMWVZ\n\n\t\
+\tAOEUIDHTNS_\t\t\
+\t:QJKXBMWVZ\t\t\t\
 \n\n\n\n\n\n\n\n\n\n\n\n\n\n";
-    const char *keymap;
-    if ( isset( DVORAK ) )
-      keymap = dvorakkeymap;
-    else
-      keymap = qwertykeymap;
+char *keymap = NULL;
+
+/**/
+char *
+get_correct_keymap(UNUSED(Param pm))
+{
+    if (!keymap || keymap == dvorakkeymap || keymap == qwertykeymap) {
+	keymap = isset(DVORAK) ? dvorakkeymap : qwertykeymap;
+    }
+    char pretty_keymap[13*8 + 2];
+    pretty_keymap[13*8 + 1] = '\0';
+
+    const size_t pos[] = { 14 + 1, 14*2 + 1, 14*3 + 1, 14*4 + 1, 14*6 + 1, 14*7 + 1, 14*8 + 1, 14*9 + 1 };
+    int line;
+    for (line = 0; line < 8; line++) {
+	memcpy(&pretty_keymap[13*line], &keymap[pos[line]], 12);
+	pretty_keymap[13*line + 12] = '\n';
+    }
+    return dupstring(pretty_keymap);
+}
+
+/**/
+void
+set_correct_keymap(UNUSED(Param pm), char *x)
+{
+    char *oldkeymap = keymap;
+    if (x && *x) {
+	char newkeymap[155];
+	memset(newkeymap, '\t', 154);
+	memset(&newkeymap[0], '\n', 14);
+	memset(&newkeymap[5*14], '\n', 14);
+	memset(&newkeymap[10*14], '\n', 14);
+	newkeymap[154] = '\0';
+	int line;
+	char *p = x;
+	const size_t pos[] = { 14 + 1, 14*2 + 1, 14*3 + 1, 14*4 + 1, 14*6 + 1, 14*7 + 1, 14*8 + 1, 14*9 + 1 };
+	for (line = 0; line < 8; line++) {
+	    char *end = strchr(p, '\n');
+	    if (!end) {
+		zwarn("CORRECT_KEYMAP needs to be set to 8 lines (even the last line needs a trailing newline in this rfc patch, because I'm lazy)");
+		free(x);
+		return;
+	    }
+	    if (end - p > 12) {
+		zwarn("Lines in CORRECT_KEYMAP can be at most 12 characters, line %d was longer", line + 1);
+		free(x);
+		return;
+	    }
+	    memcpy(&newkeymap[pos[line]], p, end-p);
+	    p = end+1;
+	}
+	keymap = ztrdup(newkeymap);
+	free(x);
+    } else {
+	keymap = NULL;
+    }
+    if (oldkeymap && oldkeymap != qwertykeymap && oldkeymap != dvorakkeymap)
+	free(oldkeymap);
+}
 
+/**/
+static int
+spdist(char *s, char *t, int thresh)
+{
+    /* TODO: Correction for non-ASCII and multibyte-input keyboards. */
+    char *p, *q;
     if (!strcmp(s, t))
 	return 0;
+
+    if (!keymap || keymap == dvorakkeymap || keymap == qwertykeymap) {
+	if ( isset( DVORAK ) )
+	    keymap = dvorakkeymap;
+	else
+	    keymap = qwertykeymap;
+    }
+
     /* any number of upper/lower mistakes allowed (dist = 1) */
     for (p = s, q = t; *p && tulower(*p) == tulower(*q); p++, q++);
     if (!*p && !*q)
-- 
2.38.1





Messages sorted by: Reverse Date, Date, Thread, Author