basedpl 0.1.81 → 0.1.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/basedpl_wasm_bg.wasm +0 -0
- package/browser/bpl-editor.js +32 -0
- package/{input.js → browser/input.js} +2 -2
- package/browser/language.js +3 -0
- package/{lb.js → browser/lb.js} +42 -41
- package/package.json +10 -2
- package/bpl-editor.js +0 -476
- /package/{SAX2B.woff2 → browser/SAX2B.woff2} +0 -0
- /package/{layout.json → browser/layout.json} +0 -0
package/README.md
CHANGED
|
@@ -11,3 +11,14 @@ new Session().run('avg←+/÷≢ ⋄ avg 2 4 9', output => console.log(output.da
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
[BPL on the web](https://answerdotai.github.io/basedpl/web.html) documents this package: loading it, its outputs, values and JavaScript functions, drawing, the language bar, and how the gallery is built. The [playground](https://answerdotai.github.io/basedpl/playground.html) and [gallery](https://answerdotai.github.io/basedpl/gallery.html) run BPL in your browser. The [BPL documentation](https://answerdotai.github.io/basedpl/) covers the language.
|
|
14
|
+
|
|
15
|
+
The symbol bar and font need no interpreter or WebAssembly:
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<script type="module">
|
|
19
|
+
import {install} from 'https://cdn.jsdelivr.net/npm/basedpl/browser/bpl-editor.js';
|
|
20
|
+
install();
|
|
21
|
+
</script>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`install()` mounts in `#bpl-toolbar` when the host supplies that slot. Otherwise the same component overlays the top of the page without moving its content. The arrow button remembers collapse state without disabling keyboard entry. Repeated calls reuse the connected controller; call its `dispose()` when the host page closes. Importing the module alone does not mount a bar; it also exports `grammar`, `configuration`, `editorOptions` and `installFont()` for editor/highlighter integrations.
|
package/basedpl_wasm_bg.wasm
CHANGED
|
Binary file
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {grammar, symbols} from './language.js';
|
|
2
|
+
import input from './input.js';
|
|
3
|
+
import languageBar from './lb.js';
|
|
4
|
+
import layout from './layout.json' with {type: 'json'};
|
|
5
|
+
|
|
6
|
+
export {grammar};
|
|
7
|
+
export const configuration = {
|
|
8
|
+
comments: {lineComment: '⍝'}, brackets: [['(', ')'], ['[', ']'], ['{', '}']],
|
|
9
|
+
autoClosingPairs: [['(', ')'], ['[', ']'], ['{', '}'], ['"', '"'], ["'", "'"]].map(([open, close]) => ({open, close, notIn: ['string', 'comment']})),
|
|
10
|
+
surroundingPairs: [['(', ')'], ['[', ']'], ['{', '}'], ['"', '"'], ["'", "'"]].map(([open, close]) => ({open, close})),
|
|
11
|
+
};
|
|
12
|
+
export const editorOptions = {fontFamily: 'SAX2B, monospace', unicodeHighlight: {ambiguousCharacters: false}};
|
|
13
|
+
const font = new URL('./SAX2B.woff2', import.meta.url);
|
|
14
|
+
const mount = languageBar(symbols, input, layout, editorOptions);
|
|
15
|
+
|
|
16
|
+
export function installFont(doc = document) {
|
|
17
|
+
if (doc.getElementById('bpl-font')) return;
|
|
18
|
+
const style = doc.createElement('style');
|
|
19
|
+
style.id = 'bpl-font';
|
|
20
|
+
style.textContent = `@font-face{font-family:SAX2B;src:url("${font}") format("woff2")}`;
|
|
21
|
+
doc.head.append(style);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function install() {
|
|
25
|
+
if (window.bplInput?.element.isConnected) { window.bplInput.fonts(); return window.bplInput; }
|
|
26
|
+
window.bplInput?.dispose();
|
|
27
|
+
installFont();
|
|
28
|
+
const container = document.getElementById('bpl-toolbar');
|
|
29
|
+
window.bplInput = mount(container || document.body);
|
|
30
|
+
if (!container) window.bplInput.element.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:2147483647';
|
|
31
|
+
return window.bplInput;
|
|
32
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(
|
|
1
|
+
export default (symbols, layout) => {
|
|
2
2
|
const comments = new Set(symbols.filter(s => s.kind === 'comment').flatMap(s => [...s.glyph, ...s.hanzi.join('')]));
|
|
3
3
|
// US physical keys, before macOS Option or another layout transforms event.key.
|
|
4
4
|
const punctuation = {Backquote: '`~', Minus: '-_', Equal: '=+', BracketLeft: '[{', BracketRight: ']}',
|
|
@@ -107,4 +107,4 @@
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
return {matches, inCode, bplStart, entry, press, reset};
|
|
110
|
-
}
|
|
110
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Generated by basedpl.editors.browser.
|
|
2
|
+
export const grammar = {"name": "bpl", "displayName": "BPL", "scopeName": "source.bpl", "fileTypes": ["bpl"], "patterns": [{"begin": "[⍝]", "beginCaptures": {"0": {"name": "comment.line.bpl"}}, "end": "$", "contentName": "comment.line.bpl", "patterns": [], "applyEndPatternLast": true}, {"begin": "\"", "beginCaptures": {"0": {"name": "string.quoted.double.bpl"}}, "end": "\"|$", "contentName": "string.quoted.double.bpl", "patterns": [{"match": "\"\"", "name": "string.quoted.double.bpl"}], "applyEndPatternLast": true, "endCaptures": {"0": {"name": "string.quoted.double.bpl"}}}, {"match": "'.?'", "name": "string.quoted.single.bpl"}, {"match": "(?:_\\d+|_\\S|_|[^\\s\\p{Cc}0-9←⎕•⍺⍵⍶⍹∇⍢⍝⋄⁝\\?¯∞⍬\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳↦:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿¨ᵇ⍨↣⍤∘⍠⍥↢\\.⊗⌸⍣⇄⊘@∂⍚⌺/⌿\\\\⍀⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ₀₁₂₃₄₅₆₇₈₉₋ₓ₁ₓ₂ₓ₄ₓ₈ₓₕₛₚ\\(\\)\\[\\]\\{\\}'\";\\$_ₑⱼᵣ])+", "name": "variable.other.bpl"}, {"match": "[•][A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*", "name": "support.function.bpl"}, {"match": "(?:[¯]?[∞]|[¯]?(\\d+([.]\\d+)?|[.]\\d+)([eEₑ][¯]?\\d+)?([jJⱼ][¯]?(\\d+([.]\\d+)?|[.]\\d+)([eEₑ][¯]?\\d+)?|[rᵣ][¯]?\\d+)?)(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)?|[ₑⱼᵣ]", "name": "constant.numeric.bpl"}, {"match": "[⍬](?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)?", "name": "constant.numeric.bpl"}, {"match": "\\$[tfn]", "name": "constant.numeric.bpl"}, {"match": "\\$[ad]", "name": "string.quoted.double.bpl"}, {"begin": "[\\])](?=(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ))", "beginCaptures": {"0": {"name": "source.bpl"}}, "end": "(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)|$", "contentName": "constant.numeric.bpl", "patterns": [], "applyEndPatternLast": true, "endCaptures": {"0": {"name": "constant.numeric.bpl"}}}, {"match": "[\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳↦:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿]", "name": "support.function.bpl"}, {"match": "(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)", "name": "keyword.operator.monadic.bpl"}, {"match": "[¨ᵇ⍨⊗⌸⇄∂/⌿\\\\⍀⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ]", "name": "keyword.operator.monadic.bpl"}, {"match": "[↣⍤∘⍠⍥↢\\.⍣⊘@⍚⌺]", "name": "keyword.operator.dyadic.bpl"}, {"match": "[⍺⍵⍶⍹∇⍢]", "name": "variable.parameter.bpl"}, {"match": "[←⎕⋄⁝\\?₀₁₂₃₄₅₆₇₈₉₋]", "name": "keyword.control.bpl"}]};
|
|
3
|
+
export const symbols = [{"glyph": "←", "name": "left-arrow", "kind": "syntax", "monad": "assign", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["是", "是"], "shortcut": " h"}, {"glyph": "⎕", "name": "quad", "kind": "syntax", "monad": "io", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["出入", "出入"], "shortcut": " q"}, {"glyph": "•", "name": "bullet", "kind": "system", "monad": "system", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["系", "系"], "shortcut": " y"}, {"glyph": "⍺", "name": "alpha", "kind": "argument", "monad": "left-argument", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["甲", "甲"], "shortcut": " a"}, {"glyph": "⍵", "name": "omega", "kind": "argument", "monad": "right-argument", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["乙", "乙"], "shortcut": " w"}, {"glyph": "⍶", "name": "alpha-underbar", "kind": "argument", "monad": "left-operand", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["丙", "丙"], "shortcut": " - a"}, {"glyph": "⍹", "name": "omega-underbar", "kind": "argument", "monad": "right-operand", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["丁", "丁"], "shortcut": " - w"}, {"glyph": "∇", "name": "del", "kind": "argument", "monad": "recursion", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["递", "遞"], "shortcut": " g"}, {"glyph": "⍢", "name": "del-diaeresis", "kind": "argument", "monad": "operator-recursion", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["循", "循"], "shortcut": " 1 g"}, {"glyph": "⍝", "name": "lamp", "kind": "comment", "monad": "comment", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["注", "注"], "shortcut": " o c"}, {"glyph": "⋄", "name": "diamond", "kind": "syntax", "monad": "separator", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["句", "句"], "shortcut": " `"}, {"glyph": "⁝", "name": "tricolon", "kind": "syntax", "monad": "token-separator", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["隔", "隔"], "shortcut": " :"}, {"glyph": "?", "name": "question", "kind": "syntax", "monad": "predicate", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["若", "若"], "shortcut": ""}, {"glyph": "¯", "name": "overbar", "kind": "literal", "monad": "negative", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["负", "負"], "shortcut": " -"}, {"glyph": "∞", "name": "infinity", "kind": "literal", "monad": "", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["永", "永"], "shortcut": " 8"}, {"glyph": "⍬", "name": "zilde", "kind": "literal", "monad": "empty", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["空", "空"], "shortcut": " )"}, {"glyph": "+", "name": "plus", "kind": "function", "monad": "conjugate", "dyad": "add", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["加", "加"], "shortcut": ""}, {"glyph": "-", "name": "minus", "kind": "function", "monad": "negate", "dyad": "subtract", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["减", "減"], "shortcut": ""}, {"glyph": "×", "name": "times", "kind": "function", "monad": "sign", "dyad": "multiply", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["乘号", "乘號"], "shortcut": " m"}, {"glyph": "÷", "name": "obelus", "kind": "function", "monad": "reciprocal", "dyad": "divide", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["除", "除"], "shortcut": " u"}, {"glyph": "⌈", "name": "upstile", "kind": "function", "monad": "ceiling", "dyad": "maximum", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["上", "上"], "shortcut": " s"}, {"glyph": "⌊", "name": "downstile", "kind": "function", "monad": "floor", "dyad": "minimum", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["下", "下"], "shortcut": " d"}, {"glyph": "|", "name": "stile", "kind": "function", "monad": "magnitude", "dyad": "residue", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["绝余", "絕餘"], "shortcut": ""}, {"glyph": "*", "name": "star", "kind": "function", "monad": "exponential", "dyad": "exponent", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["幂", "冪"], "shortcut": ""}, {"glyph": "⍟", "name": "circle-star", "kind": "function", "monad": "natural-log", "dyad": "logarithm", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["对", "對"], "shortcut": " o 8"}, {"glyph": "○", "name": "circle", "kind": "function", "monad": "cis", "dyad": "circular", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["圆", "圓"], "shortcut": " o"}, {"glyph": "π", "name": "pi", "kind": "function", "monad": "pi-times", "dyad": "pi-ratio", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["周", "周"], "shortcut": " p"}, {"glyph": "√", "name": "radical", "kind": "function", "monad": "sqrt", "dyad": "root", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["根", "根"], "shortcut": " 3"}, {"glyph": "!", "name": "exclamation", "kind": "function", "monad": "factorial", "dyad": "binomial", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["阶拣", "階揀"], "shortcut": ""}, {"glyph": "∧", "name": "wedge", "kind": "function", "monad": "polar", "dyad": "and", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["极且", "極且"], "shortcut": " 0"}, {"glyph": "∨", "name": "vee", "kind": "function", "monad": "real-imag", "dyad": "or", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["析或", "析或"], "shortcut": " 9"}, {"glyph": "⊼", "name": "wedge-bar", "kind": "function", "monad": "square", "dyad": "nand", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["方否", "方否"], "shortcut": " - 0"}, {"glyph": "⊽", "name": "vee-bar", "kind": "function", "monad": "double", "dyad": "nor", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["双莫", "雙莫"], "shortcut": " - 9"}, {"glyph": "~", "name": "tilde", "kind": "function", "monad": "not", "dyad": "without", "monad_rank": "0", "dyad_ranks": "∞ ∞", "hanzi": ["非无", "非無"], "shortcut": ""}, {"glyph": "=", "name": "equals", "kind": "function", "monad": "classify", "dyad": "equal", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["等", "等"], "shortcut": ""}, {"glyph": "≠", "name": "not-equals", "kind": "function", "monad": "unique-mask", "dyad": "not-equal", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["别初", "別初"], "shortcut": " +"}, {"glyph": "<", "name": "less-than", "kind": "function", "monad": "sort-up", "dyad": "less", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["小", "小"], "shortcut": ""}, {"glyph": "≤", "name": "less-than-or-equal", "kind": "function", "monad": "decrement", "dyad": "less-equal", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["限退", "限退"], "shortcut": " <"}, {"glyph": ">", "name": "greater-than", "kind": "function", "monad": "sort-down", "dyad": "greater", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["大", "大"], "shortcut": ""}, {"glyph": "≥", "name": "greater-than-or-equal", "kind": "function", "monad": "increment", "dyad": "greater-equal", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["达进", "達進"], "shortcut": " >"}, {"glyph": "⍳", "name": "iota", "kind": "function", "monad": "indices", "dyad": "index-of", "monad_rank": "1", "dyad_ranks": "∞ ∞", "hanzi": ["位", "位"], "shortcut": " i"}, {"glyph": "↦", "name": "right-arrow-from-bar", "kind": "function", "monad": "range", "dyad": "to", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["至", "至"], "shortcut": " l"}, {"glyph": ":", "name": "colon", "kind": "function", "monad": "unkey", "dyad": "keyed", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["键卸", "鍵卸"], "shortcut": ""}, {"glyph": "⍴", "name": "rho", "kind": "function", "monad": "shape", "dyad": "reshape", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["形", "形"], "shortcut": " r"}, {"glyph": "≢", "name": "equal-underbar-slash", "kind": "function", "monad": "tally", "dyad": "not-match", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["数异", "數異"], "shortcut": " ?"}, {"glyph": "≡", "name": "equal-underbar", "kind": "function", "monad": "depth", "dyad": "match", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["同深", "同深"], "shortcut": " ="}, {"glyph": ",", "name": "comma", "kind": "function", "monad": "ravel", "dyad": "catenate", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["连", "連"], "shortcut": ""}, {"glyph": "⍪", "name": "comma-bar", "kind": "function", "monad": "table", "dyad": "catenate-first", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["接矩", "接矩"], "shortcut": " - ,"}, {"glyph": "⊂", "name": "left-shoe", "kind": "function", "monad": "enclose", "dyad": "partitioned-enclose", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["包", "包"], "shortcut": " z"}, {"glyph": "⊃", "name": "right-shoe", "kind": "function", "monad": "mix", "dyad": "pick", "monad_rank": "0", "dyad_ranks": "1 ∞", "hanzi": ["选合", "選合"], "shortcut": " x"}, {"glyph": "⊆", "name": "left-shoe-underbar", "kind": "function", "monad": "nest", "dyad": "partition", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["巢段", "巢段"], "shortcut": " - z"}, {"glyph": "∊", "name": "epsilon", "kind": "function", "monad": "enlist", "dyad": "member", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["属展", "屬展"], "shortcut": " e"}, {"glyph": "∪", "name": "down-shoe", "kind": "function", "monad": "unique", "dyad": "union", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["并独", "併獨"], "shortcut": " v"}, {"glyph": "∩", "name": "up-shoe", "kind": "function", "monad": "duplicates", "dyad": "intersection", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["交重", "交重"], "shortcut": " c"}, {"glyph": "⍋", "name": "delta-stile", "kind": "function", "monad": "grade-up", "dyad": "grade-up-by", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["升", "升"], "shortcut": " \\ 7"}, {"glyph": "⍒", "name": "del-stile", "kind": "function", "monad": "grade-down", "dyad": "grade-down-by", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["降", "降"], "shortcut": " \\ g"}, {"glyph": "↑", "name": "up-arrow", "kind": "function", "monad": "first", "dyad": "take", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["取", "取"], "shortcut": " k"}, {"glyph": "↓", "name": "down-arrow", "kind": "function", "monad": "split", "dyad": "drop", "monad_rank": "1", "dyad_ranks": "1 ∞", "hanzi": ["去拆", "去拆"], "shortcut": " j"}, {"glyph": "⌽", "name": "circle-stile", "kind": "function", "monad": "reverse", "dyad": "rotate", "monad_rank": "1", "dyad_ranks": "0 1", "hanzi": ["转", "轉"], "shortcut": " 2"}, {"glyph": "⊖", "name": "circle-bar", "kind": "function", "monad": "reverse-first", "dyad": "rotate-first", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["纵", "縱"], "shortcut": " o -"}, {"glyph": "⍉", "name": "circle-backslash", "kind": "function", "monad": "transpose", "dyad": "reorder-axes", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["翻", "翻"], "shortcut": " o \\"}, {"glyph": "⊤", "name": "down-tack", "kind": "function", "monad": "binary-encode", "dyad": "encode", "monad_rank": "∞", "dyad_ranks": "1 0", "hanzi": ["编", "編"], "shortcut": " n"}, {"glyph": "⊥", "name": "up-tack", "kind": "function", "monad": "binary-decode", "dyad": "decode", "monad_rank": "1", "dyad_ranks": "1 1", "hanzi": ["译", "譯"], "shortcut": " b"}, {"glyph": "⍎", "name": "hydrant", "kind": "function", "monad": "execute", "dyad": "execute-in", "monad_rank": "1", "dyad_ranks": "∞ ∞", "hanzi": ["行", "行"], "shortcut": " o b"}, {"glyph": "⍕", "name": "thorn", "kind": "function", "monad": "format", "dyad": "format-spec", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["文", "文"], "shortcut": " o n"}, {"glyph": "⌷", "name": "squad", "kind": "function", "monad": "materialise", "dyad": "index", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["索", "索"], "shortcut": " q \\"}, {"glyph": "⌹", "name": "domino", "kind": "function", "monad": "matrix-inverse", "dyad": "matrix-divide", "monad_rank": "2", "dyad_ranks": "∞ 2", "hanzi": ["解逆", "解逆"], "shortcut": " q u"}, {"glyph": "#", "name": "hash", "kind": "function", "monad": "runs", "dyad": "replicate", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["复", "複"], "shortcut": ""}, {"glyph": "↕", "name": "up-down-arrow", "kind": "function", "monad": "pairs", "dyad": "windows", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["窗", "窗"], "shortcut": " K"}, {"glyph": "⍭", "name": "stile-tilde", "kind": "function", "monad": "prime", "dyad": "prime-mode", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["素", "素"], "shortcut": " \\"}, {"glyph": "⨸", "name": "circle-divide", "kind": "function", "monad": "factors", "dyad": "factor-spec", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["因", "因"], "shortcut": " o u"}, {"glyph": "⌻", "name": "quad-jot", "kind": "function", "monad": "roots", "dyad": "polyval", "monad_rank": "1", "dyad_ranks": "1 0", "hanzi": ["零值", "零值"], "shortcut": " q t"}, {"glyph": "⍸", "name": "iota-underbar", "kind": "function", "monad": "where", "dyad": "interval-index", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["处间", "處間"], "shortcut": " - i"}, {"glyph": "⍷", "name": "epsilon-underbar", "kind": "function", "monad": "groups", "dyad": "find", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["寻群", "尋群"], "shortcut": " - e"}, {"glyph": "⊢", "name": "right-tack", "kind": "function", "monad": "same", "dyad": "right", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["右", "右"], "shortcut": " '"}, {"glyph": "⊣", "name": "left-tack", "kind": "function", "monad": "same-left", "dyad": "left", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["左", "左"], "shortcut": " ;"}, {"glyph": "¿", "name": "inverted-question", "kind": "function", "monad": "roll", "dyad": "deal", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["掷抽", "擲抽"], "shortcut": " /"}, {"glyph": "¨", "name": "diaeresis", "kind": "monadic-operator", "monad": "each", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["遍", "遍"], "shortcut": " 1"}, {"glyph": "ᵇ", "name": "superscript-b", "kind": "monadic-operator", "monad": "bitwise", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["按", "按"], "shortcut": " 6 b"}, {"glyph": "⍨", "name": "tilde-diaeresis", "kind": "monadic-operator", "monad": "self", "dyad": "commute", "monad_rank": "", "dyad_ranks": "", "hanzi": ["己换", "己換"], "shortcut": " 1 `"}, {"glyph": "↣", "name": "right-tail-arrow", "kind": "dyadic-operator", "monad": "before", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["先", "先"], "shortcut": " ."}, {"glyph": "⍤", "name": "jot-diaeresis", "kind": "dyadic-operator", "monad": "rank", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["秩", "秩"], "shortcut": " 1 t"}, {"glyph": "∘", "name": "jot", "kind": "dyadic-operator", "monad": "atop", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["承", "承"], "shortcut": " t"}, {"glyph": "⍠", "name": "quad-colon", "kind": "dyadic-operator", "monad": "axis", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["轴", "軸"], "shortcut": " q ;"}, {"glyph": "⍥", "name": "circle-diaeresis", "kind": "dyadic-operator", "monad": "over", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["经", "經"], "shortcut": " 1 o"}, {"glyph": "↢", "name": "left-tail-arrow", "kind": "dyadic-operator", "monad": "after", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["后", "後"], "shortcut": " ,"}, {"glyph": ".", "name": "dot", "kind": "dyadic-operator", "monad": "determinant", "dyad": "inner-product", "monad_rank": "", "dyad_ranks": "", "hanzi": ["内", "內"], "shortcut": ""}, {"glyph": "⊗", "name": "circle-times", "kind": "monadic-operator", "monad": "outer-product", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["表", "表"], "shortcut": " o m"}, {"glyph": "⌸", "name": "quad-equal", "kind": "monadic-operator", "monad": "key", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["组", "組"], "shortcut": " q ="}, {"glyph": "⍣", "name": "star-diaeresis", "kind": "dyadic-operator", "monad": "power", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["次止", "次止"], "shortcut": " 1 8"}, {"glyph": "⇄", "name": "right-left-arrows", "kind": "monadic-operator", "monad": "optimize", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["优", "優"], "shortcut": " 4"}, {"glyph": "⊘", "name": "circle-slash", "kind": "dyadic-operator", "monad": "valences", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["兼", "兼"], "shortcut": " o /"}, {"glyph": "@", "name": "at", "kind": "dyadic-operator", "monad": "under", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["于", "於"], "shortcut": ""}, {"glyph": "∂", "name": "partial", "kind": "monadic-operator", "monad": "derivative", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["导梯", "導梯"], "shortcut": " f"}, {"glyph": "⍚", "name": "diamond-underbar", "kind": "dyadic-operator", "monad": "agenda", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["择", "擇"], "shortcut": " - `"}, {"glyph": "⌺", "name": "quad-diamond", "kind": "dyadic-operator", "monad": "stencil", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["邻", "鄰"], "shortcut": " q `"}, {"glyph": "/", "name": "slash", "kind": "monadic-operator", "monad": "reduce", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["总", "總"], "shortcut": ""}, {"glyph": "⌿", "name": "slash-bar", "kind": "monadic-operator", "monad": "reduce-first", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["汇", "匯"], "shortcut": " - /"}, {"glyph": "\\", "name": "backslash", "kind": "monadic-operator", "monad": "scan", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["累", "累"], "shortcut": ""}, {"glyph": "⍀", "name": "backslash-bar", "kind": "monadic-operator", "monad": "scan-first", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["续", "續"], "shortcut": " - \\"}];
|
package/{lb.js → browser/lb.js}
RENAMED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
// Based on Adám Brudzewsky's APL language bar: https://abrudz.github.io/lb
|
|
2
2
|
// MIT License, Copyright (c) 2011-2020 Nikolay G. Nikolov and Adam Brudzevski.
|
|
3
|
-
// BPL name completion, editor adapters
|
|
4
|
-
(
|
|
5
|
-
function
|
|
3
|
+
// BPL name completion, editor adapters and page toolbar by Jeremy Howard.
|
|
4
|
+
export default (symbols, input, layout, editorOptions) => {
|
|
5
|
+
function mount(container) {
|
|
6
6
|
const d = container.ownerDocument, w = d.defaultView, events = new AbortController();
|
|
7
7
|
const on = (target, name, fn, capture = false) => target.addEventListener(name, fn, {capture, signal: events.signal});
|
|
8
8
|
const {inCode, bplStart, entry, press, reset} = input(symbols, layout);
|
|
9
9
|
const shortcuts = new Map(symbols.map(({glyph, shortcut}) => [glyph, shortcut]));
|
|
10
10
|
let leftAlt = false, rightAlt = false;
|
|
11
|
+
let editorFonts;
|
|
12
|
+
function fonts() {
|
|
13
|
+
if (!w.monaco || editorFonts) return;
|
|
14
|
+
editorFonts = w.monaco.editor.onDidCreateEditor(e => e.updateOptions(editorOptions));
|
|
15
|
+
w.monaco.editor.getEditors().forEach(e => e.updateOptions(editorOptions));
|
|
16
|
+
}
|
|
17
|
+
fonts();
|
|
11
18
|
|
|
12
19
|
function textareaRect(t) {
|
|
13
20
|
const mirror = d.createElement('div'), caret = d.createElement('span'), css = getComputedStyle(t), rect = t.getBoundingClientRect();
|
|
@@ -25,12 +32,13 @@
|
|
|
25
32
|
|
|
26
33
|
function editor(target) {
|
|
27
34
|
if (target.closest?.('.text_cell, .jp-MarkdownCell')) return;
|
|
35
|
+
const monaco = w.monaco;
|
|
28
36
|
const m = monaco?.editor.getEditors().find(e => e.hasTextFocus());
|
|
29
37
|
if (m) {
|
|
30
38
|
const model = m.getModel(), p = m.getPosition(), selection = m.getSelection();
|
|
31
39
|
if (!model || !p || !selection) return;
|
|
32
40
|
const valid = () => m.getDomNode()?.isConnected && m.getModel() === model && !m.getOption(monaco.editor.EditorOption.readOnly)
|
|
33
|
-
&& (model.getLanguageId() === 'bpl'
|
|
41
|
+
&& bplStart({bpl: model.getLanguageId() === 'bpl', text: model.getValue(), pos: model.getOffsetAt(m.getPosition())}) >= 0;
|
|
34
42
|
if (!valid()) return;
|
|
35
43
|
const e = {id: model, valid, text: model.getValue(), pos: model.getOffsetAt(p), empty: selection.isEmpty(), bpl: model.getLanguageId() === 'bpl',
|
|
36
44
|
rect: () => {
|
|
@@ -53,7 +61,6 @@
|
|
|
53
61
|
}};
|
|
54
62
|
return bplStart(e) >= 0 ? e : undefined;
|
|
55
63
|
}
|
|
56
|
-
if (!magics) return;
|
|
57
64
|
const view = target.closest?.('.cm-editor')?.querySelector('.cm-content')?.cmTile?.view;
|
|
58
65
|
if (view) {
|
|
59
66
|
if (view.state.readOnly) return;
|
|
@@ -86,13 +93,18 @@
|
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
const host = d.createElement('div');
|
|
89
|
-
host.
|
|
96
|
+
host.className = 'bpl_tools';
|
|
97
|
+
host.innerHTML = `<button type="button" class="bpl_toggle"></button><div class="ngn_lb" aria-label="BPL symbols"></div>
|
|
90
98
|
<div class="bpl_choices" role="group" aria-label="BPL symbol completions" hidden></div>
|
|
91
99
|
<style>
|
|
92
|
-
|
|
93
|
-
.
|
|
94
|
-
.
|
|
95
|
-
.ngn_lb
|
|
100
|
+
pre,code{font-family:var(--bpl-font,SAX2B),monospace}
|
|
101
|
+
.bpl_out{line-height:1.05!important}
|
|
102
|
+
.bpl_tools{position:relative}
|
|
103
|
+
.ngn_lb,.bpl_choices,.bpl_toggle{background:var(--bpl-bar-background,light-dark(#eee,#222));color:var(--bpl-bar-color,light-dark(#111,#ddd));font:15px var(--bpl-font,SAX2B),monospace}
|
|
104
|
+
.ngn_lb{border-bottom:1px solid #999;padding:2px 26px 2px 2px;white-space:nowrap;overflow-x:auto}
|
|
105
|
+
.bpl_tools button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;padding:2px 4px}
|
|
106
|
+
.bpl_tools .bpl_toggle{position:absolute;right:0;top:0;z-index:1;background:var(--bpl-bar-background,light-dark(#eee,#222))}
|
|
107
|
+
.bpl_tools button:hover{background:#777;color:white}
|
|
96
108
|
.bpl_choices{position:fixed;z-index:2147483647;max-height:240px;max-width:calc(100vw - 16px);overflow:auto;border:1px solid #888;border-radius:4px;box-shadow:0 3px 12px #0003;padding:4px}
|
|
97
109
|
.bpl_choices button{display:block;width:100%;text-align:left;white-space:nowrap}
|
|
98
110
|
.bpl_choices small{display:block;padding:4px}
|
|
@@ -101,8 +113,22 @@
|
|
|
101
113
|
.bpl_menu button{display:inline-block;width:auto;min-width:28px;text-align:center}
|
|
102
114
|
</style>`;
|
|
103
115
|
container.append(host);
|
|
104
|
-
const bar = host.querySelector('.ngn_lb'), tip = host.querySelector('.bpl_choices');
|
|
105
|
-
|
|
116
|
+
const bar = host.querySelector('.ngn_lb'), tip = host.querySelector('.bpl_choices'), toggle = host.querySelector('.bpl_toggle');
|
|
117
|
+
let collapsed = false;
|
|
118
|
+
try { collapsed = localStorage.getItem('bpl-bar-collapsed') === '1'; } catch {}
|
|
119
|
+
function collapse() {
|
|
120
|
+
bar.hidden = collapsed;
|
|
121
|
+
toggle.textContent = collapsed ? '▼' : '▲';
|
|
122
|
+
toggle.title = collapsed ? 'Expand BPL symbols' : 'Collapse BPL symbols';
|
|
123
|
+
toggle.setAttribute('aria-label', toggle.title);
|
|
124
|
+
toggle.setAttribute('aria-expanded', String(!collapsed));
|
|
125
|
+
}
|
|
126
|
+
toggle.onmousedown = ev => ev.preventDefault();
|
|
127
|
+
toggle.onclick = () => {
|
|
128
|
+
collapsed = !collapsed; cancel(); collapse();
|
|
129
|
+
try { localStorage.setItem('bpl-bar-collapsed', collapsed ? '1' : '0'); } catch {}
|
|
130
|
+
};
|
|
131
|
+
collapse();
|
|
106
132
|
let active, lastEditor, choice, keyInput = false;
|
|
107
133
|
const names = new Map(symbols.map(({glyph, name, monad, dyad}) =>
|
|
108
134
|
[glyph, [name, monad, dyad].filter(Boolean).join(' ')]));
|
|
@@ -182,7 +208,7 @@
|
|
|
182
208
|
if (b && choice?.e.valid()) choice.e.insert(b.dataset.glyph, choice.item.start);
|
|
183
209
|
cancel();
|
|
184
210
|
});
|
|
185
|
-
on(d, 'focusin', ev => { if (!host.contains(ev.target)) lastEditor = editor(ev.target); cancel(); });
|
|
211
|
+
on(d, 'focusin', ev => { fonts(); if (!host.contains(ev.target)) lastEditor = editor(ev.target); cancel(); });
|
|
186
212
|
on(d, 'pointerdown', ev => { if (!host.contains(ev.target)) cancel(); }, true);
|
|
187
213
|
on(d, 'pointerup', ev => { if (!host.contains(ev.target)) lastEditor = editor(ev.target); });
|
|
188
214
|
for (const event of ['paste', 'cut', 'compositionstart', 'focusout']) on(d, event, cancel, true);
|
|
@@ -237,33 +263,8 @@
|
|
|
237
263
|
} else if (!(typed && plain && (/^[a-z]$/i.test(ev.key) || ev.key === 'Backspace'))) cancel();
|
|
238
264
|
keyInput = plain && (ev.key.length === 1 || ev.key === 'Backspace');
|
|
239
265
|
}, true);
|
|
240
|
-
return {dispose() { events.abort(); reset(); lastEditor = undefined; cancel(); host.remove(); }};
|
|
266
|
+
return {element: host, fonts, dispose() { events.abort(); editorFonts?.dispose(); reset(); lastEditor = undefined; cancel(); host.remove(); }};
|
|
241
267
|
}
|
|
242
268
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (d.querySelector('.bpl_page_bar') || d.querySelector('meta[name=generator][content^=quarto]') && !d.querySelector('[data-bpl]')) return;
|
|
246
|
-
const container = d.createElement('div');
|
|
247
|
-
container.className = 'bpl_page_bar';
|
|
248
|
-
container.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:2147483647';
|
|
249
|
-
d.body.append(container);
|
|
250
|
-
const input = attach(monaco, container, true), bar = container.querySelector('.ngn_lb');
|
|
251
|
-
bar.insertAdjacentHTML('afterbegin', '<button class="ngn_o" style="float:right" title="Toggle overlay/push-down"></button>');
|
|
252
|
-
let overlay = false;
|
|
253
|
-
const padding = d.body.style.paddingTop, toggle = bar.querySelector('.ngn_o');
|
|
254
|
-
try { overlay = localStorage.getItem('ngn_lb_overlay') === '1'; } catch {}
|
|
255
|
-
function reflow() {
|
|
256
|
-
toggle.textContent = overlay ? '▼' : '▲';
|
|
257
|
-
d.body.style.paddingTop = overlay || bar.hidden ? padding : `${bar.offsetHeight}px`;
|
|
258
|
-
}
|
|
259
|
-
toggle.onclick = () => {
|
|
260
|
-
overlay = !overlay;
|
|
261
|
-
try { localStorage.setItem('ngn_lb_overlay', overlay ? '1' : '0'); } catch {}
|
|
262
|
-
reflow();
|
|
263
|
-
};
|
|
264
|
-
const observer = new ResizeObserver(reflow);
|
|
265
|
-
observer.observe(bar); reflow();
|
|
266
|
-
return {dispose() { input.dispose(); observer.disconnect(); container.remove(); d.body.style.paddingTop = padding; }};
|
|
267
|
-
}
|
|
268
|
-
return {attach, page};
|
|
269
|
-
})
|
|
269
|
+
return mount;
|
|
270
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "basedpl",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.82",
|
|
4
4
|
"description": "BasedPL, the Based-array Programming Language, is an APL-derived array language, borrowing ideas from J and BQN, with an emphasis on simple, consistent notation.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,5 +8,13 @@
|
|
|
8
8
|
"url": "git+https://github.com/AnswerDotAI/basedpl.git"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
|
-
"main": "basedpl_wasm.js"
|
|
11
|
+
"main": "basedpl_wasm.js",
|
|
12
|
+
"files": [
|
|
13
|
+
"basedpl_wasm.js",
|
|
14
|
+
"basedpl_wasm_bg.wasm",
|
|
15
|
+
"*.d.ts",
|
|
16
|
+
"browser",
|
|
17
|
+
"*tmLanguage.json",
|
|
18
|
+
"canvas.js"
|
|
19
|
+
]
|
|
12
20
|
}
|
package/bpl-editor.js
DELETED
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
// Generated by basedpl.editors.browser.
|
|
2
|
-
export const grammar = {"name": "bpl", "displayName": "BPL", "scopeName": "source.bpl", "fileTypes": ["bpl"], "patterns": [{"begin": "[⍝]", "beginCaptures": {"0": {"name": "comment.line.bpl"}}, "end": "$", "contentName": "comment.line.bpl", "patterns": [], "applyEndPatternLast": true}, {"begin": "\"", "beginCaptures": {"0": {"name": "string.quoted.double.bpl"}}, "end": "\"|$", "contentName": "string.quoted.double.bpl", "patterns": [{"match": "\"\"", "name": "string.quoted.double.bpl"}], "applyEndPatternLast": true, "endCaptures": {"0": {"name": "string.quoted.double.bpl"}}}, {"match": "'.?'", "name": "string.quoted.single.bpl"}, {"match": "(?:_\\d+|_\\S|_|[^\\s\\p{Cc}0-9←⎕•⍺⍵⍶⍹∇⍢⍝⋄⁝\\?¯∞⍬\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳↦:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿¨ᵇ⍨↣⍤∘⍠⍥↢\\.⊗⌸⍣⇄⊘@∂⍚⌺/⌿\\\\⍀⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ₀₁₂₃₄₅₆₇₈₉₋ₓ₁ₓ₂ₓ₄ₓ₈ₓₕₛₚ\\(\\)\\[\\]\\{\\}'\";\\$_ₑⱼᵣ])+", "name": "variable.other.bpl"}, {"match": "[•][A-Za-z_∆⍙][A-Za-z0-9_∆⍙]*", "name": "support.function.bpl"}, {"match": "(?:[¯]?[∞]|[¯]?(\\d+([.]\\d+)?|[.]\\d+)([eEₑ][¯]?\\d+)?([jJⱼ][¯]?(\\d+([.]\\d+)?|[.]\\d+)([eEₑ][¯]?\\d+)?|[rᵣ][¯]?\\d+)?)(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)?|[ₑⱼᵣ]", "name": "constant.numeric.bpl"}, {"match": "[⍬](?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)?", "name": "constant.numeric.bpl"}, {"match": "\\$[tfn]", "name": "constant.numeric.bpl"}, {"match": "\\$[ad]", "name": "string.quoted.double.bpl"}, {"begin": "[\\])](?=(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ))", "beginCaptures": {"0": {"name": "source.bpl"}}, "end": "(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)|$", "contentName": "constant.numeric.bpl", "patterns": [], "applyEndPatternLast": true, "endCaptures": {"0": {"name": "constant.numeric.bpl"}}}, {"match": "[\\+\\-×÷⌈⌊\\|\\*⍟○π√!∧∨⊼⊽\\~=≠<≤>≥⍳↦:⍴≢≡,⍪⊂⊃⊆∊∪∩⍋⍒↑↓⌽⊖⍉⊤⊥⍎⍕⌷⌹\\#↕⍭⨸⌻⍸⍷⊢⊣¿]", "name": "support.function.bpl"}, {"match": "(?:ₓ₁|ₓ₂|ₓ₄|ₓ₈|ₓ|ₕ|ₛ|ₚ)", "name": "keyword.operator.monadic.bpl"}, {"match": "[¨ᵇ⍨⊗⌸⇄∂/⌿\\\\⍀⁰¹²³⁴⁵⁶⁷⁸⁹⁻ᵀᵘₓ]", "name": "keyword.operator.monadic.bpl"}, {"match": "[↣⍤∘⍠⍥↢\\.⍣⊘@⍚⌺]", "name": "keyword.operator.dyadic.bpl"}, {"match": "[⍺⍵⍶⍹∇⍢]", "name": "variable.parameter.bpl"}, {"match": "[←⎕⋄⁝\\?₀₁₂₃₄₅₆₇₈₉₋]", "name": "keyword.control.bpl"}]};
|
|
3
|
-
export const configuration = {"comments": {"lineComment": "⍝"}, "brackets": [["(", ")"], ["[", "]"], ["{", "}"]], "autoClosingPairs": [{"open": "(", "close": ")", "notIn": ["string", "comment"]}, {"open": "[", "close": "]", "notIn": ["string", "comment"]}, {"open": "{", "close": "}", "notIn": ["string", "comment"]}, {"open": "\"", "close": "\"", "notIn": ["string", "comment"]}, {"open": "'", "close": "'", "notIn": ["string", "comment"]}], "surroundingPairs": [{"open": "(", "close": ")"}, {"open": "[", "close": "]"}, {"open": "{", "close": "}"}, {"open": "\"", "close": "\""}, {"open": "'", "close": "'"}]};
|
|
4
|
-
export const editorOptions = {"fontFamily": "SAX2B, monospace", "unicodeHighlight": {"ambiguousCharacters": false}};
|
|
5
|
-
const bar = // Based on Adám Brudzewsky's APL language bar: https://abrudz.github.io/lb
|
|
6
|
-
// MIT License, Copyright (c) 2011-2020 Nikolay G. Nikolov and Adam Brudzevski.
|
|
7
|
-
// BPL name completion, editor adapters, dark mode and overlay layout by Jeremy Howard.
|
|
8
|
-
((symbols, input, layout) => {
|
|
9
|
-
function attach(monaco, container, magics = false) {
|
|
10
|
-
const d = container.ownerDocument, w = d.defaultView, events = new AbortController();
|
|
11
|
-
const on = (target, name, fn, capture = false) => target.addEventListener(name, fn, {capture, signal: events.signal});
|
|
12
|
-
const {inCode, bplStart, entry, press, reset} = input(symbols, layout);
|
|
13
|
-
const shortcuts = new Map(symbols.map(({glyph, shortcut}) => [glyph, shortcut]));
|
|
14
|
-
let leftAlt = false, rightAlt = false;
|
|
15
|
-
|
|
16
|
-
function textareaRect(t) {
|
|
17
|
-
const mirror = d.createElement('div'), caret = d.createElement('span'), css = getComputedStyle(t), rect = t.getBoundingClientRect();
|
|
18
|
-
for (const p of ['font', 'lineHeight', 'letterSpacing', 'padding', 'border', 'boxSizing', 'width', 'tabSize']) mirror.style[p] = css[p];
|
|
19
|
-
Object.assign(mirror.style, {position: 'fixed', visibility: 'hidden', whiteSpace: 'pre-wrap', overflowWrap: 'break-word',
|
|
20
|
-
left: `${rect.left - t.scrollLeft}px`, top: `${rect.top - t.scrollTop}px`});
|
|
21
|
-
mirror.textContent = t.value.slice(0, t.selectionStart);
|
|
22
|
-
caret.textContent = '\u200b';
|
|
23
|
-
mirror.append(caret);
|
|
24
|
-
d.body.append(mirror);
|
|
25
|
-
const result = caret.getBoundingClientRect();
|
|
26
|
-
mirror.remove();
|
|
27
|
-
return result;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function editor(target) {
|
|
31
|
-
if (target.closest?.('.text_cell, .jp-MarkdownCell')) return;
|
|
32
|
-
const m = monaco?.editor.getEditors().find(e => e.hasTextFocus());
|
|
33
|
-
if (m) {
|
|
34
|
-
const model = m.getModel(), p = m.getPosition(), selection = m.getSelection();
|
|
35
|
-
if (!model || !p || !selection) return;
|
|
36
|
-
const valid = () => m.getDomNode()?.isConnected && m.getModel() === model && !m.getOption(monaco.editor.EditorOption.readOnly)
|
|
37
|
-
&& (model.getLanguageId() === 'bpl' || magics && bplStart({text: model.getValue(), pos: model.getOffsetAt(m.getPosition())}) >= 0);
|
|
38
|
-
if (!valid()) return;
|
|
39
|
-
const e = {id: model, valid, text: model.getValue(), pos: model.getOffsetAt(p), empty: selection.isEmpty(), bpl: model.getLanguageId() === 'bpl',
|
|
40
|
-
rect: () => {
|
|
41
|
-
const r = m.getDomNode().getBoundingClientRect(), c = m.getScrolledVisiblePosition(p);
|
|
42
|
-
return {left: r.left + c.left, bottom: r.top + c.top + c.height};
|
|
43
|
-
},
|
|
44
|
-
insert: (text, from) => {
|
|
45
|
-
if (!valid()) return;
|
|
46
|
-
const selection = m.getSelection();
|
|
47
|
-
from ??= model.getOffsetAt(selection.getStartPosition());
|
|
48
|
-
const a = model.getPositionAt(from), b = selection.getEndPosition();
|
|
49
|
-
m.pushUndoStop();
|
|
50
|
-
m.executeEdits('aplnb', [{range: {startLineNumber: a.lineNumber, startColumn: a.column,
|
|
51
|
-
endLineNumber: b.lineNumber, endColumn: b.column}, text}], () => {
|
|
52
|
-
const end = model.getPositionAt(from + text.length);
|
|
53
|
-
return [new monaco.Selection(end.lineNumber, end.column, end.lineNumber, end.column)];
|
|
54
|
-
});
|
|
55
|
-
m.pushUndoStop();
|
|
56
|
-
m.focus();
|
|
57
|
-
}};
|
|
58
|
-
return bplStart(e) >= 0 ? e : undefined;
|
|
59
|
-
}
|
|
60
|
-
if (!magics) return;
|
|
61
|
-
const view = target.closest?.('.cm-editor')?.querySelector('.cm-content')?.cmTile?.view;
|
|
62
|
-
if (view) {
|
|
63
|
-
if (view.state.readOnly) return;
|
|
64
|
-
const sel = view.state.selection.main;
|
|
65
|
-
const e = {id: view, valid: () => view.dom.isConnected && !view.state.readOnly
|
|
66
|
-
&& bplStart({text: view.state.doc.toString(), pos: view.state.selection.main.head}) >= 0,
|
|
67
|
-
text: view.state.doc.toString(), pos: sel.head, empty: sel.empty,
|
|
68
|
-
rect: () => view.coordsAtPos(sel.head),
|
|
69
|
-
insert: (text, from) => {
|
|
70
|
-
if (!e.valid()) return;
|
|
71
|
-
const sel = view.state.selection.main;
|
|
72
|
-
from ??= sel.from;
|
|
73
|
-
view.dispatch({changes: {from, to: sel.to, insert: text}, selection: {anchor: from + text.length}, userEvent: 'input.complete'});
|
|
74
|
-
view.focus();
|
|
75
|
-
}};
|
|
76
|
-
return bplStart(e) >= 0 ? e : undefined;
|
|
77
|
-
}
|
|
78
|
-
if (target.tagName !== 'TEXTAREA' || target.readOnly || target.disabled) return;
|
|
79
|
-
const e = {id: target, valid: () => target.isConnected && !target.readOnly && !target.disabled
|
|
80
|
-
&& bplStart({text: target.value, pos: target.selectionStart, bpl: target.hasAttribute('data-bpl')}) >= 0,
|
|
81
|
-
text: target.value, pos: target.selectionStart, empty: target.selectionStart === target.selectionEnd, bpl: target.hasAttribute('data-bpl'),
|
|
82
|
-
rect: () => textareaRect(target),
|
|
83
|
-
insert: (text, from = target.selectionStart) => {
|
|
84
|
-
if (!e.valid()) return;
|
|
85
|
-
target.focus();
|
|
86
|
-
target.selectionStart = from;
|
|
87
|
-
d.execCommand('insertText', false, text);
|
|
88
|
-
}};
|
|
89
|
-
return bplStart(e) >= 0 ? e : undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const host = d.createElement('div');
|
|
93
|
-
host.innerHTML = `<div class="ngn_lb" aria-label="BPL symbols"><button type="button" class="ngn_x" style="float:right" title="Close symbol bar">×</button></div>
|
|
94
|
-
<div class="bpl_choices" role="group" aria-label="BPL symbol completions" hidden></div>
|
|
95
|
-
<style>
|
|
96
|
-
.ngn_lb,.bpl_choices{background:var(--bpl-bar-background,#eee);color:var(--bpl-bar-color,#111);font:15px var(--bpl-font,SAX2B),monospace}
|
|
97
|
-
.ngn_lb{border-bottom:1px solid #999;padding:2px}
|
|
98
|
-
.ngn_lb button,.bpl_choices button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;padding:2px 4px}
|
|
99
|
-
.ngn_lb button:hover,.bpl_choices button:hover{background:#777;color:white}
|
|
100
|
-
.bpl_choices{position:fixed;z-index:2147483647;max-height:240px;max-width:calc(100vw - 16px);overflow:auto;border:1px solid #888;border-radius:4px;box-shadow:0 3px 12px #0003;padding:4px}
|
|
101
|
-
.bpl_choices button{display:block;width:100%;text-align:left;white-space:nowrap}
|
|
102
|
-
.bpl_choices small{display:block;padding:4px}
|
|
103
|
-
.ngn_lb .bpl_dead::after{content:'▾';font-size:9px;margin-left:1px}
|
|
104
|
-
.bpl_choices.bpl_menu{max-width:min(320px,calc(100vw - 16px))}
|
|
105
|
-
.bpl_menu button{display:inline-block;width:auto;min-width:28px;text-align:center}
|
|
106
|
-
</style>`;
|
|
107
|
-
container.append(host);
|
|
108
|
-
const bar = host.querySelector('.ngn_lb'), tip = host.querySelector('.bpl_choices');
|
|
109
|
-
bar.querySelector('.ngn_x').onclick = () => { bar.hidden = true; };
|
|
110
|
-
let active, lastEditor, choice, keyInput = false;
|
|
111
|
-
const names = new Map(symbols.map(({glyph, name, monad, dyad}) =>
|
|
112
|
-
[glyph, [name, monad, dyad].filter(Boolean).join(' ')]));
|
|
113
|
-
function stateGlyphs(state) {
|
|
114
|
-
const {terminator, keys} = layout.states[state];
|
|
115
|
-
return [terminator, ...Object.values(keys).flatMap(value => typeof value === 'string' ? [value] : stateGlyphs(value.state))];
|
|
116
|
-
}
|
|
117
|
-
const groups = new Map(Object.values(layout.option).filter(value => value.state).map(({state}) =>
|
|
118
|
-
[layout.states[state].terminator, [...new Set(stateGlyphs(state))]]));
|
|
119
|
-
const variants = new Set([...groups.values()].flatMap(glyphs => glyphs.slice(1)));
|
|
120
|
-
function button(glyph, name) {
|
|
121
|
-
const b = d.createElement('button');
|
|
122
|
-
b.type = 'button'; b.textContent = glyph; b.title = (name || glyph) + (shortcuts.get(glyph) || ''); b.dataset.glyph = glyph;
|
|
123
|
-
return b;
|
|
124
|
-
}
|
|
125
|
-
// Related glyphs stay together; arrows meet at the boundary between menus and plain buttons.
|
|
126
|
-
const order = [...new Set([
|
|
127
|
-
...'^_¯¨○⎕≡⍭↑↓←↦↢↣⇄∨∧⍺⍵∆∇⋄∊⍳⊂⊃∩∪⊥⊤⊣⊢×÷⌊⌈≤≥≠√π', ...groups.keys(), ...names.keys()
|
|
128
|
-
])];
|
|
129
|
-
for (const glyph of [...order.filter(g => groups.has(g)), ...order.filter(g => !groups.has(g))]) {
|
|
130
|
-
if (!groups.has(glyph) && (variants.has(glyph) || /^[\x20-\x7e]+$/.test(glyph))) continue;
|
|
131
|
-
const b = button(glyph, names.get(glyph));
|
|
132
|
-
if (groups.has(glyph)) {
|
|
133
|
-
b.textContent = {'^': '²', '_': '₂'}[glyph] || glyph;
|
|
134
|
-
b.classList.add('bpl_dead');
|
|
135
|
-
b.setAttribute('aria-expanded', 'false');
|
|
136
|
-
b.title += ' (variants)';
|
|
137
|
-
}
|
|
138
|
-
bar.append(b);
|
|
139
|
-
}
|
|
140
|
-
function cancel() {
|
|
141
|
-
choice?.anchor?.setAttribute('aria-expanded', 'false');
|
|
142
|
-
active = undefined; choice = undefined; tip.hidden = true;
|
|
143
|
-
}
|
|
144
|
-
function show(e, item, anchor) {
|
|
145
|
-
tip.classList.toggle('bpl_menu', !!anchor);
|
|
146
|
-
tip.setAttribute('aria-label', anchor ? 'BPL symbol variants' : 'BPL symbol completions');
|
|
147
|
-
anchor?.setAttribute('aria-expanded', 'true');
|
|
148
|
-
if (choice?.item.query !== item.query || choice?.anchor !== anchor) {
|
|
149
|
-
tip.replaceChildren();
|
|
150
|
-
for (const [glyph, name] of item.found) {
|
|
151
|
-
const b = button(glyph, name);
|
|
152
|
-
if (!anchor) b.textContent = `${glyph} ${b.title}`;
|
|
153
|
-
tip.append(b);
|
|
154
|
-
}
|
|
155
|
-
if (!item.found.length) {
|
|
156
|
-
const note = d.createElement('small'); note.textContent = 'Unknown symbol'; tip.append(note);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
choice = {e, item, anchor};
|
|
160
|
-
tip.hidden = false;
|
|
161
|
-
const r = anchor ? anchor.getBoundingClientRect() : e.rect();
|
|
162
|
-
tip.style.left = `${Math.max(4, Math.min(r.left, w.innerWidth - tip.offsetWidth - 8))}px`;
|
|
163
|
-
tip.style.top = `${Math.max(4, Math.min(r.bottom + 4, w.innerHeight - tip.offsetHeight - 8))}px`;
|
|
164
|
-
}
|
|
165
|
-
function refresh(target) {
|
|
166
|
-
const e = editor(target), item = e && entry(e);
|
|
167
|
-
if (item && active?.id === e.id && active.start === item.start) show(e, item);
|
|
168
|
-
else cancel();
|
|
169
|
-
}
|
|
170
|
-
on(bar, 'mousedown', ev => {
|
|
171
|
-
ev.preventDefault();
|
|
172
|
-
const b = ev.target.closest('button');
|
|
173
|
-
const opened = choice?.anchor === b;
|
|
174
|
-
cancel();
|
|
175
|
-
if (!lastEditor?.valid()) lastEditor = undefined;
|
|
176
|
-
if (b?.dataset.glyph && lastEditor) {
|
|
177
|
-
const glyph = b.dataset.glyph, group = groups.get(glyph);
|
|
178
|
-
if (group) {
|
|
179
|
-
if (!opened) show(lastEditor, {query: glyph, found: group.map(g => [g, names.get(g)])}, b);
|
|
180
|
-
} else lastEditor.insert(glyph);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
on(tip, 'mousedown', ev => {
|
|
184
|
-
ev.preventDefault();
|
|
185
|
-
const b = ev.target.closest('button');
|
|
186
|
-
if (b && choice?.e.valid()) choice.e.insert(b.dataset.glyph, choice.item.start);
|
|
187
|
-
cancel();
|
|
188
|
-
});
|
|
189
|
-
on(d, 'focusin', ev => { if (!host.contains(ev.target)) lastEditor = editor(ev.target); cancel(); });
|
|
190
|
-
on(d, 'pointerdown', ev => { if (!host.contains(ev.target)) cancel(); }, true);
|
|
191
|
-
on(d, 'pointerup', ev => { if (!host.contains(ev.target)) lastEditor = editor(ev.target); });
|
|
192
|
-
for (const event of ['paste', 'cut', 'compositionstart', 'focusout']) on(d, event, cancel, true);
|
|
193
|
-
on(d, 'input', ev => {
|
|
194
|
-
if (!keyInput || ev.inputType !== 'insertText' && ev.inputType !== 'deleteContentBackward') cancel();
|
|
195
|
-
keyInput = false;
|
|
196
|
-
w.requestAnimationFrame(() => { if (!events.signal.aborted) { lastEditor = editor(ev.target); refresh(ev.target); } });
|
|
197
|
-
});
|
|
198
|
-
on(w, 'blur', () => { leftAlt = rightAlt = false; lastEditor = undefined; cancel(); reset(); });
|
|
199
|
-
on(w, 'focusin', reset, true);
|
|
200
|
-
on(w, 'keyup', ev => {
|
|
201
|
-
if (ev.code === 'AltLeft') leftAlt = false;
|
|
202
|
-
if (ev.code === 'AltRight') rightAlt = false;
|
|
203
|
-
keyInput = false; lastEditor = editor(ev.target); if (active) refresh(ev.target);
|
|
204
|
-
}, true);
|
|
205
|
-
on(w, 'keydown', ev => {
|
|
206
|
-
if (ev.key === 'Escape' && choice?.anchor) {
|
|
207
|
-
cancel(); ev.preventDefault(); ev.stopImmediatePropagation(); return;
|
|
208
|
-
}
|
|
209
|
-
keyInput = false;
|
|
210
|
-
if (ev.code === 'AltLeft') leftAlt = true;
|
|
211
|
-
if (ev.code === 'AltRight') rightAlt = true;
|
|
212
|
-
if (['Shift', 'Control', 'Alt', 'Meta'].includes(ev.key)) return;
|
|
213
|
-
const e = editor(ev.target);
|
|
214
|
-
if (!e || ev.isComposing || ev.defaultPrevented) { lastEditor = undefined; cancel(); reset(); return; }
|
|
215
|
-
if (lastEditor && lastEditor.id !== e.id) { cancel(); reset(); }
|
|
216
|
-
lastEditor = e;
|
|
217
|
-
const body = bplStart(e);
|
|
218
|
-
const pressed = press(ev, leftAlt && !rightAlt && !ev.getModifierState('AltGraph') && body >= 0);
|
|
219
|
-
if (pressed) {
|
|
220
|
-
if (pressed.text) e.insert(pressed.text);
|
|
221
|
-
if (pressed.stop) { cancel(); ev.preventDefault(); ev.stopImmediatePropagation(); return; }
|
|
222
|
-
}
|
|
223
|
-
const item = entry(e), plain = !ev.ctrlKey && !ev.altKey && !ev.metaKey;
|
|
224
|
-
const tab = ev.key === 'Tab' && plain && !ev.shiftKey, enter = ev.key === 'Enter';
|
|
225
|
-
const typed = active?.id === e.id && active.start === item?.start;
|
|
226
|
-
const delimiter = plain && ev.key.length === 1 && !/[a-z]/i.test(ev.key);
|
|
227
|
-
if (item && (tab || typed && (enter || delimiter))) {
|
|
228
|
-
if (item.found.length === 1) {
|
|
229
|
-
e.insert(item.found[0][0], item.start);
|
|
230
|
-
cancel();
|
|
231
|
-
} else if (tab) {
|
|
232
|
-
active = {id: e.id, start: item.start};
|
|
233
|
-
show(e, item);
|
|
234
|
-
}
|
|
235
|
-
if (tab) { ev.preventDefault(); ev.stopImmediatePropagation(); return; }
|
|
236
|
-
}
|
|
237
|
-
if (ev.key === '`' && plain) {
|
|
238
|
-
const updated = editor(ev.target), body = updated ? bplStart(updated) : -1;
|
|
239
|
-
if (updated && body >= 0 && updated.empty && inCode(updated.text.slice(body, updated.pos))) active = {id: updated.id, start: updated.pos};
|
|
240
|
-
else cancel();
|
|
241
|
-
} else if (!(typed && plain && (/^[a-z]$/i.test(ev.key) || ev.key === 'Backspace'))) cancel();
|
|
242
|
-
keyInput = plain && (ev.key.length === 1 || ev.key === 'Backspace');
|
|
243
|
-
}, true);
|
|
244
|
-
return {dispose() { events.abort(); reset(); lastEditor = undefined; cancel(); host.remove(); }};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function page(monaco) {
|
|
248
|
-
const d = document;
|
|
249
|
-
if (d.querySelector('.bpl_page_bar') || d.querySelector('meta[name=generator][content^=quarto]') && !d.querySelector('[data-bpl]')) return;
|
|
250
|
-
const container = d.createElement('div');
|
|
251
|
-
container.className = 'bpl_page_bar';
|
|
252
|
-
container.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:2147483647';
|
|
253
|
-
d.body.append(container);
|
|
254
|
-
const input = attach(monaco, container, true), bar = container.querySelector('.ngn_lb');
|
|
255
|
-
bar.insertAdjacentHTML('afterbegin', '<button class="ngn_o" style="float:right" title="Toggle overlay/push-down"></button>');
|
|
256
|
-
let overlay = false;
|
|
257
|
-
const padding = d.body.style.paddingTop, toggle = bar.querySelector('.ngn_o');
|
|
258
|
-
try { overlay = localStorage.getItem('ngn_lb_overlay') === '1'; } catch {}
|
|
259
|
-
function reflow() {
|
|
260
|
-
toggle.textContent = overlay ? '▼' : '▲';
|
|
261
|
-
d.body.style.paddingTop = overlay || bar.hidden ? padding : `${bar.offsetHeight}px`;
|
|
262
|
-
}
|
|
263
|
-
toggle.onclick = () => {
|
|
264
|
-
overlay = !overlay;
|
|
265
|
-
try { localStorage.setItem('ngn_lb_overlay', overlay ? '1' : '0'); } catch {}
|
|
266
|
-
reflow();
|
|
267
|
-
};
|
|
268
|
-
const observer = new ResizeObserver(reflow);
|
|
269
|
-
observer.observe(bar); reflow();
|
|
270
|
-
return {dispose() { input.dispose(); observer.disconnect(); container.remove(); d.body.style.paddingTop = padding; }};
|
|
271
|
-
}
|
|
272
|
-
return {attach, page};
|
|
273
|
-
})
|
|
274
|
-
([{"glyph": "←", "name": "left-arrow", "kind": "syntax", "monad": "assign", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["是", "是"], "shortcut": " h"}, {"glyph": "⎕", "name": "quad", "kind": "syntax", "monad": "io", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["出入", "出入"], "shortcut": " q"}, {"glyph": "•", "name": "bullet", "kind": "system", "monad": "system", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["系", "系"], "shortcut": " y"}, {"glyph": "⍺", "name": "alpha", "kind": "argument", "monad": "left-argument", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["甲", "甲"], "shortcut": " a"}, {"glyph": "⍵", "name": "omega", "kind": "argument", "monad": "right-argument", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["乙", "乙"], "shortcut": " w"}, {"glyph": "⍶", "name": "alpha-underbar", "kind": "argument", "monad": "left-operand", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["丙", "丙"], "shortcut": " - a"}, {"glyph": "⍹", "name": "omega-underbar", "kind": "argument", "monad": "right-operand", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["丁", "丁"], "shortcut": " - w"}, {"glyph": "∇", "name": "del", "kind": "argument", "monad": "recursion", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["递", "遞"], "shortcut": " g"}, {"glyph": "⍢", "name": "del-diaeresis", "kind": "argument", "monad": "operator-recursion", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["循", "循"], "shortcut": " 1 g"}, {"glyph": "⍝", "name": "lamp", "kind": "comment", "monad": "comment", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["注", "注"], "shortcut": " o c"}, {"glyph": "⋄", "name": "diamond", "kind": "syntax", "monad": "separator", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["句", "句"], "shortcut": " `"}, {"glyph": "⁝", "name": "tricolon", "kind": "syntax", "monad": "token-separator", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["隔", "隔"], "shortcut": " :"}, {"glyph": "?", "name": "question", "kind": "syntax", "monad": "predicate", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["若", "若"], "shortcut": ""}, {"glyph": "¯", "name": "overbar", "kind": "literal", "monad": "negative", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["负", "負"], "shortcut": " -"}, {"glyph": "∞", "name": "infinity", "kind": "literal", "monad": "", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["永", "永"], "shortcut": " 8"}, {"glyph": "⍬", "name": "zilde", "kind": "literal", "monad": "empty", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["空", "空"], "shortcut": " )"}, {"glyph": "+", "name": "plus", "kind": "function", "monad": "conjugate", "dyad": "add", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["加", "加"], "shortcut": ""}, {"glyph": "-", "name": "minus", "kind": "function", "monad": "negate", "dyad": "subtract", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["减", "減"], "shortcut": ""}, {"glyph": "×", "name": "times", "kind": "function", "monad": "sign", "dyad": "multiply", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["乘号", "乘號"], "shortcut": " m"}, {"glyph": "÷", "name": "obelus", "kind": "function", "monad": "reciprocal", "dyad": "divide", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["除", "除"], "shortcut": " u"}, {"glyph": "⌈", "name": "upstile", "kind": "function", "monad": "ceiling", "dyad": "maximum", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["上", "上"], "shortcut": " s"}, {"glyph": "⌊", "name": "downstile", "kind": "function", "monad": "floor", "dyad": "minimum", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["下", "下"], "shortcut": " d"}, {"glyph": "|", "name": "stile", "kind": "function", "monad": "magnitude", "dyad": "residue", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["绝余", "絕餘"], "shortcut": ""}, {"glyph": "*", "name": "star", "kind": "function", "monad": "exponential", "dyad": "exponent", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["幂", "冪"], "shortcut": ""}, {"glyph": "⍟", "name": "circle-star", "kind": "function", "monad": "natural-log", "dyad": "logarithm", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["对", "對"], "shortcut": " o 8"}, {"glyph": "○", "name": "circle", "kind": "function", "monad": "cis", "dyad": "circular", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["圆", "圓"], "shortcut": " o"}, {"glyph": "π", "name": "pi", "kind": "function", "monad": "pi-times", "dyad": "pi-ratio", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["周", "周"], "shortcut": " p"}, {"glyph": "√", "name": "radical", "kind": "function", "monad": "sqrt", "dyad": "root", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["根", "根"], "shortcut": " 3"}, {"glyph": "!", "name": "exclamation", "kind": "function", "monad": "factorial", "dyad": "binomial", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["阶拣", "階揀"], "shortcut": ""}, {"glyph": "∧", "name": "wedge", "kind": "function", "monad": "polar", "dyad": "and", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["极且", "極且"], "shortcut": " 0"}, {"glyph": "∨", "name": "vee", "kind": "function", "monad": "real-imag", "dyad": "or", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["析或", "析或"], "shortcut": " 9"}, {"glyph": "⊼", "name": "wedge-bar", "kind": "function", "monad": "square", "dyad": "nand", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["方否", "方否"], "shortcut": " - 0"}, {"glyph": "⊽", "name": "vee-bar", "kind": "function", "monad": "double", "dyad": "nor", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["双莫", "雙莫"], "shortcut": " - 9"}, {"glyph": "~", "name": "tilde", "kind": "function", "monad": "not", "dyad": "without", "monad_rank": "0", "dyad_ranks": "∞ ∞", "hanzi": ["非无", "非無"], "shortcut": ""}, {"glyph": "=", "name": "equals", "kind": "function", "monad": "classify", "dyad": "equal", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["等", "等"], "shortcut": ""}, {"glyph": "≠", "name": "not-equals", "kind": "function", "monad": "unique-mask", "dyad": "not-equal", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["别初", "別初"], "shortcut": " +"}, {"glyph": "<", "name": "less-than", "kind": "function", "monad": "sort-up", "dyad": "less", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["小", "小"], "shortcut": ""}, {"glyph": "≤", "name": "less-than-or-equal", "kind": "function", "monad": "decrement", "dyad": "less-equal", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["限退", "限退"], "shortcut": " <"}, {"glyph": ">", "name": "greater-than", "kind": "function", "monad": "sort-down", "dyad": "greater", "monad_rank": "∞", "dyad_ranks": "0 0", "hanzi": ["大", "大"], "shortcut": ""}, {"glyph": "≥", "name": "greater-than-or-equal", "kind": "function", "monad": "increment", "dyad": "greater-equal", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["达进", "達進"], "shortcut": " >"}, {"glyph": "⍳", "name": "iota", "kind": "function", "monad": "indices", "dyad": "index-of", "monad_rank": "1", "dyad_ranks": "∞ ∞", "hanzi": ["位", "位"], "shortcut": " i"}, {"glyph": "↦", "name": "right-arrow-from-bar", "kind": "function", "monad": "range", "dyad": "to", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["至", "至"], "shortcut": " l"}, {"glyph": ":", "name": "colon", "kind": "function", "monad": "unkey", "dyad": "keyed", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["键卸", "鍵卸"], "shortcut": ""}, {"glyph": "⍴", "name": "rho", "kind": "function", "monad": "shape", "dyad": "reshape", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["形", "形"], "shortcut": " r"}, {"glyph": "≢", "name": "equal-underbar-slash", "kind": "function", "monad": "tally", "dyad": "not-match", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["数异", "數異"], "shortcut": " ?"}, {"glyph": "≡", "name": "equal-underbar", "kind": "function", "monad": "depth", "dyad": "match", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["同深", "同深"], "shortcut": " ="}, {"glyph": ",", "name": "comma", "kind": "function", "monad": "ravel", "dyad": "catenate", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["连", "連"], "shortcut": ""}, {"glyph": "⍪", "name": "comma-bar", "kind": "function", "monad": "table", "dyad": "catenate-first", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["接矩", "接矩"], "shortcut": " - ,"}, {"glyph": "⊂", "name": "left-shoe", "kind": "function", "monad": "enclose", "dyad": "partitioned-enclose", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["包", "包"], "shortcut": " z"}, {"glyph": "⊃", "name": "right-shoe", "kind": "function", "monad": "mix", "dyad": "pick", "monad_rank": "0", "dyad_ranks": "1 ∞", "hanzi": ["选合", "選合"], "shortcut": " x"}, {"glyph": "⊆", "name": "left-shoe-underbar", "kind": "function", "monad": "nest", "dyad": "partition", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["巢段", "巢段"], "shortcut": " - z"}, {"glyph": "∊", "name": "epsilon", "kind": "function", "monad": "enlist", "dyad": "member", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["属展", "屬展"], "shortcut": " e"}, {"glyph": "∪", "name": "down-shoe", "kind": "function", "monad": "unique", "dyad": "union", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["并独", "併獨"], "shortcut": " v"}, {"glyph": "∩", "name": "up-shoe", "kind": "function", "monad": "duplicates", "dyad": "intersection", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["交重", "交重"], "shortcut": " c"}, {"glyph": "⍋", "name": "delta-stile", "kind": "function", "monad": "grade-up", "dyad": "grade-up-by", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["升", "升"], "shortcut": " \\ 7"}, {"glyph": "⍒", "name": "del-stile", "kind": "function", "monad": "grade-down", "dyad": "grade-down-by", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["降", "降"], "shortcut": " \\ g"}, {"glyph": "↑", "name": "up-arrow", "kind": "function", "monad": "first", "dyad": "take", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["取", "取"], "shortcut": " k"}, {"glyph": "↓", "name": "down-arrow", "kind": "function", "monad": "split", "dyad": "drop", "monad_rank": "1", "dyad_ranks": "1 ∞", "hanzi": ["去拆", "去拆"], "shortcut": " j"}, {"glyph": "⌽", "name": "circle-stile", "kind": "function", "monad": "reverse", "dyad": "rotate", "monad_rank": "1", "dyad_ranks": "0 1", "hanzi": ["转", "轉"], "shortcut": " 2"}, {"glyph": "⊖", "name": "circle-bar", "kind": "function", "monad": "reverse-first", "dyad": "rotate-first", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["纵", "縱"], "shortcut": " o -"}, {"glyph": "⍉", "name": "circle-backslash", "kind": "function", "monad": "transpose", "dyad": "reorder-axes", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["翻", "翻"], "shortcut": " o \\"}, {"glyph": "⊤", "name": "down-tack", "kind": "function", "monad": "binary-encode", "dyad": "encode", "monad_rank": "∞", "dyad_ranks": "1 0", "hanzi": ["编", "編"], "shortcut": " n"}, {"glyph": "⊥", "name": "up-tack", "kind": "function", "monad": "binary-decode", "dyad": "decode", "monad_rank": "1", "dyad_ranks": "1 1", "hanzi": ["译", "譯"], "shortcut": " b"}, {"glyph": "⍎", "name": "hydrant", "kind": "function", "monad": "execute", "dyad": "execute-in", "monad_rank": "1", "dyad_ranks": "∞ ∞", "hanzi": ["行", "行"], "shortcut": " o b"}, {"glyph": "⍕", "name": "thorn", "kind": "function", "monad": "format", "dyad": "format-spec", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["文", "文"], "shortcut": " o n"}, {"glyph": "⌷", "name": "squad", "kind": "function", "monad": "materialise", "dyad": "index", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["索", "索"], "shortcut": " q \\"}, {"glyph": "⌹", "name": "domino", "kind": "function", "monad": "matrix-inverse", "dyad": "matrix-divide", "monad_rank": "2", "dyad_ranks": "∞ 2", "hanzi": ["解逆", "解逆"], "shortcut": " q u"}, {"glyph": "#", "name": "hash", "kind": "function", "monad": "runs", "dyad": "replicate", "monad_rank": "∞", "dyad_ranks": "1 ∞", "hanzi": ["复", "複"], "shortcut": ""}, {"glyph": "↕", "name": "up-down-arrow", "kind": "function", "monad": "pairs", "dyad": "windows", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["窗", "窗"], "shortcut": " K"}, {"glyph": "⍭", "name": "stile-tilde", "kind": "function", "monad": "prime", "dyad": "prime-mode", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["素", "素"], "shortcut": " \\"}, {"glyph": "⨸", "name": "circle-divide", "kind": "function", "monad": "factors", "dyad": "factor-spec", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["因", "因"], "shortcut": " o u"}, {"glyph": "⌻", "name": "quad-jot", "kind": "function", "monad": "roots", "dyad": "polyval", "monad_rank": "1", "dyad_ranks": "1 0", "hanzi": ["零值", "零值"], "shortcut": " q t"}, {"glyph": "⍸", "name": "iota-underbar", "kind": "function", "monad": "where", "dyad": "interval-index", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["处间", "處間"], "shortcut": " - i"}, {"glyph": "⍷", "name": "epsilon-underbar", "kind": "function", "monad": "groups", "dyad": "find", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["寻群", "尋群"], "shortcut": " - e"}, {"glyph": "⊢", "name": "right-tack", "kind": "function", "monad": "same", "dyad": "right", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["右", "右"], "shortcut": " '"}, {"glyph": "⊣", "name": "left-tack", "kind": "function", "monad": "same-left", "dyad": "left", "monad_rank": "∞", "dyad_ranks": "∞ ∞", "hanzi": ["左", "左"], "shortcut": " ;"}, {"glyph": "¿", "name": "inverted-question", "kind": "function", "monad": "roll", "dyad": "deal", "monad_rank": "0", "dyad_ranks": "0 0", "hanzi": ["掷抽", "擲抽"], "shortcut": " /"}, {"glyph": "¨", "name": "diaeresis", "kind": "monadic-operator", "monad": "each", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["遍", "遍"], "shortcut": " 1"}, {"glyph": "ᵇ", "name": "superscript-b", "kind": "monadic-operator", "monad": "bitwise", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["按", "按"], "shortcut": " 6 b"}, {"glyph": "⍨", "name": "tilde-diaeresis", "kind": "monadic-operator", "monad": "self", "dyad": "commute", "monad_rank": "", "dyad_ranks": "", "hanzi": ["己换", "己換"], "shortcut": " 1 `"}, {"glyph": "↣", "name": "right-tail-arrow", "kind": "dyadic-operator", "monad": "before", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["先", "先"], "shortcut": " ."}, {"glyph": "⍤", "name": "jot-diaeresis", "kind": "dyadic-operator", "monad": "rank", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["秩", "秩"], "shortcut": " 1 t"}, {"glyph": "∘", "name": "jot", "kind": "dyadic-operator", "monad": "atop", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["承", "承"], "shortcut": " t"}, {"glyph": "⍠", "name": "quad-colon", "kind": "dyadic-operator", "monad": "axis", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["轴", "軸"], "shortcut": " q ;"}, {"glyph": "⍥", "name": "circle-diaeresis", "kind": "dyadic-operator", "monad": "over", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["经", "經"], "shortcut": " 1 o"}, {"glyph": "↢", "name": "left-tail-arrow", "kind": "dyadic-operator", "monad": "after", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["后", "後"], "shortcut": " ,"}, {"glyph": ".", "name": "dot", "kind": "dyadic-operator", "monad": "determinant", "dyad": "inner-product", "monad_rank": "", "dyad_ranks": "", "hanzi": ["内", "內"], "shortcut": ""}, {"glyph": "⊗", "name": "circle-times", "kind": "monadic-operator", "monad": "outer-product", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["表", "表"], "shortcut": " o m"}, {"glyph": "⌸", "name": "quad-equal", "kind": "monadic-operator", "monad": "key", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["组", "組"], "shortcut": " q ="}, {"glyph": "⍣", "name": "star-diaeresis", "kind": "dyadic-operator", "monad": "power", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["次止", "次止"], "shortcut": " 1 8"}, {"glyph": "⇄", "name": "right-left-arrows", "kind": "monadic-operator", "monad": "optimize", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["优", "優"], "shortcut": " 4"}, {"glyph": "⊘", "name": "circle-slash", "kind": "dyadic-operator", "monad": "valences", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["兼", "兼"], "shortcut": " o /"}, {"glyph": "@", "name": "at", "kind": "dyadic-operator", "monad": "under", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["于", "於"], "shortcut": ""}, {"glyph": "∂", "name": "partial", "kind": "monadic-operator", "monad": "derivative", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["导梯", "導梯"], "shortcut": " f"}, {"glyph": "⍚", "name": "diamond-underbar", "kind": "dyadic-operator", "monad": "agenda", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["择", "擇"], "shortcut": " - `"}, {"glyph": "⌺", "name": "quad-diamond", "kind": "dyadic-operator", "monad": "stencil", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["邻", "鄰"], "shortcut": " q `"}, {"glyph": "/", "name": "slash", "kind": "monadic-operator", "monad": "reduce", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["总", "總"], "shortcut": ""}, {"glyph": "⌿", "name": "slash-bar", "kind": "monadic-operator", "monad": "reduce-first", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["汇", "匯"], "shortcut": " - /"}, {"glyph": "\\", "name": "backslash", "kind": "monadic-operator", "monad": "scan", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["累", "累"], "shortcut": ""}, {"glyph": "⍀", "name": "backslash-bar", "kind": "monadic-operator", "monad": "scan-first", "dyad": "", "monad_rank": "", "dyad_ranks": "", "hanzi": ["续", "續"], "shortcut": " - \\"}], ((symbols, layout) => {
|
|
275
|
-
const comments = new Set(symbols.filter(s => s.kind === 'comment').flatMap(s => [...s.glyph, ...s.hanzi.join('')]));
|
|
276
|
-
// US physical keys, before macOS Option or another layout transforms event.key.
|
|
277
|
-
const punctuation = {Backquote: '`~', Minus: '-_', Equal: '=+', BracketLeft: '[{', BracketRight: ']}',
|
|
278
|
-
Backslash: '\\|', Semicolon: ';:', Quote: "'\"", Comma: ',<', Period: '.>', Slash: '/?'};
|
|
279
|
-
function usKey({code, shiftKey}) {
|
|
280
|
-
if (/^Key[A-Z]$/.test(code)) return shiftKey ? code.slice(3) : code.slice(3).toLowerCase();
|
|
281
|
-
if (/^Digit[0-9]$/.test(code)) return shiftKey ? ')!@#$%^&*('[Number(code[5])] : code[5];
|
|
282
|
-
if (code === 'Space') return ' ';
|
|
283
|
-
return punctuation[code]?.[Number(shiftKey)];
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Composed input from `layout.json`, with the same rules as the REPL and the macOS layout. `pending` is the dead-key state
|
|
287
|
-
// that the next key completes.
|
|
288
|
-
let pending = null;
|
|
289
|
-
const act = action => typeof action === 'string' ? (pending = null, action) : (pending = action.state, '');
|
|
290
|
-
// What a key types: `{text, stop}`, where `stop` means the key itself does nothing more, or nothing for an ordinary key.
|
|
291
|
-
// `option` is whether an Option chord counts here.
|
|
292
|
-
function press(ev, option) {
|
|
293
|
-
const key = usKey(ev);
|
|
294
|
-
if (pending) {
|
|
295
|
-
const name = pending, state = layout.states[name];
|
|
296
|
-
pending = null;
|
|
297
|
-
if (ev.key === 'Backspace' || ev.key === 'Escape') return {text: '', stop: true};
|
|
298
|
-
if (!ev.ctrlKey && !ev.metaKey) {
|
|
299
|
-
if (key in state.keys) return {text: act(state.keys[key]), stop: true};
|
|
300
|
-
if (key === ' ' || layout.option[key]?.state === name) return {text: state.terminator, stop: true};
|
|
301
|
-
}
|
|
302
|
-
// Any other key types the terminator, then acts as if nothing were pending.
|
|
303
|
-
const rest = press(ev, option);
|
|
304
|
-
return {text: state.terminator + (rest?.text ?? ''), stop: rest?.stop ?? false};
|
|
305
|
-
}
|
|
306
|
-
// Native Option can hide the alias character; accept its US physical chord too.
|
|
307
|
-
const action = option && ev.altKey && !ev.ctrlKey && !ev.metaKey
|
|
308
|
-
? layout.alt_aliases[ev.key] ?? (Object.values(layout.alt_aliases).includes(key) ? key : layout.option[key]) : null;
|
|
309
|
-
if (action) return {text: act(action), stop: true};
|
|
310
|
-
}
|
|
311
|
-
const reset = () => { pending = null; };
|
|
312
|
-
|
|
313
|
-
// Every name ranks alike at each level: exact, prefix, then prefixes of hyphen-separated parts. Each match carries the name it
|
|
314
|
-
// matched by, the glyph name where several of a glyph's names match equally, as in `matches` in `symbols.rs`.
|
|
315
|
-
function matches(query) {
|
|
316
|
-
query = query.toLowerCase();
|
|
317
|
-
const letters = word => word.replaceAll('-', '');
|
|
318
|
-
let best = Infinity, found = [];
|
|
319
|
-
for (const {glyph, name, monad, dyad} of symbols) {
|
|
320
|
-
let rank = Infinity, matched;
|
|
321
|
-
[name, monad, dyad].filter(Boolean).forEach(word => {
|
|
322
|
-
const level = letters(word) === query ? 0 : letters(word).startsWith(query) ? 1 : 2;
|
|
323
|
-
if (level === 2) {
|
|
324
|
-
let rest = query;
|
|
325
|
-
for (const part of word.split('-')) {
|
|
326
|
-
let n = 0;
|
|
327
|
-
while (n < part.length && part[n] === rest[n]) n++;
|
|
328
|
-
if (!n) break;
|
|
329
|
-
rest = rest.slice(n);
|
|
330
|
-
if (!rest) break;
|
|
331
|
-
}
|
|
332
|
-
if (rest) return;
|
|
333
|
-
}
|
|
334
|
-
if (level < rank) { rank = level; matched = word; }
|
|
335
|
-
});
|
|
336
|
-
if (rank < best) { best = rank; found = []; }
|
|
337
|
-
if (rank < Infinity && rank === best) found.push([glyph, matched]);
|
|
338
|
-
}
|
|
339
|
-
// A name that is a prefix of every other match wins: `om gives omega, `omu gives omega-underbar.
|
|
340
|
-
const shortest = found.find(([, a]) => found.every(([, b]) => letters(b).startsWith(letters(a))));
|
|
341
|
-
return shortest && found.length > 1 ? [shortest] : found;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
function inCode(text, python = false) {
|
|
345
|
-
let quote = '', comment = false;
|
|
346
|
-
for (let i = 0; i < text.length; i++) {
|
|
347
|
-
const c = text[i];
|
|
348
|
-
if (comment) { if (c === '\n') comment = false; }
|
|
349
|
-
else if (quote) {
|
|
350
|
-
if (python && c === '\\') i++;
|
|
351
|
-
else if (text.startsWith(quote, i)) { i += quote.length - 1; quote = ''; }
|
|
352
|
-
} else if (c === "'" && !python) {
|
|
353
|
-
if (text.startsWith("''", i) && !text.startsWith("'''", i)) i++;
|
|
354
|
-
else {
|
|
355
|
-
if (i + 2 >= text.length) return false;
|
|
356
|
-
i += 2;
|
|
357
|
-
}
|
|
358
|
-
} else if (c === "'" || c === '"') {
|
|
359
|
-
quote = python && text.startsWith(c.repeat(3), i) ? c.repeat(3) : c;
|
|
360
|
-
i += quote.length - 1;
|
|
361
|
-
} else if (python ? c === '#' : comments.has(c)) comment = true;
|
|
362
|
-
}
|
|
363
|
-
return !quote && !comment;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function bplStart(e) {
|
|
367
|
-
if (e.bpl) return 0;
|
|
368
|
-
const header = /^%%(?:bpl|apl)[^\S\n]*(?:\r?\n|$)/.exec(e.text);
|
|
369
|
-
if (header) return e.pos >= header[0].length ? header[0].length : -1;
|
|
370
|
-
const start = e.text.lastIndexOf('\n', e.pos - 1) + 1;
|
|
371
|
-
const line = /^[ \t]*(?:[\p{ID_Start}_][\p{ID_Continue}]*[ \t]*=[ \t]*)?%bpl[ \t]+/u.exec(e.text.slice(start, e.pos));
|
|
372
|
-
return line && inCode(e.text.slice(0, start), true) ? start + line[0].length : -1;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function entry(e) {
|
|
376
|
-
const body = bplStart(e), start = e.text.lastIndexOf('`', e.pos - 1);
|
|
377
|
-
if (body < 0 || start < body || !e.empty || !inCode(e.text.slice(body, start))) return;
|
|
378
|
-
const query = e.text.slice(start + 1, e.pos);
|
|
379
|
-
if (/^[a-z]*$/i.test(query)) return {start, query, found: matches(query)};
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
return {matches, inCode, bplStart, entry, press, reset};
|
|
383
|
-
})
|
|
384
|
-
, {
|
|
385
|
-
"alt_aliases": {"£": "#"},
|
|
386
|
-
"unshifted": {"!": "1", "@": "2", "#": "3", "$": "4", "%": "5", "^": "6", "&": "7", "*": "8", "(": "9", ")": "0", "~": "`", "_": "-", "|": "\\", ":": ";"},
|
|
387
|
-
"optional_shift": {"!": "1", "@": "2", "#": "3", "$": "4", "%": "5", "^": "6", "&": "7", "*": "8", "(": "9", "_": "-"},
|
|
388
|
-
"option": {
|
|
389
|
-
"`": "⋄",
|
|
390
|
-
"1": {"state": "diaeresis"},
|
|
391
|
-
"2": "⌽",
|
|
392
|
-
"3": "√",
|
|
393
|
-
"4": "⇄",
|
|
394
|
-
"5": {"state": "subscript"},
|
|
395
|
-
"6": {"state": "superscript"},
|
|
396
|
-
"7": "∆",
|
|
397
|
-
"8": "∞",
|
|
398
|
-
"9": "∨",
|
|
399
|
-
"0": "∧",
|
|
400
|
-
")": "⍬",
|
|
401
|
-
"!": "¹",
|
|
402
|
-
"@": "²",
|
|
403
|
-
"#": "³",
|
|
404
|
-
"$": "⁴",
|
|
405
|
-
"%": "⁵",
|
|
406
|
-
"^": "⁶",
|
|
407
|
-
"&": "⁷",
|
|
408
|
-
"*": "⁸",
|
|
409
|
-
"(": "⁹",
|
|
410
|
-
"_": "⁻",
|
|
411
|
-
"-": {"state": "bar"},
|
|
412
|
-
"=": "≡",
|
|
413
|
-
"q": {"state": "quad"},
|
|
414
|
-
"w": "⍵",
|
|
415
|
-
"e": "∊",
|
|
416
|
-
"r": "⍴",
|
|
417
|
-
"t": "∘",
|
|
418
|
-
"y": "•",
|
|
419
|
-
"u": "÷",
|
|
420
|
-
"i": "⍳",
|
|
421
|
-
"o": {"state": "circle"},
|
|
422
|
-
"p": "π",
|
|
423
|
-
"+": "≠",
|
|
424
|
-
"\\": {"state": "stile"},
|
|
425
|
-
"a": "⍺",
|
|
426
|
-
"s": "⌈",
|
|
427
|
-
"d": "⌊",
|
|
428
|
-
"f": "∂",
|
|
429
|
-
"g": "∇",
|
|
430
|
-
"h": "←",
|
|
431
|
-
"j": "↓",
|
|
432
|
-
"k": "↑",
|
|
433
|
-
"K": "↕",
|
|
434
|
-
"l": "↦",
|
|
435
|
-
";": "⊣",
|
|
436
|
-
":": "⁝",
|
|
437
|
-
"'": "⊢",
|
|
438
|
-
"z": "⊂",
|
|
439
|
-
"x": "⊃",
|
|
440
|
-
"c": "∩",
|
|
441
|
-
"v": "∪",
|
|
442
|
-
"b": "⊥",
|
|
443
|
-
"n": "⊤",
|
|
444
|
-
"m": "×",
|
|
445
|
-
",": "↢",
|
|
446
|
-
".": "↣",
|
|
447
|
-
"<": "≤",
|
|
448
|
-
">": "≥",
|
|
449
|
-
"/": "¿",
|
|
450
|
-
"?": "≢"
|
|
451
|
-
},
|
|
452
|
-
"states": {
|
|
453
|
-
"diaeresis": {"terminator": "¨", "keys": {"t": "⍤", "o": "⍥", "*": "⍣", "~": "⍨", "g": "⍢", "8": "⍣", "`": "⍨"}},
|
|
454
|
-
"superscript": {"terminator": "⁶", "keys": {"0": "⁰", "1": "¹", "2": "²", "3": "³", "4": "⁴", "5": "⁵", "6": "⁶", "7": "⁷", "8": "⁸", "9": "⁹", ")": "⁰", "!": "¹", "@": "²", "#": "³", "$": "⁴", "%": "⁵", "^": "⁶", "&": "⁷", "*": "⁸", "(": "⁹", "-": {"state": "superscript-minus"}, "b": "ᵇ", "t": "ᵀ", "u": "ᵘ"}},
|
|
455
|
-
"superscript-minus": {"terminator": "⁻", "keys": {"0": "⁻⁰", "1": "⁻¹", "2": "⁻²", "3": "⁻³", "4": "⁻⁴", "5": "⁻⁵", "6": "⁻⁶", "7": "⁻⁷", "8": "⁻⁸", "9": "⁻⁹", ")": "⁻⁰", "!": "⁻¹", "@": "⁻²", "#": "⁻³", "$": "⁻⁴", "%": "⁻⁵", "^": "⁻⁶", "&": "⁻⁷", "*": "⁻⁸", "(": "⁻⁹"}},
|
|
456
|
-
"subscript": {"terminator": "₅", "keys": {"0": "₀", "1": "₁", "2": "₂", "3": "₃", "4": "₄", "5": "₅", "6": "₆", "7": "₇", "8": "₈", "9": "₉", ")": "₀", "!": "₁", "@": "₂", "#": "₃", "$": "₄", "%": "₅", "^": "₆", "&": "₇", "*": "₈", "(": "₉", "x": "ₓ", "j": "ⱼ", "e": "ₑ", "r": "ᵣ", "h": "ₕ", "s": "ₛ", "p": "ₚ", "-": {"state": "subscript-minus"}}},
|
|
457
|
-
"subscript-minus": {"terminator": "₋", "keys": {"0": "₋₀", "1": "₋₁", "2": "₋₂", "3": "₋₃", "4": "₋₄", "5": "₋₅", "6": "₋₆", "7": "₋₇", "8": "₋₈", "9": "₋₉", ")": "₋₀", "!": "₋₁", "@": "₋₂", "#": "₋₃", "$": "₋₄", "%": "₋₅", "^": "₋₆", "&": "₋₇", "*": "₋₈", "(": "₋₉"}},
|
|
458
|
-
"bar": {"terminator": "¯", "keys": {",": "⍪", "\\": "⍀", "/": "⌿", "a": "⍶", "w": "⍹", "7": "⍙", "`": "⍚", "0": "⊼", "9": "⊽", "e": "⍷", "i": "⍸", "z": "⊆"}},
|
|
459
|
-
"quad": {"terminator": "⎕", "keys": {"t": "⌻", ":": "⍠", "=": "⌸", "u": "⌹", "|": "⌷", "`": "⌺", ";": "⍠", "\\": "⌷"}},
|
|
460
|
-
"circle": {"terminator": "○", "keys": {"-": "⊖", "\\": "⍉", "/": "⊘", "*": "⍟", "m": "⊗", "u": "⨸", "8": "⍟", "c": "⍝", "b": "⍎", "n": "⍕"}},
|
|
461
|
-
"stile": {"terminator": "⍭", "keys": {"7": "⍋", "g": "⍒"}}
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
);
|
|
465
|
-
const font = new URL("SAX2B.woff2", import.meta.url);
|
|
466
|
-
export function installFont(doc = document) {
|
|
467
|
-
if (doc.getElementById('bpl-font')) return;
|
|
468
|
-
const style = doc.createElement('style');
|
|
469
|
-
style.id = 'bpl-font';
|
|
470
|
-
style.textContent = `@font-face{font-family:SAX2B;src:url("${font}") format("woff2")}`;
|
|
471
|
-
doc.head.append(style);
|
|
472
|
-
}
|
|
473
|
-
export function attach(monaco, container) {
|
|
474
|
-
installFont(container.ownerDocument);
|
|
475
|
-
return bar.attach(monaco, container);
|
|
476
|
-
}
|
|
File without changes
|
|
File without changes
|