Updates to xterm
This commit is contained in:
Generated
+38
-52
@@ -10,11 +10,11 @@
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@novnc/novnc": "^1.5.0",
|
||||
"xterm": "5.3.0",
|
||||
"xterm-addon-fit": "0.8.0",
|
||||
"xterm-addon-search": "0.13.0",
|
||||
"xterm-addon-unicode11": "0.6.0",
|
||||
"xterm-addon-web-links": "0.9.0"
|
||||
"@xterm/addon-fit": "0.11.0",
|
||||
"@xterm/addon-search": "0.16.0",
|
||||
"@xterm/addon-unicode11": "0.9.0",
|
||||
"@xterm/addon-web-links": "0.12.0",
|
||||
"@xterm/xterm": "6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.28.1"
|
||||
@@ -468,6 +468,39 @@
|
||||
"integrity": "sha512-ucEJOx4T2avIRCleodk7YobZj5O2Ga2AeLfQ69A/yjG9HHba2+PDgwSkN3FttrmG+70ZGx21sElNFouK13RzyA==",
|
||||
"license": "MPL-2.0"
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.11.0.tgz",
|
||||
"integrity": "sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xterm/addon-search": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-search/-/addon-search-0.16.0.tgz",
|
||||
"integrity": "sha512-9OeuBFu0/uZJPu+9AHKY6g/w0Czyb/Ut0A5t79I4ULoU4IfU5BEpPFVGQxP4zTTMdfZEYkVIRYbHBX1xWwjeSA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xterm/addon-unicode11": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-unicode11/-/addon-unicode11-0.9.0.tgz",
|
||||
"integrity": "sha512-FxDnYcyuXhNl+XSqGZL/t0U9eiNb/q3EWT5rYkQT/zuig8Gz/VagnQANKHdDWFM2lTMk9ly0EFQxxxtZUoRetw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xterm/addon-web-links": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/addon-web-links/-/addon-web-links-0.12.0.tgz",
|
||||
"integrity": "sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@xterm/xterm": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-6.0.0.tgz",
|
||||
"integrity": "sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"addons/*"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
|
||||
@@ -509,53 +542,6 @@
|
||||
"@esbuild/win32-ia32": "0.28.1",
|
||||
"@esbuild/win32-x64": "0.28.1"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
|
||||
"integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/xterm instead.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/xterm-addon-fit": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
|
||||
"integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"xterm": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm-addon-search": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-search/-/xterm-addon-search-0.13.0.tgz",
|
||||
"integrity": "sha512-sDUwG4CnqxUjSEFh676DlS3gsh3XYCzAvBPSvJ5OPgF3MRL3iHLPfsb06doRicLC2xXNpeG2cWk8x1qpESWJMA==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/addon-search instead.",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"xterm": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm-addon-unicode11": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-unicode11/-/xterm-addon-unicode11-0.6.0.tgz",
|
||||
"integrity": "sha512-5pkb8YoS/deRtNqQRw8t640mu+Ga8B2MG3RXGQu0bwgcfr8XiXIRI880TWM49ICAHhTmnOLPzIIBIjEnCq7k2A==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/addon-unicode11 instead.",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"xterm": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm-addon-web-links": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.9.0.tgz",
|
||||
"integrity": "sha512-LIzi4jBbPlrKMZF3ihoyqayWyTXAwGfu4yprz1aK2p71e9UKXN6RRzVONR0L+Zd+Ik5tPVI9bwp9e8fDTQh49Q==",
|
||||
"deprecated": "This package is now deprecated. Move to @xterm/addon-web-links instead.",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"xterm": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@novnc/novnc": "^1.5.0",
|
||||
"xterm": "5.3.0",
|
||||
"xterm-addon-fit": "0.8.0",
|
||||
"xterm-addon-search": "0.13.0",
|
||||
"xterm-addon-unicode11": "0.6.0",
|
||||
"xterm-addon-web-links": "0.9.0"
|
||||
"@xterm/addon-fit": "0.11.0",
|
||||
"@xterm/addon-search": "0.16.0",
|
||||
"@xterm/addon-unicode11": "0.9.0",
|
||||
"@xterm/addon-web-links": "0.12.0",
|
||||
"@xterm/xterm": "6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.28.1"
|
||||
|
||||
@@ -1 +1 @@
|
||||
0726a81c633cf310d2b07f5c7e100225
|
||||
2f3e27ceb2ed8494c242e0b06d9f4da3
|
||||
@@ -14,27 +14,27 @@ const frontendDir = path.resolve(__dirname, "..");
|
||||
// Mapping: source (relative to node_modules) → destination (relative to frontend/)
|
||||
const assets = [
|
||||
{
|
||||
src: "xterm/css/xterm.css",
|
||||
src: "@xterm/xterm/css/xterm.css",
|
||||
dest: "src/css/lib/xterm.css",
|
||||
},
|
||||
{
|
||||
src: "xterm/lib/xterm.js",
|
||||
src: "@xterm/xterm/lib/xterm.js",
|
||||
dest: "src/js/lib/xterm.min.js",
|
||||
},
|
||||
{
|
||||
src: "xterm-addon-fit/lib/xterm-addon-fit.js",
|
||||
src: "@xterm/addon-fit/lib/addon-fit.js",
|
||||
dest: "src/js/lib/xterm-addon-fit.min.js",
|
||||
},
|
||||
{
|
||||
src: "xterm-addon-search/lib/xterm-addon-search.js",
|
||||
src: "@xterm/addon-search/lib/addon-search.js",
|
||||
dest: "src/js/lib/xterm-addon-search.min.js",
|
||||
},
|
||||
{
|
||||
src: "xterm-addon-unicode11/lib/xterm-addon-unicode11.js",
|
||||
src: "@xterm/addon-unicode11/lib/addon-unicode11.js",
|
||||
dest: "src/js/lib/xterm-addon-unicode11.min.js",
|
||||
},
|
||||
{
|
||||
src: "xterm-addon-web-links/lib/xterm-addon-web-links.js",
|
||||
src: "@xterm/addon-web-links/lib/addon-web-links.js",
|
||||
dest: "src/js/lib/xterm-addon-web-links.min.js",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -129,6 +129,21 @@ assertContains(
|
||||
"margin-left: auto;",
|
||||
"Leviathan mode label must sit on the right side of the sidebar header",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/css/tokens.css",
|
||||
"--tab-bar-height: 44px;",
|
||||
"tab bar row must match the sidebar header height",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/css/sidebar.css",
|
||||
"height: var(--tab-bar-height);",
|
||||
"sidebar header must use the shared tab bar height",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/css/layout.css",
|
||||
"height: var(--tab-bar-height);",
|
||||
"tab bar must use the shared sidebar header height",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/leviathan.js",
|
||||
"Hex Editor",
|
||||
@@ -139,6 +154,21 @@ assertContains(
|
||||
"LeviathanSetByte",
|
||||
"Leviathan hex view must support byte editing",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/leviathan.js",
|
||||
"_handleHexByteInput",
|
||||
"Leviathan hex byte edits must update while typing",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/leviathan.js",
|
||||
"_updateHexAsciiCell",
|
||||
"Leviathan hex byte edits must update the ASCII preview immediately",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/leviathan.js",
|
||||
"_focusHexByte(cell, 1)",
|
||||
"Leviathan hex byte edits must advance to the next byte after entry",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/src/js/leviathan.js",
|
||||
"spectrogram-encode",
|
||||
@@ -214,6 +244,46 @@ assertContains(
|
||||
"window.go?.api?.Service",
|
||||
"Wails service bridge must use the normal named Wails API",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/package.json",
|
||||
'"@xterm/xterm":',
|
||||
"frontend dependencies must use the maintained scoped xterm package",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/package.json",
|
||||
'"@xterm/addon-fit":',
|
||||
"frontend dependencies must use the maintained scoped xterm addons",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/scripts/copy-assets.js",
|
||||
"@xterm/xterm/lib/xterm.js",
|
||||
"xterm browser assets must be copied from the maintained scoped package",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/scripts/copy-assets.js",
|
||||
"@xterm/addon-fit/lib/addon-fit.js",
|
||||
"xterm addon browser assets must be copied from the maintained scoped packages",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/package.json",
|
||||
'"xterm":',
|
||||
"deprecated unscoped xterm dependency must not be restored",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/package.json",
|
||||
'"xterm-addon-',
|
||||
"deprecated unscoped xterm addon dependencies must not be restored",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/package-lock.json",
|
||||
'"node_modules/xterm"',
|
||||
"package lock must not contain the deprecated unscoped xterm package",
|
||||
);
|
||||
assertNotContains(
|
||||
"frontend/package-lock.json",
|
||||
'"node_modules/xterm-addon-',
|
||||
"package lock must not contain deprecated unscoped xterm addon packages",
|
||||
);
|
||||
assertContains(
|
||||
"frontend/scripts/build.js",
|
||||
"sourceMappingURL",
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: var(--tab-bar-height);
|
||||
min-height: var(--tab-bar-height);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -686,6 +686,14 @@
|
||||
background: var(--bg-input);
|
||||
}
|
||||
|
||||
.leviathan-byte.is-editing {
|
||||
border-color: var(--warning);
|
||||
}
|
||||
|
||||
.leviathan-byte.is-saving {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.leviathan-byte.is-search-hit {
|
||||
border-color: var(--warning);
|
||||
color: var(--text-inverse);
|
||||
|
||||
@@ -112,10 +112,6 @@
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
@@ -140,7 +136,7 @@
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-accessibility:not(.debug),
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@@ -152,6 +148,21 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree:not(.debug) *::selection {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree {
|
||||
font-family: monospace;
|
||||
user-select: text;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility-tree > div {
|
||||
transform-origin: left;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
@@ -207,3 +218,68 @@
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Derived from vs/base/browser/ui/scrollbar/media/scrollbar.css */
|
||||
|
||||
/* xterm.js customization: Override xterm's cursor style */
|
||||
.xterm .xterm-scrollable-element > .scrollbar {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Arrows */
|
||||
.xterm .xterm-scrollable-element > .scrollbar > .scra {
|
||||
cursor: pointer;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
.xterm .xterm-scrollable-element > .visible {
|
||||
opacity: 1;
|
||||
|
||||
/* Background rule added for IE9 - to allow clicks on dom node */
|
||||
background:rgba(0,0,0,0);
|
||||
|
||||
transition: opacity 100ms linear;
|
||||
/* In front of peek view */
|
||||
z-index: 11;
|
||||
}
|
||||
.xterm .xterm-scrollable-element > .invisible {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.xterm .xterm-scrollable-element > .invisible.fade {
|
||||
transition: opacity 800ms linear;
|
||||
}
|
||||
|
||||
/* Scrollable Content Inset Shadow */
|
||||
.xterm .xterm-scrollable-element > .shadow {
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
.xterm .xterm-scrollable-element > .shadow.top {
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 3px;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
box-shadow: var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset;
|
||||
}
|
||||
.xterm .xterm-scrollable-element > .shadow.left {
|
||||
display: block;
|
||||
top: 3px;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 3px;
|
||||
box-shadow: var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset;
|
||||
}
|
||||
.xterm .xterm-scrollable-element > .shadow.top-left-corner {
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
width: 3px;
|
||||
}
|
||||
.xterm .xterm-scrollable-element > .shadow.top.left {
|
||||
box-shadow: var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--space-3) var(--space-4);
|
||||
height: var(--tab-bar-height);
|
||||
min-height: var(--tab-bar-height);
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
flex-shrink: 0;
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
----------------------------------------------------------------------- */
|
||||
--sidebar-width: 260px;
|
||||
--sidebar-width-collapsed: 48px;
|
||||
--tab-bar-height: 36px;
|
||||
--tab-bar-height: 44px;
|
||||
--toolbar-height: 40px;
|
||||
--status-bar-height: 24px;
|
||||
}
|
||||
|
||||
+183
-12
@@ -572,34 +572,205 @@
|
||||
line.appendChild(createElement("span", "leviathan-offset", { textContent: this._hexOffset(row.offset) }));
|
||||
const bytes = createElement("span", "leviathan-byte-cells");
|
||||
const cells = row.bytes || String(row.hex || "").split(/\s+/).filter(Boolean);
|
||||
const ascii = createElement("span", "leviathan-ascii", { textContent: row.ascii || "" });
|
||||
cells.forEach((value, idx) => {
|
||||
const cellOffset = (row.offset || 0) + idx;
|
||||
const hexValue = this._normaliseHexByte(value) || "00";
|
||||
const cell = createElement("input", "leviathan-byte", {
|
||||
value,
|
||||
value: hexValue,
|
||||
maxlength: "2",
|
||||
inputmode: "text",
|
||||
autocomplete: "off",
|
||||
spellcheck: "false",
|
||||
"aria-label": `Byte ${this._hexOffset(cellOffset)}`,
|
||||
dataset: {
|
||||
offset: String(cellOffset),
|
||||
committedHex: hexValue,
|
||||
},
|
||||
});
|
||||
if (activeHit && cellOffset >= activeHit.offset && cellOffset < activeHit.offset + activeHit.length) {
|
||||
cell.classList.add("is-search-hit");
|
||||
}
|
||||
cell.addEventListener("change", async () => {
|
||||
try {
|
||||
await window.NexusTerminal.wailsService.LeviathanSetByte(cellOffset, cell.value);
|
||||
cell.value = cell.value.trim().padStart(2, "0").slice(-2).toLowerCase();
|
||||
status.textContent = "Edited " + this._hexOffset(cellOffset);
|
||||
} catch (err) {
|
||||
status.textContent = String(err);
|
||||
cell.value = value;
|
||||
}
|
||||
});
|
||||
this._wireHexByteCell(cell, bytes, ascii, idx, status);
|
||||
bytes.appendChild(cell);
|
||||
});
|
||||
line.appendChild(bytes);
|
||||
line.appendChild(createElement("span", "leviathan-ascii", { textContent: row.ascii || "" }));
|
||||
line.appendChild(ascii);
|
||||
grid.appendChild(line);
|
||||
}
|
||||
}
|
||||
|
||||
_wireHexByteCell(cell, rowCells, ascii, asciiIndex, status) {
|
||||
cell.addEventListener("focus", () => {
|
||||
cell.select();
|
||||
});
|
||||
cell.addEventListener("keydown", (event) => {
|
||||
if (event.key === "ArrowRight") {
|
||||
event.preventDefault();
|
||||
this._focusHexByte(cell, 1);
|
||||
} else if (event.key === "ArrowLeft") {
|
||||
event.preventDefault();
|
||||
this._focusHexByte(cell, -1);
|
||||
} else if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
this._finaliseHexByte(cell, rowCells, ascii, asciiIndex, status, { advance: 1 });
|
||||
} else if (event.key === "Backspace" && cell.value.length === 0) {
|
||||
event.preventDefault();
|
||||
this._focusHexByte(cell, -1);
|
||||
}
|
||||
});
|
||||
cell.addEventListener("input", () => {
|
||||
this._handleHexByteInput(cell, rowCells, ascii, asciiIndex, status);
|
||||
});
|
||||
cell.addEventListener("paste", (event) => {
|
||||
this._pasteHexBytes(event, cell, rowCells, ascii, asciiIndex, status);
|
||||
});
|
||||
cell.addEventListener("blur", () => {
|
||||
this._finaliseHexByte(cell, rowCells, ascii, asciiIndex, status, { advance: 0 });
|
||||
});
|
||||
}
|
||||
|
||||
_handleHexByteInput(cell, rowCells, ascii, asciiIndex, status) {
|
||||
const clean = this._normaliseHexByte(cell.value);
|
||||
if (cell.value !== clean) cell.value = clean;
|
||||
cell.classList.toggle("is-editing", clean.length === 1);
|
||||
if (clean.length === 0) {
|
||||
this._updateHexAsciiCell(ascii, asciiIndex, cell.dataset.committedHex || "00");
|
||||
rowCells.classList.toggle("is-editing", Boolean(rowCells.querySelector(".leviathan-byte.is-editing")));
|
||||
return;
|
||||
}
|
||||
if (clean.length === 2) {
|
||||
this._updateHexAsciiCell(ascii, asciiIndex, clean);
|
||||
this._commitHexByte(cell, ascii, asciiIndex, status);
|
||||
this._focusHexByte(cell, 1);
|
||||
}
|
||||
rowCells.classList.toggle("is-editing", Boolean(rowCells.querySelector(".leviathan-byte.is-editing")));
|
||||
}
|
||||
|
||||
_finaliseHexByte(cell, rowCells, ascii, asciiIndex, status, options = {}) {
|
||||
let clean = this._normaliseHexByte(cell.value);
|
||||
if (clean.length === 0) {
|
||||
clean = cell.dataset.committedHex || "00";
|
||||
} else if (clean.length === 1) {
|
||||
clean = clean.padStart(2, "0");
|
||||
}
|
||||
cell.value = clean;
|
||||
cell.classList.remove("is-editing");
|
||||
rowCells.classList.toggle("is-editing", Boolean(rowCells.querySelector(".leviathan-byte.is-editing")));
|
||||
this._updateHexAsciiCell(ascii, asciiIndex, clean);
|
||||
this._commitHexByte(cell, ascii, asciiIndex, status);
|
||||
if (options.advance) this._focusHexByte(cell, options.advance);
|
||||
}
|
||||
|
||||
_pasteHexBytes(event, cell, rowCells, ascii, asciiIndex, status) {
|
||||
const text = event.clipboardData?.getData("text/plain") || "";
|
||||
const pasted = this._hexByteList(text);
|
||||
if (!pasted.length) return;
|
||||
event.preventDefault();
|
||||
const scope = cell.closest(".leviathan-hex-grid") || rowCells;
|
||||
const cells = Array.from(scope.querySelectorAll(".leviathan-byte"));
|
||||
const startIndex = cells.indexOf(cell);
|
||||
if (startIndex < 0) return;
|
||||
pasted.forEach((hex, idx) => {
|
||||
const target = cells[startIndex + idx];
|
||||
if (!target) return;
|
||||
const context = this._hexCellContext(target);
|
||||
if (!context) return;
|
||||
target.value = hex;
|
||||
target.classList.remove("is-editing");
|
||||
this._updateHexAsciiCell(context.ascii, context.index, hex);
|
||||
this._commitHexByte(target, context.ascii, context.index, status);
|
||||
});
|
||||
const next = cells[Math.min(startIndex + pasted.length, cells.length - 1)];
|
||||
if (next) {
|
||||
next.focus();
|
||||
next.select();
|
||||
}
|
||||
}
|
||||
|
||||
_commitHexByte(cell, ascii, asciiIndex, status) {
|
||||
const hex = this._normaliseHexByte(cell.value);
|
||||
if (hex.length !== 2) return;
|
||||
if (hex === cell.dataset.committedHex || hex === cell.dataset.pendingHex) return;
|
||||
const previous = cell.dataset.committedHex || "00";
|
||||
const offset = Number(cell.dataset.offset || 0);
|
||||
cell.dataset.pendingHex = hex;
|
||||
cell.classList.add("is-saving");
|
||||
window.NexusTerminal.wailsService
|
||||
.LeviathanSetByte(offset, hex)
|
||||
.then((payload) => {
|
||||
if (cell.dataset.pendingHex === hex) {
|
||||
delete cell.dataset.pendingHex;
|
||||
cell.dataset.committedHex = hex;
|
||||
cell.classList.remove("is-saving");
|
||||
status.textContent = "Edited " + this._hexOffset(offset);
|
||||
this.applyState(payload);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (cell.dataset.pendingHex === hex) {
|
||||
delete cell.dataset.pendingHex;
|
||||
cell.classList.remove("is-saving");
|
||||
cell.value = previous;
|
||||
this._updateHexAsciiCell(ascii, asciiIndex, previous);
|
||||
status.textContent = String(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_focusHexByte(cell, direction) {
|
||||
const scope = cell.closest(".leviathan-hex-grid") || cell.closest(".leviathan-byte-cells");
|
||||
if (!scope) return;
|
||||
const cells = Array.from(scope.querySelectorAll(".leviathan-byte"));
|
||||
const index = cells.indexOf(cell);
|
||||
const next = cells[index + direction];
|
||||
if (!next) return;
|
||||
next.focus();
|
||||
next.select();
|
||||
}
|
||||
|
||||
_hexCellContext(cell) {
|
||||
const row = cell.closest(".leviathan-hex-row");
|
||||
if (!row) return null;
|
||||
const ascii = row.querySelector(".leviathan-ascii");
|
||||
const rowCells = Array.from(row.querySelectorAll(".leviathan-byte"));
|
||||
const index = rowCells.indexOf(cell);
|
||||
if (!ascii || index < 0) return null;
|
||||
return { ascii, index };
|
||||
}
|
||||
|
||||
_updateHexAsciiCell(ascii, index, hex) {
|
||||
const chars = Array.from(ascii.textContent || "");
|
||||
while (chars.length <= index) chars.push(" ");
|
||||
chars[index] = this._hexByteToAscii(hex);
|
||||
ascii.textContent = chars.join("");
|
||||
}
|
||||
|
||||
_hexByteToAscii(hex) {
|
||||
const value = Number.parseInt(hex, 16);
|
||||
if (!Number.isFinite(value)) return ".";
|
||||
return value >= 32 && value < 127 ? String.fromCharCode(value) : ".";
|
||||
}
|
||||
|
||||
_normaliseHexByte(value) {
|
||||
return String(value || "")
|
||||
.replace(/[^0-9a-f]/gi, "")
|
||||
.slice(0, 2)
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
_hexByteList(value) {
|
||||
const clean = String(value || "")
|
||||
.replace(/0x/gi, "")
|
||||
.replace(/[^0-9a-f]/gi, "")
|
||||
.toLowerCase();
|
||||
const bytes = [];
|
||||
for (let i = 0; i + 1 < clean.length; i += 2) {
|
||||
bytes.push(clean.slice(i, i + 2));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
_renderParams(toolId, container) {
|
||||
container.innerHTML = "";
|
||||
const cfg = defaults[toolId] || {};
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core,t=e._renderService.dimensions;if(0===t.css.cell.width||0===t.css.cell.height)return;const r=0===this._terminal.options.scrollback?0:e.viewport.scrollBarWidth,i=window.getComputedStyle(this._terminal.element.parentElement),o=parseInt(i.getPropertyValue("height")),s=Math.max(0,parseInt(i.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),l=o-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=s-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-r;return{cols:Math.max(2,Math.floor(a/t.css.cell.width)),rows:Math.max(1,Math.floor(l/t.css.cell.height))}}}})(),e})()));
|
||||
//# sourceMappingURL=xterm-addon-fit.js.map
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(globalThis,(()=>(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0,t.FitAddon=class{activate(e){this._terminal=e}dispose(){}fit(){const e=this.proposeDimensions();if(!e||!this._terminal||isNaN(e.cols)||isNaN(e.rows))return;const t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}proposeDimensions(){if(!this._terminal)return;if(!this._terminal.element||!this._terminal.element.parentElement)return;const e=this._terminal._core._renderService.dimensions;if(0===e.css.cell.width||0===e.css.cell.height)return;const t=0===this._terminal.options.scrollback?0:this._terminal.options.overviewRuler?.width||14,r=window.getComputedStyle(this._terminal.element.parentElement),i=parseInt(r.getPropertyValue("height")),o=Math.max(0,parseInt(r.getPropertyValue("width"))),s=window.getComputedStyle(this._terminal.element),n=i-(parseInt(s.getPropertyValue("padding-top"))+parseInt(s.getPropertyValue("padding-bottom"))),l=o-(parseInt(s.getPropertyValue("padding-right"))+parseInt(s.getPropertyValue("padding-left")))-t;return{cols:Math.max(2,Math.floor(l/e.css.cell.width)),rows:Math.max(1,Math.floor(n/e.css.cell.height))}}}})(),e})()));
|
||||
//# sourceMappingURL=addon-fit.js.map
|
||||
+2
-2
File diff suppressed because one or more lines are too long
+2
-2
@@ -1,2 +1,2 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WebLinksAddon=t():e.WebLinksAddon=t()}(self,(()=>(()=>{"use strict";var e={6:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LinkComputer=t.WebLinkProvider=void 0,t.WebLinkProvider=class{constructor(e,t,n,i={}){this._terminal=e,this._regex=t,this._handler=n,this._options=i}provideLinks(e,t){const i=n.computeLink(e,this._regex,this._terminal,this._handler);t(this._addCallbacks(i))}_addCallbacks(e){return e.map((e=>(e.leave=this._options.leave,e.hover=(t,n)=>{if(this._options.hover){const{range:i}=e;this._options.hover(t,n,i)}},e)))}};class n{static computeLink(e,t,i,r){const o=new RegExp(t.source,(t.flags||"")+"g"),[s,a]=n._getWindowedLineStrings(e-1,i),c=s.join("");let d;const l=[];for(;d=o.exec(c);){const e=d[0];try{const t=new URL(e),n=decodeURI(t.toString());if(e!==n&&e+"/"!==n)continue}catch(e){continue}const[t,o]=n._mapStrIdx(i,a,0,d.index),[s,c]=n._mapStrIdx(i,t,o,e.length);if(-1===t||-1===o||-1===s||-1===c)continue;const p={start:{x:o+1,y:t+1},end:{x:c,y:s+1}};l.push({range:p,text:e,activate:r})}return l}static _getWindowedLineStrings(e,t){let n,i=e,r=e,o=0,s="";const a=[];if(n=t.buffer.active.getLine(e)){const e=n.translateToString(!0);if(n.isWrapped&&" "!==e[0]){for(o=0;(n=t.buffer.active.getLine(--i))&&o<2048&&(s=n.translateToString(!0),o+=s.length,a.push(s),n.isWrapped&&-1===s.indexOf(" ")););a.reverse()}for(a.push(e),o=0;(n=t.buffer.active.getLine(++r))&&n.isWrapped&&o<2048&&(s=n.translateToString(!0),o+=s.length,a.push(s),-1===s.indexOf(" ")););}return[a,i]}static _mapStrIdx(e,t,n,i){const r=e.buffer.active,o=r.getNullCell();let s=n;for(;i;){const e=r.getLine(t);if(!e)return[-1,-1];for(let n=s;n<e.length;++n){e.getCell(n,o);const s=o.getChars();if(o.getWidth()&&(i-=s.length||1,n===e.length-1&&""===s)){const e=r.getLine(t+1);e&&e.isWrapped&&(e.getCell(0,o),2===o.getWidth()&&(i+=1))}if(i<0)return[t,n]}t++,s=0}return[t,s]}}t.LinkComputer=n}},t={};function n(i){var r=t[i];if(void 0!==r)return r.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,n),o.exports}var i={};return(()=>{var e=i;Object.defineProperty(e,"__esModule",{value:!0}),e.WebLinksAddon=void 0;const t=n(6),r=/https?:[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function o(e,t){const n=window.open();if(n){try{n.opener=null}catch(e){}n.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}e.WebLinksAddon=class{constructor(e=o,t={}){this._handler=e,this._options=t}activate(e){this._terminal=e;const n=this._options,i=n.urlRegex||r;this._linkProvider=this._terminal.registerLinkProvider(new t.WebLinkProvider(this._terminal,i,this._handler,n))}dispose(){var e;null===(e=this._linkProvider)||void 0===e||e.dispose()}}})(),i})()));
|
||||
//# sourceMappingURL=xterm-addon-web-links.js.map
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.WebLinksAddon=t():e.WebLinksAddon=t()}(globalThis,(()=>(()=>{"use strict";var e={490:(e,t)=>{function n(e){try{const t=new URL(e),n=t.password&&t.username?`${t.protocol}//${t.username}:${t.password}@${t.host}`:t.username?`${t.protocol}//${t.username}@${t.host}`:`${t.protocol}//${t.host}`;return e.toLocaleLowerCase().startsWith(n.toLocaleLowerCase())}catch(e){return!1}}Object.defineProperty(t,"__esModule",{value:!0}),t.LinkComputer=t.WebLinkProvider=void 0,t.WebLinkProvider=class{constructor(e,t,n,o={}){this._terminal=e,this._regex=t,this._handler=n,this._options=o}provideLinks(e,t){const n=o.computeLink(e,this._regex,this._terminal,this._handler);t(this._addCallbacks(n))}_addCallbacks(e){return e.map((e=>(e.leave=this._options.leave,e.hover=(t,n)=>{if(this._options.hover){const{range:o}=e;this._options.hover(t,n,o)}},e)))}};class o{static computeLink(e,t,r,i){const s=new RegExp(t.source,(t.flags||"")+"g"),[a,c]=o._getWindowedLineStrings(e-1,r),l=a.join("");let d;const p=[];for(;d=s.exec(l);){const e=d[0];if(!n(e))continue;const[t,s]=o._mapStrIdx(r,c,0,d.index),[a,l]=o._mapStrIdx(r,t,s,e.length);if(-1===t||-1===s||-1===a||-1===l)continue;const h={start:{x:s+1,y:t+1},end:{x:l,y:a+1}};p.push({range:h,text:e,activate:i})}return p}static _getWindowedLineStrings(e,t){let n,o=e,r=e,i=0,s="";const a=[];if(n=t.buffer.active.getLine(e)){const e=n.translateToString(!0);if(n.isWrapped&&" "!==e[0]){for(i=0;(n=t.buffer.active.getLine(--o))&&i<2048&&(s=n.translateToString(!0),i+=s.length,a.push(s),n.isWrapped&&-1===s.indexOf(" ")););a.reverse()}for(a.push(e),i=0;(n=t.buffer.active.getLine(++r))&&n.isWrapped&&i<2048&&(s=n.translateToString(!0),i+=s.length,a.push(s),-1===s.indexOf(" ")););}return[a,o]}static _mapStrIdx(e,t,n,o){const r=e.buffer.active,i=r.getNullCell();let s=n;for(;o;){const e=r.getLine(t);if(!e)return[-1,-1];for(let n=s;n<e.length;++n){e.getCell(n,i);const s=i.getChars();if(i.getWidth()&&(o-=s.length||1,n===e.length-1&&""===s)){const e=r.getLine(t+1);e&&e.isWrapped&&(e.getCell(0,i),2===i.getWidth()&&(o+=1))}if(o<0)return[t,n]}t++,s=0}return[t,s]}}t.LinkComputer=o}},t={};function n(o){var r=t[o];if(void 0!==r)return r.exports;var i=t[o]={exports:{}};return e[o](i,i.exports,n),i.exports}var o={};return(()=>{var e=o;Object.defineProperty(e,"__esModule",{value:!0}),e.WebLinksAddon=void 0;const t=n(490),r=/(https?|HTTPS?):[/]{2}[^\s"'!*(){}|\\\^<>`]*[^\s"':,.!?{}|\\\^~\[\]`()<>]/;function i(e,t){const n=window.open();if(n){try{n.opener=null}catch{}n.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}e.WebLinksAddon=class{constructor(e=i,t={}){this._handler=e,this._options=t}activate(e){this._terminal=e;const n=this._options,o=n.urlRegex||r;this._linkProvider=this._terminal.registerLinkProvider(new t.WebLinkProvider(this._terminal,o,this._handler,n))}dispose(){this._linkProvider?.dispose()}}})(),o})()));
|
||||
//# sourceMappingURL=addon-web-links.js.map
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user