Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: PATCH: Preliminary-ish hacky implementation of custom correction keymaps
- X-seq: zsh-workers 54467
- From: Mikael Magnusson <mikachu@xxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Cc: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>, Nikita Romanyuk <ufh8945@xxxxxxxxx>
- Subject: Re: PATCH: Preliminary-ish hacky implementation of custom correction keymaps
- Date: Mon, 4 May 2026 10:24:37 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=YqscPcYuA3FbEtCjyi8JzyPiDc8yGxaMoOHdFO54IX4=; fh=qNxsy9a5Gi+GQ/LgKKhXCS2vl+IL928stP+quQWFGhY=; b=QWR8H+qEeFIlNRIt2++UWXPlvxJZDqtly/dUKNjtaz3nsSyEX02QDiANarZwBrJG2K jBGvUOkHj/daGy/H3EaXTgXhzntMd/M3eXfz82Rbww1H2hiNHi+E9ZFzZxSmPlJ6jMgb G9eSmcJ8I9Bcof/04uxOVNqcVwHeym7cbvxY6rznLZto1mTx3b57gaNCFE1YrmPP2Zl0 Rdcwo41+lq0qNCbpFpqlQUrkJ58QcfJ9sbh0bdO4wkoSbE3QYxRqHeY44rxZF1dcn0qW XnyYEo9PvsXlwY4z4aYpcLMj/NCOMTfVcD1jsJARL8X7C9V4BUme5eEiSJtk03Yp01Ok 4JBQ==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1777883092; cv=none; d=google.com; s=arc-20240605; b=kVh1O97ofAK13rBOSe83E7Fj2w8NXVkPVSj6JGpgxnrRjuzkdO62rUqHrwHl48teeZ BsVQ/b6qXYPBOLVfsY9lQT2Z8xqQ4xWuBg92NtSxybytBO6Eed/sL/j4fgS/BLGnouuh PHplNG0EqrqIljDJAoziWh03ordDA26lrpJN9Qop/m/KBmz1R+XVJKBQB2+xj4O4haEX sPmQAVWWFCtaEhLcD/KRtgc4bXzyH0HTZnFIF1T8JqEmT2BBOXm5Or94TLdIHXR4Zlik HZLoa7AgQOOol5mDj/OSDnaWEF+ChkYvJO9h9SmFzce3sF2BJvtyPHEh3nhnfmO5x+X1 VrBA==
- Archived-at: <https://zsh.org/workers/54467>
- In-reply-to: <20260504050444.5106-1-mikachu@gmail.com>
- List-id: <zsh-workers.zsh.org>
- References: <CAH+w=7Y71NtPNCdpKsVo4SsdCh+dussNpvML365UOdB6urp_bw@mail.gmail.com> <20260504050444.5106-1-mikachu@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 <mikachu@xxxxxxxxx> 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
>
Messages sorted by:
Reverse Date,
Date,
Thread,
Author