@eclipse-docks/extension-plain-editor 0.7.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/binary.d.ts +7 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/hexeditor-BYd_tpCW.js +476 -0
- package/dist/hexeditor-BYd_tpCW.js.map +1 -0
- package/dist/hexeditor.d.ts +26 -0
- package/dist/hexeditor.d.ts.map +1 -0
- package/dist/i18n.de-Ddrm6naw.js +15 -0
- package/dist/i18n.de-Ddrm6naw.js.map +1 -0
- package/dist/i18n.en-Og49LNLR.js +15 -0
- package/dist/i18n.en-Og49LNLR.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/plain-editor-06SNmG-t.js +221 -0
- package/dist/plain-editor-06SNmG-t.js.map +1 -0
- package/dist/plain-editor-extension-DmlYtE9-.js +29 -0
- package/dist/plain-editor-extension-DmlYtE9-.js.map +1 -0
- package/dist/plain-editor-extension.d.ts +2 -0
- package/dist/plain-editor-extension.d.ts.map +1 -0
- package/dist/plain-editor.d.ts +41 -0
- package/dist/plain-editor.d.ts.map +1 -0
- package/dist/texteditor.d.ts +38 -0
- package/dist/texteditor.d.ts.map +1 -0
- package/dist/widgets.d.ts +3 -0
- package/dist/widgets.d.ts.map +1 -0
- package/dist/widgets.js +2 -0
- package/package.json +36 -0
package/dist/binary.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { DocksWidget } from "@eclipse-docks/core";
|
|
2
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
3
|
+
import { css, html } from "lit";
|
|
4
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
|
+
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
6
|
+
//#region src/texteditor.ts
|
|
7
|
+
var DocksTextEditor = class DocksTextEditor extends DocksWidget {
|
|
8
|
+
constructor(..._args) {
|
|
9
|
+
super(..._args);
|
|
10
|
+
this.value = "";
|
|
11
|
+
this.readOnly = false;
|
|
12
|
+
this.lineCount = 1;
|
|
13
|
+
this.gutterScrollHeight = 0;
|
|
14
|
+
this.textareaRef = createRef();
|
|
15
|
+
this.innerTextarea = null;
|
|
16
|
+
this.gutterEl = null;
|
|
17
|
+
this.resizeObserver = null;
|
|
18
|
+
this.onTextScroll = () => {
|
|
19
|
+
const inner = this.innerTextarea;
|
|
20
|
+
const gutter = this.gutterEl;
|
|
21
|
+
if (!inner || !gutter) return;
|
|
22
|
+
if (gutter.scrollTop !== inner.scrollTop) gutter.scrollTop = inner.scrollTop;
|
|
23
|
+
};
|
|
24
|
+
this.onGutterScroll = () => {
|
|
25
|
+
const inner = this.innerTextarea;
|
|
26
|
+
const gutter = this.gutterEl;
|
|
27
|
+
if (!inner || !gutter) return;
|
|
28
|
+
if (inner.scrollTop !== gutter.scrollTop) inner.scrollTop = gutter.scrollTop;
|
|
29
|
+
};
|
|
30
|
+
this.onInput = (e) => {
|
|
31
|
+
this.value = e.target.value;
|
|
32
|
+
const lines = this.value.split("\n").length;
|
|
33
|
+
this.lineCount = Math.max(1, lines);
|
|
34
|
+
this.emitChange();
|
|
35
|
+
queueMicrotask(() => this.syncScrollMetrics());
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
willUpdate(changed) {
|
|
39
|
+
if (changed.has("value")) {
|
|
40
|
+
const lines = this.value.split("\n").length;
|
|
41
|
+
this.lineCount = Math.max(1, lines);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
updated() {
|
|
45
|
+
queueMicrotask(() => {
|
|
46
|
+
this.cacheElements();
|
|
47
|
+
this.syncScrollMetrics();
|
|
48
|
+
this.attachScrollListeners();
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
disconnectedCallback() {
|
|
52
|
+
this.teardownScrollListeners();
|
|
53
|
+
super.disconnectedCallback();
|
|
54
|
+
}
|
|
55
|
+
cacheElements() {
|
|
56
|
+
this.innerTextarea = this.textareaRef.value?.shadowRoot?.querySelector("textarea") ?? null;
|
|
57
|
+
this.gutterEl = this.renderRoot?.querySelector(".line-gutter") ?? null;
|
|
58
|
+
}
|
|
59
|
+
attachScrollListeners() {
|
|
60
|
+
const inner = this.innerTextarea;
|
|
61
|
+
const gutter = this.gutterEl;
|
|
62
|
+
if (!inner || !gutter) return;
|
|
63
|
+
inner.removeEventListener("scroll", this.onTextScroll);
|
|
64
|
+
inner.addEventListener("scroll", this.onTextScroll, { passive: true });
|
|
65
|
+
gutter.removeEventListener("scroll", this.onGutterScroll);
|
|
66
|
+
gutter.addEventListener("scroll", this.onGutterScroll, { passive: true });
|
|
67
|
+
if (!this.resizeObserver) this.resizeObserver = new ResizeObserver(() => {
|
|
68
|
+
this.syncScrollMetrics();
|
|
69
|
+
});
|
|
70
|
+
this.resizeObserver.disconnect();
|
|
71
|
+
this.resizeObserver.observe(inner);
|
|
72
|
+
}
|
|
73
|
+
teardownScrollListeners() {
|
|
74
|
+
this.innerTextarea?.removeEventListener("scroll", this.onTextScroll);
|
|
75
|
+
this.gutterEl?.removeEventListener("scroll", this.onGutterScroll);
|
|
76
|
+
this.resizeObserver?.disconnect();
|
|
77
|
+
this.resizeObserver = null;
|
|
78
|
+
this.innerTextarea = null;
|
|
79
|
+
this.gutterEl = null;
|
|
80
|
+
}
|
|
81
|
+
syncScrollMetrics() {
|
|
82
|
+
const inner = this.innerTextarea;
|
|
83
|
+
if (!inner) return;
|
|
84
|
+
const sh = inner.scrollHeight;
|
|
85
|
+
if (sh !== this.gutterScrollHeight) this.gutterScrollHeight = sh;
|
|
86
|
+
this.onTextScroll();
|
|
87
|
+
}
|
|
88
|
+
emitChange() {
|
|
89
|
+
this.dispatchEvent(new CustomEvent("content-change", {
|
|
90
|
+
detail: { value: this.value },
|
|
91
|
+
bubbles: true,
|
|
92
|
+
composed: true
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
getValue() {
|
|
96
|
+
return this.value;
|
|
97
|
+
}
|
|
98
|
+
getSelection() {
|
|
99
|
+
const inner = this.textareaRef.value?.shadowRoot?.querySelector("textarea");
|
|
100
|
+
if (!inner) return null;
|
|
101
|
+
const { selectionStart, selectionEnd, value } = inner;
|
|
102
|
+
if (selectionStart === selectionEnd) return "";
|
|
103
|
+
return value.slice(selectionStart, selectionEnd);
|
|
104
|
+
}
|
|
105
|
+
getSnippet(linesAround = 5) {
|
|
106
|
+
const inner = this.textareaRef.value?.shadowRoot?.querySelector("textarea");
|
|
107
|
+
if (!inner) return null;
|
|
108
|
+
const text = this.value;
|
|
109
|
+
const pos = inner.selectionStart;
|
|
110
|
+
let line = 0;
|
|
111
|
+
for (let i = 0; i < text.length && i < pos; i++) if (text[i] === "\n") {
|
|
112
|
+
line++;
|
|
113
|
+
i + 1;
|
|
114
|
+
}
|
|
115
|
+
const allLines = text.split("\n");
|
|
116
|
+
const cur = line;
|
|
117
|
+
const from = Math.max(0, cur - linesAround);
|
|
118
|
+
const to = Math.min(allLines.length, cur + linesAround + 1);
|
|
119
|
+
return {
|
|
120
|
+
snippet: allLines.slice(from, to).join("\n"),
|
|
121
|
+
cursorLine: cur
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
render() {
|
|
125
|
+
const numbers = [];
|
|
126
|
+
for (let i = 1; i <= this.lineCount; i++) numbers.push(i);
|
|
127
|
+
return html`
|
|
128
|
+
<div class="wrap">
|
|
129
|
+
<div class="line-gutter" aria-hidden="true">
|
|
130
|
+
<div class="line-gutter-inner" style="min-height: ${this.gutterScrollHeight > 0 ? `${this.gutterScrollHeight}px` : "100%"}">
|
|
131
|
+
${numbers.map((n) => html`<div class="ln">${n}</div>`)}
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
<wa-textarea
|
|
135
|
+
class="editor-ta"
|
|
136
|
+
resize="none"
|
|
137
|
+
.value=${this.value}
|
|
138
|
+
?readonly=${this.readOnly}
|
|
139
|
+
@input=${this.onInput}
|
|
140
|
+
${ref(this.textareaRef)}
|
|
141
|
+
></wa-textarea>
|
|
142
|
+
</div>
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
static {
|
|
146
|
+
this.styles = css`
|
|
147
|
+
:host {
|
|
148
|
+
display: block;
|
|
149
|
+
height: 100%;
|
|
150
|
+
min-height: 0;
|
|
151
|
+
}
|
|
152
|
+
.wrap {
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: row;
|
|
155
|
+
height: 100%;
|
|
156
|
+
min-height: 0;
|
|
157
|
+
gap: var(--wa-space-s, 0.5rem);
|
|
158
|
+
}
|
|
159
|
+
.line-gutter {
|
|
160
|
+
flex: 0 0 auto;
|
|
161
|
+
min-width: 2.5rem;
|
|
162
|
+
min-height: 0;
|
|
163
|
+
align-self: stretch;
|
|
164
|
+
padding: 0;
|
|
165
|
+
text-align: right;
|
|
166
|
+
font-family: var(--wa-font-mono, ui-monospace, monospace);
|
|
167
|
+
font-size: var(--wa-font-size-s, 0.875rem);
|
|
168
|
+
/* Match wa-textarea value line metrics (gutter used 1.5 while controls use --wa-form-control-value-line-height, e.g. 1.2) */
|
|
169
|
+
line-height: var(--wa-form-control-value-line-height, 1.5);
|
|
170
|
+
color: var(--wa-color-neutral-50, #888);
|
|
171
|
+
user-select: none;
|
|
172
|
+
overflow-x: hidden;
|
|
173
|
+
overflow-y: auto;
|
|
174
|
+
scrollbar-width: none;
|
|
175
|
+
box-sizing: border-box;
|
|
176
|
+
}
|
|
177
|
+
.line-gutter::-webkit-scrollbar {
|
|
178
|
+
display: none;
|
|
179
|
+
}
|
|
180
|
+
.line-gutter-inner {
|
|
181
|
+
box-sizing: border-box;
|
|
182
|
+
line-height: inherit;
|
|
183
|
+
/* Same vertical padding as wa-textarea inner control (see webawesome textarea.styles) */
|
|
184
|
+
padding-block: calc(var(--wa-form-control-padding-block, 0.75em) - ((1lh - 1em) / 2));
|
|
185
|
+
padding-inline: 0;
|
|
186
|
+
}
|
|
187
|
+
.ln {
|
|
188
|
+
padding-right: var(--wa-space-xs, 0.25rem);
|
|
189
|
+
box-sizing: border-box;
|
|
190
|
+
line-height: inherit;
|
|
191
|
+
min-height: 1lh;
|
|
192
|
+
}
|
|
193
|
+
.editor-ta {
|
|
194
|
+
flex: 1 1 auto;
|
|
195
|
+
align-self: stretch;
|
|
196
|
+
min-width: 0;
|
|
197
|
+
min-height: 0;
|
|
198
|
+
width: 100%;
|
|
199
|
+
height: 100%;
|
|
200
|
+
font-family: var(--wa-font-mono, ui-monospace, monospace);
|
|
201
|
+
font-size: var(--wa-font-size-s, 0.875rem);
|
|
202
|
+
line-height: var(--wa-form-control-value-line-height, 1.5);
|
|
203
|
+
}
|
|
204
|
+
.editor-ta::part(base) {
|
|
205
|
+
flex: 1 1 auto;
|
|
206
|
+
min-height: 0;
|
|
207
|
+
height: 100%;
|
|
208
|
+
align-items: stretch;
|
|
209
|
+
justify-items: stretch;
|
|
210
|
+
}
|
|
211
|
+
.editor-ta::part(textarea) {
|
|
212
|
+
min-height: 100%;
|
|
213
|
+
height: 100%;
|
|
214
|
+
resize: none;
|
|
215
|
+
line-height: inherit;
|
|
216
|
+
}
|
|
217
|
+
`;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
_decorate([property()], DocksTextEditor.prototype, "value", void 0);
|
|
221
|
+
_decorate([property({ type: Boolean })], DocksTextEditor.prototype, "readOnly", void 0);
|
|
222
|
+
_decorate([state()], DocksTextEditor.prototype, "lineCount", void 0);
|
|
223
|
+
_decorate([state()], DocksTextEditor.prototype, "gutterScrollHeight", void 0);
|
|
224
|
+
DocksTextEditor = _decorate([customElement("docks-texteditor")], DocksTextEditor);
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/hexeditor.ts
|
|
227
|
+
var BYTES_PER_LINE = 16;
|
|
228
|
+
/** Printable ASCII for preview column (typical hex dump). */
|
|
229
|
+
function byteToPreviewChar(b) {
|
|
230
|
+
if (b >= 32 && b <= 126) return String.fromCharCode(b);
|
|
231
|
+
return ".";
|
|
232
|
+
}
|
|
233
|
+
function asciiPreview(slice) {
|
|
234
|
+
let s = "";
|
|
235
|
+
for (let i = 0; i < slice.length; i++) s += byteToPreviewChar(slice[i]);
|
|
236
|
+
return s.padEnd(BYTES_PER_LINE, " ");
|
|
237
|
+
}
|
|
238
|
+
/** "aa bb cc ..." with extra gap after 8th byte */
|
|
239
|
+
function formatHexBytes(slice) {
|
|
240
|
+
const pairs = [];
|
|
241
|
+
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(" ")}`;
|
|
244
|
+
}
|
|
245
|
+
function parseHexFlexible(text) {
|
|
246
|
+
const hex = text.replace(/[^0-9a-fA-F]/g, "");
|
|
247
|
+
const len = Math.floor(hex.length / 2);
|
|
248
|
+
const out = new Uint8Array(len);
|
|
249
|
+
for (let i = 0; i < len; i++) out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
/** Parse one line of hex pairs (16 or fewer bytes). */
|
|
253
|
+
function parseHexLine(line) {
|
|
254
|
+
const hex = line.replace(/[^0-9a-fA-F]/g, "");
|
|
255
|
+
const bytes = [];
|
|
256
|
+
for (let i = 0; i + 1 < hex.length; i += 2) bytes.push(parseInt(hex.slice(i, i + 2), 16));
|
|
257
|
+
return bytes;
|
|
258
|
+
}
|
|
259
|
+
function lineCountForLength(byteLength) {
|
|
260
|
+
if (byteLength === 0) return 1;
|
|
261
|
+
return Math.ceil(byteLength / BYTES_PER_LINE);
|
|
262
|
+
}
|
|
263
|
+
/** Multi-line text dump (offset + hex + ASCII), for consumers / debugging. */
|
|
264
|
+
function formatHexDump(bytes) {
|
|
265
|
+
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));
|
|
268
|
+
const addr = i.toString(16).padStart(8, "0");
|
|
269
|
+
lines.push(`${addr}h ${formatHexBytes(slice)} |${asciiPreview(slice)}`);
|
|
270
|
+
}
|
|
271
|
+
if (bytes.length === 0) lines.push(`${0 .toString(16).padStart(8, "0")}h |${asciiPreview(new Uint8Array(0))}`);
|
|
272
|
+
return lines.join("\n");
|
|
273
|
+
}
|
|
274
|
+
var DocksHexEditor = class DocksHexEditor extends DocksWidget {
|
|
275
|
+
constructor(..._args) {
|
|
276
|
+
super(..._args);
|
|
277
|
+
this.initialBytes = new Uint8Array(0);
|
|
278
|
+
this.seed = 0;
|
|
279
|
+
this.readOnly = false;
|
|
280
|
+
this.bytes = new Uint8Array(0);
|
|
281
|
+
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);
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
willUpdate(changed) {
|
|
298
|
+
if (changed.has("seed") && this.seed !== this.lastSeed) {
|
|
299
|
+
this.lastSeed = this.seed;
|
|
300
|
+
this.bytes = new Uint8Array(this.initialBytes);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
emitChange(bytes) {
|
|
304
|
+
this.dispatchEvent(new CustomEvent("content-change", {
|
|
305
|
+
detail: { bytes },
|
|
306
|
+
bubbles: true,
|
|
307
|
+
composed: true
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
getBytesSnapshot() {
|
|
311
|
+
return new Uint8Array(this.bytes);
|
|
312
|
+
}
|
|
313
|
+
render() {
|
|
314
|
+
const len = this.bytes.length;
|
|
315
|
+
const rows = lineCountForLength(len || 1);
|
|
316
|
+
const headerCells = [];
|
|
317
|
+
for (let h = 0; h < BYTES_PER_LINE; h++) headerCells.push(html`<span class="hex-col-head">${h.toString(16)}</span>`);
|
|
318
|
+
const dataRows = [];
|
|
319
|
+
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));
|
|
322
|
+
const addr = offset.toString(16).padStart(8, "0");
|
|
323
|
+
const hexVal = formatHexBytes(slice);
|
|
324
|
+
const asciiVal = asciiPreview(slice);
|
|
325
|
+
dataRows.push(html`
|
|
326
|
+
<div class="hex-row" part="hex-row">
|
|
327
|
+
<span class="addr-col">${addr}h</span>
|
|
328
|
+
<div class="hex-cols" role="group" aria-label="hex bytes">
|
|
329
|
+
<input
|
|
330
|
+
type="text"
|
|
331
|
+
class="hex-line-input"
|
|
332
|
+
spellcheck="false"
|
|
333
|
+
autocomplete="off"
|
|
334
|
+
?readonly=${this.readOnly}
|
|
335
|
+
.value=${hexVal}
|
|
336
|
+
@input=${(e) => this.onHexLineChange(offset, e)}
|
|
337
|
+
/>
|
|
338
|
+
</div>
|
|
339
|
+
<span class="ascii-col">${asciiVal}</span>
|
|
340
|
+
</div>
|
|
341
|
+
`);
|
|
342
|
+
}
|
|
343
|
+
return html`
|
|
344
|
+
<div class="hex-shell">
|
|
345
|
+
<div class="hex-header" part="hex-header">
|
|
346
|
+
<span class="addr-col"></span>
|
|
347
|
+
<div class="hex-cols hex-header-cols">${headerCells}</div>
|
|
348
|
+
<span class="ascii-header" title="ASCII">ASCII</span>
|
|
349
|
+
</div>
|
|
350
|
+
<wa-scroller class="hex-scroll" orientation="vertical">
|
|
351
|
+
<div class="hex-body">${dataRows}</div>
|
|
352
|
+
</wa-scroller>
|
|
353
|
+
</div>
|
|
354
|
+
`;
|
|
355
|
+
}
|
|
356
|
+
static {
|
|
357
|
+
this.styles = css`
|
|
358
|
+
:host {
|
|
359
|
+
display: block;
|
|
360
|
+
height: 100%;
|
|
361
|
+
min-height: 0;
|
|
362
|
+
}
|
|
363
|
+
.hex-shell {
|
|
364
|
+
box-sizing: border-box;
|
|
365
|
+
display: flex;
|
|
366
|
+
flex-direction: column;
|
|
367
|
+
height: 100%;
|
|
368
|
+
min-height: 0;
|
|
369
|
+
padding: var(--wa-space-s, 0.5rem);
|
|
370
|
+
font-family: var(--wa-font-mono, ui-monospace, monospace);
|
|
371
|
+
font-size: var(--wa-font-size-s, 0.875rem);
|
|
372
|
+
line-height: 1.5;
|
|
373
|
+
width: fit-content;
|
|
374
|
+
max-width: 100%;
|
|
375
|
+
min-width: 0;
|
|
376
|
+
}
|
|
377
|
+
.hex-scroll {
|
|
378
|
+
flex: 1 1 auto;
|
|
379
|
+
min-height: 0;
|
|
380
|
+
}
|
|
381
|
+
.hex-header {
|
|
382
|
+
display: grid;
|
|
383
|
+
/* addr | hex (48 chars for 16 bytes) | ASCII preview (16 chars) */
|
|
384
|
+
grid-template-columns: 5.5rem 48ch 16ch;
|
|
385
|
+
gap: var(--wa-space-s, 0.5rem);
|
|
386
|
+
align-items: end;
|
|
387
|
+
padding-bottom: var(--wa-space-xs, 0.25rem);
|
|
388
|
+
margin-bottom: var(--wa-space-xs, 0.25rem);
|
|
389
|
+
border-bottom: 1px solid var(--wa-color-neutral-border, #444);
|
|
390
|
+
color: var(--wa-color-neutral-50, #888);
|
|
391
|
+
user-select: none;
|
|
392
|
+
}
|
|
393
|
+
.hex-header-cols {
|
|
394
|
+
display: grid;
|
|
395
|
+
grid-template-columns: repeat(16, 1fr);
|
|
396
|
+
gap: 0;
|
|
397
|
+
text-align: center;
|
|
398
|
+
width: 48ch;
|
|
399
|
+
min-width: 0;
|
|
400
|
+
}
|
|
401
|
+
.hex-col-head {
|
|
402
|
+
font-size: var(--wa-font-size-xs, 0.75rem);
|
|
403
|
+
}
|
|
404
|
+
.ascii-header {
|
|
405
|
+
text-align: left;
|
|
406
|
+
width: 16ch;
|
|
407
|
+
min-width: 16ch;
|
|
408
|
+
}
|
|
409
|
+
.hex-body {
|
|
410
|
+
display: flex;
|
|
411
|
+
flex-direction: column;
|
|
412
|
+
gap: 0;
|
|
413
|
+
}
|
|
414
|
+
.hex-row {
|
|
415
|
+
display: grid;
|
|
416
|
+
grid-template-columns: 5.5rem 48ch 16ch;
|
|
417
|
+
gap: var(--wa-space-s, 0.5rem);
|
|
418
|
+
align-items: center;
|
|
419
|
+
min-height: 1.5em;
|
|
420
|
+
}
|
|
421
|
+
.addr-col {
|
|
422
|
+
color: var(--wa-color-neutral-50, #888);
|
|
423
|
+
text-align: right;
|
|
424
|
+
user-select: none;
|
|
425
|
+
padding-right: var(--wa-space-xs, 0.25rem);
|
|
426
|
+
}
|
|
427
|
+
.hex-cols {
|
|
428
|
+
width: 48ch;
|
|
429
|
+
min-width: 0;
|
|
430
|
+
max-width: 100%;
|
|
431
|
+
}
|
|
432
|
+
.hex-line-input {
|
|
433
|
+
box-sizing: border-box;
|
|
434
|
+
width: 100%;
|
|
435
|
+
max-width: none;
|
|
436
|
+
margin: 0;
|
|
437
|
+
padding: 0.1em 0.25em;
|
|
438
|
+
border: 1px solid transparent;
|
|
439
|
+
border-radius: var(--wa-border-radius-s, 2px);
|
|
440
|
+
background: var(--wa-color-neutral-fill-quiet, rgba(128, 128, 128, 0.08));
|
|
441
|
+
color: inherit;
|
|
442
|
+
font: inherit;
|
|
443
|
+
letter-spacing: 0.02em;
|
|
444
|
+
}
|
|
445
|
+
.hex-line-input:hover:not(:read-only) {
|
|
446
|
+
border-color: var(--wa-color-neutral-border, #555);
|
|
447
|
+
}
|
|
448
|
+
.hex-line-input:focus {
|
|
449
|
+
outline: var(--wa-focus-ring-width, 2px) solid var(--wa-color-focus, #3b82f6);
|
|
450
|
+
outline-offset: 0;
|
|
451
|
+
border-color: transparent;
|
|
452
|
+
}
|
|
453
|
+
.hex-line-input:read-only {
|
|
454
|
+
opacity: 0.9;
|
|
455
|
+
}
|
|
456
|
+
.ascii-col {
|
|
457
|
+
color: var(--wa-color-neutral-80, #bbb);
|
|
458
|
+
white-space: pre;
|
|
459
|
+
overflow: visible;
|
|
460
|
+
width: 16ch;
|
|
461
|
+
min-width: 16ch;
|
|
462
|
+
padding-left: var(--wa-space-xs, 0.25rem);
|
|
463
|
+
user-select: none;
|
|
464
|
+
}
|
|
465
|
+
`;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
_decorate([property({ attribute: false })], DocksHexEditor.prototype, "initialBytes", void 0);
|
|
469
|
+
_decorate([property({ type: Number })], DocksHexEditor.prototype, "seed", void 0);
|
|
470
|
+
_decorate([property({ type: Boolean })], DocksHexEditor.prototype, "readOnly", void 0);
|
|
471
|
+
_decorate([state()], DocksHexEditor.prototype, "bytes", void 0);
|
|
472
|
+
DocksHexEditor = _decorate([customElement("docks-hexeditor")], DocksHexEditor);
|
|
473
|
+
//#endregion
|
|
474
|
+
export { DocksTextEditor as i, formatHexDump as n, parseHexFlexible as r, DocksHexEditor as t };
|
|
475
|
+
|
|
476
|
+
//# sourceMappingURL=hexeditor-BYd_tpCW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { DocksWidget } from '@eclipse-docks/core';
|
|
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
|
+
export declare class DocksHexEditor extends DocksWidget {
|
|
9
|
+
initialBytes: Uint8Array;
|
|
10
|
+
seed: number;
|
|
11
|
+
readOnly: boolean;
|
|
12
|
+
private bytes;
|
|
13
|
+
private lastSeed;
|
|
14
|
+
protected willUpdate(changed: PropertyValues<this>): void;
|
|
15
|
+
private emitChange;
|
|
16
|
+
private onHexLineChange;
|
|
17
|
+
getBytesSnapshot(): Uint8Array;
|
|
18
|
+
protected render(): import('lit-html').TemplateResult<1>;
|
|
19
|
+
static styles: import('lit').CSSResult;
|
|
20
|
+
}
|
|
21
|
+
declare global {
|
|
22
|
+
interface HTMLElementTagNameMap {
|
|
23
|
+
'docks-hexeditor': DocksHexEditor;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=hexeditor.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/i18n.de.json
|
|
2
|
+
var EXT_PLAIN_NAME = "Einfacher Texteditor";
|
|
3
|
+
var EXT_PLAIN_DESC = "Standard-Text- und Hex-Editor für Workspace-Dateien";
|
|
4
|
+
var HEX_VIEW_LABEL = "Hex-Ansicht";
|
|
5
|
+
var BINARY_VIEW_TRUNCATED = "Es werden nur die ersten {shown} von {total} Bytes angezeigt (schreibgeschützt).";
|
|
6
|
+
var i18n_de_default = {
|
|
7
|
+
EXT_PLAIN_NAME,
|
|
8
|
+
EXT_PLAIN_DESC,
|
|
9
|
+
HEX_VIEW_LABEL,
|
|
10
|
+
BINARY_VIEW_TRUNCATED
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { BINARY_VIEW_TRUNCATED, EXT_PLAIN_DESC, EXT_PLAIN_NAME, HEX_VIEW_LABEL, i18n_de_default as default };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=i18n.de-Ddrm6naw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.de-Ddrm6naw.js","names":[],"sources":["../src/i18n.de.json"],"sourcesContent":["{\n \"EXT_PLAIN_NAME\": \"Einfacher Texteditor\",\n \"EXT_PLAIN_DESC\": \"Standard-Text- und Hex-Editor für Workspace-Dateien\",\n \"HEX_VIEW_LABEL\": \"Hex-Ansicht\",\n \"BINARY_VIEW_TRUNCATED\": \"Es werden nur die ersten {shown} von {total} Bytes angezeigt (schreibgeschützt).\"\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/i18n.en.json
|
|
2
|
+
var EXT_PLAIN_NAME = "Plain text editor";
|
|
3
|
+
var EXT_PLAIN_DESC = "Default lightweight text and hex editor for workspace files";
|
|
4
|
+
var HEX_VIEW_LABEL = "Hex view";
|
|
5
|
+
var BINARY_VIEW_TRUNCATED = "Showing first {shown} of {total} bytes (read-only).";
|
|
6
|
+
var i18n_en_default = {
|
|
7
|
+
EXT_PLAIN_NAME,
|
|
8
|
+
EXT_PLAIN_DESC,
|
|
9
|
+
HEX_VIEW_LABEL,
|
|
10
|
+
BINARY_VIEW_TRUNCATED
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { BINARY_VIEW_TRUNCATED, EXT_PLAIN_DESC, EXT_PLAIN_NAME, HEX_VIEW_LABEL, i18n_en_default as default };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=i18n.en-Og49LNLR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.en-Og49LNLR.js","names":[],"sources":["../src/i18n.en.json"],"sourcesContent":["{\n \"EXT_PLAIN_NAME\": \"Plain text editor\",\n \"EXT_PLAIN_DESC\": \"Default lightweight text and hex editor for workspace files\",\n \"HEX_VIEW_LABEL\": \"Hex view\",\n \"BINARY_VIEW_TRUNCATED\": \"Showing first {shown} of {total} bytes (read-only).\"\n}\n"],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,kCAAkC,gCAAgC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { extensionRegistry, i18n } from "@eclipse-docks/core";
|
|
2
|
+
import pkg from "../package.json";
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
var t = await i18n(/* @__PURE__ */ Object.assign({
|
|
5
|
+
"./i18n.de.json": () => import("./i18n.de-Ddrm6naw.js"),
|
|
6
|
+
"./i18n.en.json": () => import("./i18n.en-Og49LNLR.js")
|
|
7
|
+
}), true);
|
|
8
|
+
extensionRegistry.registerExtension({
|
|
9
|
+
id: pkg.name,
|
|
10
|
+
name: t.EXT_PLAIN_NAME,
|
|
11
|
+
description: t.EXT_PLAIN_DESC,
|
|
12
|
+
loader: () => import("./plain-editor-extension-DmlYtE9-.js"),
|
|
13
|
+
icon: "file-lines"
|
|
14
|
+
});
|
|
15
|
+
var PLAIN_EDITOR_TOOLBAR_TARGET_PREFIX = "toolbar:system.plain-editor";
|
|
16
|
+
//#endregion
|
|
17
|
+
export { PLAIN_EDITOR_TOOLBAR_TARGET_PREFIX };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { extensionRegistry, i18n } from '@eclipse-docks/core';\nimport pkg from '../package.json';\n\nconst t = await i18n(import.meta.glob('./i18n*.json'), true);\n\nextensionRegistry.registerExtension({\n id: pkg.name,\n name: t.EXT_PLAIN_NAME,\n description: t.EXT_PLAIN_DESC,\n loader: () => import('./plain-editor-extension.js'),\n icon: 'file-lines',\n});\n\nexport const PLAIN_EDITOR_TOOLBAR_TARGET_PREFIX = 'toolbar:system.plain-editor';\n"],"mappings":";;;AAGA,IAAM,IAAI,MAAM,KAAK,uBAAA,OAAA;CAAA,wBAAA,OAAA;CAAA,wBAAA,OAAA;CAAA,CAAgC,EAAE,KAAK;AAE5D,kBAAkB,kBAAkB;CAClC,IAAI,IAAI;CACR,MAAM,EAAE;CACR,aAAa,EAAE;CACf,cAAc,OAAO;CACrB,MAAM;CACP,CAAC;AAEF,IAAa,qCAAqC"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import "./hexeditor-BYd_tpCW.js";
|
|
2
|
+
import { DocksPart, i18n } from "@eclipse-docks/core";
|
|
3
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
4
|
+
import { css, html, nothing } from "lit";
|
|
5
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
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
|
+
//#region src/plain-editor.ts
|
|
29
|
+
var t = await i18n(/* @__PURE__ */ Object.assign({
|
|
30
|
+
"./i18n.de.json": () => import("./i18n.de-Ddrm6naw.js"),
|
|
31
|
+
"./i18n.en.json": () => import("./i18n.en-Og49LNLR.js")
|
|
32
|
+
}), true);
|
|
33
|
+
var DocksPlainEditor = class DocksPlainEditor extends DocksPart {
|
|
34
|
+
constructor(..._args) {
|
|
35
|
+
super(..._args);
|
|
36
|
+
this.scrollMode = "native";
|
|
37
|
+
this.readOnly = false;
|
|
38
|
+
this.ready = false;
|
|
39
|
+
this.hexMode = false;
|
|
40
|
+
this.textValue = "";
|
|
41
|
+
this.bytes = new Uint8Array(0);
|
|
42
|
+
this.hexSeed = 0;
|
|
43
|
+
this.hexInitialBytes = new Uint8Array(0);
|
|
44
|
+
this.binaryViewTruncated = false;
|
|
45
|
+
this.binarySourceByteLength = 0;
|
|
46
|
+
this.textRef = createRef();
|
|
47
|
+
this.hexRef = createRef();
|
|
48
|
+
this.onTextChange = (e) => {
|
|
49
|
+
this.textValue = e.detail.value;
|
|
50
|
+
this.bytes = new TextEncoder().encode(this.textValue);
|
|
51
|
+
this.markDirty(true);
|
|
52
|
+
};
|
|
53
|
+
this.onHexChange = (e) => {
|
|
54
|
+
this.bytes = e.detail.bytes;
|
|
55
|
+
this.textValue = new TextDecoder("utf-8", { fatal: false }).decode(this.bytes);
|
|
56
|
+
this.markDirty(true);
|
|
57
|
+
};
|
|
58
|
+
this.onHexViewToggle = (e) => {
|
|
59
|
+
const on = e.target.checked;
|
|
60
|
+
if (on === this.hexMode) return;
|
|
61
|
+
if (on) {
|
|
62
|
+
this.bytes = new TextEncoder().encode(this.textValue);
|
|
63
|
+
this.hexInitialBytes = new Uint8Array(this.bytes);
|
|
64
|
+
this.hexSeed += 1;
|
|
65
|
+
this.hexMode = true;
|
|
66
|
+
} else {
|
|
67
|
+
this.textValue = new TextDecoder("utf-8", { fatal: false }).decode(this.bytes);
|
|
68
|
+
this.hexMode = false;
|
|
69
|
+
}
|
|
70
|
+
this.requestUpdate();
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async doInitUI() {
|
|
74
|
+
const blob = await this.input.data.getContents({ blob: true });
|
|
75
|
+
this.hexMode = await detectBinaryBlob(blob);
|
|
76
|
+
if (this.hexMode) {
|
|
77
|
+
if (blob.size > 8192) {
|
|
78
|
+
this.bytes = new Uint8Array(await blob.slice(0, BINARY_HEX_VIEW_MAX_BYTES).arrayBuffer());
|
|
79
|
+
this.binaryViewTruncated = true;
|
|
80
|
+
this.binarySourceByteLength = blob.size;
|
|
81
|
+
} else {
|
|
82
|
+
this.bytes = new Uint8Array(await blob.arrayBuffer());
|
|
83
|
+
this.binaryViewTruncated = false;
|
|
84
|
+
this.binarySourceByteLength = 0;
|
|
85
|
+
}
|
|
86
|
+
this.textValue = new TextDecoder("utf-8", { fatal: false }).decode(this.bytes);
|
|
87
|
+
this.hexInitialBytes = new Uint8Array(this.bytes);
|
|
88
|
+
this.hexSeed = 1;
|
|
89
|
+
} else {
|
|
90
|
+
this.bytes = new Uint8Array(await blob.arrayBuffer());
|
|
91
|
+
this.binaryViewTruncated = false;
|
|
92
|
+
this.binarySourceByteLength = 0;
|
|
93
|
+
this.textValue = new TextDecoder("utf-8", { fatal: false }).decode(this.bytes);
|
|
94
|
+
}
|
|
95
|
+
this.ready = true;
|
|
96
|
+
}
|
|
97
|
+
save() {
|
|
98
|
+
if (this.binaryViewTruncated) return;
|
|
99
|
+
const blob = new Blob([new Uint8Array(this.bytes)]);
|
|
100
|
+
this.input?.data.saveContents(blob);
|
|
101
|
+
this.markDirty(false);
|
|
102
|
+
}
|
|
103
|
+
doClose() {
|
|
104
|
+
this.ready = false;
|
|
105
|
+
this.binaryViewTruncated = false;
|
|
106
|
+
this.binarySourceByteLength = 0;
|
|
107
|
+
}
|
|
108
|
+
getContent() {
|
|
109
|
+
if (this.hexMode) {
|
|
110
|
+
const hex = this.hexRef.value?.getBytesSnapshot();
|
|
111
|
+
if (hex) return [...hex].map((b) => b.toString(16).padStart(2, "0")).join(" ");
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return this.textRef.value?.getValue() ?? this.textValue;
|
|
115
|
+
}
|
|
116
|
+
getSelection() {
|
|
117
|
+
if (this.hexMode) return null;
|
|
118
|
+
return this.textRef.value?.getSelection() ?? null;
|
|
119
|
+
}
|
|
120
|
+
getSnippet(lines = 5) {
|
|
121
|
+
if (this.hexMode) return null;
|
|
122
|
+
return this.textRef.value?.getSnippet(lines) ?? null;
|
|
123
|
+
}
|
|
124
|
+
getLanguage() {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
getFilePath() {
|
|
128
|
+
return this.input?.data?.getWorkspacePath() ?? null;
|
|
129
|
+
}
|
|
130
|
+
renderToolbar() {
|
|
131
|
+
if (!this.ready) return nothing;
|
|
132
|
+
const fmt = (n) => n.toLocaleString();
|
|
133
|
+
const truncMsg = this.binaryViewTruncated && this.binarySourceByteLength > 0 ? t.BINARY_VIEW_TRUNCATED({
|
|
134
|
+
shown: fmt(BINARY_HEX_VIEW_MAX_BYTES),
|
|
135
|
+
total: fmt(this.binarySourceByteLength)
|
|
136
|
+
}) : null;
|
|
137
|
+
return html`
|
|
138
|
+
${truncMsg ? html`<span class="binary-trunc-msg" title=${truncMsg}>${truncMsg}</span>` : nothing}
|
|
139
|
+
<label class="hex-toggle">
|
|
140
|
+
<span class="hex-label">${t.HEX_VIEW_LABEL}</span>
|
|
141
|
+
<wa-switch ?checked=${this.hexMode} @change=${this.onHexViewToggle}></wa-switch>
|
|
142
|
+
</label>
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
renderContent() {
|
|
146
|
+
if (!this.ready) return html`<div class="placeholder"></div>`;
|
|
147
|
+
if (this.hexMode) return html`
|
|
148
|
+
<docks-hexeditor
|
|
149
|
+
${ref(this.hexRef)}
|
|
150
|
+
.initialBytes=${this.hexInitialBytes}
|
|
151
|
+
.seed=${this.hexSeed}
|
|
152
|
+
.readOnly=${this.readOnly || this.binaryViewTruncated}
|
|
153
|
+
@content-change=${this.onHexChange}
|
|
154
|
+
></docks-hexeditor>
|
|
155
|
+
`;
|
|
156
|
+
return html`
|
|
157
|
+
<docks-texteditor
|
|
158
|
+
${ref(this.textRef)}
|
|
159
|
+
.value=${this.textValue}
|
|
160
|
+
.readOnly=${this.readOnly || this.binaryViewTruncated}
|
|
161
|
+
@content-change=${this.onTextChange}
|
|
162
|
+
></docks-texteditor>
|
|
163
|
+
`;
|
|
164
|
+
}
|
|
165
|
+
static {
|
|
166
|
+
this.styles = css`
|
|
167
|
+
:host {
|
|
168
|
+
display: flex;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
min-height: 0;
|
|
171
|
+
height: 100%;
|
|
172
|
+
}
|
|
173
|
+
/* Fill tab panel: let the editor surface stretch with the layout grid */
|
|
174
|
+
.part-content-inner {
|
|
175
|
+
display: flex;
|
|
176
|
+
flex-direction: column;
|
|
177
|
+
min-height: 0;
|
|
178
|
+
}
|
|
179
|
+
.part-content-inner > docks-texteditor,
|
|
180
|
+
.part-content-inner > docks-hexeditor {
|
|
181
|
+
flex: 1 1 auto;
|
|
182
|
+
min-height: 0;
|
|
183
|
+
}
|
|
184
|
+
.placeholder {
|
|
185
|
+
flex: 1;
|
|
186
|
+
min-height: 2rem;
|
|
187
|
+
}
|
|
188
|
+
.binary-trunc-msg {
|
|
189
|
+
flex: 1 1 auto;
|
|
190
|
+
min-width: 0;
|
|
191
|
+
margin-right: var(--wa-space-m, 0.75rem);
|
|
192
|
+
font-size: var(--wa-font-size-xs, 0.75rem);
|
|
193
|
+
color: var(--wa-color-neutral-50, #888);
|
|
194
|
+
line-height: 1.3;
|
|
195
|
+
}
|
|
196
|
+
.hex-toggle {
|
|
197
|
+
display: inline-flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
gap: var(--wa-space-s, 0.5rem);
|
|
200
|
+
margin: 0;
|
|
201
|
+
font-size: var(--wa-font-size-s, 0.875rem);
|
|
202
|
+
flex-shrink: 0;
|
|
203
|
+
}
|
|
204
|
+
.hex-label {
|
|
205
|
+
user-select: none;
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
_decorate([property({ attribute: false })], DocksPlainEditor.prototype, "input", void 0);
|
|
211
|
+
_decorate([property({ type: Boolean })], DocksPlainEditor.prototype, "readOnly", void 0);
|
|
212
|
+
_decorate([state()], DocksPlainEditor.prototype, "ready", void 0);
|
|
213
|
+
_decorate([state()], DocksPlainEditor.prototype, "hexMode", void 0);
|
|
214
|
+
_decorate([state()], DocksPlainEditor.prototype, "textValue", void 0);
|
|
215
|
+
_decorate([state()], DocksPlainEditor.prototype, "hexSeed", void 0);
|
|
216
|
+
_decorate([state()], DocksPlainEditor.prototype, "hexInitialBytes", void 0);
|
|
217
|
+
_decorate([state()], DocksPlainEditor.prototype, "binaryViewTruncated", void 0);
|
|
218
|
+
DocksPlainEditor = _decorate([customElement("docks-plain-editor")], DocksPlainEditor);
|
|
219
|
+
//#endregion
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=plain-editor-06SNmG-t.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":";;;;;;;;AACA,IAAM,aAAa;;AAGnB,IAAa,4BAA4B,IAAI;;;;AAK7C,eAAsB,iBAAiB,MAA8B;AACnE,KAAI,KAAK,SAAS,EAChB,QAAO;CAET,MAAM,IAAI,KAAK,IAAI,KAAK,MAAM,WAAW;CACzC,MAAM,MAAM,IAAI,WAAW,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,aAAa,CAAC;AAChE,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,IAC9B,KAAI,IAAI,OAAO,EACb,QAAO;AAGX,KAAI;AACF,MAAI,YAAY,SAAS,EAAE,OAAO,MAAM,CAAC,CAAC,OAAO,IAAI;AACrD,SAAO;SACD;AACN,SAAO;;;;;ACRX,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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { File, editorRegistry } from "@eclipse-docks/core";
|
|
2
|
+
import { html } from "lit";
|
|
3
|
+
//#region src/plain-editor-extension.ts
|
|
4
|
+
editorRegistry.registerEditorInputHandler({
|
|
5
|
+
editorId: "system.plain-editor",
|
|
6
|
+
label: "Text",
|
|
7
|
+
icon: "file-lines",
|
|
8
|
+
ranking: 1,
|
|
9
|
+
lazyInit: async () => {
|
|
10
|
+
await import("./plain-editor-06SNmG-t.js");
|
|
11
|
+
},
|
|
12
|
+
canHandle: (input) => input instanceof File,
|
|
13
|
+
handle: async (input) => {
|
|
14
|
+
const editorInput = {
|
|
15
|
+
title: input.getWorkspacePath(),
|
|
16
|
+
data: input,
|
|
17
|
+
key: input.getWorkspacePath(),
|
|
18
|
+
icon: editorRegistry.getFileIcon(input.getName()),
|
|
19
|
+
state: {}
|
|
20
|
+
};
|
|
21
|
+
editorInput.component = (id) => html`
|
|
22
|
+
<docks-plain-editor id=${id} .input=${editorInput}></docks-plain-editor>
|
|
23
|
+
`;
|
|
24
|
+
return editorInput;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
//#endregion
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=plain-editor-extension-DmlYtE9-.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-editor-extension.d.ts","sourceRoot":"","sources":["../src/plain-editor-extension.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DocksPart, EditorContentProvider, EditorInput } from '@eclipse-docks/core';
|
|
2
|
+
import { nothing, TemplateResult } from 'lit';
|
|
3
|
+
export declare class DocksPlainEditor extends DocksPart implements EditorContentProvider {
|
|
4
|
+
protected scrollMode: 'scroller' | 'native';
|
|
5
|
+
input?: EditorInput;
|
|
6
|
+
readOnly: boolean;
|
|
7
|
+
private ready;
|
|
8
|
+
private hexMode;
|
|
9
|
+
private textValue;
|
|
10
|
+
private bytes;
|
|
11
|
+
private hexSeed;
|
|
12
|
+
private hexInitialBytes;
|
|
13
|
+
/** True when binary mode loaded only a prefix of a larger file (editing disabled). */
|
|
14
|
+
private binaryViewTruncated;
|
|
15
|
+
private binarySourceByteLength;
|
|
16
|
+
private textRef;
|
|
17
|
+
private hexRef;
|
|
18
|
+
protected doInitUI(): Promise<void>;
|
|
19
|
+
private onTextChange;
|
|
20
|
+
private onHexChange;
|
|
21
|
+
private onHexViewToggle;
|
|
22
|
+
save(): void;
|
|
23
|
+
protected doClose(): void;
|
|
24
|
+
getContent(): string | null;
|
|
25
|
+
getSelection(): string | null;
|
|
26
|
+
getSnippet(lines?: number): {
|
|
27
|
+
snippet: string;
|
|
28
|
+
cursorLine: number;
|
|
29
|
+
} | null;
|
|
30
|
+
getLanguage(): string | null;
|
|
31
|
+
getFilePath(): string | null;
|
|
32
|
+
protected renderToolbar(): TemplateResult | typeof nothing;
|
|
33
|
+
protected renderContent(): TemplateResult | typeof nothing;
|
|
34
|
+
static styles: import('lit').CSSResult;
|
|
35
|
+
}
|
|
36
|
+
declare global {
|
|
37
|
+
interface HTMLElementTagNameMap {
|
|
38
|
+
'docks-plain-editor': DocksPlainEditor;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=plain-editor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plain-editor.d.ts","sourceRoot":"","sources":["../src/plain-editor.ts"],"names":[],"mappings":"AACA,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,WAAW,EAGZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAa,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAG9D,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AAMzB,qBACa,gBAAiB,SAAQ,SAAU,YAAW,qBAAqB;IAC9E,SAAS,CAAC,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAY;IAGvD,KAAK,CAAC,EAAE,WAAW,CAAC;IAGpB,QAAQ,UAAS;IAGjB,OAAO,CAAC,KAAK,CAAS;IAGtB,OAAO,CAAC,OAAO,CAAS;IAGxB,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,KAAK,CAAiC;IAG9C,OAAO,CAAC,OAAO,CAAK;IAGpB,OAAO,CAAC,eAAe,CAAiC;IAExD,sFAAsF;IAEtF,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO,CAAC,sBAAsB,CAAK;IAEnC,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,MAAM,CAA+B;cAE7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BzC,OAAO,CAAC,YAAY,CAIlB;IAEF,OAAO,CAAC,WAAW,CAIjB;IAEF,OAAO,CAAC,eAAe,CAarB;IAEF,IAAI,IAAI,IAAI;IASZ,SAAS,CAAC,OAAO,IAAI,IAAI;IAMzB,UAAU,IAAI,MAAM,GAAG,IAAI;IAW3B,YAAY,IAAI,MAAM,GAAG,IAAI;IAK7B,UAAU,CAAC,KAAK,SAAI,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKrE,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,WAAW,IAAI,MAAM,GAAG,IAAI;IAI5B,SAAS,CAAC,aAAa,IAAI,cAAc,GAAG,OAAO,OAAO;IAqB1D,SAAS,CAAC,aAAa,IAAI,cAAc,GAAG,OAAO,OAAO;IAyB1D,MAAM,CAAC,MAAM,0BAyCX;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,gBAAgB,CAAC;KACxC;CACF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DocksWidget } from '@eclipse-docks/core';
|
|
2
|
+
import { PropertyValues } from 'lit';
|
|
3
|
+
export declare class DocksTextEditor extends DocksWidget {
|
|
4
|
+
value: string;
|
|
5
|
+
readOnly: boolean;
|
|
6
|
+
private lineCount;
|
|
7
|
+
/** Matches textarea.scrollHeight so gutter scroll range equals text scroll range. */
|
|
8
|
+
private gutterScrollHeight;
|
|
9
|
+
private textareaRef;
|
|
10
|
+
private innerTextarea;
|
|
11
|
+
private gutterEl;
|
|
12
|
+
private resizeObserver;
|
|
13
|
+
protected willUpdate(changed: PropertyValues<this>): void;
|
|
14
|
+
protected updated(): void;
|
|
15
|
+
disconnectedCallback(): void;
|
|
16
|
+
private cacheElements;
|
|
17
|
+
private attachScrollListeners;
|
|
18
|
+
private teardownScrollListeners;
|
|
19
|
+
private onTextScroll;
|
|
20
|
+
private onGutterScroll;
|
|
21
|
+
private syncScrollMetrics;
|
|
22
|
+
private emitChange;
|
|
23
|
+
private onInput;
|
|
24
|
+
getValue(): string;
|
|
25
|
+
getSelection(): string | null;
|
|
26
|
+
getSnippet(linesAround?: number): {
|
|
27
|
+
snippet: string;
|
|
28
|
+
cursorLine: number;
|
|
29
|
+
} | null;
|
|
30
|
+
protected render(): import('lit-html').TemplateResult<1>;
|
|
31
|
+
static styles: import('lit').CSSResult;
|
|
32
|
+
}
|
|
33
|
+
declare global {
|
|
34
|
+
interface HTMLElementTagNameMap {
|
|
35
|
+
'docks-texteditor': DocksTextEditor;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=texteditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"texteditor.d.ts","sourceRoot":"","sources":["../src/texteditor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAGrD,qBACa,eAAgB,SAAQ,WAAW;IAE9C,KAAK,SAAM;IAGX,QAAQ,UAAS;IAGjB,OAAO,CAAC,SAAS,CAAK;IAEtB,qFAAqF;IAErF,OAAO,CAAC,kBAAkB,CAAK;IAE/B,OAAO,CAAC,WAAW,CAAgD;IACnE,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,cAAc,CAA+B;IAErD,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI;IAOzD,SAAS,CAAC,OAAO,IAAI,IAAI;IAQzB,oBAAoB,IAAI,IAAI;IAK5B,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,YAAY,CAOlB;IAEF,OAAO,CAAC,cAAc,CAOpB;IAEF,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,OAAO,CAOb;IAEF,QAAQ,IAAI,MAAM;IAIlB,YAAY,IAAI,MAAM,GAAG,IAAI;IAS7B,UAAU,CAAC,WAAW,SAAI,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAsB3E,SAAS,CAAC,MAAM;IAyBhB,MAAM,CAAC,MAAM,0BAuEX;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,eAAe,CAAC;KACrC;CACF"}
|
|
@@ -0,0 +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"}
|
package/dist/widgets.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eclipse-docks/extension-plain-editor",
|
|
3
|
+
"version": "0.7.81",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./widgets": {
|
|
12
|
+
"types": "./dist/widgets.d.ts",
|
|
13
|
+
"import": "./dist/widgets.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@eclipse-docks/core": "*"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"typescript": "^6.0.0",
|
|
21
|
+
"vite": "^8.0.0",
|
|
22
|
+
"vite-plugin-dts": "^4.5.4"
|
|
23
|
+
},
|
|
24
|
+
"module": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "vite build"
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/eclipse-docks/core"
|
|
35
|
+
}
|
|
36
|
+
}
|