@eclipse-docks/extension-plain-editor 0.7.81 → 0.7.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -223,24 +223,45 @@ _decorate([state()], DocksTextEditor.prototype, "lineCount", void 0);
223
223
  _decorate([state()], DocksTextEditor.prototype, "gutterScrollHeight", void 0);
224
224
  DocksTextEditor = _decorate([customElement("docks-texteditor")], DocksTextEditor);
225
225
  //#endregion
226
- //#region src/hexeditor.ts
227
- var BYTES_PER_LINE = 16;
228
- /** Printable ASCII for preview column (typical hex dump). */
226
+ //#region src/utils.ts
227
+ /** Max bytes loaded into the hex editor when content is detected as binary (UI/memory guard). */
228
+ var BINARY_HEX_VIEW_MAX_BYTES = 8 * 1024;
229
+ /** Same cap as hex view: detection only needs a prefix (NUL / UTF-8 validity). */
230
+ var SAMPLE_MAX = BINARY_HEX_VIEW_MAX_BYTES;
231
+ /** Bytes per row in the hex view / dump layout. */
232
+ var HEX_BYTES_PER_LINE = 16;
233
+ /**
234
+ * Heuristic: binary if NUL in sample or UTF-8 strict decode fails on the sample.
235
+ */
236
+ async function detectBinaryBlob(blob) {
237
+ if (blob.size === 0) return false;
238
+ const n = Math.min(blob.size, SAMPLE_MAX);
239
+ const buf = new Uint8Array(await blob.slice(0, n).arrayBuffer());
240
+ for (let i = 0; i < buf.length; i++) if (buf[i] === 0) return true;
241
+ try {
242
+ new TextDecoder("utf-8", { fatal: true }).decode(buf);
243
+ return false;
244
+ } catch {
245
+ return true;
246
+ }
247
+ }
229
248
  function byteToPreviewChar(b) {
230
249
  if (b >= 32 && b <= 126) return String.fromCharCode(b);
231
250
  return ".";
232
251
  }
252
+ /** Printable ASCII for one row of the hex preview column (typical hex dump). */
233
253
  function asciiPreview(slice) {
234
254
  let s = "";
235
255
  for (let i = 0; i < slice.length; i++) s += byteToPreviewChar(slice[i]);
236
- return s.padEnd(BYTES_PER_LINE, " ");
256
+ return s.padEnd(16, " ");
237
257
  }
238
258
  /** "aa bb cc ..." with extra gap after 8th byte */
239
259
  function formatHexBytes(slice) {
240
260
  const pairs = [];
241
261
  for (let i = 0; i < slice.length; i++) pairs.push(slice[i].toString(16).padStart(2, "0"));
242
- if (pairs.length <= 8) return pairs.join(" ");
243
- return `${pairs.slice(0, 8).join(" ")} ${pairs.slice(8).join(" ")}`;
262
+ const half = 16 / 2;
263
+ if (pairs.length <= half) return pairs.join(" ");
264
+ return `${pairs.slice(0, half).join(" ")} ${pairs.slice(half).join(" ")}`;
244
265
  }
