@jsenv/terminal-recorder 1.5.54 → 1.5.56

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.
Files changed (35) hide show
  1. package/dist/jsenv_terminal_recorder_node_modules.js +3 -2
  2. package/package.json +5 -5
  3. package/src/.jsenv/chrome@149.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/packages/internal/plugin-supervisor/src/client/supervisor.js +24 -3
  4. package/src/.jsenv/chrome@149.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/dependency_status/client/dependency_status.js +233 -2
  5. package/src/.jsenv/chrome@149.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/page_switcher/client/page_switcher.js +136 -13
  6. package/src/.jsenv/chrome@149.0.0/xterm.html +5 -1
  7. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-fit/lib/addon-fit.mjs +18 -0
  8. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-fit/lib/addon-fit.mjs.map +28 -0
  9. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs +19 -0
  10. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-serialize/lib/addon-serialize.mjs.map +176 -0
  11. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-webgl/lib/addon-webgl.mjs +101 -0
  12. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-webgl/lib/addon-webgl.mjs.map +1623 -0
  13. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/xterm/css/xterm.css +267 -0
  14. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/xterm/lib/xterm.mjs +53 -0
  15. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/xterm/lib/xterm.mjs.map +7 -0
  16. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/packages/backend/server/src/plugins/autoreload_on_server_restart/client/autoreload_on_server_restart.js +133 -0
  17. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/packages/frontend/custom-elements-redefine/src/main.js +217 -0
  18. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/packages/internal/plugin-supervisor/src/client/supervisor.js +1607 -0
  19. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/client_monitoring/client/client_reporter.js +578 -0
  20. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/dependency_status/client/dependency_status.js +290 -0
  21. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/drop_to_open/client/drop_to_open.js +49 -0
  22. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/page_switcher/client/page_switcher.js +854 -0
  23. package/src/.jsenv/chrome@151.0.0/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/server_events/client/server_events_client.js +461 -0
  24. package/src/.jsenv/chrome@151.0.0/gif_encoder.js +400 -0
  25. package/src/.jsenv/chrome@151.0.0/gif_encoder.js.map +11 -0
  26. package/src/.jsenv/chrome@151.0.0/lzw_encoder.js +253 -0
  27. package/src/.jsenv/chrome@151.0.0/neuquant.js +498 -0
  28. package/src/.jsenv/chrome@151.0.0/terminal_recorder.js +384 -0
  29. package/src/.jsenv/chrome@151.0.0/terminal_recorder.js.map +11 -0
  30. package/src/.jsenv/chrome@151.0.0/xterm.html +88 -0
  31. package/src/.jsenv/chrome@151.0.0/xterm.html@L11C7-L15C16.js +5 -0
  32. package/src/.jsenv/chrome@151.0.0/xterm.html@L14C5-L18C14.js +5 -0
  33. package/src/.jsenv/chrome@151.0.0/xterm.html@L17C7-L21C16.js +5 -0
  34. package/src/.jsenv/chrome@151.0.0/xterm.html@L19C5-L24C14.js +7 -0
  35. package/src/.jsenv/chrome@151.0.0/xterm.html@L19C5-L24C14.js.map +11 -0
