@neuroplastio/xterm-addon-hotty 0.1.0-next.4 → 0.1.0-next.6

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.
@@ -898,6 +898,7 @@ var ACTIONS = /* @__PURE__ */ new Set([
898
898
  "page-down",
899
899
  "input-start",
900
900
  "input-end",
901
+ "select-all",
901
902
  "newline",
902
903
  "submit",
903
904
  "program",
@@ -913,7 +914,21 @@ var ACTIONS = /* @__PURE__ */ new Set([
913
914
  "scroll-end"
914
915
  ]);
915
916
  var SCROLL_ACTIONS = new Set([...ACTIONS].filter((a) => a.startsWith("scroll-")));
916
- var MULTILINE_ACTIONS = /* @__PURE__ */ new Set(["line-previous", "line-next", "page-up", "page-down", "input-start", "input-end", "newline"]);
917
+ var MULTILINE_ACTIONS = /* @__PURE__ */ new Set(["line-previous", "line-next", "page-up", "page-down", "newline"]);
918
+ var MOVES = /* @__PURE__ */ new Set([
919
+ "char-backward",
920
+ "char-forward",
921
+ "word-backward",
922
+ "word-forward",
923
+ "line-start",
924
+ "line-end",
925
+ "line-previous",
926
+ "line-next",
927
+ "page-up",
928
+ "page-down",
929
+ "input-start",
930
+ "input-end"
931
+ ]);
917
932
  var ROW_ACTIONS = /* @__PURE__ */ new Set(["line-previous", "line-next", "page-up", "page-down"]);
918
933
  var BACKWARD = /* @__PURE__ */ new Set(["char-backward", "word-backward", "line-start", "line-previous", "page-up", "input-start"]);
919
934
  var INSERT = "insert";
@@ -921,7 +936,7 @@ var TERMINAL_KEYS = [
921
936
  "ArrowLeft=char-backward Control+b=char-backward ArrowRight=char-forward Control+f=char-forward",
922
937
  "Alt+ArrowLeft=word-backward Control+ArrowLeft=word-backward Alt+b=word-backward",
923
938
  "Alt+ArrowRight=word-forward Control+ArrowRight=word-forward Alt+f=word-forward",
924
- "Home=line-start Control+a=line-start End=line-end Control+e=line-end",
939
+ "Home=line-start End=line-end Control+e=line-end",
925
940
  "Backspace=delete-char-backward Control+h=delete-char-backward",
926
941
  "Delete=delete-char-forward Control+d=delete-char-forward",
927
942
  "Alt+Backspace=delete-word-backward Control+w=delete-word-backward Control+Backspace=delete-word-backward",
@@ -930,6 +945,7 @@ var TERMINAL_KEYS = [
930
945
  "ArrowUp=line-previous Control+p=line-previous ArrowDown=line-next Control+n=line-next",
931
946
  "PageUp=page-up PageDown=page-down",
932
947
  "Alt+<=input-start Control+Home=input-start Alt+>=input-end Control+End=input-end",
948
+ "Control+a=select-all",
933
949
  "Control+m=newline"
934
950
  ].join(" ");
935
951
  var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
@@ -1181,6 +1197,15 @@ var Keymap = class {
1181
1197
  if (isChar(value) && !mods.some((m) => m !== "Shift")) return INSERT;
1182
1198
  return null;
1183
1199
  }
1200
+ /** Whether the field selects with a key (SPEC §10.2, *Shift selects*):
1201
+ * it looks up a move, and the key's name has Shift. The field then moves
1202
+ * its caret and keeps the selection's anchor. */
1203
+ selects(name) {
1204
+ const k = parseKey(name);
1205
+ if (k === null) return false;
1206
+ const a = this.lookup(k);
1207
+ return a !== null && MOVES.has(a) && splitKey(k)[0].includes("Shift");
1208
+ }
1184
1209
  };
1185
1210
  function* bindingsOf(value) {
1186
1211
  for (const b of value.split(/[ \t\n\f\r]+/)) {
@@ -1207,14 +1232,25 @@ function resolve(multiline, ...values) {
1207
1232
  for (const [k, a] of [
1208
1233
  ["ArrowLeft", "char-backward"],
1209
1234
  ["ArrowRight", "char-forward"],
1235
+ ["Control+ArrowLeft", "word-backward"],
1236
+ ["Control+ArrowRight", "word-forward"],
1237
+ ["Alt+ArrowLeft", "word-backward"],
1238
+ ["Alt+ArrowRight", "word-forward"],
1210
1239
  ["Home", "line-start"],
1211
1240
  ["End", "line-end"],
1241
+ ["Control+Home", "input-start"],
1242
+ ["Control+End", "input-end"],
1212
1243
  ["Backspace", "delete-char-backward"],
1213
1244
  ["Delete", "delete-char-forward"],
1245
+ ["Control+Backspace", "delete-word-backward"],
1246
+ ["Control+Delete", "delete-word-forward"],
1247
+ ["Alt+Backspace", "delete-word-backward"],
1248
+ ["Alt+Delete", "delete-word-forward"],
1214
1249
  ["ArrowUp", "line-previous"],
1215
1250
  ["ArrowDown", "line-next"],
1216
1251
  ["PageUp", "page-up"],
1217
1252
  ["PageDown", "page-down"],
1253
+ ["Control+a", "select-all"],
1218
1254
  ["Enter", multiline ? "newline" : "submit"]
1219
1255
  ])
1220
1256
  m.bind(k, a);
@@ -1241,10 +1277,16 @@ function wordForward(t, p) {
1241
1277
  while (p < t.chars.length && !isSpace(t.chars[p])) p++;
1242
1278
  return p;
1243
1279
  }
1244
- function plan(t, action, rows, goal = null) {
1280
+ function plan(t, action, rows, goal = null, extend = false) {
1245
1281
  if (MULTILINE_ACTIONS.has(action) && !t.multiline) return { kind: "none" };
1246
1282
  const n = t.chars.length;
1247
1283
  const selected = t.start < t.end;
1284
+ if (action === "select-all") return { kind: "move", anchor: 0, to: n };
1285
+ if (extend && MOVES.has(action)) {
1286
+ const anchor = t.caret === t.start ? t.end : t.start;
1287
+ const moved = plan({ ...t, start: t.caret, end: t.caret }, action, rows, goal);
1288
+ return moved.kind === "move" ? { ...moved, anchor } : moved;
1289
+ }
1248
1290
  if (action.startsWith("delete-")) {
1249
1291
  if (selected) return { kind: "replace", from: t.start, to: t.end, text: "" };
1250
1292
  const p2 = t.start;
@@ -1384,6 +1426,9 @@ var Surface = class {
1384
1426
  /** The document's base URL (SPEC §7.3). */
1385
1427
  base = NO_BASE;
1386
1428
  keyboard = false;
1429
+ /** The element the program knows has focus: the last `focus` named it,
1430
+ * or the program's `a=focus` gave it (SPEC §10.1). */
1431
+ told = null;
1387
1432
  /** Detached (SPEC §5.5): nothing in the surface reaches the program. */
1388
1433
  detachedState = false;
1389
1434
  /** A press is on something that takes no focus (SPEC §10.1): the focus
@@ -1560,6 +1605,7 @@ var Surface = class {
1560
1605
  this.dropDrag();
1561
1606
  const had = this.keyboard || this.frameFocused();
1562
1607
  this.keyboard = false;
1608
+ this.told = null;
1563
1609
  this.focusedControl()?.blur();
1564
1610
  if (had) this.giveBack();
1565
1611
  }
@@ -1751,17 +1797,21 @@ var Surface = class {
1751
1797
  if (target && !el) throw new Error(target);
1752
1798
  this.programFocus = true;
1753
1799
  try {
1754
- this.frame.focus();
1755
- this.frame.contentWindow?.focus();
1800
+ if (!this.frameFocused()) {
1801
+ this.frame.focus();
1802
+ this.frame.contentWindow?.focus();
1803
+ }
1756
1804
  if (el) el.focus();
1757
1805
  else if (!this.focusedControl()) this.tabbable()[0]?.focus();
1758
1806
  this.keyboard = true;
1807
+ this.told = this.focusedControl();
1759
1808
  } finally {
1760
1809
  setTimeout(() => this.programFocus = false, 0);
1761
1810
  }
1762
1811
  }
1763
1812
  /** `a=blur`, or the keyboard leaving: the edited control commits first. */
1764
1813
  blur() {
1814
+ this.pressed = null;
1765
1815
  this.commit();
1766
1816
  if (this.keyboard) this.giveBack();
1767
1817
  }
@@ -1812,6 +1862,7 @@ var Surface = class {
1812
1862
  if (this.keyboard) {
1813
1863
  this.commit();
1814
1864
  this.keyboard = false;
1865
+ this.told = null;
1815
1866
  this.emit("blur", "");
1816
1867
  }
1817
1868
  this.settle();
@@ -1839,16 +1890,24 @@ var Surface = class {
1839
1890
  }
1840
1891
  /** An element got focus: the surface takes the keyboard if the element is
1841
1892
  * one that takes focus, and the focus is neither the program's (no echo)
1842
- * nor a detached surface's. */
1893
+ * nor a detached surface's. The program hears where the user put focus,
1894
+ * each time it is another element than the one it knows (SPEC §10.1). */
1843
1895
  onFocusIn(e) {
1844
- if (this.programFocus || this.auxPress) return;
1845
- if (this.detachedState || this.pressNothing || !isElement(e.target) || !takesFocus(e.target, this.hyper)) {
1896
+ const el = isElement(e.target) ? e.target : null;
1897
+ if (this.programFocus) {
1898
+ this.told = el;
1899
+ return;
1900
+ }
1901
+ if (this.auxPress) return;
1902
+ if (this.detachedState || this.pressNothing || !el || !takesFocus(el, this.hyper)) {
1846
1903
  this.settle();
1847
1904
  return;
1848
1905
  }
1849
- if (this.keyboard) return;
1906
+ const gained = !this.keyboard;
1850
1907
  this.keyboard = true;
1851
- this.emit("focus", "");
1908
+ if (!gained && el === this.told) return;
1909
+ this.told = el;
1910
+ this.emit("focus", el.closest('[id]:not([id=""])')?.id ?? "");
1852
1911
  }
1853
1912
  tabbable() {
1854
1913
  const all = this.doc.querySelectorAll(
@@ -2001,6 +2060,7 @@ var Surface = class {
2001
2060
  const keys = data === null ? [{ key: domKeyName(e), data: "" }] : inputKeys(data);
2002
2061
  const keymap = this.keymapOf(el, multiline);
2003
2062
  const uses = keys.map((k) => k.key === null ? null : keymap.lookup(k.key));
2063
+ const extend = keys.map((k) => k.key !== null && keymap.selects(k.key));
2004
2064
  if (uses.every((u) => u === null)) {
2005
2065
  const program = keys.some((k) => k.key !== null && keymap.program(k.key));
2006
2066
  if (!program && this.axes && this.scrollKey(e)) return;
@@ -2029,7 +2089,7 @@ var Surface = class {
2029
2089
  } else if (use === "submit") {
2030
2090
  this.goal = null;
2031
2091
  submitFrom(el);
2032
- } else this.edit(el, multiline, { kind: "action", action: use });
2092
+ } else this.edit(el, multiline, { kind: "action", action: use, extend: extend[i] });
2033
2093
  });
2034
2094
  }
2035
2095
  /** A field's keymap (SPEC §10.2): the default, then the `data-keys` of
@@ -2057,6 +2117,7 @@ var Surface = class {
2057
2117
  };
2058
2118
  const start = index(el.selectionStart ?? el.value.length);
2059
2119
  const end = index(el.selectionEnd ?? el.value.length);
2120
+ const caret = el.selectionDirection === "backward" ? start : end;
2060
2121
  if (what.kind === "type") {
2061
2122
  this.goal = null;
2062
2123
  this.replace(el, at[start], at[end], what.text);
@@ -2064,14 +2125,16 @@ var Surface = class {
2064
2125
  }
2065
2126
  const action = what.action;
2066
2127
  const password = el.localName === "input" && this.inputType(el) === "password";
2067
- const text2 = { chars: cl, start, end, multiline, password };
2128
+ const text2 = { chars: cl, start, end, caret, multiline, password };
2068
2129
  const g = this.goal;
2069
- const goal = ROW_ACTIONS.has(action) && g && g.el === el && start === end && g.caret === start ? g.x : null;
2130
+ const goal = ROW_ACTIONS.has(action) && g && g.el === el && g.caret === caret ? g.x : null;
2070
2131
  const rows = multiline && ROW_ACTIONS.has(action) ? this.textareaRows(el, cl) : null;
2071
- const p = plan(text2, action, rows, goal);
2132
+ const p = plan(text2, action, rows, goal, what.extend);
2072
2133
  this.goal = p.kind === "move" && p.goal !== void 0 ? { el, caret: p.to, x: p.goal } : null;
2073
- if (p.kind === "move") el.setSelectionRange(at[p.to], at[p.to]);
2074
- else if (p.kind === "replace") this.replace(el, at[p.from], at[p.to], p.text);
2134
+ if (p.kind === "move") {
2135
+ const a = p.anchor ?? p.to;
2136
+ el.setSelectionRange(at[Math.min(a, p.to)], at[Math.max(a, p.to)], a > p.to ? "backward" : "forward");
2137
+ } else if (p.kind === "replace") this.replace(el, at[p.from], at[p.to], p.text);
2075
2138
  }
2076
2139
  /** Replaces code units `from` to `to` of a field's value with `text`, the
2077
2140
  * caret after it, as typing does. */
@@ -2160,6 +2223,10 @@ var Surface = class {
2160
2223
  d.execCommand("insertLineBreak", false);
2161
2224
  return;
2162
2225
  }
2226
+ if (action === "select-all") {
2227
+ sel.selectAllChildren(host);
2228
+ return;
2229
+ }
2163
2230
  const within = () => sel.focusNode !== null && host.contains(sel.focusNode);
2164
2231
  const next = (dir) => {
2165
2232
  const [an, ao, fn, fo] = [sel.anchorNode, sel.anchorOffset, sel.focusNode, sel.focusOffset];
@@ -2169,26 +2236,26 @@ var Surface = class {
2169
2236
  sel.setBaseAndExtent(an, ao, fn, fo);
2170
2237
  return c;
2171
2238
  };
2172
- const walk = (alter, dir, go) => {
2239
+ const walk = (alter2, dir, go) => {
2173
2240
  for (let i = 0; i < 1e5; i++) {
2174
2241
  const c = next(dir);
2175
2242
  if (!c || !go(c)) return;
2176
- sel.modify(alter, dir, "character");
2243
+ sel.modify(alter2, dir, "character");
2177
2244
  }
2178
2245
  };
2179
- const back = (alter, unit) => {
2246
+ const back = (alter2, unit) => {
2180
2247
  if (unit === "word") {
2181
- walk(alter, "backward", isSpace);
2182
- walk(alter, "backward", (c) => !isSpace(c));
2183
- } else if (unit === "line") walk(alter, "backward", (c) => !isBreak(c));
2184
- else sel.modify(alter, "backward", "character");
2248
+ walk(alter2, "backward", isSpace);
2249
+ walk(alter2, "backward", (c) => !isSpace(c));
2250
+ } else if (unit === "line") walk(alter2, "backward", (c) => !isBreak(c));
2251
+ else sel.modify(alter2, "backward", "character");
2185
2252
  };
2186
- const forward = (alter, unit) => {
2253
+ const forward = (alter2, unit) => {
2187
2254
  if (unit === "word") {
2188
- walk(alter, "forward", isSpace);
2189
- walk(alter, "forward", (c) => !isSpace(c));
2190
- } else if (unit === "line") walk(alter, "forward", (c) => !isBreak(c));
2191
- else sel.modify(alter, "forward", "character");
2255
+ walk(alter2, "forward", isSpace);
2256
+ walk(alter2, "forward", (c) => !isSpace(c));
2257
+ } else if (unit === "line") walk(alter2, "forward", (c) => !isBreak(c));
2258
+ else sel.modify(alter2, "forward", "character");
2192
2259
  };
2193
2260
  if (action.startsWith("delete-")) {
2194
2261
  if (sel.isCollapsed) {
@@ -2200,28 +2267,29 @@ var Surface = class {
2200
2267
  return;
2201
2268
  }
2202
2269
  const backward = ["char-backward", "word-backward", "line-start", "line-previous", "page-up", "input-start"].includes(action);
2203
- if (!sel.isCollapsed) {
2270
+ const alter = what.extend ? "extend" : "move";
2271
+ if (!what.extend && !sel.isCollapsed) {
2204
2272
  if (backward) sel.collapseToStart();
2205
2273
  else sel.collapseToEnd();
2206
2274
  if (action === "char-backward" || action === "char-forward") return;
2207
2275
  }
2208
2276
  const by = { "char-backward": "char", "char-forward": "char", "word-backward": "word", "word-forward": "word", "line-start": "line", "line-end": "line" }[action];
2209
2277
  if (by) {
2210
- if (backward) back("move", by);
2211
- else forward("move", by);
2278
+ if (backward) back(alter, by);
2279
+ else forward(alter, by);
2212
2280
  return;
2213
2281
  }
2214
2282
  if (action === "input-start" || action === "input-end") {
2215
- sel.modify("move", backward ? "backward" : "forward", "documentboundary");
2283
+ sel.modify(alter, backward ? "backward" : "forward", "documentboundary");
2216
2284
  return;
2217
2285
  }
2218
2286
  if (ROW_ACTIONS.has(action)) {
2219
2287
  const rows = action.startsWith("page") ? Math.max(1, Math.round(host.clientHeight / (parseFloat(this.frame.contentWindow.getComputedStyle(host).lineHeight) || 16))) : 1;
2220
2288
  for (let i = 0; i < rows; i++) {
2221
2289
  const [fn, fo] = [sel.focusNode, sel.focusOffset];
2222
- sel.modify("move", backward ? "backward" : "forward", "line");
2290
+ sel.modify(alter, backward ? "backward" : "forward", "line");
2223
2291
  if (sel.focusNode === fn && sel.focusOffset === fo) {
2224
- sel.modify("move", backward ? "backward" : "forward", "documentboundary");
2292
+ sel.modify(alter, backward ? "backward" : "forward", "documentboundary");
2225
2293
  return;
2226
2294
  }
2227
2295
  }
@@ -2712,6 +2780,7 @@ var Surface = class {
2712
2780
  this.commit();
2713
2781
  if (this.keyboard) {
2714
2782
  this.keyboard = false;
2783
+ this.told = null;
2715
2784
  this.emit("blur", "");
2716
2785
  }
2717
2786
  });