basedpl 0.1.81 → 0.1.83

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/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