@@ -2,8 +2,9 @@ function ansiRegex({onlyFirst = false} = {}) {
2
2
  // Valid string terminator sequences are BEL, ESC\, and 0x9c
3
3
  const ST = '(?:\\u0007|\\u001B\\u005C|\\u009C)';
4
4
 
5
- // OSC sequences only: ESC ] ... ST (non-greedy until the first ST)
6
- const osc = `(?:\\u001B\\][\\s\\S]*?${ST})`;
5
+ // OSC sequences only: ESC ] ... ST
6
+ // The payload stops at the first terminator character rather than scanning ahead for one, so an unterminated `ESC ]` cannot rescan the rest of the input. Terminals likewise abort a control string on an unexpected ESC.
7
+ const osc = `(?:\\u001B\\][^\\u0007\\u001B\\u009C]*${ST})`;
7
8
 
8
9
  // CSI and related: ESC/C1, optional intermediates, optional params (supports ; and :) then final byte
9
10
  const csi = '[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/terminal-recorder",
3
- "version": "1.5.54",
3
+ "version": "1.5.56",
4
4
  "type": "module",
5
5
  "description": "Record terminal output as .svg, .gif, .webm, .mp4",
6
6
  "repository": {
@@ -35,13 +35,13 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@jsenv/humanize": "1.7.8",
38
- "@jsenv/server": "17.6.0",
38
+ "@jsenv/server": "17.6.1",
39
39
  "@jsenv/terminal-text-size": "0.0.4",
40
- "@playwright/browser-chromium": "1.61.1",
41
- "ansi-regex": "6.2.2",
40
+ "@playwright/browser-chromium": "1.62.1",
41
+ "ansi-regex": "6.3.0",
42
42
  "eastasianwidth": "0.3.0",
43
43
  "he": "1.2.0",
44
- "playwright": "1.61.1",
44
+ "playwright": "1.62.1",
45
45
  "strip-ansi": "7.2.0",
46
46
  "webm-to-mp4": "1.0.0"
47
47
  },
@@ -1107,7 +1107,9 @@ window.__supervisor__ = (() => {
1107
1107
  * a warning, never the other way around.
1108
1108
  */
1109
1109
  class JsenvWarningOverlay extends HTMLElement {
1110
- constructor({ title, text, details = [] }) {
1110
+ // "node" is for what a string cannot say: a live indicator, something
1111
+ // animated, anything the code reporting the warning wants to render itself
1112
+ constructor({ title, text, details = [], node }) {
1111
1113
  super();
1112
1114
  const root = this.attachShadow({ mode: "open" });
1113
1115
  root.innerHTML = `
@@ -1124,10 +1126,14 @@ window.__supervisor__ = (() => {
1124
1126
  <div class="details">
1125
1127
  ${details.map((detail) => `<p>${escapeHtml(detail)}</p>`).join("\n ")}
1126
1128
  </div>
1129
+ <div class="extra"></div>
1127
1130
  <div class="tip">
1128
1131
  Click outside to close.
1129
1132
  </div>
1130
1133
  </div>`;
1134
+ if (node) {
1135
+ root.querySelector(".extra").appendChild(node);
1136
+ }
1131
1137
  enableCopyButton(root);
1132
1138
  root.querySelector(".backdrop").onclick = () => {
1133
1139
  if (!this.parentNode) {
@@ -1160,6 +1166,14 @@ window.__supervisor__ = (() => {
1160
1166
  parts.push(paragraph.textContent.trim());
1161
1167
  }
1162
1168
  }
1169
+ // a node rendered by the warning reporter says which of its parts are
1170
+ // worth pasting, the rest being decoration
1171
+ const extraNode = overlay.querySelector(".extra");
1172
+ if (extraNode) {
1173
+ for (const line of extraNode.querySelectorAll("[data-copy-line]")) {
1174
+ parts.push(line.textContent.trim().replace(/\s+/g, " "));
1175
+ }
1176
+ }
1163
1177
  const copied = await writeTextToClipboard(parts.join("\n"));
1164
1178
  button.textContent = copied ? "Copied" : "Copy failed";
1165
1179
  clearTimeout(resetTimeout);
@@ -1376,6 +1390,13 @@ window.__supervisor__ = (() => {
1376
1390
  overflow: auto;
1377
1391
  }
1378
1392
 
1393
+ .extra {
1394
+ padding: 0 20px 16px;
1395
+ }
1396
+ .extra:empty {
1397
+ display: none;
1398
+ }
1399
+
1379
1400
  .tip {
1380
1401
  padding-top: 12px;
1381
1402
  border-top: 1px solid #999;
@@ -1406,11 +1427,11 @@ window.__supervisor__ = (() => {
1406
1427
  }
1407
1428
 
1408
1429
  supervisor.createException = createException;
1409
- supervisor.reportWarning = ({ title, text, details }) => {
1430
+ supervisor.reportWarning = ({ title, text, details, node }) => {
1410
1431
  if (!errorOverlay) {
1411
1432
  return () => {};
1412
1433
  }
1413
- return displayJsenvWarningOverlay({ title, text, details });
1434
+ return displayJsenvWarningOverlay({ title, text, details, node });
1414
1435
  };
1415
1436
  supervisor.reportException = (exception) => {
1416
1437
  if (errorOverlay) {
@@ -3,11 +3,22 @@
3
3
  *
4
4
  * A missing dependency is not handled here: it makes the import fail, so the
5
5
  * error overlay already says it, with more precision (which import, where).
6
+ *
7
+ * The overlay does not only describe the problem, it shows the dev server
8
+ * watching for the fix: the paths being looked at are named and kept alive on
9
+ * screen, so waiting for "npm install" feels like waiting for something that is
10
+ * actually going to happen.
6
11
  */
7
12
 
8
13
  let removeOverlay = () => {};
14
+ let watchInfoFromServer = {};
15
+ // packages listed as outdated at some point, and the path watched for each;
16
+ // what leaves this map has been installed while the overlay was open, which is
17
+ // worth showing as such
18
+ const outdatedPathMap = new Map();
9
19
 
10
- export const initDependencyStatus = ({ problems }) => {
20
+ export const initDependencyStatus = ({ problems, watchInfo }) => {
21
+ watchInfoFromServer = watchInfo || {};
11
22
  render(problems);
12
23
  // without the server events channel the page only knows the state it was
13
24
  // served with, which is still better than nothing
@@ -24,9 +35,19 @@ const render = (problems) => {
24
35
  const outdatedList = problems.filter(({ state }) => state === "outdated");
25
36
  removeOverlay();
26
37
  removeOverlay = () => {};
38
+ const installedList = [];
39
+ for (const [packageName, watchedPath] of outdatedPathMap) {
40
+ if (!outdatedList.some((problem) => problem.packageName === packageName)) {
41
+ installedList.push({ packageName, watchedPath });
42
+ }
43
+ }
27
44
  if (outdatedList.length === 0) {
45
+ outdatedPathMap.clear();
28
46
  return;
29
47
  }
48
+ for (const { packageName, watchedPath } of outdatedList) {
49
+ outdatedPathMap.set(packageName, watchedPath);
50
+ }
30
51
  const supervisor = window.__supervisor__;
31
52
  if (!supervisor || !supervisor.reportWarning) {
32
53
  console.warn(summarize(outdatedList));
@@ -41,8 +62,8 @@ const render = (problems) => {
41
62
  details: [
42
63
  "The page is running with what is installed in node_modules, which is not what package.json asks for. It may work, but it is not the code the project expects.",
43
64
  "Run npm install to fix it. If an install is already running, there is nothing to do but wait.",
44
- "This page reloads on its own as soon as node_modules matches package.json.",
45
65
  ],
66
+ node: createWatchNode(outdatedList, installedList),
46
67
  });
47
68
  };
48
69
 
@@ -57,3 +78,213 @@ const summarize = (outdatedList) => {
57
78
  .map(({ packageName }) => packageName)
58
79
  .join(", ")}`;
59
80
  };
81
+
82
+ const createWatchNode = (outdatedList, installedList) => {
83
+ const { packageJsonPath = "package.json", pollInterval } =
84
+ watchInfoFromServer;
85
+ const node = document.createElement("div");
86
+ node.className = "dependency_watch";
87
+ const rows = [];
88
+ rows.push(
89
+ createRow({
90
+ state: "watching",
91
+ path: packageJsonPath,
92
+ // a file watcher, not a poll: an edit here is what puts a dependency out
93
+ // of date in the first place
94
+ note: "on every change",
95
+ pollInterval,
96
+ }),
97
+ );
98
+ for (const { packageName, declaredVersion, watchedPath } of outdatedList) {
99
+ rows.push(
100
+ createRow({
101
+ state: "watching",
102
+ path: watchedPath || `node_modules/${packageName}/package.json`,
103
+ note: pollInterval
104
+ ? `waiting for ${declaredVersion}, read every ${pollInterval}ms`
105
+ : `waiting for ${declaredVersion}`,
106
+ pollInterval,
107
+ }),
108
+ );
109
+ }
110
+ for (const { packageName, watchedPath } of installedList) {
111
+ rows.push(
112
+ createRow({
113
+ state: "done",
114
+ path: watchedPath || `node_modules/${packageName}/package.json`,
115
+ note: "installed",
116
+ }),
117
+ );
118
+ }
119
+ node.innerHTML = `
120
+ <style>
121
+ ${watchCSS}
122
+ </style>
123
+ <div class="dependency_watch_head">
124
+ <span class="dependency_watch_live">
125
+ <span class="dependency_watch_live_dot"></span>watching
126
+ </span>
127
+ <span class="dependency_watch_head_text">
128
+ the files that will tell the install is over
129
+ </span>
130
+ </div>
131
+ <div class="dependency_watch_rows">
132
+ ${rows.join("\n ")}
133
+ </div>
134
+ <div class="dependency_watch_effect" data-copy-line>
135
+ As soon as node_modules matches package.json, this page reloads by itself.
136
+ </div>`;
137
+ return node;
138
+ };
139
+
140
+ const createRow = ({ state, path, note, pollInterval }) => {
141
+ const sweepStyle = pollInterval
142
+ ? ` style="animation-duration: ${pollInterval}ms"`
143
+ : "";
144
+ return `<div class="dependency_watch_row" data-state="${state}">
145
+ <span class="dependency_watch_row_icon"></span>
146
+ <code class="dependency_watch_row_path">${escapeHtml(path)}</code>
147
+ <span class="dependency_watch_row_note">${escapeHtml(note)}</span>
148
+ ${
149
+ state === "watching"
150
+ ? `<span class="dependency_watch_row_sweep"${sweepStyle}></span>`
151
+ : ""
152
+ }
153
+ </div>`;
154
+ };
155
+
156
+ const escapeHtml = (string) => {
157
+ return String(string)
158
+ .replace(/&/g, "&amp;")
159
+ .replace(/</g, "&lt;")
160
+ .replace(/>/g, "&gt;")
161
+ .replace(/"/g, "&quot;")
162
+ .replace(/'/g, "&#039;");
163
+ };
164
+
165
+ const watchCSS = /* css */ `
166
+ .dependency_watch_head {
167
+ display: flex;
168
+ margin-bottom: 8px;
169
+ align-items: center;
170
+ gap: 8px;
171
+ }
172
+ .dependency_watch_live {
173
+ display: flex;
174
+ padding: 2px 8px;
175
+ align-items: center;
176
+ gap: 6px;
177
+ color: #ffab40;
178
+ font-size: 12px;
179
+ text-transform: uppercase;
180
+ letter-spacing: 0.08em;
181
+ border: 1px solid currentColor;
182
+ border-radius: 999px;
183
+ }
184
+ .dependency_watch_live_dot {
185
+ width: 7px;
186
+ height: 7px;
187
+ background: currentColor;
188
+ border-radius: 50%;
189
+ animation: dependency_watch_pulse 1.4s ease-in-out infinite;
190
+ }
191
+ @keyframes dependency_watch_pulse {
192
+ 0%,
193
+ 100% {
194
+ opacity: 0.25;
195
+ transform: scale(0.8);
196
+ }
197
+ 50% {
198
+ opacity: 1;
199
+ transform: scale(1.15);
200
+ }
201
+ }
202
+ .dependency_watch_head_text {
203
+ font-size: 13px;
204
+ }
205
+
206
+ .dependency_watch_rows {
207
+ display: flex;
208
+ flex-direction: column;
209
+ gap: 4px;
210
+ }
211
+ .dependency_watch_row {
212
+ position: relative;
213
+ display: flex;
214
+ padding: 6px 10px;
215
+ align-items: center;
216
+ gap: 8px;
217
+ font-size: 13px;
218
+ background: rgba(255, 255, 255, 0.04);
219
+ border: 1px solid #333;
220
+ border-radius: 4px;
221
+ overflow: hidden;
222
+ }
223
+ .dependency_watch_row_icon {
224
+ width: 8px;
225
+ height: 8px;
226
+ flex: none;
227
+ border: 1px solid #ffab40;
228
+ border-radius: 50%;
229
+ }
230
+ .dependency_watch_row[data-state="done"] .dependency_watch_row_icon {
231
+ background: #7fd67f;
232
+ border-color: #7fd67f;
233
+ }
234
+ .dependency_watch_row_path {
235
+ color: #eee;
236
+ text-overflow: ellipsis;
237
+ white-space: nowrap;
238
+ overflow: hidden;
239
+ }
240
+ .dependency_watch_row_note {
241
+ margin-left: auto;
242
+ padding-left: 8px;
243
+ font-size: 12px;
244
+ white-space: nowrap;
245
+ opacity: 0.8;
246
+ }
247
+ .dependency_watch_row[data-state="done"] .dependency_watch_row_note {
248
+ color: #7fd67f;
249
+ opacity: 1;
250
+ }
251
+ /* the sweep is the watching made visible: one pass per read */
252
+ .dependency_watch_row_sweep {
253
+ position: absolute;
254
+ top: 0;
255
+ left: 0;
256
+ width: 35%;
257
+ height: 100%;
258
+ background: linear-gradient(
259
+ 90deg,
260
+ transparent,
261
+ rgba(255, 171, 64, 0.16),
262
+ transparent
263
+ );
264
+ animation: dependency_watch_sweep 2s linear infinite;
265
+ pointer-events: none;
266
+ }
267
+ @keyframes dependency_watch_sweep {
268
+ from {
269
+ transform: translateX(-100%);
270
+ }
271
+ to {
272
+ transform: translateX(340%);
273
+ }
274
+ }
275
+
276
+ .dependency_watch_effect {
277
+ margin-top: 8px;
278
+ color: #ffab40;
279
+ font-size: 13px;
280
+ }
281
+
282
+ @media (prefers-reduced-motion: reduce) {
283
+ .dependency_watch_live_dot {
284
+ animation: none;
285
+ }
286
+ .dependency_watch_row_sweep {
287
+ display: none;
288
+ }
289
+ }
290
+ `;
@@ -2,6 +2,11 @@
2
2
  * cmd+K / ctrl+K on any dev-served page: the .html files the server serves, as a
3
3
  * tree one walks, filter as you type, Enter to go there.
4
4
  *
5
+ * cmd+E / ctrl+E is the other half of the same question: instead of going to a
6
+ * page, open its file in the editor (the server does it, see
7
+ * GET /.internal/open_file/*). Pressed on the page itself it opens the page one
8
+ * is on; pressed inside the switcher it opens the row one is looking at.
9
+ *
5
10
  * A tree rather than a list of paths, because the paths are mostly the same
6
11
  * path: folding every directory that holds a single thing turns
7
12
  * "packages/frontend/navi/src/layout/demos/…" repeated forty times into one
@@ -25,6 +30,10 @@
25
30
  // another injected client. A function scope owes nothing to anybody.
26
31
  (() => {
27
32
  const PAGES_ENDPOINT = "/.internal/pages.json";
33
+ // The server asks the OS to open a file in whatever editor is configured
34
+ // (VSCode here) — it takes a file url, which is why the page list carries one
35
+ // per page (see html_pages.js).
36
+ const OPEN_FILE_ENDPOINT = "/.internal/open_file/";
28
37
  const STORAGE_KEY = "jsenv_page_switcher";
29
38
  // Open across a reload: this is a dev tool on a page one is editing, and a hot
30
39
  // reload in the middle of looking for the next page should not close what one
@@ -56,15 +65,20 @@
56
65
  }
57
66
  };
58
67
 
59
- const isSwitcherKey = (event) => {
60
- if (event.key !== "k" && event.key !== "K") {
61
- return false;
62
- }
63
- // cmd on mac, ctrl elsewhere — the same split every editor makes.
64
- return window.navigator.platform.toLowerCase().includes("mac")
68
+ // cmd on mac, ctrl elsewhere — the same split every editor makes.
69
+ const isCommandKey = (event) =>
70
+ window.navigator.platform.toLowerCase().includes("mac")
65
71
  ? event.metaKey && !event.ctrlKey
66
72
  : event.ctrlKey && !event.metaKey;
67
- };
73
+
74
+ const isSwitcherKey = (event) =>
75
+ (event.key === "k" || event.key === "K") && isCommandKey(event);
76
+ // E for edit, next to K for the same reason the two belong together: K asks
77
+ // "which page", E asks "where does this page live". Outside the switcher it
78
+ // means the page one is on; inside it, the row one is looking at — so the
79
+ // same press reads the same way in both places.
80
+ const isEditorKey = (event) =>
81
+ (event.key === "e" || event.key === "E") && isCommandKey(event);
68
82
 
69
83
  const STYLE_TEXT = /* css */ `
70
84
  :host {
@@ -230,6 +244,32 @@
230
244
  }
231
245
  `;
232
246
 
247
+ const FLASH_STYLE_TEXT = /* css */ `
248
+ :host {
249
+ position: fixed;
250
+ right: 16px;
251
+ bottom: 16px;
252
+ /* Above the switcher's own panel: it is the switcher that triggers it. */
253
+ z-index: 2147483647;
254
+ display: block;
255
+ font-family: system-ui, sans-serif;
256
+ pointer-events: none;
257
+ }
258
+ .flash {
259
+ padding: 8px 14px;
260
+ color: light-dark(#0f172a, #e2e8f0);
261
+ font-size: 13px;
262
+ background: light-dark(white, #1e293b);
263
+ border-radius: 8px;
264
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
265
+ color-scheme: light dark;
266
+ }
267
+ .flash[data-error] {
268
+ color: light-dark(#991b1b, #fecaca);
269
+ background: light-dark(#fee2e2, #7f1d1d);
270
+ }
271
+ `;
272
+
233
273
  let pagesPromise = null;
234
274
  const loadPages = () => {
235
275
  // Once per page load: the list is a filesystem scan behind a short cache
@@ -240,6 +280,54 @@
240
280
  return pagesPromise;
241
281
  };
242
282
 
283
+ // Opening a file in an editor happens in another application, on another
284
+ // screen sometimes: without a word here, a press that failed and a press that
285
+ // worked look exactly the same. Its own host and its own shadow root, so it
286
+ // can be shown whether or not the switcher is open.
287
+ let flashHost = null;
288
+ let flashBox = null;
289
+ let flashTimeout = null;
290
+ const flash = (message, isError) => {
291
+ if (!flashHost) {
292
+ flashHost = document.createElement("div");
293
+ const shadow = flashHost.attachShadow({ mode: "open" });
294
+ const style = document.createElement("style");
295
+ style.textContent = FLASH_STYLE_TEXT;
296
+ flashBox = document.createElement("div");
297
+ flashBox.className = "flash";
298
+ shadow.append(style, flashBox);
299
+ }
300
+ flashBox.textContent = message;
301
+ flashBox.toggleAttribute("data-error", Boolean(isError));
302
+ // Appended last every time, so it sits above the switcher's host when both
303
+ // are on the page and they share the same z-index.
304
+ document.body.append(flashHost);
305
+ window.clearTimeout(flashTimeout);
306
+ flashTimeout = window.setTimeout(() => flashHost.remove(), 2500);
307
+ };
308
+
309
+ const openInEditor = async (file) => {
310
+ if (!file || !file.fileUrl) {
311
+ flash("This page is not a file the server lists.", true);
312
+ return;
313
+ }
314
+ flash(`Opening ${file.name || file.url} in editor…`);
315
+ try {
316
+ const response = await fetch(
317
+ `${OPEN_FILE_ENDPOINT}${encodeURIComponent(file.fileUrl)}`,
318
+ );
319
+ if (response.status === 404) {
320
+ // The route exists only when the server is willing to expose the
321
+ // machine it runs on (see start_server.js).
322
+ flash("This server does not open files in an editor.", true);
323
+ } else if (!response.ok) {
324
+ flash(`Editor said no (${response.status}).`, true);
325
+ }
326
+ } catch {
327
+ flash("Could not reach the dev server.", true);
328
+ }
329
+ };
330
+
243
331
  const readStoredState = () => {
244
332
  try {
245
333
  const stored = JSON.parse(
@@ -396,7 +484,11 @@
396
484
  panel.className = "panel";
397
485
  const input = document.createElement("input");
398
486
  input.type = "search";
399
- input.placeholder = "Go to page…";
487
+ // The other key is written where one is already looking: a shortcut nobody
488
+ // is told about is a shortcut nobody presses. Both names, not the one this
489
+ // platform uses — the reader knows which of the two their keyboard has, and
490
+ // it keeps what the panel says the same everywhere.
491
+ input.placeholder = "Go to page… (cmd/ctrl+E to open in editor)";
400
492
  input.setAttribute("aria-label", "Go to page");
401
493
  const kindsRow = document.createElement("div");
402
494
  kindsRow.className = "kinds";
@@ -664,6 +756,21 @@
664
756
  toggleCollapsed(row.node.path);
665
757
  return;
666
758
  }
759
+ if (isEditorKey(event)) {
760
+ // Taken whatever the row is: let go of on a directory it would reach
761
+ // the page below and open the page one came from, which is not what a
762
+ // key pressed inside an open switcher can be asking for.
763
+ stop();
764
+ const row = rows[currentIndex];
765
+ if (!row || row.type !== "file") {
766
+ return;
767
+ }
768
+ // Done with the switcher: the answer to "where does this live" arrives
769
+ // in the editor, not here.
770
+ close();
771
+ openInEditor(row.file);
772
+ return;
773
+ }
667
774
  if (isSwitcherKey(event)) {
668
775
  stop();
669
776
  close();
@@ -708,15 +815,31 @@
708
815
  // preventDefault, the key was theirs and nothing happens here.
709
816
  const listenSwitcherKey = () => {
710
817
  window.addEventListener("keydown", (event) => {
711
- if (event.defaultPrevented || !isSwitcherKey(event)) {
818
+ if (event.defaultPrevented) {
712
819
  return;
713
820
  }
714
- // Ours now: the browser has its own use for cmd+K (the address bar), which
715
- // it must not get.
716
- event.preventDefault();
717
- openSwitcher();
821
+ if (isSwitcherKey(event)) {
822
+ // Ours now: the browser has its own use for cmd+K (the address bar),
823
+ // which it must not get.
824
+ event.preventDefault();
825
+ openSwitcher();
826
+ return;
827
+ }
828
+ if (isEditorKey(event)) {
829
+ event.preventDefault();
830
+ openCurrentPageInEditor();
831
+ }
718
832
  });
719
833
  };
834
+ // The page one is looking at, in the editor. The list is where the file url
835
+ // comes from, so a page the server does not list (an @fs url, something under
836
+ // node_modules) says so rather than opening the wrong thing.
837
+ const openCurrentPageInEditor = async () => {
838
+ const here = currentPageUrl();
839
+ const pages = await loadPages();
840
+ const page = pages.find((candidate) => candidate.url === here);
841
+ openInEditor(page && { ...page, name: here.split("/").pop() });
842
+ };
720
843
  const setup = () => {
721
844
  listenSwitcherKey();
722
845
  if (wasOpen()) {
@@ -46,7 +46,11 @@
46
46
  import { initDependencyStatus } from "/@fs/Users/dmail/Documents/dev/jsenv/core/src/plugins/dependency_status/client/dependency_status.js";
47
47
 
48
48
  initDependencyStatus({
49
- "problems": []
49
+ "problems": [],
50
+ "watchInfo": {
51
+ "packageJsonPath": "package.json",
52
+ "pollInterval": 500
53
+ }
50
54
  });
51
55
  </script>
52
56
  <script type="module" jsenv-injected-by="jsenv:drop_to_open" content-indented="">
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2014-2024 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ *
5
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
6
+ * @license MIT
7
+ *
8
+ * Originally forked from (with the author's permission):
9
+ * Fabrice Bellard's javascript vt100 for jslinux:
10
+ * http://bellard.org/jslinux/
11
+ * Copyright (c) 2011 Fabrice Bellard
12
+ */
13
+ /*---------------------------------------------------------------------------------------------
14
+ * Copyright (c) Microsoft Corporation. All rights reserved.
15
+ * Licensed under the MIT License. See License.txt in the project root for license information.
16
+ *--------------------------------------------------------------------------------------------*/
17
+ var h=2,_=1,o=class{activate(e){this._terminal=e}dispose(){}fit(){let e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;let t=this._terminal._core;(this._terminal.rows!==e.rows||this._terminal.cols!==e.cols)&&(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal||!this._terminal.element||!this._terminal.element.parentElement)return;let t=this._terminal._core._renderService.dimensions;if(t.css.cell.width===0||t.css.cell.height===0)return;let s=this._terminal.options.scrollback===0?0:this._terminal.options.overviewRuler?.width||14,r=window.getComputedStyle(this._terminal.element.parentElement),l=parseInt(r.getPropertyValue("height")),a=Math.max(0,parseInt(r.getPropertyValue("width"))),i=window.getComputedStyle(this._terminal.element),n={top:parseInt(i.getPropertyValue("padding-top")),bottom:parseInt(i.getPropertyValue("padding-bottom")),right:parseInt(i.getPropertyValue("padding-right")),left:parseInt(i.getPropertyValue("padding-left"))},m=n.top+n.bottom,d=n.right+n.left,c=l-m,p=a-d-s;return{cols:Math.max(h,Math.floor(p/t.css.cell.width)),rows:Math.max(_,Math.floor(c/t.css.cell.height))}}};export{o as FitAddon};
18
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vVXNlcnMvZG1haWwvRG9jdW1lbnRzL2Rldi9qc2Vudi9jb3JlL25vZGVfbW9kdWxlcy9AeHRlcm0vYWRkb24tZml0L3NyYy9GaXRBZGRvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgMjAxNyBUaGUgeHRlcm0uanMgYXV0aG9ycy4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqIEBsaWNlbnNlIE1JVFxuICovXG5cbmltcG9ydCB0eXBlIHsgVGVybWluYWwsIElUZXJtaW5hbEFkZG9uIH0gZnJvbSAnQHh0ZXJtL3h0ZXJtJztcbmltcG9ydCB0eXBlIHsgRml0QWRkb24gYXMgSUZpdEFwaSB9IGZyb20gJ0B4dGVybS9hZGRvbi1maXQnO1xuaW1wb3J0IHsgSVJlbmRlckRpbWVuc2lvbnMgfSBmcm9tICdicm93c2VyL3JlbmRlcmVyL3NoYXJlZC9UeXBlcyc7XG5pbXBvcnQgeyBWaWV3cG9ydENvbnN0YW50cyB9IGZyb20gJ2Jyb3dzZXIvc2hhcmVkL0NvbnN0YW50cyc7XG5cbmludGVyZmFjZSBJVGVybWluYWxEaW1lbnNpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2Ygcm93cyBpbiB0aGUgdGVybWluYWwuXG4gICAqL1xuICByb3dzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBudW1iZXIgb2YgY29sdW1ucyBpbiB0aGUgdGVybWluYWwuXG4gICAqL1xuICBjb2xzOiBudW1iZXI7XG59XG5cbmNvbnN0IE1JTklNVU1fQ09MUyA9IDI7XG5jb25zdCBNSU5JTVVNX1JPV1MgPSAxO1xuXG5leHBvcnQgY2xhc3MgRml0QWRkb24gaW1wbGVtZW50cyBJVGVybWluYWxBZGRvbiAsIElGaXRBcGkge1xuICBwcml2YXRlIF90ZXJtaW5hbDogVGVybWluYWwgfCB1bmRlZmluZWQ7XG5cbiAgcHVibGljIGFjdGl2YXRlKHRlcm1pbmFsOiBUZXJtaW5hbCk6IHZvaWQge1xuICAgIHRoaXMuX3Rlcm1pbmFsID0gdGVybWluYWw7XG4gIH1cblxuICBwdWJsaWMgZGlzcG9zZSgpOiB2b2lkIHt9XG5cbiAgcHVibGljIGZpdCgpOiB2b2lkIHtcbiAgICBjb25zdCBkaW1zID0gdGhpcy5wcm9wb3NlRGltZW5zaW9ucygpO1xuICAgIGlmICghZGltcyB8fCAhdGhpcy5fdGVybWluYWwgfHwgaXNOYU4oZGltcy5jb2xzKSB8fCBpc05hTihkaW1zLnJvd3MpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVE9ETzogUmVtb3ZlIHJlbGlhbmNlIG9uIHByaXZhdGUgQVBJXG4gICAgY29uc3QgY29yZSA9ICh0aGlzLl90ZXJtaW5hbCBhcyBhbnkpLl9jb3JlO1xuXG4gICAgLy8gRm9yY2UgYSBmdWxsIHJlbmRlclxuICAgIGlmICh0aGlzLl90ZXJtaW5hbC5yb3dzICE9PSBkaW1zLnJvd3MgfHwgdGhpcy5fdGVybWluYWwuY29scyAhPT0gZGltcy5jb2xzKSB7XG4gICAgICBjb3JlLl9yZW5kZXJTZXJ2aWNlLmNsZWFyKCk7XG4gICAgICB0aGlzLl90ZXJtaW5hbC5yZXNpemUoZGltcy5jb2xzLCBkaW1zLnJvd3MpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBwcm9wb3NlRGltZW5zaW9ucygpOiBJVGVybWluYWxEaW1lbnNpb25zIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMuX3Rlcm1pbmFsKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5fdGVybWluYWwuZWxlbWVudCB8fCAhdGhpcy5fdGVybWluYWwuZWxlbWVudC5wYXJlbnRFbGVtZW50KSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8vIFRPRE86IFJlbW92ZSByZWxpYW5jZSBvbiBwcml2YXRlIEFQSVxuICAgIGNvbnN0IGNvcmUgPSAodGhpcy5fdGVybWluYWwgYXMgYW55KS5fY29yZTtcbiAgICBjb25zdCBkaW1zOiBJUmVuZGVyRGltZW5zaW9ucyA9IGNvcmUuX3JlbmRlclNlcnZpY2UuZGltZW5zaW9ucztcblxuICAgIGlmIChkaW1zLmNzcy5jZWxsLndpZHRoID09PSAwIHx8IGRpbXMuY3NzLmNlbGwuaGVpZ2h0ID09PSAwKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGNvbnN0IHNjcm9sbGJhcldpZHRoID0gKHRoaXMuX3Rlcm1pbmFsLm9wdGlvbnMuc2Nyb2xsYmFjayA9PT0gMFxuICAgICAgPyAwXG4gICAgICA6ICh0aGlzLl90ZXJtaW5hbC5vcHRpb25zLm92ZXJ2aWV3UnVsZXI/LndpZHRoIHx8IFZpZXdwb3J0Q29uc3RhbnRzLkRFRkFVTFRfU0NST0xMX0JBUl9XSURUSCkpO1xuXG4gICAgY29uc3QgcGFyZW50RWxlbWVudFN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUodGhpcy5fdGVybWluYWwuZWxlbWVudC5wYXJlbnRFbGVtZW50KTtcbiAgICBjb25zdCBwYXJlbnRFbGVtZW50SGVpZ2h0ID0gcGFyc2VJbnQocGFyZW50RWxlbWVudFN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ2hlaWdodCcpKTtcbiAgICBjb25zdCBwYXJlbnRFbGVtZW50V2lkdGggPSBNYXRoLm1heCgwLCBwYXJzZUludChwYXJlbnRFbGVtZW50U3R5bGUuZ2V0UHJvcGVydHlWYWx1ZSgnd2lkdGgnKSkpO1xuICAgIGNvbnN0IGVsZW1lbnRTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKHRoaXMuX3Rlcm1pbmFsLmVsZW1lbnQpO1xuICAgIGNvbnN0IGVsZW1lbnRQYWRkaW5nID0ge1xuICAgICAgdG9wOiBwYXJzZUludChlbGVtZW50U3R5bGUuZ2V0UHJvcGVydHlWYWx1ZSgncGFkZGluZy10b3AnKSksXG4gICAgICBib3R0b206IHBhcnNlSW50KGVsZW1lbnRTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCdwYWRkaW5nLWJvdHRvbScpKSxcbiAgICAgIHJpZ2h0OiBwYXJzZUludChlbGVtZW50U3R5bGUuZ2V0UHJvcGVydHlWYWx1ZSgncGFkZGluZy1yaWdodCcpKSxcbiAgICAgIGxlZnQ6IHBhcnNlSW50KGVsZW1lbnRTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCdwYWRkaW5nLWxlZnQnKSlcbiAgICB9O1xuICAgIGNvbnN0IGVsZW1lbnRQYWRkaW5nVmVyID0gZWxlbWVudFBhZGRpbmcudG9wICsgZWxlbWVudFBhZGRpbmcuYm90dG9tO1xuICAgIGNvbnN0IGVsZW1lbnRQYWRkaW5nSG9yID0gZWxlbWVudFBhZGRpbmcucmlnaHQgKyBlbGVtZW50UGFkZGluZy5sZWZ0O1xuICAgIGNvbnN0IGF2YWlsYWJsZUhlaWdodCA9IHBhcmVudEVsZW1lbnRIZWlnaHQgLSBlbGVtZW50UGFkZGluZ1ZlcjtcbiAgICBjb25zdCBhdmFpbGFibGVXaWR0aCA9IHBhcmVudEVsZW1lbnRXaWR0aCAtIGVsZW1lbnRQYWRkaW5nSG9yIC0gc2Nyb2xsYmFyV2lkdGg7XG4gICAgY29uc3QgZ2VvbWV0cnkgPSB7XG4gICAgICBjb2xzOiBNYXRoLm1heChNSU5JTVVNX0NPTFMsIE1hdGguZmxvb3IoYXZhaWxhYmxlV2lkdGggLyBkaW1zLmNzcy5jZWxsLndpZHRoKSksXG4gICAgICByb3dzOiBNYXRoLm1heChNSU5JTVVNX1JPV1MsIE1hdGguZmxvb3IoYXZhaWxhYmxlSGVpZ2h0IC8gZGltcy5jc3MuY2VsbC5oZWlnaHQpKVxuICAgIH07XG4gICAgcmV0dXJuIGdlb21ldHJ5O1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFzQkEsSUFBTUEsRUFBZSxFQUNmQyxFQUFlLEVBRVJDLEVBQU4sS0FBbUQsQ0FHakQsU0FBU0MsRUFBMEIsQ0FDeEMsS0FBSyxVQUFZQSxDQUNuQixDQUVPLFNBQWdCLENBQUMsQ0FFakIsS0FBWSxDQUNqQixJQUFNQyxFQUFPLEtBQUssa0JBQWtCLEVBQ3BDLEdBQUksQ0FBQ0EsR0FBUSxDQUFDLEtBQUssV0FBYSxNQUFNQSxFQUFLLElBQUksR0FBSyxNQUFNQSxFQUFLLElBQUksRUFDakUsT0FJRixJQUFNQyxFQUFRLEtBQUssVUFBa0IsT0FHakMsS0FBSyxVQUFVLE9BQVNELEVBQUssTUFBUSxLQUFLLFVBQVUsT0FBU0EsRUFBSyxRQUNwRUMsRUFBSyxlQUFlLE1BQU0sRUFDMUIsS0FBSyxVQUFVLE9BQU9ELEVBQUssS0FBTUEsRUFBSyxJQUFJLEVBRTlDLENBRU8sbUJBQXFELENBSzFELEdBSkksQ0FBQyxLQUFLLFdBSU4sQ0FBQyxLQUFLLFVBQVUsU0FBVyxDQUFDLEtBQUssVUFBVSxRQUFRLGNBQ3JELE9BS0YsSUFBTUEsRUFEUSxLQUFLLFVBQWtCLE1BQ0EsZUFBZSxXQUVwRCxHQUFJQSxFQUFLLElBQUksS0FBSyxRQUFVLEdBQUtBLEVBQUssSUFBSSxLQUFLLFNBQVcsRUFDeEQsT0FHRixJQUFNRSxFQUFrQixLQUFLLFVBQVUsUUFBUSxhQUFlLEVBQzFELEVBQ0MsS0FBSyxVQUFVLFFBQVEsZUFBZSxPQUFTLEdBRTlDQyxFQUFxQixPQUFPLGlCQUFpQixLQUFLLFVBQVUsUUFBUSxhQUFhLEVBQ2pGQyxFQUFzQixTQUFTRCxFQUFtQixpQkFBaUIsUUFBUSxDQUFDLEVBQzVFRSxFQUFxQixLQUFLLElBQUksRUFBRyxTQUFTRixFQUFtQixpQkFBaUIsT0FBTyxDQUFDLENBQUMsRUFDdkZHLEVBQWUsT0FBTyxpQkFBaUIsS0FBSyxVQUFVLE9BQU8sRUFDN0RDLEVBQWlCLENBQ3JCLElBQUssU0FBU0QsRUFBYSxpQkFBaUIsYUFBYSxDQUFDLEVBQzFELE9BQVEsU0FBU0EsRUFBYSxpQkFBaUIsZ0JBQWdCLENBQUMsRUFDaEUsTUFBTyxTQUFTQSxFQUFhLGlCQUFpQixlQUFlLENBQUMsRUFDOUQsS0FBTSxTQUFTQSxFQUFhLGlCQUFpQixjQUFjLENBQUMsQ0FDOUQsRUFDTUUsRUFBb0JELEVBQWUsSUFBTUEsRUFBZSxPQUN4REUsRUFBb0JGLEVBQWUsTUFBUUEsRUFBZSxLQUMxREcsRUFBa0JOLEVBQXNCSSxFQUN4Q0csRUFBaUJOLEVBQXFCSSxFQUFvQlAsRUFLaEUsTUFKaUIsQ0FDZixLQUFNLEtBQUssSUFBSU4sRUFBYyxLQUFLLE1BQU1lLEVBQWlCWCxFQUFLLElBQUksS0FBSyxLQUFLLENBQUMsRUFDN0UsS0FBTSxLQUFLLElBQUlILEVBQWMsS0FBSyxNQUFNYSxFQUFrQlYsRUFBSyxJQUFJLEtBQUssTUFBTSxDQUFDLENBQ2pGLENBRUYsQ0FDRiIsIm5hbWVzIjpbIk1JTklNVU1fQ09MUyIsIk1JTklNVU1fUk9XUyIsIkZpdEFkZG9uIiwidGVybWluYWwiLCJkaW1zIiwiY29yZSIsInNjcm9sbGJhcldpZHRoIiwicGFyZW50RWxlbWVudFN0eWxlIiwicGFyZW50RWxlbWVudEhlaWdodCIsInBhcmVudEVsZW1lbnRXaWR0aCIsImVsZW1lbnRTdHlsZSIsImVsZW1lbnRQYWRkaW5nIiwiZWxlbWVudFBhZGRpbmdWZXIiLCJlbGVtZW50UGFkZGluZ0hvciIsImF2YWlsYWJsZUhlaWdodCIsImF2YWlsYWJsZVdpZHRoIl19
@@ -0,0 +1,28 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [
4
+ "file:///Users/dmail/Documents/dev/jsenv/core/node_modules/@xterm/addon-fit/src/FitAddon.ts"
5
+ ],
6
+ "sourcesContent": [
7
+ "/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport type { Terminal, ITerminalAddon } from '@xterm/xterm';\nimport type { FitAddon as IFitApi } from '@xterm/addon-fit';\nimport { IRenderDimensions } from 'browser/renderer/shared/Types';\nimport { ViewportConstants } from 'browser/shared/Constants';\n\ninterface ITerminalDimensions {\n /**\n * The number of rows in the terminal.\n */\n rows: number;\n\n /**\n * The number of columns in the terminal.\n */\n cols: number;\n}\n\nconst MINIMUM_COLS = 2;\nconst MINIMUM_ROWS = 1;\n\nexport class FitAddon implements ITerminalAddon , IFitApi {\n private _terminal: Terminal | undefined;\n\n public activate(terminal: Terminal): void {\n this._terminal = terminal;\n }\n\n public dispose(): void {}\n\n public fit(): void {\n const dims = this.proposeDimensions();\n if (!dims || !this._terminal || isNaN(dims.cols) || isNaN(dims.rows)) {\n return;\n }\n\n // TODO: Remove reliance on private API\n const core = (this._terminal as any)._core;\n\n // Force a full render\n if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) {\n core._renderService.clear();\n this._terminal.resize(dims.cols, dims.rows);\n }\n }\n\n public proposeDimensions(): ITerminalDimensions | undefined {\n if (!this._terminal) {\n return undefined;\n }\n\n if (!this._terminal.element || !this._terminal.element.parentElement) {\n return undefined;\n }\n\n // TODO: Remove reliance on private API\n const core = (this._terminal as any)._core;\n const dims: IRenderDimensions = core._renderService.dimensions;\n\n if (dims.css.cell.width === 0 || dims.css.cell.height === 0) {\n return undefined;\n }\n\n const scrollbarWidth = (this._terminal.options.scrollback === 0\n ? 0\n : (this._terminal.options.overviewRuler?.width || ViewportConstants.DEFAULT_SCROLL_BAR_WIDTH));\n\n const parentElementStyle = window.getComputedStyle(this._terminal.element.parentElement);\n const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));\n const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));\n const elementStyle = window.getComputedStyle(this._terminal.element);\n const elementPadding = {\n top: parseInt(elementStyle.getPropertyValue('padding-top')),\n bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),\n right: parseInt(elementStyle.getPropertyValue('padding-right')),\n left: parseInt(elementStyle.getPropertyValue('padding-left'))\n };\n const elementPaddingVer = elementPadding.top + elementPadding.bottom;\n const elementPaddingHor = elementPadding.right + elementPadding.left;\n const availableHeight = parentElementHeight - elementPaddingVer;\n const availableWidth = parentElementWidth - elementPaddingHor - scrollbarWidth;\n const geometry = {\n cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / dims.css.cell.width)),\n rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / dims.css.cell.height))\n };\n return geometry;\n }\n}\n"
8
+ ],
9
+ "mappings": ";;;;;;;;;;;;;;;;AAsBA,IAAMA,EAAe,EACfC,EAAe,EAERC,EAAN,KAAmD,CAGjD,SAASC,EAA0B,CACxC,KAAK,UAAYA,CACnB,CAEO,SAAgB,CAAC,CAEjB,KAAY,CACjB,IAAMC,EAAO,KAAK,kBAAkB,EACpC,GAAI,CAACA,GAAQ,CAAC,KAAK,WAAa,MAAMA,EAAK,IAAI,GAAK,MAAMA,EAAK,IAAI,EACjE,OAIF,IAAMC,EAAQ,KAAK,UAAkB,OAGjC,KAAK,UAAU,OAASD,EAAK,MAAQ,KAAK,UAAU,OAASA,EAAK,QACpEC,EAAK,eAAe,MAAM,EAC1B,KAAK,UAAU,OAAOD,EAAK,KAAMA,EAAK,IAAI,EAE9C,CAEO,mBAAqD,CAK1D,GAJI,CAAC,KAAK,WAIN,CAAC,KAAK,UAAU,SAAW,CAAC,KAAK,UAAU,QAAQ,cACrD,OAKF,IAAMA,EADQ,KAAK,UAAkB,MACA,eAAe,WAEpD,GAAIA,EAAK,IAAI,KAAK,QAAU,GAAKA,EAAK,IAAI,KAAK,SAAW,EACxD,OAGF,IAAME,EAAkB,KAAK,UAAU,QAAQ,aAAe,EAC1D,EACC,KAAK,UAAU,QAAQ,eAAe,OAAS,GAE9CC,EAAqB,OAAO,iBAAiB,KAAK,UAAU,QAAQ,aAAa,EACjFC,EAAsB,SAASD,EAAmB,iBAAiB,QAAQ,CAAC,EAC5EE,EAAqB,KAAK,IAAI,EAAG,SAASF,EAAmB,iBAAiB,OAAO,CAAC,CAAC,EACvFG,EAAe,OAAO,iBAAiB,KAAK,UAAU,OAAO,EAC7DC,EAAiB,CACrB,IAAK,SAASD,EAAa,iBAAiB,aAAa,CAAC,EAC1D,OAAQ,SAASA,EAAa,iBAAiB,gBAAgB,CAAC,EAChE,MAAO,SAASA,EAAa,iBAAiB,eAAe,CAAC,EAC9D,KAAM,SAASA,EAAa,iBAAiB,cAAc,CAAC,CAC9D,EACME,EAAoBD,EAAe,IAAMA,EAAe,OACxDE,EAAoBF,EAAe,MAAQA,EAAe,KAC1DG,EAAkBN,EAAsBI,EACxCG,EAAiBN,EAAqBI,EAAoBP,EAKhE,MAJiB,CACf,KAAM,KAAK,IAAIN,EAAc,KAAK,MAAMe,EAAiBX,EAAK,IAAI,KAAK,KAAK,CAAC,EAC7E,KAAM,KAAK,IAAIH,EAAc,KAAK,MAAMa,EAAkBV,EAAK,IAAI,KAAK,MAAM,CAAC,CACjF,CAEF,CACF",
10
+ "names": [
11
+ "MINIMUM_COLS",
12
+ "MINIMUM_ROWS",
13
+ "FitAddon",
14
+ "terminal",
15
+ "dims",
16
+ "core",
17
+ "scrollbarWidth",
18
+ "parentElementStyle",
19
+ "parentElementHeight",
20
+ "parentElementWidth",
21
+ "elementStyle",
22
+ "elementPadding",
23
+ "elementPaddingVer",
24
+ "elementPaddingHor",
25
+ "availableHeight",
26
+ "availableWidth"
27
+ ]
28
+ }