Re: PATCH: Preliminary-ish hacky implementation of custom correction keymaps
Mikael Magnusson <[email protected]>
| Newsgroups | gmane.comp.shells.zsh.devel |
|---|---|
| Message-ID | <CAHYJk3RgjUvdanrXqU9EUtL41ZkNsFudhUp0qjQFD=uPzzfypg@mail.gmail.com> |
[maybe i should have explicitly noted that this is in response to zw/51544 https://www.zsh.org/mla/workers/2023/msg00273.html since the mail i replied to is from a while ago, the archive doesn't seem to have picked up on the in-reply-to header] On Mon, May 4, 2026 at 7:04 AM Mikael Magnusson <[email protected]> wrote: > > 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 >