245
266
  function parseHexFlexible(text) {
246
267
  const hex = text.replace(/[^0-9a-fA-F]/g, "");
@@ -249,28 +270,108 @@ function parseHexFlexible(text) {
249
270
  for (let i = 0; i < len; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
250
271
  return out;
251
272
  }
252
- /** Parse one line of hex pairs (16 or fewer bytes). */
273
+ /** Parse one line of hex pairs (HEX_BYTES_PER_LINE or fewer bytes). */
253
274
  function parseHexLine(line) {
254
275
  const hex = line.replace(/[^0-9a-fA-F]/g, "");
255
276
  const bytes = [];
256
277
  for (let i = 0; i + 1 < hex.length; i += 2) bytes.push(parseInt(hex.slice(i, i + 2), 16));
257
278
  return bytes;
258
279
  }
259
- function lineCountForLength(byteLength) {
280
+ var HEX_CHAR = /[0-9a-fA-F]/;
281
+ function findNextHexSlot(line, from) {
282
+ for (let i = Math.max(0, from); i < line.length; i++) if (HEX_CHAR.test(line[i])) return i;
283
+ return -1;
284
+ }
285
+ function findPrevHexSlot(line, from) {
286
+ for (let i = Math.min(from, line.length - 1); i >= 0; i--) if (HEX_CHAR.test(line[i])) return i;
287
+ return -1;
288
+ }
289
+ /** If `pos` is not on a hex digit, snap to the next hex slot, else the previous. */
290
+ function snapToHexSlot(line, pos) {
291
+ if (line.length === 0) return -1;
292
+ if (pos >= line.length) return findPrevHexSlot(line, line.length - 1);
293
+ if (pos < 0) return findNextHexSlot(line, 0);
294
+ if (HEX_CHAR.test(line[pos])) return pos;
295
+ const next = findNextHexSlot(line, pos);
296
+ if (next >= 0) return next;
297
+ return findPrevHexSlot(line, pos);
298
+ }
299
+ function firstHexSlotInRange(line, start, end) {
300
+ const lo = Math.min(start, end);
301
+ const hi = Math.max(start, end);
302
+ for (let i = lo; i < hi && i < line.length; i++) if (HEX_CHAR.test(line[i])) return i;
303
+ return findNextHexSlot(line, lo);
304
+ }
305
+ function caretAfterOverwrite(line, replacedAt) {
306
+ const next = findNextHexSlot(line, replacedAt + 1);
307
+ return next >= 0 ? next : line.length;
308
+ }
309
+ /**
310
+ * Overwrite a single hex digit at the caret (never changes string length).
311
+ * Returns null if there is no hex slot to write.
312
+ */
313
+ function applyHexDigitOverwrite(line, selectionStart, selectionEnd, digit) {
314
+ const d = digit.toLowerCase();
315
+ if (!/^[0-9a-f]$/.test(d)) return null;
316
+ let pos = selectionStart !== selectionEnd ? firstHexSlotInRange(line, selectionStart, selectionEnd) : snapToHexSlot(line, selectionStart);
317
+ if (pos < 0) return null;
318
+ if (!HEX_CHAR.test(line[pos])) {
319
+ pos = findNextHexSlot(line, pos);
320
+ if (pos < 0) return null;
321
+ }
322
+ const chars = [...line];
323
+ chars[pos] = d;
324
+ const newLine = chars.join("");
325
+ return {
326
+ line: newLine,
327
+ caret: caretAfterOverwrite(newLine, pos)
328
+ };
329
+ }
330
+ /** Move caret to the previous hex digit (for Backspace navigation). */
331
+ function hexLineCaretPrev(line, caret) {
332
+ const prev = findPrevHexSlot(line, caret - 1);
333
+ return prev >= 0 ? prev : caret;
334
+ }
335
+ /** Move caret to the next hex digit (for Delete / Space navigation). */
336
+ function hexLineCaretNext(line, caret) {
337
+ const pos = caret >= line.length ? line.length - 1 : caret;
338
+ const next = findNextHexSlot(line, HEX_CHAR.test(line[pos]) ? pos + 1 : pos);
339
+ return next >= 0 ? next : caret;
340
+ }
341
+ function hexRowCountForByteLength(byteLength) {
260
342
  if (byteLength === 0) return 1;
261
- return Math.ceil(byteLength / BYTES_PER_LINE);
343
+ return Math.ceil(byteLength / 16);
344
+ }
345
+ /**
346
+ * Replace the row at `byteOffset` (one row = up to {@link HEX_BYTES_PER_LINE} bytes)
347
+ * with bytes parsed from a hex line input string.
348
+ */
349
+ function mergeHexLineAtOffset(bytes, byteOffset, lineText) {
350
+ const parsed = parseHexLine(lineText).slice(0, 16);
351
+ const before = bytes.subarray(0, byteOffset);
352
+ const oldRowByteCount = Math.min(16, Math.max(0, bytes.length - byteOffset));
353
+ const after = bytes.subarray(byteOffset + oldRowByteCount);
354
+ const newRow = Uint8Array.from(parsed);
355
+ const merged = new Uint8Array(before.length + newRow.length + after.length);
356
+ merged.set(before, 0);
357
+ merged.set(newRow, before.length);
358
+ merged.set(after, before.length + newRow.length);
359
+ return merged;
262
360
  }
263
361
  /** Multi-line text dump (offset + hex + ASCII), for consumers / debugging. */
264
362
  function formatHexDump(bytes) {
265
363
  const lines = [];
266
- for (let i = 0; i < bytes.length; i += BYTES_PER_LINE) {
267
- const slice = bytes.subarray(i, Math.min(i + BYTES_PER_LINE, bytes.length));
364
+ for (let i = 0; i < bytes.length; i += 16) {
365
+ const slice = bytes.subarray(i, Math.min(i + 16, bytes.length));
268
366
  const addr = i.toString(16).padStart(8, "0");
269
367
  lines.push(`${addr}h ${formatHexBytes(slice)} |${asciiPreview(slice)}`);
270
368
  }
271
369
  if (bytes.length === 0) lines.push(`${0 .toString(16).padStart(8, "0")}h |${asciiPreview(new Uint8Array(0))}`);
272
370
  return lines.join("\n");
273
371
  }
372
+ //#endregion
373
+ //#region src/hexeditor.ts
374
+ var supportsBeforeInput = typeof InputEvent !== "undefined" && "inputType" in InputEvent.prototype;
274
375
  var DocksHexEditor = class DocksHexEditor extends DocksWidget {
275
376
  constructor(..._args) {
276
377
  super(..._args);
@@ -279,19 +380,59 @@ var DocksHexEditor = class DocksHexEditor extends DocksWidget {
279
380
  this.readOnly = false;
280
381
  this.bytes = new Uint8Array(0);
281
382
  this.lastSeed = -1;
282
- this.onHexLineChange = (offset, e) => {
283
- const t = e.target;
284
- const parsed = parseHexLine(t.value).slice(0, BYTES_PER_LINE);
285
- const before = this.bytes.subarray(0, offset);
286
- const oldRowByteCount = Math.min(BYTES_PER_LINE, Math.max(0, this.bytes.length - offset));
287
- const after = this.bytes.subarray(offset + oldRowByteCount);
288
- const newRow = Uint8Array.from(parsed);
289
- const merged = new Uint8Array(before.length + newRow.length + after.length);
290
- merged.set(before, 0);
291
- merged.set(newRow, before.length);
292
- merged.set(after, before.length + newRow.length);
293
- this.bytes = merged;
294
- this.emitChange(merged);
383
+ this.onHexLineBeforeInput = (byteOffset, e) => {
384
+ if (this.readOnly || !supportsBeforeInput) return;
385
+ const ie = e;
386
+ if (ie.isComposing) return;
387
+ if (ie.inputType === "insertText" && ie.data && /^[0-9a-fA-F]$/.test(ie.data)) {
388
+ ie.preventDefault();
389
+ const input = ie.target;
390
+ const next = applyHexDigitOverwrite(input.value, input.selectionStart ?? 0, input.selectionEnd ?? 0, ie.data);
391
+ if (!next) return;
392
+ input.value = next.line;
393
+ input.setSelectionRange(next.caret, next.caret);
394
+ this.commitHexLine(byteOffset, next.line, input, next.caret);
395
+ return;
396
+ }
397
+ if (ie.inputType === "insertText" || ie.inputType === "insertLineBreak" || ie.inputType === "insertParagraph" || ie.inputType === "insertFromPaste") ie.preventDefault();
398
+ };
399
+ this.onHexLineKeydown = (byteOffset, e) => {
400
+ if (this.readOnly) return;
401
+ const input = e.target;
402
+ if (e.key === "Backspace" || e.key === "Delete") {
403
+ e.preventDefault();
404
+ const start = input.selectionStart ?? 0;
405
+ if (start !== (input.selectionEnd ?? 0)) {
406
+ input.setSelectionRange(start, start);
407
+ return;
408
+ }
409
+ const caret = e.key === "Backspace" ? hexLineCaretPrev(input.value, start) : hexLineCaretNext(input.value, start);
410
+ input.setSelectionRange(caret, caret);
411
+ return;
412
+ }
413
+ if (e.key === " " || e.key === "Spacebar") {
414
+ e.preventDefault();
415
+ const caret = hexLineCaretNext(input.value, input.selectionStart ?? 0);
416
+ input.setSelectionRange(caret, caret);
417
+ return;
418
+ }
419
+ if (!supportsBeforeInput && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
420
+ if (/[0-9a-fA-F]/.test(e.key)) {
421
+ e.preventDefault();
422
+ const next = applyHexDigitOverwrite(input.value, input.selectionStart ?? 0, input.selectionEnd ?? 0, e.key);
423
+ if (!next) return;
424
+ input.value = next.line;
425
+ input.setSelectionRange(next.caret, next.caret);
426
+ this.commitHexLine(byteOffset, next.line, input, next.caret);
427
+ return;
428
+ }
429
+ e.preventDefault();
430
+ }
431
+ };
432
+ this.onHexLinePaste = (byteOffset, e) => {
433
+ if (this.readOnly) return;
434
+ e.preventDefault();
435
+ this.applyHexPaste(byteOffset, e);
295
436
  };
296
437
  }
297
438
  willUpdate(changed) {
@@ -307,18 +448,38 @@ var DocksHexEditor = class DocksHexEditor extends DocksWidget {
307
448
  composed: true
308
449
  }));
309
450
  }
451
+ commitHexLine(byteOffset, line, input, caret) {
452
+ const merged = mergeHexLineAtOffset(this.bytes, byteOffset, line);
453
+ this.bytes = merged;
454
+ this.emitChange(merged);
455
+ this.updateComplete.then(() => {
456
+ if (!input.isConnected) return;
457
+ const formatted = formatHexBytes(merged.subarray(byteOffset, Math.min(byteOffset + 16, merged.length)));
458
+ input.value = formatted;
459
+ const c = Math.min(caret, formatted.length);
460
+ input.setSelectionRange(c, c);
461
+ });
462
+ }
463
+ applyHexPaste(byteOffset, e) {
464
+ const input = e.target;
465
+ if (!input) return;
466
+ const raw = parseHexFlexible(e.clipboardData?.getData("text/plain") ?? "");
467
+ const n = Math.min(raw.length, 16);
468
+ const line = formatHexBytes(raw.subarray(0, n));
469
+ this.commitHexLine(byteOffset, line, input, 0);
470
+ }
310
471
  getBytesSnapshot() {
311
472
  return new Uint8Array(this.bytes);
312
473
  }
313
474
  render() {
314
475
  const len = this.bytes.length;
315
- const rows = lineCountForLength(len || 1);
476
+ const rows = hexRowCountForByteLength(len || 1);
316
477
  const headerCells = [];
317
- for (let h = 0; h < BYTES_PER_LINE; h++) headerCells.push(html`<span class="hex-col-head">${h.toString(16)}</span>`);
478
+ for (let h = 0; h < 16; h++) headerCells.push(html`<span class="hex-col-head">${h.toString(16)}</span>`);
318
479
  const dataRows = [];
319
480
  for (let r = 0; r < rows; r++) {
320
- const offset = r * BYTES_PER_LINE;
321
- const slice = this.bytes.subarray(offset, Math.min(offset + BYTES_PER_LINE, this.bytes.length));
481
+ const offset = r * 16;
482
+ const slice = this.bytes.subarray(offset, Math.min(offset + 16, this.bytes.length));
322
483
  const addr = offset.toString(16).padStart(8, "0");
323
484
  const hexVal = formatHexBytes(slice);
324
485
  const asciiVal = asciiPreview(slice);
@@ -333,7 +494,10 @@ var DocksHexEditor = class DocksHexEditor extends DocksWidget {
333
494
  autocomplete="off"
334
495
  ?readonly=${this.readOnly}
335
496
  .value=${hexVal}
336
- @input=${(e) => this.onHexLineChange(offset, e)}
497
+ @beforeinput=${(e) => this.onHexLineBeforeInput(offset, e)}
498
+ @keydown=${(e) => this.onHexLineKeydown(offset, e)}
499
+ @paste=${(e) => this.onHexLinePaste(offset, e)}
500
+ @cut=${(e) => e.preventDefault()}
337
501
  />
338
502
  </div>
339
503
  <span class="ascii-col">${asciiVal}</span>
@@ -471,6 +635,6 @@ _decorate([property({ type: Boolean })], DocksHexEditor.prototype, "readOnly", v
471
635
  _decorate([state()], DocksHexEditor.prototype, "bytes", void 0);
472
636
  DocksHexEditor = _decorate([customElement("docks-hexeditor")], DocksHexEditor);
473
637
  //#endregion
474
- export { DocksTextEditor as i, formatHexDump as n, parseHexFlexible as r, DocksHexEditor as t };
638
+ export { asciiPreview as a, formatHexDump as c, hexRowCountForByteLength as d, mergeHexLineAtOffset as f, DocksTextEditor as h, applyHexDigitOverwrite as i, hexLineCaretNext as l, parseHexLine as m, BINARY_HEX_VIEW_MAX_BYTES as n, detectBinaryBlob as o, parseHexFlexible as p, HEX_BYTES_PER_LINE as r, formatHexBytes as s, DocksHexEditor as t, hexLineCaretPrev as u };
475
639
 
476
- //# sourceMappingURL=hexeditor-BYd_tpCW.js.map
640
+ //# sourceMappingURL=hexeditor-BNJnxcFk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hexeditor-BNJnxcFk.js","names":[],"sources":["../src/texteditor.ts","../src/utils.ts","../src/hexeditor.ts"],"sourcesContent":["import { customElement, property, state } from 'lit/decorators.js';\nimport { DocksWidget } from '@eclipse-docks/core';\nimport { css, html, type PropertyValues } from 'lit';\nimport { createRef, ref } from 'lit/directives/ref.js';\n\n@customElement('docks-texteditor')\nexport class DocksTextEditor extends DocksWidget {\n @property()\n value = '';\n\n @property({ type: Boolean })\n readOnly = false;\n\n @state()\n private lineCount = 1;\n\n /** Matches textarea.scrollHeight so gutter scroll range equals text scroll range. */\n @state()\n private gutterScrollHeight = 0;\n\n private textareaRef = createRef<HTMLElement & { value: string }>();\n private innerTextarea: HTMLTextAreaElement | null = null;\n private gutterEl: HTMLElement | null = null;\n private resizeObserver: ResizeObserver | null = null;\n\n protected willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('value')) {\n const lines = this.value.split('\\n').length;\n this.lineCount = Math.max(1, lines);\n }\n }\n\n protected updated(): void {\n queueMicrotask(() => {\n this.cacheElements();\n this.syncScrollMetrics();\n this.attachScrollListeners();\n });\n }\n\n disconnectedCallback(): void {\n this.teardownScrollListeners();\n super.disconnectedCallback();\n }\n\n private cacheElements(): void {\n const wa = this.textareaRef.value;\n this.innerTextarea = wa?.shadowRoot?.querySelector('textarea') ?? null;\n this.gutterEl = (this.renderRoot as ShadowRoot)?.querySelector('.line-gutter') ?? null;\n }\n\n private attachScrollListeners(): void {\n const inner = this.innerTextarea;\n const gutter = this.gutterEl;\n if (!inner || !gutter) return;\n\n inner.removeEventListener('scroll', this.onTextScroll);\n inner.addEventListener('scroll', this.onTextScroll, { passive: true });\n\n gutter.removeEventListener('scroll', this.onGutterScroll);\n gutter.addEventListener('scroll', this.onGutterScroll, { passive: true });\n\n if (!this.resizeObserver) {\n this.resizeObserver = new ResizeObserver(() => {\n this.syncScrollMetrics();\n });\n }\n this.resizeObserver.disconnect();\n this.resizeObserver.observe(inner);\n }\n\n private teardownScrollListeners(): void {\n this.innerTextarea?.removeEventListener('scroll', this.onTextScroll);\n this.gutterEl?.removeEventListener('scroll', this.onGutterScroll);\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.innerTextarea = null;\n this.gutterEl = null;\n }\n\n private onTextScroll = (): void => {\n const inner = this.innerTextarea;\n const gutter = this.gutterEl;\n if (!inner || !gutter) return;\n if (gutter.scrollTop !== inner.scrollTop) {\n gutter.scrollTop = inner.scrollTop;\n }\n };\n\n private onGutterScroll = (): void => {\n const inner = this.innerTextarea;\n const gutter = this.gutterEl;\n if (!inner || !gutter) return;\n if (inner.scrollTop !== gutter.scrollTop) {\n inner.scrollTop = gutter.scrollTop;\n }\n };\n\n private syncScrollMetrics(): void {\n const inner = this.innerTextarea;\n if (!inner) return;\n const sh = inner.scrollHeight;\n if (sh !== this.gutterScrollHeight) {\n this.gutterScrollHeight = sh;\n }\n this.onTextScroll();\n }\n\n private emitChange() {\n this.dispatchEvent(\n new CustomEvent('content-change', {\n detail: { value: this.value },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private onInput = (e: Event) => {\n const t = e.target as HTMLElement & { value: string };\n this.value = t.value;\n const lines = this.value.split('\\n').length;\n this.lineCount = Math.max(1, lines);\n this.emitChange();\n queueMicrotask(() => this.syncScrollMetrics());\n };\n\n getValue(): string {\n return this.value;\n }\n\n getSelection(): string | null {\n const wa = this.textareaRef.value;\n const inner = wa?.shadowRoot?.querySelector('textarea') as HTMLTextAreaElement | null;\n if (!inner) return null;\n const { selectionStart, selectionEnd, value } = inner;\n if (selectionStart === selectionEnd) return '';\n return value.slice(selectionStart, selectionEnd);\n }\n\n getSnippet(linesAround = 5): { snippet: string; cursorLine: number } | null {\n const wa = this.textareaRef.value;\n const inner = wa?.shadowRoot?.querySelector('textarea') as HTMLTextAreaElement | null;\n if (!inner) return null;\n const text = this.value;\n const pos = inner.selectionStart;\n let lineStart = 0;\n let line = 0;\n for (let i = 0; i < text.length && i < pos; i++) {\n if (text[i] === '\\n') {\n line++;\n lineStart = i + 1;\n }\n }\n const allLines = text.split('\\n');\n const cur = line;\n const from = Math.max(0, cur - linesAround);\n const to = Math.min(allLines.length, cur + linesAround + 1);\n const snippet = allLines.slice(from, to).join('\\n');\n return { snippet, cursorLine: cur };\n }\n\n protected render() {\n const numbers: number[] = [];\n for (let i = 1; i <= this.lineCount; i++) {\n numbers.push(i);\n }\n const innerMinHeight = this.gutterScrollHeight > 0 ? `${this.gutterScrollHeight}px` : '100%';\n return html`\n <div class=\"wrap\">\n <div class=\"line-gutter\" aria-hidden=\"true\">\n <div class=\"line-gutter-inner\" style=\"min-height: ${innerMinHeight}\">\n ${numbers.map((n) => html`<div class=\"ln\">${n}</div>`)}\n </div>\n </div>\n <wa-textarea\n class=\"editor-ta\"\n resize=\"none\"\n .value=${this.value}\n ?readonly=${this.readOnly}\n @input=${this.onInput}\n ${ref(this.textareaRef)}\n ></wa-textarea>\n </div>\n `;\n }\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n min-height: 0;\n }\n .wrap {\n display: flex;\n flex-direction: row;\n height: 100%;\n min-height: 0;\n gap: var(--wa-space-s, 0.5rem);\n }\n .line-gutter {\n flex: 0 0 auto;\n min-width: 2.5rem;\n min-height: 0;\n align-self: stretch;\n padding: 0;\n text-align: right;\n font-family: var(--wa-font-mono, ui-monospace, monospace);\n font-size: var(--wa-font-size-s, 0.875rem);\n /* Match wa-textarea value line metrics (gutter used 1.5 while controls use --wa-form-control-value-line-height, e.g. 1.2) */\n line-height: var(--wa-form-control-value-line-height, 1.5);\n color: var(--wa-color-neutral-50, #888);\n user-select: none;\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: none;\n box-sizing: border-box;\n }\n .line-gutter::-webkit-scrollbar {\n display: none;\n }\n .line-gutter-inner {\n box-sizing: border-box;\n line-height: inherit;\n /* Same vertical padding as wa-textarea inner control (see webawesome textarea.styles) */\n padding-block: calc(var(--wa-form-control-padding-block, 0.75em) - ((1lh - 1em) / 2));\n padding-inline: 0;\n }\n .ln {\n padding-right: var(--wa-space-xs, 0.25rem);\n box-sizing: border-box;\n line-height: inherit;\n min-height: 1lh;\n }\n .editor-ta {\n flex: 1 1 auto;\n align-self: stretch;\n min-width: 0;\n min-height: 0;\n width: 100%;\n height: 100%;\n font-family: var(--wa-font-mono, ui-monospace, monospace);\n font-size: var(--wa-font-size-s, 0.875rem);\n line-height: var(--wa-form-control-value-line-height, 1.5);\n }\n .editor-ta::part(base) {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n align-items: stretch;\n justify-items: stretch;\n }\n .editor-ta::part(textarea) {\n min-height: 100%;\n height: 100%;\n resize: none;\n line-height: inherit;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-texteditor': DocksTextEditor;\n }\n}\n","/** Max bytes loaded into the hex editor when content is detected as binary (UI/memory guard). */\nexport const BINARY_HEX_VIEW_MAX_BYTES = 8 * 1024;\n\n/** Same cap as hex view: detection only needs a prefix (NUL / UTF-8 validity). */\nconst SAMPLE_MAX = BINARY_HEX_VIEW_MAX_BYTES;\n\n/** Bytes per row in the hex view / dump layout. */\nexport const HEX_BYTES_PER_LINE = 16;\n\n/**\n * Heuristic: binary if NUL in sample or UTF-8 strict decode fails on the sample.\n */\nexport async function detectBinaryBlob(blob: Blob): Promise<boolean> {\n if (blob.size === 0) {\n return false;\n }\n const n = Math.min(blob.size, SAMPLE_MAX);\n const buf = new Uint8Array(await blob.slice(0, n).arrayBuffer());\n for (let i = 0; i < buf.length; i++) {\n if (buf[i] === 0) {\n return true;\n }\n }\n try {\n new TextDecoder('utf-8', { fatal: true }).decode(buf);\n return false;\n } catch {\n return true;\n }\n}\n\nfunction byteToPreviewChar(b: number): string {\n if (b >= 0x20 && b <= 0x7e) {\n return String.fromCharCode(b);\n }\n return '.';\n}\n\n/** Printable ASCII for one row of the hex preview column (typical hex dump). */\nexport function asciiPreview(slice: Uint8Array): string {\n let s = '';\n for (let i = 0; i < slice.length; i++) {\n s += byteToPreviewChar(slice[i]!);\n }\n return s.padEnd(HEX_BYTES_PER_LINE, ' ');\n}\n\n/** \"aa bb cc ...\" with extra gap after 8th byte */\nexport function formatHexBytes(slice: Uint8Array): string {\n const pairs: string[] = [];\n for (let i = 0; i < slice.length; i++) {\n pairs.push(slice[i]!.toString(16).padStart(2, '0'));\n }\n const half = HEX_BYTES_PER_LINE / 2;\n if (pairs.length <= half) {\n return pairs.join(' ');\n }\n return `${pairs.slice(0, half).join(' ')} ${pairs.slice(half).join(' ')}`;\n}\n\nexport function parseHexFlexible(text: string): Uint8Array {\n const hex = text.replace(/[^0-9a-fA-F]/g, '');\n const len = Math.floor(hex.length / 2);\n const out = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/** Parse one line of hex pairs (HEX_BYTES_PER_LINE or fewer bytes). */\nexport function parseHexLine(line: string): number[] {\n const hex = line.replace(/[^0-9a-fA-F]/g, '');\n const bytes: number[] = [];\n for (let i = 0; i + 1 < hex.length; i += 2) {\n bytes.push(parseInt(hex.slice(i, i + 2), 16));\n }\n return bytes;\n}\n\nconst HEX_CHAR = /[0-9a-fA-F]/;\n\nfunction findNextHexSlot(line: string, from: number): number {\n for (let i = Math.max(0, from); i < line.length; i++) {\n if (HEX_CHAR.test(line[i]!)) return i;\n }\n return -1;\n}\n\nfunction findPrevHexSlot(line: string, from: number): number {\n for (let i = Math.min(from, line.length - 1); i >= 0; i--) {\n if (HEX_CHAR.test(line[i]!)) return i;\n }\n return -1;\n}\n\n/** If `pos` is not on a hex digit, snap to the next hex slot, else the previous. */\nfunction snapToHexSlot(line: string, pos: number): number {\n if (line.length === 0) return -1;\n if (pos >= line.length) return findPrevHexSlot(line, line.length - 1);\n if (pos < 0) return findNextHexSlot(line, 0);\n if (HEX_CHAR.test(line[pos]!)) return pos;\n const next = findNextHexSlot(line, pos);\n if (next >= 0) return next;\n return findPrevHexSlot(line, pos);\n}\n\nfunction firstHexSlotInRange(line: string, start: number, end: number): number {\n const lo = Math.min(start, end);\n const hi = Math.max(start, end);\n for (let i = lo; i < hi && i < line.length; i++) {\n if (HEX_CHAR.test(line[i]!)) return i;\n }\n return findNextHexSlot(line, lo);\n}\n\nfunction caretAfterOverwrite(line: string, replacedAt: number): number {\n const next = findNextHexSlot(line, replacedAt + 1);\n return next >= 0 ? next : line.length;\n}\n\n/**\n * Overwrite a single hex digit at the caret (never changes string length).\n * Returns null if there is no hex slot to write.\n */\nexport function applyHexDigitOverwrite(\n line: string,\n selectionStart: number,\n selectionEnd: number,\n digit: string,\n): { line: string; caret: number } | null {\n const d = digit.toLowerCase();\n if (!/^[0-9a-f]$/.test(d)) return null;\n\n let pos =\n selectionStart !== selectionEnd\n ? firstHexSlotInRange(line, selectionStart, selectionEnd)\n : snapToHexSlot(line, selectionStart);\n\n if (pos < 0) return null;\n if (!HEX_CHAR.test(line[pos]!)) {\n pos = findNextHexSlot(line, pos);\n if (pos < 0) return null;\n }\n\n const chars = [...line];\n chars[pos] = d;\n const newLine = chars.join('');\n return { line: newLine, caret: caretAfterOverwrite(newLine, pos) };\n}\n\n/** Move caret to the previous hex digit (for Backspace navigation). */\nexport function hexLineCaretPrev(line: string, caret: number): number {\n const prev = findPrevHexSlot(line, caret - 1);\n return prev >= 0 ? prev : caret;\n}\n\n/** Move caret to the next hex digit (for Delete / Space navigation). */\nexport function hexLineCaretNext(line: string, caret: number): number {\n const pos = caret >= line.length ? line.length - 1 : caret;\n const next = findNextHexSlot(line, HEX_CHAR.test(line[pos]!) ? pos + 1 : pos);\n return next >= 0 ? next : caret;\n}\n\nexport function hexRowCountForByteLength(byteLength: number): number {\n if (byteLength === 0) return 1;\n return Math.ceil(byteLength / HEX_BYTES_PER_LINE);\n}\n\n/**\n * Replace the row at `byteOffset` (one row = up to {@link HEX_BYTES_PER_LINE} bytes)\n * with bytes parsed from a hex line input string.\n */\nexport function mergeHexLineAtOffset(\n bytes: Uint8Array,\n byteOffset: number,\n lineText: string,\n): Uint8Array {\n const parsed = parseHexLine(lineText).slice(0, HEX_BYTES_PER_LINE);\n const before = bytes.subarray(0, byteOffset);\n const oldRowByteCount = Math.min(HEX_BYTES_PER_LINE, Math.max(0, bytes.length - byteOffset));\n const after = bytes.subarray(byteOffset + oldRowByteCount);\n const newRow = Uint8Array.from(parsed);\n const merged = new Uint8Array(before.length + newRow.length + after.length);\n merged.set(before, 0);\n merged.set(newRow, before.length);\n merged.set(after, before.length + newRow.length);\n return merged;\n}\n\n/** Multi-line text dump (offset + hex + ASCII), for consumers / debugging. */\nexport function formatHexDump(bytes: Uint8Array): string {\n const lines: string[] = [];\n for (let i = 0; i < bytes.length; i += HEX_BYTES_PER_LINE) {\n const slice = bytes.subarray(i, Math.min(i + HEX_BYTES_PER_LINE, bytes.length));\n const addr = i.toString(16).padStart(8, '0');\n lines.push(`${addr}h ${formatHexBytes(slice)} |${asciiPreview(slice)}`);\n }\n if (bytes.length === 0) {\n lines.push(`${(0).toString(16).padStart(8, '0')}h ${''} |${asciiPreview(new Uint8Array(0))}`);\n }\n return lines.join('\\n');\n}\n","import { customElement, property, state } from 'lit/decorators.js';\nimport { DocksWidget } from '@eclipse-docks/core';\nimport { css, html, type PropertyValues } from 'lit';\nimport {\n applyHexDigitOverwrite,\n asciiPreview,\n formatHexBytes,\n HEX_BYTES_PER_LINE,\n hexLineCaretNext,\n hexLineCaretPrev,\n hexRowCountForByteLength,\n mergeHexLineAtOffset,\n parseHexFlexible,\n} from './utils.js';\n\nconst supportsBeforeInput =\n typeof InputEvent !== 'undefined' && 'inputType' in InputEvent.prototype;\n\n@customElement('docks-hexeditor')\nexport class DocksHexEditor extends DocksWidget {\n @property({ attribute: false })\n initialBytes: Uint8Array = new Uint8Array(0);\n\n @property({ type: Number })\n seed = 0;\n\n @property({ type: Boolean })\n readOnly = false;\n\n @state()\n private bytes: Uint8Array = new Uint8Array(0);\n\n private lastSeed = -1;\n\n protected willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('seed') && this.seed !== this.lastSeed) {\n this.lastSeed = this.seed;\n this.bytes = new Uint8Array(this.initialBytes);\n }\n }\n\n private emitChange(bytes: Uint8Array) {\n this.dispatchEvent(\n new CustomEvent('content-change', {\n detail: { bytes },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private commitHexLine(byteOffset: number, line: string, input: HTMLInputElement, caret: number) {\n const merged = mergeHexLineAtOffset(this.bytes, byteOffset, line);\n this.bytes = merged;\n this.emitChange(merged);\n void this.updateComplete.then(() => {\n if (!input.isConnected) return;\n const formatted = formatHexBytes(\n merged.subarray(byteOffset, Math.min(byteOffset + HEX_BYTES_PER_LINE, merged.length)),\n );\n input.value = formatted;\n const c = Math.min(caret, formatted.length);\n input.setSelectionRange(c, c);\n });\n }\n\n private onHexLineBeforeInput = (byteOffset: number, e: Event) => {\n if (this.readOnly || !supportsBeforeInput) return;\n const ie = e as InputEvent;\n if (ie.isComposing) return;\n if (ie.inputType === 'insertText' && ie.data && /^[0-9a-fA-F]$/.test(ie.data)) {\n ie.preventDefault();\n const input = ie.target as HTMLInputElement;\n const next = applyHexDigitOverwrite(input.value, input.selectionStart ?? 0, input.selectionEnd ?? 0, ie.data);\n if (!next) return;\n input.value = next.line;\n input.setSelectionRange(next.caret, next.caret);\n this.commitHexLine(byteOffset, next.line, input, next.caret);\n return;\n }\n if (\n ie.inputType === 'insertText' ||\n ie.inputType === 'insertLineBreak' ||\n ie.inputType === 'insertParagraph' ||\n ie.inputType === 'insertFromPaste'\n ) {\n ie.preventDefault();\n }\n };\n\n private onHexLineKeydown = (byteOffset: number, e: KeyboardEvent) => {\n if (this.readOnly) return;\n const input = e.target as HTMLInputElement;\n\n if (e.key === 'Backspace' || e.key === 'Delete') {\n e.preventDefault();\n const start = input.selectionStart ?? 0;\n const end = input.selectionEnd ?? 0;\n if (start !== end) {\n input.setSelectionRange(start, start);\n return;\n }\n const caret =\n e.key === 'Backspace' ? hexLineCaretPrev(input.value, start) : hexLineCaretNext(input.value, start);\n input.setSelectionRange(caret, caret);\n return;\n }\n\n if (e.key === ' ' || e.key === 'Spacebar') {\n e.preventDefault();\n const caret = hexLineCaretNext(input.value, input.selectionStart ?? 0);\n input.setSelectionRange(caret, caret);\n return;\n }\n\n if (!supportsBeforeInput && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {\n if (/[0-9a-fA-F]/.test(e.key)) {\n e.preventDefault();\n const next = applyHexDigitOverwrite(\n input.value,\n input.selectionStart ?? 0,\n input.selectionEnd ?? 0,\n e.key,\n );\n if (!next) return;\n input.value = next.line;\n input.setSelectionRange(next.caret, next.caret);\n this.commitHexLine(byteOffset, next.line, input, next.caret);\n return;\n }\n e.preventDefault();\n }\n };\n\n private onHexLinePaste = (byteOffset: number, e: ClipboardEvent) => {\n if (this.readOnly) return;\n e.preventDefault();\n this.applyHexPaste(byteOffset, e);\n };\n\n private applyHexPaste(byteOffset: number, e: ClipboardEvent) {\n const input = e.target as HTMLInputElement | null;\n if (!input) return;\n const text = e.clipboardData?.getData('text/plain') ?? '';\n const raw = parseHexFlexible(text);\n const n = Math.min(raw.length, HEX_BYTES_PER_LINE);\n const line = formatHexBytes(raw.subarray(0, n));\n this.commitHexLine(byteOffset, line, input, 0);\n }\n\n getBytesSnapshot(): Uint8Array {\n return new Uint8Array(this.bytes);\n }\n\n protected render() {\n const len = this.bytes.length;\n const rows = hexRowCountForByteLength(len || 1);\n const headerCells = [];\n for (let h = 0; h < HEX_BYTES_PER_LINE; h++) {\n headerCells.push(html`<span class=\"hex-col-head\">${h.toString(16)}</span>`);\n }\n\n const dataRows = [];\n for (let r = 0; r < rows; r++) {\n const offset = r * HEX_BYTES_PER_LINE;\n const slice = this.bytes.subarray(offset, Math.min(offset + HEX_BYTES_PER_LINE, this.bytes.length));\n const addr = offset.toString(16).padStart(8, '0');\n const hexVal = formatHexBytes(slice);\n const asciiVal = asciiPreview(slice);\n\n dataRows.push(html`\n <div class=\"hex-row\" part=\"hex-row\">\n <span class=\"addr-col\">${addr}h</span>\n <div class=\"hex-cols\" role=\"group\" aria-label=\"hex bytes\">\n <input\n type=\"text\"\n class=\"hex-line-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n ?readonly=${this.readOnly}\n .value=${hexVal}\n @beforeinput=${(e: Event) => this.onHexLineBeforeInput(offset, e)}\n @keydown=${(e: KeyboardEvent) => this.onHexLineKeydown(offset, e)}\n @paste=${(e: ClipboardEvent) => this.onHexLinePaste(offset, e)}\n @cut=${(e: ClipboardEvent) => e.preventDefault()}\n />\n </div>\n <span class=\"ascii-col\">${asciiVal}</span>\n </div>\n `);\n }\n\n return html`\n <div class=\"hex-shell\">\n <div class=\"hex-header\" part=\"hex-header\">\n <span class=\"addr-col\"></span>\n <div class=\"hex-cols hex-header-cols\">${headerCells}</div>\n <span class=\"ascii-header\" title=\"ASCII\">ASCII</span>\n </div>\n <wa-scroller class=\"hex-scroll\" orientation=\"vertical\">\n <div class=\"hex-body\">${dataRows}</div>\n </wa-scroller>\n </div>\n `;\n }\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n min-height: 0;\n }\n .hex-shell {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n padding: var(--wa-space-s, 0.5rem);\n font-family: var(--wa-font-mono, ui-monospace, monospace);\n font-size: var(--wa-font-size-s, 0.875rem);\n line-height: 1.5;\n width: fit-content;\n max-width: 100%;\n min-width: 0;\n }\n .hex-scroll {\n flex: 1 1 auto;\n min-height: 0;\n }\n .hex-header {\n display: grid;\n /* addr | hex (48 chars for 16 bytes) | ASCII preview (16 chars) */\n grid-template-columns: 5.5rem 48ch 16ch;\n gap: var(--wa-space-s, 0.5rem);\n align-items: end;\n padding-bottom: var(--wa-space-xs, 0.25rem);\n margin-bottom: var(--wa-space-xs, 0.25rem);\n border-bottom: 1px solid var(--wa-color-neutral-border, #444);\n color: var(--wa-color-neutral-50, #888);\n user-select: none;\n }\n .hex-header-cols {\n display: grid;\n grid-template-columns: repeat(16, 1fr);\n gap: 0;\n text-align: center;\n width: 48ch;\n min-width: 0;\n }\n .hex-col-head {\n font-size: var(--wa-font-size-xs, 0.75rem);\n }\n .ascii-header {\n text-align: left;\n width: 16ch;\n min-width: 16ch;\n }\n .hex-body {\n display: flex;\n flex-direction: column;\n gap: 0;\n }\n .hex-row {\n display: grid;\n grid-template-columns: 5.5rem 48ch 16ch;\n gap: var(--wa-space-s, 0.5rem);\n align-items: center;\n min-height: 1.5em;\n }\n .addr-col {\n color: var(--wa-color-neutral-50, #888);\n text-align: right;\n user-select: none;\n padding-right: var(--wa-space-xs, 0.25rem);\n }\n .hex-cols {\n width: 48ch;\n min-width: 0;\n max-width: 100%;\n }\n .hex-line-input {\n box-sizing: border-box;\n width: 100%;\n max-width: none;\n margin: 0;\n padding: 0.1em 0.25em;\n border: 1px solid transparent;\n border-radius: var(--wa-border-radius-s, 2px);\n background: var(--wa-color-neutral-fill-quiet, rgba(128, 128, 128, 0.08));\n color: inherit;\n font: inherit;\n letter-spacing: 0.02em;\n }\n .hex-line-input:hover:not(:read-only) {\n border-color: var(--wa-color-neutral-border, #555);\n }\n .hex-line-input:focus {\n outline: var(--wa-focus-ring-width, 2px) solid var(--wa-color-focus, #3b82f6);\n outline-offset: 0;\n border-color: transparent;\n }\n .hex-line-input:read-only {\n opacity: 0.9;\n }\n .ascii-col {\n color: var(--wa-color-neutral-80, #bbb);\n white-space: pre;\n overflow: visible;\n width: 16ch;\n min-width: 16ch;\n padding-left: var(--wa-space-xs, 0.25rem);\n user-select: none;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-hexeditor': DocksHexEditor;\n }\n}\n"],"mappings":"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"}
@@ -1,10 +1,5 @@
1
1
  import { DocksWidget } from '@eclipse-docks/core';
2
2
  import { PropertyValues } from 'lit';
3
- /** "aa bb cc ..." with extra gap after 8th byte */
4
- export declare function formatHexBytes(slice: Uint8Array): string;
5
- export declare function parseHexFlexible(text: string): Uint8Array;
6
- /** Multi-line text dump (offset + hex + ASCII), for consumers / debugging. */
7
- export declare function formatHexDump(bytes: Uint8Array): string;
8
3
  export declare class DocksHexEditor extends DocksWidget {
9
4
  initialBytes: Uint8Array;
10
5
  seed: number;
@@ -13,7 +8,11 @@ export declare class DocksHexEditor extends DocksWidget {
13
8
  private lastSeed;
14
9
  protected willUpdate(changed: PropertyValues<this>): void;
15
10
  private emitChange;
16
- private onHexLineChange;
11
+ private commitHexLine;
12
+ private onHexLineBeforeInput;
13
+ private onHexLineKeydown;
14
+ private onHexLinePaste;
15
+ private applyHexPaste;
17
16
  getBytesSnapshot(): Uint8Array;
18
17
  protected render(): import('lit-html').TemplateResult<1>;
19
18
  static styles: import('lit').CSSResult;
@@ -1 +1 @@
1
- {"version":3,"file":"hexeditor.d.ts","sourceRoot":"","sources":["../src/hexeditor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAoBrD,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CASxD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAQzD;AAiBD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAWvD;AAED,qBACa,cAAe,SAAQ,WAAW;IAE7C,YAAY,EAAE,UAAU,CAAqB;IAG7C,IAAI,SAAK;IAGT,QAAQ,UAAS;IAGjB,OAAO,CAAC,KAAK,CAAiC;IAE9C,OAAO,CAAC,QAAQ,CAAM;IAEtB,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAOzD,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,eAAe,CAarB;IAEF,gBAAgB,IAAI,UAAU;IAI9B,SAAS,CAAC,MAAM;IAiDhB,MAAM,CAAC,MAAM,0BA4GX;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,cAAc,CAAC;KACnC;CACF"}
1
+ {"version":3,"file":"hexeditor.d.ts","sourceRoot":"","sources":["../src/hexeditor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAgBrD,qBACa,cAAe,SAAQ,WAAW;IAE7C,YAAY,EAAE,UAAU,CAAqB;IAG7C,IAAI,SAAK;IAGT,QAAQ,UAAS;IAGjB,OAAO,CAAC,KAAK,CAAiC;IAE9C,OAAO,CAAC,QAAQ,CAAM;IAEtB,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAOzD,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,oBAAoB,CAsB1B;IAEF,OAAO,CAAC,gBAAgB,CA0CtB;IAEF,OAAO,CAAC,cAAc,CAIpB;IAEF,OAAO,CAAC,aAAa;IAUrB,gBAAgB,IAAI,UAAU;IAI9B,SAAS,CAAC,MAAM;IAoDhB,MAAM,CAAC,MAAM,0BA4GX;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,cAAc,CAAC;KACnC;CACF"}
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ extensionRegistry.registerExtension({
9
9
  id: pkg.name,
10
10
  name: t.EXT_PLAIN_NAME,
11
11
  description: t.EXT_PLAIN_DESC,
12
- loader: () => import("./plain-editor-extension-DmlYtE9-.js"),
12
+ loader: () => import("./plain-editor-extension-RRv6pSQe.js"),
13
13
  icon: "file-lines"
14
14
  });
15
15
  var PLAIN_EDITOR_TOOLBAR_TARGET_PREFIX = "toolbar:system.plain-editor";
@@ -1,30 +1,9 @@
1
- import "./hexeditor-BYd_tpCW.js";
1
+ import { n as BINARY_HEX_VIEW_MAX_BYTES, o as detectBinaryBlob } from "./hexeditor-BNJnxcFk.js";
2
2
  import { DocksPart, i18n } from "@eclipse-docks/core";
3
3
  import { customElement, property, state } from "lit/decorators.js";
4
4
  import { css, html, nothing } from "lit";
5
5
  import { createRef, ref } from "lit/directives/ref.js";
6
6
  import _decorate from "@oxc-project/runtime/helpers/decorate";
7
- //#region src/binary.ts
8
- /** Sample at most this many bytes for binary-vs-text detection. */
9
- var SAMPLE_MAX = 65536;
10
- /** Max bytes loaded into the hex editor when content is detected as binary (UI/memory guard). */
11
- var BINARY_HEX_VIEW_MAX_BYTES = 8 * 1024;
12
- /**
13
- * Heuristic: binary if NUL in sample or UTF-8 strict decode fails on the sample.
14
- */
15
- async function detectBinaryBlob(blob) {
16
- if (blob.size === 0) return false;
17
- const n = Math.min(blob.size, SAMPLE_MAX);
18
- const buf = new Uint8Array(await blob.slice(0, n).arrayBuffer());
19
- for (let i = 0; i < buf.length; i++) if (buf[i] === 0) return true;
20
- try {
21
- new TextDecoder("utf-8", { fatal: true }).decode(buf);
22
- return false;
23
- } catch {
24
- return true;
25
- }
26
- }
27
- //#endregion
28
7
  //#region src/plain-editor.ts
29
8
  var t = await i18n(/* @__PURE__ */ Object.assign({
30
9
  "./i18n.de.json": () => import("./i18n.de-Ddrm6naw.js"),
@@ -218,4 +197,4 @@ _decorate([state()], DocksPlainEditor.prototype, "binaryViewTruncated", void 0);
218
197
  DocksPlainEditor = _decorate([customElement("docks-plain-editor")], DocksPlainEditor);
219
198
  //#endregion
220
199
 
221
- //# sourceMappingURL=plain-editor-06SNmG-t.js.map
200
+ //# sourceMappingURL=plain-editor-B5aVx7Bw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plain-editor-B5aVx7Bw.js","names":[],"sources":["../src/plain-editor.ts"],"sourcesContent":["import { customElement, property, state } from 'lit/decorators.js';\nimport {\n DocksPart,\n EditorContentProvider,\n EditorInput,\n File,\n i18n,\n} from '@eclipse-docks/core';\nimport { css, html, nothing, type TemplateResult } from 'lit';\nimport { createRef, ref } from 'lit/directives/ref.js';\nimport { BINARY_HEX_VIEW_MAX_BYTES, detectBinaryBlob } from './utils.js';\nimport './hexeditor.js';\nimport './texteditor.js';\nimport type { DocksHexEditor } from './hexeditor.js';\nimport type { DocksTextEditor } from './texteditor.js';\n\nconst t = await i18n(import.meta.glob('./i18n*.json'), true);\n\n@customElement('docks-plain-editor')\nexport class DocksPlainEditor extends DocksPart implements EditorContentProvider {\n protected scrollMode: 'scroller' | 'native' = 'native';\n\n @property({ attribute: false })\n input?: EditorInput;\n\n @property({ type: Boolean })\n readOnly = false;\n\n @state()\n private ready = false;\n\n @state()\n private hexMode = false;\n\n @state()\n private textValue = '';\n\n private bytes: Uint8Array = new Uint8Array(0);\n\n @state()\n private hexSeed = 0;\n\n @state()\n private hexInitialBytes: Uint8Array = new Uint8Array(0);\n\n /** True when binary mode loaded only a prefix of a larger file (editing disabled). */\n @state()\n private binaryViewTruncated = false;\n\n private binarySourceByteLength = 0;\n\n private textRef = createRef<DocksTextEditor>();\n private hexRef = createRef<DocksHexEditor>();\n\n protected async doInitUI(): Promise<void> {\n const file = this.input!.data as File;\n const blob = await file.getContents({ blob: true });\n this.hexMode = await detectBinaryBlob(blob);\n\n if (this.hexMode) {\n if (blob.size > BINARY_HEX_VIEW_MAX_BYTES) {\n this.bytes = new Uint8Array(\n await blob.slice(0, BINARY_HEX_VIEW_MAX_BYTES).arrayBuffer(),\n );\n this.binaryViewTruncated = true;\n this.binarySourceByteLength = blob.size;\n } else {\n this.bytes = new Uint8Array(await blob.arrayBuffer());\n this.binaryViewTruncated = false;\n this.binarySourceByteLength = 0;\n }\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n this.hexInitialBytes = new Uint8Array(this.bytes);\n this.hexSeed = 1;\n } else {\n this.bytes = new Uint8Array(await blob.arrayBuffer());\n this.binaryViewTruncated = false;\n this.binarySourceByteLength = 0;\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n }\n this.ready = true;\n }\n\n private onTextChange = (e: CustomEvent<{ value: string }>) => {\n this.textValue = e.detail.value;\n this.bytes = new TextEncoder().encode(this.textValue);\n this.markDirty(true);\n };\n\n private onHexChange = (e: CustomEvent<{ bytes: Uint8Array }>) => {\n this.bytes = e.detail.bytes;\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n this.markDirty(true);\n };\n\n private onHexViewToggle = (e: Event) => {\n const on = (e.target as HTMLInputElement).checked;\n if (on === this.hexMode) return;\n if (on) {\n this.bytes = new TextEncoder().encode(this.textValue);\n this.hexInitialBytes = new Uint8Array(this.bytes);\n this.hexSeed += 1;\n this.hexMode = true;\n } else {\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n this.hexMode = false;\n }\n this.requestUpdate();\n };\n\n save(): void {\n if (this.binaryViewTruncated) {\n return;\n }\n const blob = new Blob([new Uint8Array(this.bytes)]);\n this.input?.data.saveContents(blob);\n this.markDirty(false);\n }\n\n protected doClose(): void {\n this.ready = false;\n this.binaryViewTruncated = false;\n this.binarySourceByteLength = 0;\n }\n\n getContent(): string | null {\n if (this.hexMode) {\n const hex = this.hexRef.value?.getBytesSnapshot();\n if (hex) {\n return [...hex].map((b) => b.toString(16).padStart(2, '0')).join(' ');\n }\n return null;\n }\n return this.textRef.value?.getValue() ?? this.textValue;\n }\n\n getSelection(): string | null {\n if (this.hexMode) return null;\n return this.textRef.value?.getSelection() ?? null;\n }\n\n getSnippet(lines = 5): { snippet: string; cursorLine: number } | null {\n if (this.hexMode) return null;\n return this.textRef.value?.getSnippet(lines) ?? null;\n }\n\n getLanguage(): string | null {\n return null;\n }\n\n getFilePath(): string | null {\n return this.input?.data?.getWorkspacePath() ?? null;\n }\n\n protected renderToolbar(): TemplateResult | typeof nothing {\n if (!this.ready) return nothing;\n const fmt = (n: number) => n.toLocaleString();\n const truncMsg =\n this.binaryViewTruncated && this.binarySourceByteLength > 0\n ? t.BINARY_VIEW_TRUNCATED({\n shown: fmt(BINARY_HEX_VIEW_MAX_BYTES),\n total: fmt(this.binarySourceByteLength),\n })\n : null;\n return html`\n ${truncMsg\n ? html`<span class=\"binary-trunc-msg\" title=${truncMsg}>${truncMsg}</span>`\n : nothing}\n <label class=\"hex-toggle\">\n <span class=\"hex-label\">${t.HEX_VIEW_LABEL}</span>\n <wa-switch ?checked=${this.hexMode} @change=${this.onHexViewToggle}></wa-switch>\n </label>\n `;\n }\n\n protected renderContent(): TemplateResult | typeof nothing {\n if (!this.ready) {\n return html`<div class=\"placeholder\"></div>`;\n }\n if (this.hexMode) {\n return html`\n <docks-hexeditor\n ${ref(this.hexRef)}\n .initialBytes=${this.hexInitialBytes}\n .seed=${this.hexSeed}\n .readOnly=${this.readOnly || this.binaryViewTruncated}\n @content-change=${this.onHexChange}\n ></docks-hexeditor>\n `;\n }\n return html`\n <docks-texteditor\n ${ref(this.textRef)}\n .value=${this.textValue}\n .readOnly=${this.readOnly || this.binaryViewTruncated}\n @content-change=${this.onTextChange}\n ></docks-texteditor>\n `;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n }\n /* Fill tab panel: let the editor surface stretch with the layout grid */\n .part-content-inner {\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n .part-content-inner > docks-texteditor,\n .part-content-inner > docks-hexeditor {\n flex: 1 1 auto;\n min-height: 0;\n }\n .placeholder {\n flex: 1;\n min-height: 2rem;\n }\n .binary-trunc-msg {\n flex: 1 1 auto;\n min-width: 0;\n margin-right: var(--wa-space-m, 0.75rem);\n font-size: var(--wa-font-size-xs, 0.75rem);\n color: var(--wa-color-neutral-50, #888);\n line-height: 1.3;\n }\n .hex-toggle {\n display: inline-flex;\n align-items: center;\n gap: var(--wa-space-s, 0.5rem);\n margin: 0;\n font-size: var(--wa-font-size-s, 0.875rem);\n flex-shrink: 0;\n }\n .hex-label {\n user-select: none;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-plain-editor': DocksPlainEditor;\n }\n}\n"],"mappings":";;;;;;;AAgBA,IAAM,IAAI,MAAM,KAAK,uBAAA,OAAA;CAAA,wBAAA,OAAA;CAAA,wBAAA,OAAA;CAAA,CAAgC,EAAE,KAAK;AAGrD,IAAA,mBAAA,MAAM,yBAAyB,UAA2C;;;oBACjC;kBAMnC;eAGK;iBAGE;mBAGE;eAEQ,IAAI,WAAW,EAAE;iBAG3B;yBAGoB,IAAI,WAAW,EAAE;6BAIzB;gCAEG;iBAEf,WAA4B;gBAC7B,WAA2B;uBA+BpB,MAAsC;AAC5D,QAAK,YAAY,EAAE,OAAO;AAC1B,QAAK,QAAQ,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU;AACrD,QAAK,UAAU,KAAK;;sBAGC,MAA0C;AAC/D,QAAK,QAAQ,EAAE,OAAO;AACtB,QAAK,YAAY,IAAI,YAAY,SAAS,EAAE,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,MAAM;AAC9E,QAAK,UAAU,KAAK;;0BAGK,MAAa;GACtC,MAAM,KAAM,EAAE,OAA4B;AAC1C,OAAI,OAAO,KAAK,QAAS;AACzB,OAAI,IAAI;AACN,SAAK,QAAQ,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU;AACrD,SAAK,kBAAkB,IAAI,WAAW,KAAK,MAAM;AACjD,SAAK,WAAW;AAChB,SAAK,UAAU;UACV;AACL,SAAK,YAAY,IAAI,YAAY,SAAS,EAAE,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,MAAM;AAC9E,SAAK,UAAU;;AAEjB,QAAK,eAAe;;;CArDtB,MAAgB,WAA0B;EAExC,MAAM,OAAO,MADA,KAAK,MAAO,KACD,YAAY,EAAE,MAAM,MAAM,CAAC;AACnD,OAAK,UAAU,MAAM,iBAAiB,KAAK;AAE3C,MAAI,KAAK,SAAS;AAChB,OAAI,KAAK,OAAA,MAAkC;AACzC,SAAK,QAAQ,IAAI,WACf,MAAM,KAAK,MAAM,GAAG,0BAA0B,CAAC,aAAa,CAC7D;AACD,SAAK,sBAAsB;AAC3B,SAAK,yBAAyB,KAAK;UAC9B;AACL,SAAK,QAAQ,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC;AACrD,SAAK,sBAAsB;AAC3B,SAAK,yBAAyB;;AAEhC,QAAK,YAAY,IAAI,YAAY,SAAS,EAAE,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,MAAM;AAC9E,QAAK,kBAAkB,IAAI,WAAW,KAAK,MAAM;AACjD,QAAK,UAAU;SACV;AACL,QAAK,QAAQ,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC;AACrD,QAAK,sBAAsB;AAC3B,QAAK,yBAAyB;AAC9B,QAAK,YAAY,IAAI,YAAY,SAAS,EAAE,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,MAAM;;AAEhF,OAAK,QAAQ;;CA8Bf,OAAa;AACX,MAAI,KAAK,oBACP;EAEF,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,WAAW,KAAK,MAAM,CAAC,CAAC;AACnD,OAAK,OAAO,KAAK,aAAa,KAAK;AACnC,OAAK,UAAU,MAAM;;CAGvB,UAA0B;AACxB,OAAK,QAAQ;AACb,OAAK,sBAAsB;AAC3B,OAAK,yBAAyB;;CAGhC,aAA4B;AAC1B,MAAI,KAAK,SAAS;GAChB,MAAM,MAAM,KAAK,OAAO,OAAO,kBAAkB;AACjD,OAAI,IACF,QAAO,CAAC,GAAG,IAAI,CAAC,KAAK,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,KAAK,IAAI;AAEvE,UAAO;;AAET,SAAO,KAAK,QAAQ,OAAO,UAAU,IAAI,KAAK;;CAGhD,eAA8B;AAC5B,MAAI,KAAK,QAAS,QAAO;AACzB,SAAO,KAAK,QAAQ,OAAO,cAAc,IAAI;;CAG/C,WAAW,QAAQ,GAAmD;AACpE,MAAI,KAAK,QAAS,QAAO;AACzB,SAAO,KAAK,QAAQ,OAAO,WAAW,MAAM,IAAI;;CAGlD,cAA6B;AAC3B,SAAO;;CAGT,cAA6B;AAC3B,SAAO,KAAK,OAAO,MAAM,kBAAkB,IAAI;;CAGjD,gBAA2D;AACzD,MAAI,CAAC,KAAK,MAAO,QAAO;EACxB,MAAM,OAAO,MAAc,EAAE,gBAAgB;EAC7C,MAAM,WACJ,KAAK,uBAAuB,KAAK,yBAAyB,IACtD,EAAE,sBAAsB;GACtB,OAAO,IAAI,0BAA0B;GACrC,OAAO,IAAI,KAAK,uBAAA;GACjB,CAAC,GACF;AACN,SAAO,IAAI;QACP,WACE,IAAI,wCAAwC,SAAS,GAAG,SAAS,WACjE,QAAA;;kCAEwB,EAAE,eAAe;8BACrB,KAAK,QAAQ,WAAW,KAAK,gBAAgB;;;;CAKzE,gBAA2D;AACzD,MAAI,CAAC,KAAK,MACR,QAAO,IAAI;AAEb,MAAI,KAAK,QACP,QAAO,IAAI;;YAEL,IAAI,KAAK,OAAO,CAAA;0BACF,KAAK,gBAAA;kBACb,KAAK,QAAA;sBACD,KAAK,YAAY,KAAK,oBAAA;4BAChB,KAAK,YAAA;;;AAI7B,SAAO,IAAI;;UAEL,IAAI,KAAK,QAAQ,CAAA;iBACV,KAAK,UAAA;oBACF,KAAK,YAAY,KAAK,oBAAA;0BAChB,KAAK,aAAA;;;;;gBAKb,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAlLlB,SAAS,EAAE,WAAW,OAAO,CAAC,CAAA,EAAA,iBAAA,WAAA,SAAA,KAAA,EAAA;WAG9B,SAAS,EAAE,MAAM,SAAS,CAAC,CAAA,EAAA,iBAAA,WAAA,YAAA,KAAA,EAAA;WAG3B,OAAO,CAAA,EAAA,iBAAA,WAAA,SAAA,KAAA,EAAA;WAGP,OAAO,CAAA,EAAA,iBAAA,WAAA,WAAA,KAAA,EAAA;WAGP,OAAO,CAAA,EAAA,iBAAA,WAAA,aAAA,KAAA,EAAA;WAKP,OAAO,CAAA,EAAA,iBAAA,WAAA,WAAA,KAAA,EAAA;WAGP,OAAO,CAAA,EAAA,iBAAA,WAAA,mBAAA,KAAA,EAAA;WAIP,OAAO,CAAA,EAAA,iBAAA,WAAA,uBAAA,KAAA,EAAA;8BA5BT,cAAc,qBAAqB,CAAA,EAAA,iBAAA"}
@@ -7,7 +7,7 @@ editorRegistry.registerEditorInputHandler({
7
7
  icon: "file-lines",
8
8
  ranking: 1,
9
9
  lazyInit: async () => {
10
- await import("./plain-editor-06SNmG-t.js");
10
+ await import("./plain-editor-B5aVx7Bw.js");
11
11
  },
12
12
  canHandle: (input) => input instanceof File,
13
13
  handle: async (input) => {
@@ -26,4 +26,4 @@ editorRegistry.registerEditorInputHandler({
26
26
  });
27
27
  //#endregion
28
28
 
29
- //# sourceMappingURL=plain-editor-extension-DmlYtE9-.js.map
29
+ //# sourceMappingURL=plain-editor-extension-RRv6pSQe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plain-editor-extension-DmlYtE9-.js","names":[],"sources":["../src/plain-editor-extension.ts"],"sourcesContent":["import { html } from 'lit';\nimport { EditorInput, editorRegistry, File } from '@eclipse-docks/core';\n\neditorRegistry.registerEditorInputHandler({\n editorId: 'system.plain-editor',\n label: 'Text',\n icon: 'file-lines',\n ranking: 1,\n lazyInit: async () => {\n await import('./plain-editor.js');\n },\n canHandle: (input: unknown) => input instanceof File,\n handle: async (input: File) => {\n const editorInput = {\n title: input.getWorkspacePath(),\n data: input,\n key: input.getWorkspacePath(),\n icon: editorRegistry.getFileIcon(input.getName()),\n state: {},\n } as EditorInput;\n editorInput.component = (id: string) => html`\n <docks-plain-editor id=${id} .input=${editorInput}></docks-plain-editor>\n `;\n return editorInput;\n },\n});\n"],"mappings":";;;AAGA,eAAe,2BAA2B;CACxC,UAAU;CACV,OAAO;CACP,MAAM;CACN,SAAS;CACT,UAAU,YAAY;AACpB,QAAM,OAAO;;CAEf,YAAY,UAAmB,iBAAiB;CAChD,QAAQ,OAAO,UAAgB;EAC7B,MAAM,cAAc;GAClB,OAAO,MAAM,kBAAkB;GAC/B,MAAM;GACN,KAAK,MAAM,kBAAkB;GAC7B,MAAM,eAAe,YAAY,MAAM,SAAS,CAAC;GACjD,OAAO,EAAE;GACV;AACD,cAAY,aAAa,OAAe,IAAI;+BACjB,GAAG,UAAU,YAAY;;AAEpD,SAAO;;CAEV,CAAC"}
1
+ {"version":3,"file":"plain-editor-extension-RRv6pSQe.js","names":[],"sources":["../src/plain-editor-extension.ts"],"sourcesContent":["import { html } from 'lit';\nimport { EditorInput, editorRegistry, File } from '@eclipse-docks/core';\n\neditorRegistry.registerEditorInputHandler({\n editorId: 'system.plain-editor',\n label: 'Text',\n icon: 'file-lines',\n ranking: 1,\n lazyInit: async () => {\n await import('./plain-editor.js');\n },\n canHandle: (input: unknown) => input instanceof File,\n handle: async (input: File) => {\n const editorInput = {\n title: input.getWorkspacePath(),\n data: input,\n key: input.getWorkspacePath(),\n icon: editorRegistry.getFileIcon(input.getName()),\n state: {},\n } as EditorInput;\n editorInput.component = (id: string) => html`\n <docks-plain-editor id=${id} .input=${editorInput}></docks-plain-editor>\n `;\n return editorInput;\n },\n});\n"],"mappings":";;;AAGA,eAAe,2BAA2B;CACxC,UAAU;CACV,OAAO;CACP,MAAM;CACN,SAAS;CACT,UAAU,YAAY;AACpB,QAAM,OAAO;;CAEf,YAAY,UAAmB,iBAAiB;CAChD,QAAQ,OAAO,UAAgB;EAC7B,MAAM,cAAc;GAClB,OAAO,MAAM,kBAAkB;GAC/B,MAAM;GACN,KAAK,MAAM,kBAAkB;GAC7B,MAAM,eAAe,YAAY,MAAM,SAAS,CAAC;GACjD,OAAO,EAAE;GACV;AACD,cAAY,aAAa,OAAe,IAAI;+BACjB,GAAG,UAAU,YAAY;;AAEpD,SAAO;;CAEV,CAAC"}
@@ -0,0 +1,36 @@
1
+ /** Max bytes loaded into the hex editor when content is detected as binary (UI/memory guard). */
2
+ export declare const BINARY_HEX_VIEW_MAX_BYTES: number;
3
+ /** Bytes per row in the hex view / dump layout. */
4
+ export declare const HEX_BYTES_PER_LINE = 16;
5
+ /**
6
+ * Heuristic: binary if NUL in sample or UTF-8 strict decode fails on the sample.
7
+ */
8
+ export declare function detectBinaryBlob(blob: Blob): Promise<boolean>;
9
+ /** Printable ASCII for one row of the hex preview column (typical hex dump). */
10
+ export declare function asciiPreview(slice: Uint8Array): string;
11
+ /** "aa bb cc ..." with extra gap after 8th byte */
12
+ export declare function formatHexBytes(slice: Uint8Array): string;
13
+ export declare function parseHexFlexible(text: string): Uint8Array;
14
+ /** Parse one line of hex pairs (HEX_BYTES_PER_LINE or fewer bytes). */
15
+ export declare function parseHexLine(line: string): number[];
16
+ /**
17
+ * Overwrite a single hex digit at the caret (never changes string length).
18
+ * Returns null if there is no hex slot to write.
19
+ */
20
+ export declare function applyHexDigitOverwrite(line: string, selectionStart: number, selectionEnd: number, digit: string): {
21
+ line: string;
22
+ caret: number;
23
+ } | null;
24
+ /** Move caret to the previous hex digit (for Backspace navigation). */
25
+ export declare function hexLineCaretPrev(line: string, caret: number): number;
26
+ /** Move caret to the next hex digit (for Delete / Space navigation). */
27
+ export declare function hexLineCaretNext(line: string, caret: number): number;
28
+ export declare function hexRowCountForByteLength(byteLength: number): number;
29
+ /**
30
+ * Replace the row at `byteOffset` (one row = up to {@link HEX_BYTES_PER_LINE} bytes)
31
+ * with bytes parsed from a hex line input string.
32
+ */
33
+ export declare function mergeHexLineAtOffset(bytes: Uint8Array, byteOffset: number, lineText: string): Uint8Array;
34
+ /** Multi-line text dump (offset + hex + ASCII), for consumers / debugging. */
35
+ export declare function formatHexDump(bytes: Uint8Array): string;
36
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,eAAO,MAAM,yBAAyB,QAAW,CAAC;AAKlD,mDAAmD;AACnD,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBnE;AASD,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMtD;AAED,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAUxD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAQzD;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOnD;AA2CD;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAmBxC;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpE;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGnE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,UAAU,CAWZ;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAWvD"}
package/dist/widgets.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { DocksTextEditor } from './texteditor.js';
2
- export { DocksHexEditor, formatHexDump, parseHexFlexible } from './hexeditor.js';
2
+ export { applyHexDigitOverwrite, asciiPreview, formatHexBytes, formatHexDump, HEX_BYTES_PER_LINE, hexLineCaretNext, hexLineCaretPrev, hexRowCountForByteLength, mergeHexLineAtOffset, parseHexFlexible, parseHexLine, } from './utils.js';
3
+ export { DocksHexEditor } from './hexeditor.js';
3
4
  //# sourceMappingURL=widgets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"widgets.d.ts","sourceRoot":"","sources":["../src/widgets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"widgets.d.ts","sourceRoot":"","sources":["../src/widgets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/widgets.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as DocksTextEditor, n as formatHexDump, r as parseHexFlexible, t as DocksHexEditor } from "./hexeditor-BYd_tpCW.js";
2
- export { DocksHexEditor, DocksTextEditor, formatHexDump, parseHexFlexible };
1
+ import { a as asciiPreview, c as formatHexDump, d as hexRowCountForByteLength, f as mergeHexLineAtOffset, h as DocksTextEditor, i as applyHexDigitOverwrite, l as hexLineCaretNext, m as parseHexLine, p as parseHexFlexible, r as HEX_BYTES_PER_LINE, s as formatHexBytes, t as DocksHexEditor, u as hexLineCaretPrev } from "./hexeditor-BNJnxcFk.js";
2
+ export { DocksHexEditor, DocksTextEditor, HEX_BYTES_PER_LINE, applyHexDigitOverwrite, asciiPreview, formatHexBytes, formatHexDump, hexLineCaretNext, hexLineCaretPrev, hexRowCountForByteLength, mergeHexLineAtOffset, parseHexFlexible, parseHexLine };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-docks/extension-plain-editor",
3
- "version": "0.7.81",
3
+ "version": "0.7.82",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
package/dist/binary.d.ts DELETED
@@ -1,7 +0,0 @@
1
- /** Max bytes loaded into the hex editor when content is detected as binary (UI/memory guard). */
2
- export declare const BINARY_HEX_VIEW_MAX_BYTES: number;
3
- /**
4
- * Heuristic: binary if NUL in sample or UTF-8 strict decode fails on the sample.
5
- */
6
- export declare function detectBinaryBlob(blob: Blob): Promise<boolean>;
7
- //# sourceMappingURL=binary.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"binary.d.ts","sourceRoot":"","sources":["../src/binary.ts"],"names":[],"mappings":"AAGA,iGAAiG;AACjG,eAAO,MAAM,yBAAyB,QAAW,CAAC;AAElD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBnE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hexeditor-BYd_tpCW.js","names":[],"sources":["../src/texteditor.ts","../src/hexeditor.ts"],"sourcesContent":["import { customElement, property, state } from 'lit/decorators.js';\nimport { DocksWidget } from '@eclipse-docks/core';\nimport { css, html, type PropertyValues } from 'lit';\nimport { createRef, ref } from 'lit/directives/ref.js';\n\n@customElement('docks-texteditor')\nexport class DocksTextEditor extends DocksWidget {\n @property()\n value = '';\n\n @property({ type: Boolean })\n readOnly = false;\n\n @state()\n private lineCount = 1;\n\n /** Matches textarea.scrollHeight so gutter scroll range equals text scroll range. */\n @state()\n private gutterScrollHeight = 0;\n\n private textareaRef = createRef<HTMLElement & { value: string }>();\n private innerTextarea: HTMLTextAreaElement | null = null;\n private gutterEl: HTMLElement | null = null;\n private resizeObserver: ResizeObserver | null = null;\n\n protected willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('value')) {\n const lines = this.value.split('\\n').length;\n this.lineCount = Math.max(1, lines);\n }\n }\n\n protected updated(): void {\n queueMicrotask(() => {\n this.cacheElements();\n this.syncScrollMetrics();\n this.attachScrollListeners();\n });\n }\n\n disconnectedCallback(): void {\n this.teardownScrollListeners();\n super.disconnectedCallback();\n }\n\n private cacheElements(): void {\n const wa = this.textareaRef.value;\n this.innerTextarea = wa?.shadowRoot?.querySelector('textarea') ?? null;\n this.gutterEl = (this.renderRoot as ShadowRoot)?.querySelector('.line-gutter') ?? null;\n }\n\n private attachScrollListeners(): void {\n const inner = this.innerTextarea;\n const gutter = this.gutterEl;\n if (!inner || !gutter) return;\n\n inner.removeEventListener('scroll', this.onTextScroll);\n inner.addEventListener('scroll', this.onTextScroll, { passive: true });\n\n gutter.removeEventListener('scroll', this.onGutterScroll);\n gutter.addEventListener('scroll', this.onGutterScroll, { passive: true });\n\n if (!this.resizeObserver) {\n this.resizeObserver = new ResizeObserver(() => {\n this.syncScrollMetrics();\n });\n }\n this.resizeObserver.disconnect();\n this.resizeObserver.observe(inner);\n }\n\n private teardownScrollListeners(): void {\n this.innerTextarea?.removeEventListener('scroll', this.onTextScroll);\n this.gutterEl?.removeEventListener('scroll', this.onGutterScroll);\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.innerTextarea = null;\n this.gutterEl = null;\n }\n\n private onTextScroll = (): void => {\n const inner = this.innerTextarea;\n const gutter = this.gutterEl;\n if (!inner || !gutter) return;\n if (gutter.scrollTop !== inner.scrollTop) {\n gutter.scrollTop = inner.scrollTop;\n }\n };\n\n private onGutterScroll = (): void => {\n const inner = this.innerTextarea;\n const gutter = this.gutterEl;\n if (!inner || !gutter) return;\n if (inner.scrollTop !== gutter.scrollTop) {\n inner.scrollTop = gutter.scrollTop;\n }\n };\n\n private syncScrollMetrics(): void {\n const inner = this.innerTextarea;\n if (!inner) return;\n const sh = inner.scrollHeight;\n if (sh !== this.gutterScrollHeight) {\n this.gutterScrollHeight = sh;\n }\n this.onTextScroll();\n }\n\n private emitChange() {\n this.dispatchEvent(\n new CustomEvent('content-change', {\n detail: { value: this.value },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private onInput = (e: Event) => {\n const t = e.target as HTMLElement & { value: string };\n this.value = t.value;\n const lines = this.value.split('\\n').length;\n this.lineCount = Math.max(1, lines);\n this.emitChange();\n queueMicrotask(() => this.syncScrollMetrics());\n };\n\n getValue(): string {\n return this.value;\n }\n\n getSelection(): string | null {\n const wa = this.textareaRef.value;\n const inner = wa?.shadowRoot?.querySelector('textarea') as HTMLTextAreaElement | null;\n if (!inner) return null;\n const { selectionStart, selectionEnd, value } = inner;\n if (selectionStart === selectionEnd) return '';\n return value.slice(selectionStart, selectionEnd);\n }\n\n getSnippet(linesAround = 5): { snippet: string; cursorLine: number } | null {\n const wa = this.textareaRef.value;\n const inner = wa?.shadowRoot?.querySelector('textarea') as HTMLTextAreaElement | null;\n if (!inner) return null;\n const text = this.value;\n const pos = inner.selectionStart;\n let lineStart = 0;\n let line = 0;\n for (let i = 0; i < text.length && i < pos; i++) {\n if (text[i] === '\\n') {\n line++;\n lineStart = i + 1;\n }\n }\n const allLines = text.split('\\n');\n const cur = line;\n const from = Math.max(0, cur - linesAround);\n const to = Math.min(allLines.length, cur + linesAround + 1);\n const snippet = allLines.slice(from, to).join('\\n');\n return { snippet, cursorLine: cur };\n }\n\n protected render() {\n const numbers: number[] = [];\n for (let i = 1; i <= this.lineCount; i++) {\n numbers.push(i);\n }\n const innerMinHeight = this.gutterScrollHeight > 0 ? `${this.gutterScrollHeight}px` : '100%';\n return html`\n <div class=\"wrap\">\n <div class=\"line-gutter\" aria-hidden=\"true\">\n <div class=\"line-gutter-inner\" style=\"min-height: ${innerMinHeight}\">\n ${numbers.map((n) => html`<div class=\"ln\">${n}</div>`)}\n </div>\n </div>\n <wa-textarea\n class=\"editor-ta\"\n resize=\"none\"\n .value=${this.value}\n ?readonly=${this.readOnly}\n @input=${this.onInput}\n ${ref(this.textareaRef)}\n ></wa-textarea>\n </div>\n `;\n }\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n min-height: 0;\n }\n .wrap {\n display: flex;\n flex-direction: row;\n height: 100%;\n min-height: 0;\n gap: var(--wa-space-s, 0.5rem);\n }\n .line-gutter {\n flex: 0 0 auto;\n min-width: 2.5rem;\n min-height: 0;\n align-self: stretch;\n padding: 0;\n text-align: right;\n font-family: var(--wa-font-mono, ui-monospace, monospace);\n font-size: var(--wa-font-size-s, 0.875rem);\n /* Match wa-textarea value line metrics (gutter used 1.5 while controls use --wa-form-control-value-line-height, e.g. 1.2) */\n line-height: var(--wa-form-control-value-line-height, 1.5);\n color: var(--wa-color-neutral-50, #888);\n user-select: none;\n overflow-x: hidden;\n overflow-y: auto;\n scrollbar-width: none;\n box-sizing: border-box;\n }\n .line-gutter::-webkit-scrollbar {\n display: none;\n }\n .line-gutter-inner {\n box-sizing: border-box;\n line-height: inherit;\n /* Same vertical padding as wa-textarea inner control (see webawesome textarea.styles) */\n padding-block: calc(var(--wa-form-control-padding-block, 0.75em) - ((1lh - 1em) / 2));\n padding-inline: 0;\n }\n .ln {\n padding-right: var(--wa-space-xs, 0.25rem);\n box-sizing: border-box;\n line-height: inherit;\n min-height: 1lh;\n }\n .editor-ta {\n flex: 1 1 auto;\n align-self: stretch;\n min-width: 0;\n min-height: 0;\n width: 100%;\n height: 100%;\n font-family: var(--wa-font-mono, ui-monospace, monospace);\n font-size: var(--wa-font-size-s, 0.875rem);\n line-height: var(--wa-form-control-value-line-height, 1.5);\n }\n .editor-ta::part(base) {\n flex: 1 1 auto;\n min-height: 0;\n height: 100%;\n align-items: stretch;\n justify-items: stretch;\n }\n .editor-ta::part(textarea) {\n min-height: 100%;\n height: 100%;\n resize: none;\n line-height: inherit;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-texteditor': DocksTextEditor;\n }\n}\n","import { customElement, property, state } from 'lit/decorators.js';\nimport { DocksWidget } from '@eclipse-docks/core';\nimport { css, html, type PropertyValues } from 'lit';\n\nconst BYTES_PER_LINE = 16;\n\n/** Printable ASCII for preview column (typical hex dump). */\nfunction byteToPreviewChar(b: number): string {\n if (b >= 0x20 && b <= 0x7e) {\n return String.fromCharCode(b);\n }\n return '.';\n}\n\nfunction asciiPreview(slice: Uint8Array): string {\n let s = '';\n for (let i = 0; i < slice.length; i++) {\n s += byteToPreviewChar(slice[i]!);\n }\n return s.padEnd(BYTES_PER_LINE, ' ');\n}\n\n/** \"aa bb cc ...\" with extra gap after 8th byte */\nexport function formatHexBytes(slice: Uint8Array): string {\n const pairs: string[] = [];\n for (let i = 0; i < slice.length; i++) {\n pairs.push(slice[i]!.toString(16).padStart(2, '0'));\n }\n if (pairs.length <= 8) {\n return pairs.join(' ');\n }\n return `${pairs.slice(0, 8).join(' ')} ${pairs.slice(8).join(' ')}`;\n}\n\nexport function parseHexFlexible(text: string): Uint8Array {\n const hex = text.replace(/[^0-9a-fA-F]/g, '');\n const len = Math.floor(hex.length / 2);\n const out = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n/** Parse one line of hex pairs (16 or fewer bytes). */\nfunction parseHexLine(line: string): number[] {\n const hex = line.replace(/[^0-9a-fA-F]/g, '');\n const bytes: number[] = [];\n for (let i = 0; i + 1 < hex.length; i += 2) {\n bytes.push(parseInt(hex.slice(i, i + 2), 16));\n }\n return bytes;\n}\n\nfunction lineCountForLength(byteLength: number): number {\n if (byteLength === 0) return 1;\n return Math.ceil(byteLength / BYTES_PER_LINE);\n}\n\n/** Multi-line text dump (offset + hex + ASCII), for consumers / debugging. */\nexport function formatHexDump(bytes: Uint8Array): string {\n const lines: string[] = [];\n for (let i = 0; i < bytes.length; i += BYTES_PER_LINE) {\n const slice = bytes.subarray(i, Math.min(i + BYTES_PER_LINE, bytes.length));\n const addr = i.toString(16).padStart(8, '0');\n lines.push(`${addr}h ${formatHexBytes(slice)} |${asciiPreview(slice)}`);\n }\n if (bytes.length === 0) {\n lines.push(`${(0).toString(16).padStart(8, '0')}h ${''} |${asciiPreview(new Uint8Array(0))}`);\n }\n return lines.join('\\n');\n}\n\n@customElement('docks-hexeditor')\nexport class DocksHexEditor extends DocksWidget {\n @property({ attribute: false })\n initialBytes: Uint8Array = new Uint8Array(0);\n\n @property({ type: Number })\n seed = 0;\n\n @property({ type: Boolean })\n readOnly = false;\n\n @state()\n private bytes: Uint8Array = new Uint8Array(0);\n\n private lastSeed = -1;\n\n protected willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('seed') && this.seed !== this.lastSeed) {\n this.lastSeed = this.seed;\n this.bytes = new Uint8Array(this.initialBytes);\n }\n }\n\n private emitChange(bytes: Uint8Array) {\n this.dispatchEvent(\n new CustomEvent('content-change', {\n detail: { bytes },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n private onHexLineChange = (offset: number, e: Event) => {\n const t = e.target as HTMLInputElement;\n const parsed = parseHexLine(t.value).slice(0, BYTES_PER_LINE);\n const before = this.bytes.subarray(0, offset);\n const oldRowByteCount = Math.min(BYTES_PER_LINE, Math.max(0, this.bytes.length - offset));\n const after = this.bytes.subarray(offset + oldRowByteCount);\n const newRow = Uint8Array.from(parsed);\n const merged = new Uint8Array(before.length + newRow.length + after.length);\n merged.set(before, 0);\n merged.set(newRow, before.length);\n merged.set(after, before.length + newRow.length);\n this.bytes = merged;\n this.emitChange(merged);\n };\n\n getBytesSnapshot(): Uint8Array {\n return new Uint8Array(this.bytes);\n }\n\n protected render() {\n const len = this.bytes.length;\n const rows = lineCountForLength(len || 1);\n const headerCells = [];\n for (let h = 0; h < BYTES_PER_LINE; h++) {\n headerCells.push(html`<span class=\"hex-col-head\">${h.toString(16)}</span>`);\n }\n\n const dataRows = [];\n for (let r = 0; r < rows; r++) {\n const offset = r * BYTES_PER_LINE;\n const slice = this.bytes.subarray(offset, Math.min(offset + BYTES_PER_LINE, this.bytes.length));\n const addr = offset.toString(16).padStart(8, '0');\n const hexVal = formatHexBytes(slice);\n const asciiVal = asciiPreview(slice);\n\n dataRows.push(html`\n <div class=\"hex-row\" part=\"hex-row\">\n <span class=\"addr-col\">${addr}h</span>\n <div class=\"hex-cols\" role=\"group\" aria-label=\"hex bytes\">\n <input\n type=\"text\"\n class=\"hex-line-input\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n ?readonly=${this.readOnly}\n .value=${hexVal}\n @input=${(e: Event) => this.onHexLineChange(offset, e)}\n />\n </div>\n <span class=\"ascii-col\">${asciiVal}</span>\n </div>\n `);\n }\n\n return html`\n <div class=\"hex-shell\">\n <div class=\"hex-header\" part=\"hex-header\">\n <span class=\"addr-col\"></span>\n <div class=\"hex-cols hex-header-cols\">${headerCells}</div>\n <span class=\"ascii-header\" title=\"ASCII\">ASCII</span>\n </div>\n <wa-scroller class=\"hex-scroll\" orientation=\"vertical\">\n <div class=\"hex-body\">${dataRows}</div>\n </wa-scroller>\n </div>\n `;\n }\n\n static styles = css`\n :host {\n display: block;\n height: 100%;\n min-height: 0;\n }\n .hex-shell {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n padding: var(--wa-space-s, 0.5rem);\n font-family: var(--wa-font-mono, ui-monospace, monospace);\n font-size: var(--wa-font-size-s, 0.875rem);\n line-height: 1.5;\n width: fit-content;\n max-width: 100%;\n min-width: 0;\n }\n .hex-scroll {\n flex: 1 1 auto;\n min-height: 0;\n }\n .hex-header {\n display: grid;\n /* addr | hex (48 chars for 16 bytes) | ASCII preview (16 chars) */\n grid-template-columns: 5.5rem 48ch 16ch;\n gap: var(--wa-space-s, 0.5rem);\n align-items: end;\n padding-bottom: var(--wa-space-xs, 0.25rem);\n margin-bottom: var(--wa-space-xs, 0.25rem);\n border-bottom: 1px solid var(--wa-color-neutral-border, #444);\n color: var(--wa-color-neutral-50, #888);\n user-select: none;\n }\n .hex-header-cols {\n display: grid;\n grid-template-columns: repeat(16, 1fr);\n gap: 0;\n text-align: center;\n width: 48ch;\n min-width: 0;\n }\n .hex-col-head {\n font-size: var(--wa-font-size-xs, 0.75rem);\n }\n .ascii-header {\n text-align: left;\n width: 16ch;\n min-width: 16ch;\n }\n .hex-body {\n display: flex;\n flex-direction: column;\n gap: 0;\n }\n .hex-row {\n display: grid;\n grid-template-columns: 5.5rem 48ch 16ch;\n gap: var(--wa-space-s, 0.5rem);\n align-items: center;\n min-height: 1.5em;\n }\n .addr-col {\n color: var(--wa-color-neutral-50, #888);\n text-align: right;\n user-select: none;\n padding-right: var(--wa-space-xs, 0.25rem);\n }\n .hex-cols {\n width: 48ch;\n min-width: 0;\n max-width: 100%;\n }\n .hex-line-input {\n box-sizing: border-box;\n width: 100%;\n max-width: none;\n margin: 0;\n padding: 0.1em 0.25em;\n border: 1px solid transparent;\n border-radius: var(--wa-border-radius-s, 2px);\n background: var(--wa-color-neutral-fill-quiet, rgba(128, 128, 128, 0.08));\n color: inherit;\n font: inherit;\n letter-spacing: 0.02em;\n }\n .hex-line-input:hover:not(:read-only) {\n border-color: var(--wa-color-neutral-border, #555);\n }\n .hex-line-input:focus {\n outline: var(--wa-focus-ring-width, 2px) solid var(--wa-color-focus, #3b82f6);\n outline-offset: 0;\n border-color: transparent;\n }\n .hex-line-input:read-only {\n opacity: 0.9;\n }\n .ascii-col {\n color: var(--wa-color-neutral-80, #bbb);\n white-space: pre;\n overflow: visible;\n width: 16ch;\n min-width: 16ch;\n padding-left: var(--wa-space-xs, 0.25rem);\n user-select: none;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-hexeditor': DocksHexEditor;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"plain-editor-06SNmG-t.js","names":[],"sources":["../src/binary.ts","../src/plain-editor.ts"],"sourcesContent":["/** Sample at most this many bytes for binary-vs-text detection. */\nconst SAMPLE_MAX = 65536;\n\n/** Max bytes loaded into the hex editor when content is detected as binary (UI/memory guard). */\nexport const BINARY_HEX_VIEW_MAX_BYTES = 8 * 1024;\n\n/**\n * Heuristic: binary if NUL in sample or UTF-8 strict decode fails on the sample.\n */\nexport async function detectBinaryBlob(blob: Blob): Promise<boolean> {\n if (blob.size === 0) {\n return false;\n }\n const n = Math.min(blob.size, SAMPLE_MAX);\n const buf = new Uint8Array(await blob.slice(0, n).arrayBuffer());\n for (let i = 0; i < buf.length; i++) {\n if (buf[i] === 0) {\n return true;\n }\n }\n try {\n new TextDecoder('utf-8', { fatal: true }).decode(buf);\n return false;\n } catch {\n return true;\n }\n}\n","import { customElement, property, state } from 'lit/decorators.js';\nimport {\n DocksPart,\n EditorContentProvider,\n EditorInput,\n File,\n i18n,\n} from '@eclipse-docks/core';\nimport { css, html, nothing, type TemplateResult } from 'lit';\nimport { createRef, ref } from 'lit/directives/ref.js';\nimport { BINARY_HEX_VIEW_MAX_BYTES, detectBinaryBlob } from './binary.js';\nimport './hexeditor.js';\nimport './texteditor.js';\nimport type { DocksHexEditor } from './hexeditor.js';\nimport type { DocksTextEditor } from './texteditor.js';\n\nconst t = await i18n(import.meta.glob('./i18n*.json'), true);\n\n@customElement('docks-plain-editor')\nexport class DocksPlainEditor extends DocksPart implements EditorContentProvider {\n protected scrollMode: 'scroller' | 'native' = 'native';\n\n @property({ attribute: false })\n input?: EditorInput;\n\n @property({ type: Boolean })\n readOnly = false;\n\n @state()\n private ready = false;\n\n @state()\n private hexMode = false;\n\n @state()\n private textValue = '';\n\n private bytes: Uint8Array = new Uint8Array(0);\n\n @state()\n private hexSeed = 0;\n\n @state()\n private hexInitialBytes: Uint8Array = new Uint8Array(0);\n\n /** True when binary mode loaded only a prefix of a larger file (editing disabled). */\n @state()\n private binaryViewTruncated = false;\n\n private binarySourceByteLength = 0;\n\n private textRef = createRef<DocksTextEditor>();\n private hexRef = createRef<DocksHexEditor>();\n\n protected async doInitUI(): Promise<void> {\n const file = this.input!.data as File;\n const blob = await file.getContents({ blob: true });\n this.hexMode = await detectBinaryBlob(blob);\n\n if (this.hexMode) {\n if (blob.size > BINARY_HEX_VIEW_MAX_BYTES) {\n this.bytes = new Uint8Array(\n await blob.slice(0, BINARY_HEX_VIEW_MAX_BYTES).arrayBuffer(),\n );\n this.binaryViewTruncated = true;\n this.binarySourceByteLength = blob.size;\n } else {\n this.bytes = new Uint8Array(await blob.arrayBuffer());\n this.binaryViewTruncated = false;\n this.binarySourceByteLength = 0;\n }\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n this.hexInitialBytes = new Uint8Array(this.bytes);\n this.hexSeed = 1;\n } else {\n this.bytes = new Uint8Array(await blob.arrayBuffer());\n this.binaryViewTruncated = false;\n this.binarySourceByteLength = 0;\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n }\n this.ready = true;\n }\n\n private onTextChange = (e: CustomEvent<{ value: string }>) => {\n this.textValue = e.detail.value;\n this.bytes = new TextEncoder().encode(this.textValue);\n this.markDirty(true);\n };\n\n private onHexChange = (e: CustomEvent<{ bytes: Uint8Array }>) => {\n this.bytes = e.detail.bytes;\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n this.markDirty(true);\n };\n\n private onHexViewToggle = (e: Event) => {\n const on = (e.target as HTMLInputElement).checked;\n if (on === this.hexMode) return;\n if (on) {\n this.bytes = new TextEncoder().encode(this.textValue);\n this.hexInitialBytes = new Uint8Array(this.bytes);\n this.hexSeed += 1;\n this.hexMode = true;\n } else {\n this.textValue = new TextDecoder('utf-8', { fatal: false }).decode(this.bytes);\n this.hexMode = false;\n }\n this.requestUpdate();\n };\n\n save(): void {\n if (this.binaryViewTruncated) {\n return;\n }\n const blob = new Blob([new Uint8Array(this.bytes)]);\n this.input?.data.saveContents(blob);\n this.markDirty(false);\n }\n\n protected doClose(): void {\n this.ready = false;\n this.binaryViewTruncated = false;\n this.binarySourceByteLength = 0;\n }\n\n getContent(): string | null {\n if (this.hexMode) {\n const hex = this.hexRef.value?.getBytesSnapshot();\n if (hex) {\n return [...hex].map((b) => b.toString(16).padStart(2, '0')).join(' ');\n }\n return null;\n }\n return this.textRef.value?.getValue() ?? this.textValue;\n }\n\n getSelection(): string | null {\n if (this.hexMode) return null;\n return this.textRef.value?.getSelection() ?? null;\n }\n\n getSnippet(lines = 5): { snippet: string; cursorLine: number } | null {\n if (this.hexMode) return null;\n return this.textRef.value?.getSnippet(lines) ?? null;\n }\n\n getLanguage(): string | null {\n return null;\n }\n\n getFilePath(): string | null {\n return this.input?.data?.getWorkspacePath() ?? null;\n }\n\n protected renderToolbar(): TemplateResult | typeof nothing {\n if (!this.ready) return nothing;\n const fmt = (n: number) => n.toLocaleString();\n const truncMsg =\n this.binaryViewTruncated && this.binarySourceByteLength > 0\n ? t.BINARY_VIEW_TRUNCATED({\n shown: fmt(BINARY_HEX_VIEW_MAX_BYTES),\n total: fmt(this.binarySourceByteLength),\n })\n : null;\n return html`\n ${truncMsg\n ? html`<span class=\"binary-trunc-msg\" title=${truncMsg}>${truncMsg}</span>`\n : nothing}\n <label class=\"hex-toggle\">\n <span class=\"hex-label\">${t.HEX_VIEW_LABEL}</span>\n <wa-switch ?checked=${this.hexMode} @change=${this.onHexViewToggle}></wa-switch>\n </label>\n `;\n }\n\n protected renderContent(): TemplateResult | typeof nothing {\n if (!this.ready) {\n return html`<div class=\"placeholder\"></div>`;\n }\n if (this.hexMode) {\n return html`\n <docks-hexeditor\n ${ref(this.hexRef)}\n .initialBytes=${this.hexInitialBytes}\n .seed=${this.hexSeed}\n .readOnly=${this.readOnly || this.binaryViewTruncated}\n @content-change=${this.onHexChange}\n ></docks-hexeditor>\n `;\n }\n return html`\n <docks-texteditor\n ${ref(this.textRef)}\n .value=${this.textValue}\n .readOnly=${this.readOnly || this.binaryViewTruncated}\n @content-change=${this.onTextChange}\n ></docks-texteditor>\n `;\n }\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n height: 100%;\n }\n /* Fill tab panel: let the editor surface stretch with the layout grid */\n .part-content-inner {\n display: flex;\n flex-direction: column;\n min-height: 0;\n }\n .part-content-inner > docks-texteditor,\n .part-content-inner > docks-hexeditor {\n flex: 1 1 auto;\n min-height: 0;\n }\n .placeholder {\n flex: 1;\n min-height: 2rem;\n }\n .binary-trunc-msg {\n flex: 1 1 auto;\n min-width: 0;\n margin-right: var(--wa-space-m, 0.75rem);\n font-size: var(--wa-font-size-xs, 0.75rem);\n color: var(--wa-color-neutral-50, #888);\n line-height: 1.3;\n }\n .hex-toggle {\n display: inline-flex;\n align-items: center;\n gap: var(--wa-space-s, 0.5rem);\n margin: 0;\n font-size: var(--wa-font-size-s, 0.875rem);\n flex-shrink: 0;\n }\n .hex-label {\n user-select: none;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'docks-plain-editor': DocksPlainEditor;\n }\n}\n"],"mappings":"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"}