feat(sterni/acme/plan9port): allow entering BQN chars via compose

plan9port completely ignores XCompose because it has its own compose
mechanism (which is mapped to the same key). The sequences are defined
in /lib/keyboard and need to be compiled in.

Support for the BQN unicode characters is achieved by generating the
necessary lines for /lib/keyboard from the .inputrc (for GNU readline)
that is part of mlochbaum/BQN (simply because that file is somewhat
parseable and stores the sequences in ASCII, contrary to .XCompose).
This is implemented by a small BQN script which is executed in
postPatch.

All usual sequences are supported except those that map to the second
ASCII character of the sequence. These exist to keep certain characters
typeable in other input system. Thanks to the explicit compose key,
Plan 9 doesn't have this problem.

Change-Id: I590c03fd69a2aae3cbbbd39ebcbce6cec0418b50
Reviewed-on: https://cl.tvl.fyi/c/depot/+/13034
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Autosubmit: sterni <sternenseemann@systemli.org>
This commit is contained in:
sterni 2025-01-21 20:23:24 +01:00 committed by clbot
parent 3b9d5a02ce
commit 9743fbf6b7
3 changed files with 91 additions and 0 deletions

View file

@ -0,0 +1,67 @@
#!/usr/bin/env BQN
# SPDX-FileCopyrightText: Copyright © 2024-2025 by sterni
# SPDX-License-Identifier: MIT
#
# Generate Compose Sequences for /lib/keyboard that enable entering BQN specific
# Unicode characters using their familiar key combinations in Plan 9 programs.
# TODO(sterni): move these helper functions somewhere reusable
LogBase ÷˜•math.Log10
Digs ( 1+)LogBase
DivMod ÷˜|
hd"0123456789ABCDEF"
ToHex {hd˜(16DivMod 1)(-1 𝕨(16Digs)) 𝕩} # 𝕨 is the min amount of digits
FromHex {+´(16𝕩)×hd𝕩}
IsAscii 127-@
# Parse CLI
opts {
flagsargs 2'-' (()¨) 𝕩
# TODO(sterni): support multiple flags in one argument, e.g. -si
sort,help,inPlace flags˜"-s","-h","-i"
argCount 2
{𝕤
•Out "Usage: "•name" [-s] [-i] /path/to/inputrc /path/to/lib/keyboard
-i Modify lib/keyboard in place. If not given, print to stdout.
-s Sort output by Unicode Codepoint."
•Exit ¬help
}(helpargCountargs) @
inputrcPathkeyboardPath •wdpath•file.At¨args
WriteOutput inPlace•out¨,keyboardPath•fLines
} •args
# Main Program
# Read inputrc, dropping comment and empty lines. Also drop the rule for \\.
# Since Plan9 requires an explicit keypress before entering a compose sequence,
# we don't need to add a way to type \ (or any ASCII character for that matter).
# This simplifies the parser below since we don't need to unescape anything.
inputrc1(("#"(1)0)¨/)•FLines opts.inputrcPath
# After removing all backslashes, the ASCII character used representing the used
# key and the resulting codepoint have a consistent position in the lines.
# Remove all ASCII chars in a second step.
# map contains pairs of ⟨BQN char, key used to type it as an ASCII char⟩
map(¬IsAscii¨/)51¨'\'(/)¨inputrc
# Render the first three fields of lib/keyboard:
# ⟨Codepoint (Hex), Compose Sequence, Resulting Character⟩
newfields{𝕊 ck: 4 ToHex c-@,"\"k,c}¨map
# In the file, the fields need be padded to a specific length…
fieldsz6120´˘¨>newfields
# … and there's a fourth name field separated by a tab.
# We don't make an effort to add a per character description there (yet).
tab@+9
newlines((tab"BQN char") ´fieldsz(¨))¨ newfields
# Due to the consistent spacing we can just compute the sort order on the
# resulting character at index 18.
Sort ( 18¨)
# Deduplicate output before writing, so the script can be executed multiple
# times or after inputrc has been changed without introducing duplicates. Since
# we duplicate on entire lines, existing alternative compose sequences aren't
# removed.
opts.WriteOutput Sortopts.sort (•FLines opts.keyboardPath)newlines

View file

@ -7,10 +7,18 @@ let
(lib.mapAttrsToList
(name: _: dir + "/${name}")
(builtins.readDir dir));
mkbqnkeyboard' = pkgs.writeShellScript "mkbqnkeyboard'" ''
exec ${pkgs.cbqn}/bin/BQN ${../mkbqnkeyboard.bqn} -s -i \
"${pkgs.srcOnly pkgs.mbqn}/editors/inputrc" "$1"
'';
in
pkgs.plan9port.overrideAttrs (old: {
patches = old.patches or [ ] ++ patchesFromDir ./.;
postPatch = old.postPatch or "" + ''
${mkbqnkeyboard'} lib/keyboard
'';
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [
pkgs.buildPackages.makeWrapper

View file

@ -0,0 +1,16 @@
All BQN character compose sequence use the same leading character (\). Since there
are about 80 of them, the standard lookup table size is not enough.
diff --git a/src/cmd/devdraw/latin1.c b/src/cmd/devdraw/latin1.c
index 87c0be45..c8e79e33 100644
--- a/src/cmd/devdraw/latin1.c
+++ b/src/cmd/devdraw/latin1.c
@@ -10,7 +10,7 @@ static struct cvlist
{
char *ld; /* must be seen before using this conversion */
char *si; /* options for last input characters */
- Rune so[60]; /* the corresponding Rune for each si entry */
+ Rune so[100]; /* the corresponding Rune for each si entry */
} latintab[] = {
#include "latin1.h"
0, 0, { 0 }