dsh-vscode-workbench 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +199 -71
- package/lib/client.js.map +1 -1
- package/lib/index.js +16 -7
- package/lib/index.js.map +1 -1
- package/lib/types/client/Workbench.d.ts +7 -0
- package/lib/types/client/api.d.ts +4 -0
- package/lib/types/types.d.ts +2 -2
- package/package.json +1 -1
- package/src/client/Workbench.tsx +30 -16
- package/src/client/api.ts +6 -2
- package/src/client/styles.ts +1 -1
- package/src/host.ts +6 -3
- package/src/index.ts +5 -2
- package/src/types.ts +1 -1
package/lib/client.js
CHANGED
|
@@ -115,6 +115,13 @@ window.__ModuleLoader__.load({
|
|
|
115
115
|
};
|
|
116
116
|
//#endregion
|
|
117
117
|
//#region src/client/api.ts
|
|
118
|
+
var ApiError = class extends Error {
|
|
119
|
+
code;
|
|
120
|
+
constructor(code, message) {
|
|
121
|
+
super(message);
|
|
122
|
+
this.code = code;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
118
125
|
async function api(method, body, signal) {
|
|
119
126
|
const response = await fetch(`/dsh-vscode/api/${method}`, {
|
|
120
127
|
method: "POST",
|
|
@@ -123,7 +130,7 @@ window.__ModuleLoader__.load({
|
|
|
123
130
|
signal
|
|
124
131
|
});
|
|
125
132
|
const answer = await response.json();
|
|
126
|
-
if (!response.ok || !answer.ok) throw new
|
|
133
|
+
if (!response.ok || !answer.ok) throw new ApiError(answer.error?.code ?? "request-failed", answer.error?.message ?? `request failed (${response.status})`);
|
|
127
134
|
return answer.value;
|
|
128
135
|
}
|
|
129
136
|
//#endregion
|
|
@@ -4468,6 +4475,32 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4468
4475
|
};
|
|
4469
4476
|
//#endregion
|
|
4470
4477
|
//#region src/client/Workbench.tsx
|
|
4478
|
+
function unloadedTab(path) {
|
|
4479
|
+
return {
|
|
4480
|
+
path,
|
|
4481
|
+
content: "",
|
|
4482
|
+
draft: "",
|
|
4483
|
+
revision: "",
|
|
4484
|
+
size: 0,
|
|
4485
|
+
binary: false,
|
|
4486
|
+
tooLarge: false,
|
|
4487
|
+
dirty: false,
|
|
4488
|
+
loaded: false,
|
|
4489
|
+
preview: /\.md$/i.test(path)
|
|
4490
|
+
};
|
|
4491
|
+
}
|
|
4492
|
+
/** Restore tab headers without reading their file contents. */
|
|
4493
|
+
function restoreTabPaths(paths) {
|
|
4494
|
+
return [...new Set(paths)].map(unloadedTab);
|
|
4495
|
+
}
|
|
4496
|
+
/** Return whether file changes require reloading one visible directory. */
|
|
4497
|
+
function directoryAffected(directory, changedPaths) {
|
|
4498
|
+
return changedPaths.some((changed) => {
|
|
4499
|
+
const normalized = changed.replace(/\\/g, "/");
|
|
4500
|
+
const parent = normalized.includes("/") ? normalized.slice(0, normalized.lastIndexOf("/")) : "";
|
|
4501
|
+
return normalized === directory || parent === directory;
|
|
4502
|
+
});
|
|
4503
|
+
}
|
|
4471
4504
|
/** Return the basename shown in a tab while preserving its full internal path. */
|
|
4472
4505
|
function tabLabel(tab) {
|
|
4473
4506
|
const path = tab.title ?? tab.diffSourcePath ?? tab.path.replace(/^diff:/, "");
|
|
@@ -4497,7 +4530,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4497
4530
|
}, []);
|
|
4498
4531
|
return dark;
|
|
4499
4532
|
}
|
|
4500
|
-
function Tree({ sessionId, path, depth, expanded, selected, selectedDirectory, statuses, onToggle, onSelectDirectory, onOpen, onChange, onUpload }) {
|
|
4533
|
+
function Tree({ sessionId, path, depth, expanded, selected, selectedDirectory, statuses, onToggle, onSelectDirectory, onOpen, onChange, onUpload, creating, onCreatingChange, onCreatingCancel, onCreatingSubmit }) {
|
|
4501
4534
|
const [rows, setRows] = (0, react.useState)([]);
|
|
4502
4535
|
const [error, setError] = (0, react.useState)();
|
|
4503
4536
|
const [dropTarget, setDropTarget] = (0, react.useState)(false);
|
|
@@ -4512,7 +4545,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4512
4545
|
}, [sessionId, path]);
|
|
4513
4546
|
(0, react.useEffect)(load, [load]);
|
|
4514
4547
|
(0, react.useEffect)(() => {
|
|
4515
|
-
const handler = () =>
|
|
4548
|
+
const handler = (event) => {
|
|
4549
|
+
const paths = event.detail;
|
|
4550
|
+
if (paths === void 0 || directoryAffected(path, paths)) load();
|
|
4551
|
+
};
|
|
4516
4552
|
window.addEventListener("dvw-files-changed", handler);
|
|
4517
4553
|
return () => window.removeEventListener("dvw-files-changed", handler);
|
|
4518
4554
|
}, [load]);
|
|
@@ -4579,6 +4615,41 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4579
4615
|
className: "dvw-error",
|
|
4580
4616
|
children: error
|
|
4581
4617
|
}),
|
|
4618
|
+
creating?.directory === path && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4619
|
+
className: "dvw-tree-row dvw-tree-create-row",
|
|
4620
|
+
style: { paddingLeft: 6 + depth * 13 },
|
|
4621
|
+
children: [
|
|
4622
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dvw-chevron" }),
|
|
4623
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
4624
|
+
name: creating.kind === "directory" ? "folder" : "new-file",
|
|
4625
|
+
className: `dvw-file-icon ${creating.kind === "directory" ? "folder" : ""}`
|
|
4626
|
+
}),
|
|
4627
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4628
|
+
className: "dvw-tree-create-input",
|
|
4629
|
+
value: creating.value,
|
|
4630
|
+
autoFocus: true,
|
|
4631
|
+
"aria-label": creating.kind === "directory" ? "新建文件夹名称" : "新建文件名称",
|
|
4632
|
+
"aria-invalid": creating.error !== void 0,
|
|
4633
|
+
placeholder: creating.kind === "directory" ? "文件夹名称" : "文件名称",
|
|
4634
|
+
onChange: (event) => onCreatingChange(event.target.value),
|
|
4635
|
+
onKeyDown: (event) => {
|
|
4636
|
+
if (event.key === "Enter") {
|
|
4637
|
+
event.preventDefault();
|
|
4638
|
+
onCreatingSubmit();
|
|
4639
|
+
}
|
|
4640
|
+
if (event.key === "Escape") {
|
|
4641
|
+
event.preventDefault();
|
|
4642
|
+
onCreatingCancel();
|
|
4643
|
+
}
|
|
4644
|
+
},
|
|
4645
|
+
onBlur: onCreatingCancel
|
|
4646
|
+
})
|
|
4647
|
+
]
|
|
4648
|
+
}), creating.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4649
|
+
className: "dvw-tree-create-error",
|
|
4650
|
+
style: { paddingLeft: 42 + depth * 13 },
|
|
4651
|
+
children: creating.error
|
|
4652
|
+
})] }),
|
|
4582
4653
|
rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4583
4654
|
className: "dvw-tree-row",
|
|
4584
4655
|
"data-dvw-upload-directory": row.kind === "directory" ? row.path : void 0,
|
|
@@ -4656,7 +4727,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4656
4727
|
onSelectDirectory,
|
|
4657
4728
|
onOpen,
|
|
4658
4729
|
onChange,
|
|
4659
|
-
onUpload
|
|
4730
|
+
onUpload,
|
|
4731
|
+
creating,
|
|
4732
|
+
onCreatingChange,
|
|
4733
|
+
onCreatingCancel,
|
|
4734
|
+
onCreatingSubmit
|
|
4660
4735
|
})] }, row.path)),
|
|
4661
4736
|
context && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4662
4737
|
className: "dvw-context-menu",
|
|
@@ -4732,6 +4807,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4732
4807
|
const [statuses, setStatuses] = (0, react.useState)(/* @__PURE__ */ new Map());
|
|
4733
4808
|
const [dropTarget, setDropTarget] = (0, react.useState)(false);
|
|
4734
4809
|
const [selectedDirectory, setSelectedDirectory] = (0, react.useState)("");
|
|
4810
|
+
const [creating, setCreating] = (0, react.useState)();
|
|
4735
4811
|
const picker = (0, react.useRef)(null);
|
|
4736
4812
|
(0, react.useEffect)(() => {
|
|
4737
4813
|
if (props.cwd) try {
|
|
@@ -4753,19 +4829,42 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4753
4829
|
window.addEventListener("dvw-files-changed", handler);
|
|
4754
4830
|
return () => window.removeEventListener("dvw-files-changed", handler);
|
|
4755
4831
|
}, [refreshStatus, refreshStatusDebounced]);
|
|
4756
|
-
const
|
|
4757
|
-
const
|
|
4758
|
-
if (
|
|
4832
|
+
const startCreating = (kind) => {
|
|
4833
|
+
const directory = selectedDirectory;
|
|
4834
|
+
if (directory) setExpanded((current) => new Set(current).add(directory));
|
|
4835
|
+
setCreating({
|
|
4836
|
+
kind,
|
|
4837
|
+
directory,
|
|
4838
|
+
value: ""
|
|
4839
|
+
});
|
|
4840
|
+
};
|
|
4841
|
+
const submitCreating = async () => {
|
|
4842
|
+
if (creating === void 0) return;
|
|
4843
|
+
const value = creating.value.trim();
|
|
4844
|
+
if (value === "") {
|
|
4845
|
+
setCreating((current) => current && {
|
|
4846
|
+
...current,
|
|
4847
|
+
error: "请输入名称"
|
|
4848
|
+
});
|
|
4849
|
+
return;
|
|
4850
|
+
}
|
|
4851
|
+
const path = createdEntryPath(creating.directory, value);
|
|
4759
4852
|
try {
|
|
4760
4853
|
await api("fs.create", {
|
|
4761
4854
|
sessionId: props.sessionId,
|
|
4762
4855
|
path,
|
|
4763
|
-
kind
|
|
4856
|
+
kind: creating.kind
|
|
4764
4857
|
});
|
|
4858
|
+
const created = path;
|
|
4859
|
+
setCreating(void 0);
|
|
4860
|
+
setSelectedDirectory(creating.kind === "directory" ? created : creating.directory);
|
|
4765
4861
|
setRevision((x) => x + 1);
|
|
4766
4862
|
window.dispatchEvent(new Event("dvw-files-changed"));
|
|
4767
4863
|
} catch (error) {
|
|
4768
|
-
|
|
4864
|
+
setCreating((current) => current && {
|
|
4865
|
+
...current,
|
|
4866
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4867
|
+
});
|
|
4769
4868
|
}
|
|
4770
4869
|
};
|
|
4771
4870
|
const upload = (0, react.useCallback)(async (directory, files) => {
|
|
@@ -4876,13 +4975,13 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4876
4975
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4877
4976
|
className: "dvw-icon",
|
|
4878
4977
|
title: "新建文件",
|
|
4879
|
-
onClick: () =>
|
|
4978
|
+
onClick: () => startCreating("file"),
|
|
4880
4979
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "new-file" })
|
|
4881
4980
|
}),
|
|
4882
4981
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4883
4982
|
className: "dvw-icon",
|
|
4884
|
-
title: "
|
|
4885
|
-
onClick: () =>
|
|
4983
|
+
title: "新建文件夹",
|
|
4984
|
+
onClick: () => startCreating("directory"),
|
|
4886
4985
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "new-folder" })
|
|
4887
4986
|
}),
|
|
4888
4987
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -4920,7 +5019,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4920
5019
|
onSelectDirectory: setSelectedDirectory,
|
|
4921
5020
|
onOpen: props.onOpen,
|
|
4922
5021
|
onChange: () => setRevision((x) => x + 1),
|
|
4923
|
-
onUpload: (directory, files) => void upload(directory, files)
|
|
5022
|
+
onUpload: (directory, files) => void upload(directory, files),
|
|
5023
|
+
creating,
|
|
5024
|
+
onCreatingChange: (value) => setCreating((current) => current && {
|
|
5025
|
+
...current,
|
|
5026
|
+
value,
|
|
5027
|
+
error: void 0
|
|
5028
|
+
}),
|
|
5029
|
+
onCreatingCancel: () => setCreating(void 0),
|
|
5030
|
+
onCreatingSubmit: () => void submitCreating()
|
|
4924
5031
|
})
|
|
4925
5032
|
}, revision)] });
|
|
4926
5033
|
}
|
|
@@ -4928,6 +5035,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
4928
5035
|
function uploadDestination(selectedDirectory) {
|
|
4929
5036
|
return selectedDirectory ?? "";
|
|
4930
5037
|
}
|
|
5038
|
+
/** Join an inline-created entry name to the currently selected Explorer directory. */
|
|
5039
|
+
function createdEntryPath(directory, name) {
|
|
5040
|
+
return directory ? `${directory}/${name}` : name;
|
|
5041
|
+
}
|
|
4931
5042
|
/** Replace the final path component while preserving its workspace-relative directory. */
|
|
4932
5043
|
function renamedPath(path, name) {
|
|
4933
5044
|
return [...path.split("/").slice(0, -1), name].filter(Boolean).join("/");
|
|
@@ -5329,7 +5440,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5329
5440
|
setStatus(nextStatus);
|
|
5330
5441
|
setCommits(nextCommits);
|
|
5331
5442
|
setError(void 0);
|
|
5332
|
-
}).catch((error) =>
|
|
5443
|
+
}).catch((error) => {
|
|
5444
|
+
setStatus(void 0);
|
|
5445
|
+
setCommits([]);
|
|
5446
|
+
setError(error instanceof ApiError && error.code === "not-repository" ? void 0 : String(error));
|
|
5447
|
+
});
|
|
5333
5448
|
}, [props.sessionId]);
|
|
5334
5449
|
const refreshDebounced = useDebouncedCallback(refresh, 500);
|
|
5335
5450
|
(0, react.useEffect)(refresh, [refresh]);
|
|
@@ -5598,6 +5713,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5598
5713
|
const tabsRef = (0, react.useRef)(tabs);
|
|
5599
5714
|
tabsRef.current = tabs;
|
|
5600
5715
|
const workspaceRequests = (0, react.useRef)(new WorkspaceRequestScope());
|
|
5716
|
+
const loadingTabs = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
5601
5717
|
const dshDark = useDshDarkTheme();
|
|
5602
5718
|
const [theme, setTheme] = (0, react.useState)(() => {
|
|
5603
5719
|
const saved = localStorage.getItem("dvw:theme");
|
|
@@ -5620,61 +5736,24 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5620
5736
|
window.addEventListener("keydown", onKey, true);
|
|
5621
5737
|
return () => window.removeEventListener("keydown", onKey, true);
|
|
5622
5738
|
}, [snapshot.visible]);
|
|
5623
|
-
const openForWorkspace =
|
|
5624
|
-
if (
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
}
|
|
5634
|
-
|
|
5635
|
-
const imageUrl = `/dsh-vscode/file?sessionId=${encodeURIComponent(targetSessionId)}&path=${encodeURIComponent(path)}`;
|
|
5636
|
-
if (!workspaceRequests.current.isCurrent(epoch)) return;
|
|
5637
|
-
setTabs((rows) => workspaceRequests.current.isCurrent(epoch) ? [...rows.filter((tab) => tab.path !== path), {
|
|
5638
|
-
path,
|
|
5639
|
-
content: "",
|
|
5640
|
-
draft: "",
|
|
5641
|
-
revision: "",
|
|
5642
|
-
size: 0,
|
|
5643
|
-
binary: false,
|
|
5644
|
-
tooLarge: false,
|
|
5645
|
-
dirty: false,
|
|
5646
|
-
imageUrl
|
|
5647
|
-
}] : rows);
|
|
5648
|
-
setActive(path);
|
|
5649
|
-
return;
|
|
5650
|
-
}
|
|
5651
|
-
try {
|
|
5652
|
-
const doc = await api("fs.read", {
|
|
5653
|
-
sessionId: targetSessionId,
|
|
5654
|
-
path
|
|
5655
|
-
});
|
|
5656
|
-
if (!workspaceRequests.current.isCurrent(epoch)) return;
|
|
5657
|
-
if (doc.binary || doc.tooLarge) {
|
|
5658
|
-
setError(doc.binary ? "二进制文件不能在文本编辑器中打开" : `文件超过 5 MiB:${path}`);
|
|
5659
|
-
return;
|
|
5660
|
-
}
|
|
5661
|
-
setTabs((rows) => workspaceRequests.current.isCurrent(epoch) ? [...rows.filter((tab) => tab.path !== path), {
|
|
5662
|
-
...doc,
|
|
5663
|
-
draft: doc.content,
|
|
5664
|
-
dirty: false,
|
|
5665
|
-
line,
|
|
5666
|
-
column,
|
|
5667
|
-
preview: /\.md$/i.test(path)
|
|
5668
|
-
}] : rows);
|
|
5669
|
-
setActive(path);
|
|
5670
|
-
} catch (error) {
|
|
5671
|
-
if (workspaceRequests.current.isCurrent(epoch)) setError(String(error));
|
|
5672
|
-
}
|
|
5739
|
+
const openForWorkspace = (path, line, column) => {
|
|
5740
|
+
if (tabsRef.current.find((tab) => tab.path === path)) setTabs((rows) => rows.map((tab) => tab.path === path ? {
|
|
5741
|
+
...tab,
|
|
5742
|
+
line,
|
|
5743
|
+
column
|
|
5744
|
+
} : tab));
|
|
5745
|
+
else setTabs((rows) => [...rows, {
|
|
5746
|
+
...unloadedTab(path),
|
|
5747
|
+
line,
|
|
5748
|
+
column
|
|
5749
|
+
}]);
|
|
5750
|
+
setActive(path);
|
|
5673
5751
|
};
|
|
5674
5752
|
(0, react.useEffect)(() => {
|
|
5675
5753
|
if (!snapshot.visible || sessionId === void 0) return;
|
|
5676
5754
|
const epoch = workspaceRequests.current.begin();
|
|
5677
5755
|
const cleared = resetWorkspaceDocuments();
|
|
5756
|
+
loadingTabs.current.clear();
|
|
5678
5757
|
setWorkspace(void 0);
|
|
5679
5758
|
setTabs(cleared.tabs);
|
|
5680
5759
|
tabsRef.current = cleared.tabs;
|
|
@@ -5690,13 +5769,16 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5690
5769
|
if (parsed.view) service.show(parsed.view);
|
|
5691
5770
|
if (typeof parsed.panelHeight === "number") setPanelHeight(parsed.panelHeight);
|
|
5692
5771
|
if (typeof parsed.sideWidth === "number") setSideWidth(Math.max(210, Math.min(640, Math.round(parsed.sideWidth))));
|
|
5693
|
-
|
|
5772
|
+
const restored = restoreTabPaths(parsed.paths ?? []);
|
|
5773
|
+
setTabs(restored);
|
|
5774
|
+
setActive(restored.some((tab) => tab.path === parsed.active) ? parsed.active : restored.at(-1)?.path);
|
|
5694
5775
|
} catch {}
|
|
5695
5776
|
}).catch((error) => {
|
|
5696
5777
|
if (!controller.signal.aborted && workspaceRequests.current.isCurrent(epoch)) setError(String(error));
|
|
5697
5778
|
});
|
|
5698
5779
|
return () => {
|
|
5699
5780
|
controller.abort();
|
|
5781
|
+
loadingTabs.current.clear();
|
|
5700
5782
|
workspaceRequests.current.invalidate(epoch);
|
|
5701
5783
|
};
|
|
5702
5784
|
}, [snapshot.visible, sessionId]);
|
|
@@ -5704,6 +5786,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5704
5786
|
if (workspace) localStorage.setItem(`dvw:${workspace.cwd}`, JSON.stringify({
|
|
5705
5787
|
view: snapshot.view,
|
|
5706
5788
|
paths: tabs.filter((t) => !t.path.startsWith("diff:")).map((t) => t.path),
|
|
5789
|
+
active,
|
|
5707
5790
|
panelHeight,
|
|
5708
5791
|
sideWidth
|
|
5709
5792
|
}));
|
|
@@ -5711,6 +5794,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5711
5794
|
workspace,
|
|
5712
5795
|
snapshot.view,
|
|
5713
5796
|
tabs,
|
|
5797
|
+
active,
|
|
5714
5798
|
panelHeight,
|
|
5715
5799
|
sideWidth
|
|
5716
5800
|
]);
|
|
@@ -5718,8 +5802,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5718
5802
|
if (!snapshot.visible || sessionId === void 0) return;
|
|
5719
5803
|
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
|
5720
5804
|
const ws = new WebSocket(`${protocol}://${location.host}/dsh-vscode/ws/files?sessionId=${encodeURIComponent(sessionId)}`);
|
|
5721
|
-
ws.onmessage = () => {
|
|
5722
|
-
|
|
5805
|
+
ws.onmessage = (event) => {
|
|
5806
|
+
let paths = [];
|
|
5807
|
+
try {
|
|
5808
|
+
paths = JSON.parse(String(event.data)).paths ?? [];
|
|
5809
|
+
} catch {}
|
|
5810
|
+
window.dispatchEvent(new CustomEvent("dvw-files-changed", { detail: paths }));
|
|
5723
5811
|
setTabs((current) => current.map((tab) => tab.dirty ? {
|
|
5724
5812
|
...tab,
|
|
5725
5813
|
external: true
|
|
@@ -5727,9 +5815,49 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
5727
5815
|
};
|
|
5728
5816
|
return () => ws.close();
|
|
5729
5817
|
}, [snapshot.visible, sessionId]);
|
|
5730
|
-
|
|
5731
|
-
if (sessionId === void 0) return;
|
|
5732
|
-
|
|
5818
|
+
(0, react.useEffect)(() => {
|
|
5819
|
+
if (sessionId === void 0 || active === void 0) return;
|
|
5820
|
+
const tab = tabsRef.current.find((row) => row.path === active);
|
|
5821
|
+
if (tab === void 0 || tab.loaded !== false || loadingTabs.current.has(active)) return;
|
|
5822
|
+
const epoch = workspaceRequests.current.current();
|
|
5823
|
+
loadingTabs.current.add(active);
|
|
5824
|
+
if (/\.(?:avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(active)) {
|
|
5825
|
+
const imageUrl = `/dsh-vscode/file?sessionId=${encodeURIComponent(sessionId)}&path=${encodeURIComponent(active)}`;
|
|
5826
|
+
setTabs((rows) => rows.map((row) => row.path === active ? {
|
|
5827
|
+
...row,
|
|
5828
|
+
loaded: true,
|
|
5829
|
+
imageUrl
|
|
5830
|
+
} : row));
|
|
5831
|
+
loadingTabs.current.delete(active);
|
|
5832
|
+
return;
|
|
5833
|
+
}
|
|
5834
|
+
api("fs.read", {
|
|
5835
|
+
sessionId,
|
|
5836
|
+
path: active
|
|
5837
|
+
}).then((doc) => {
|
|
5838
|
+
if (!workspaceRequests.current.isCurrent(epoch)) return;
|
|
5839
|
+
if (doc.binary || doc.tooLarge) {
|
|
5840
|
+
setTabs((rows) => rows.filter((row) => row.path !== active));
|
|
5841
|
+
setActive((current) => current === active ? void 0 : current);
|
|
5842
|
+
setError(doc.binary ? "二进制文件不能在文本编辑器中打开" : `文件超过 5 MiB:${active}`);
|
|
5843
|
+
return;
|
|
5844
|
+
}
|
|
5845
|
+
setTabs((rows) => rows.map((row) => row.path === active ? {
|
|
5846
|
+
...row,
|
|
5847
|
+
...doc,
|
|
5848
|
+
draft: doc.content,
|
|
5849
|
+
loaded: true
|
|
5850
|
+
} : row));
|
|
5851
|
+
}).catch((error) => {
|
|
5852
|
+
if (workspaceRequests.current.isCurrent(epoch)) setError(String(error));
|
|
5853
|
+
}).finally(() => loadingTabs.current.delete(active));
|
|
5854
|
+
}, [
|
|
5855
|
+
active,
|
|
5856
|
+
sessionId,
|
|
5857
|
+
tabs
|
|
5858
|
+
]);
|
|
5859
|
+
const open = (path, line, column) => {
|
|
5860
|
+
if (sessionId !== void 0) openForWorkspace(path, line, column);
|
|
5733
5861
|
};
|
|
5734
5862
|
(0, react.useEffect)(() => {
|
|
5735
5863
|
const listener = (event) => void open(event.detail);
|
|
@@ -6313,7 +6441,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6313
6441
|
body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-scheme:dark}
|
|
6314
6442
|
.dvw-overlay[data-dvw-theme=dark]{--dvw-base:#151517;--dvw-surface-1:#232324;--dvw-surface-2:#2c2c2e;--dvw-surface-3:#353638;--dvw-text:#f9fafb;--dvw-text-2:#cfd3d6;--dvw-text-3:#adb2b8;--dvw-border:#ffffff1f;--dvw-border-soft:#ffffff29;--dvw-hover:#ffffff14;--dvw-active:#ffffff24;--dvw-accent:#679efe;--dvw-error:#f25a5a;--dvw-success:#22c55e;--dvw-warn:#f59e0b}
|
|
6315
6443
|
.dvw-overlay[data-dvw-theme=light]{--dvw-base:#fff;--dvw-surface-1:#fff;--dvw-surface-2:#fff;--dvw-surface-3:#fff;--dvw-text:#0f1115;--dvw-text-2:#61666b;--dvw-text-3:#81858c;--dvw-border:#0000001a;--dvw-border-soft:#0000001f;--dvw-hover:#2631480f;--dvw-active:#2631481a;--dvw-accent:#4176e6;--dvw-error:#ec1313;--dvw-success:#22c55e;--dvw-warn:#f59e0b;color-scheme:light}
|
|
6316
|
-
.dvw-overlay *{box-sizing:border-box}.dvw-activity{grid-row:1/3;background:var(--dvw-base);border-right:1px solid var(--dvw-border-soft);display:flex;flex-direction:column;align-items:center}.dvw-act{width:48px;height:48px;border:0;border-left:2px solid transparent;background:transparent;color:var(--dvw-text-3);font-size:22px;cursor:pointer}.dvw-act:hover,.dvw-act[data-active=true]{color:var(--dvw-text)}.dvw-act[data-active=true]{border-left-color:var(--dvw-accent)}.dvw-act.dsh{margin-top:auto}.dvw-side{grid-column:2;grid-row:1/3;min-width:0;width:100%;background:var(--dvw-surface-1);border-right:1px solid var(--dvw-border);display:flex;flex-direction:column}.dvw-side-resizer{grid-column:2;grid-row:1/3;justify-self:end;width:7px;height:100%;z-index:4;cursor:ew-resize;transform:translateX(3px);touch-action:none}.dvw-side-resizer:hover,.dvw-side-resizer:active{background:var(--dvw-accent)}.dvw-side-head{height:36px;display:flex;align-items:center;padding:0 12px;text-transform:uppercase;font-size:11px;letter-spacing:.4px}.dvw-toolbar{margin-left:auto;display:flex;gap:2px}.dvw-icon{border:0;background:transparent;color:var(--dvw-text-2);border-radius:4px;min-width:24px;height:24px;display:inline-grid;place-items:center;cursor:pointer}.dvw-icon:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-icon:disabled{opacity:.45;cursor:default}.dvw-file-picker{display:none}.dvw-tree,.dvw-results,.dvw-git{overflow:auto;flex:1}.dvw-tree[data-drop-target=true]{outline:1px dashed var(--dvw-accent);outline-offset:-3px}.dvw-tree-row{display:flex;align-items:center;height:24px;padding-right:6px;cursor:pointer;white-space:nowrap}.dvw-tree-row:hover{background:var(--dvw-hover)}.dvw-tree-row[data-selected=true],.dvw-tree-row[data-drop-target=true]{background:var(--dvw-active)}.dvw-chevron{width:16px;text-align:center;color:var(--dvw-text-3)}.dvw-file-icon{width:18px;color:var(--dvw-text-2)}.dvw-file-icon.folder{color:var(--dvw-accent)}.dvw-tree-name{overflow:hidden;text-overflow:ellipsis}.dvw-tree-rename{min-width:0;flex:1;height:20px;border:1px solid var(--dvw-accent);background:var(--dvw-surface-1);color:var(--dvw-text);font:inherit;outline:0}.dvw-tree-status{margin-left:auto;padding-left:6px;font-size:11px;font-weight:600;color:var(--dvw-warn)}.dvw-tree-status[data-status=M]{color:var(--dvw-warn)}.dvw-tree-status[data-status=A]{color:var(--dvw-success)}.dvw-tree-status[data-status=D]{color:var(--dvw-error)}.dvw-context-menu{position:fixed;z-index:40;min-width:148px;padding:4px;border:1px solid var(--dvw-border);border-radius:5px;background:var(--dvw-surface-3);box-shadow:0 6px 20px rgba(0,0,0,.3)}.dvw-context-menu button{width:100%;height:28px;border:0;border-radius:3px;background:transparent;color:var(--dvw-text);display:flex;align-items:center;gap:8px;padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-context-menu button:hover{background:var(--dvw-hover)}.dvw-context-menu .dvw-context-delete{color:var(--dvw-error)}
|
|
6444
|
+
.dvw-overlay *{box-sizing:border-box}.dvw-activity{grid-row:1/3;background:var(--dvw-base);border-right:1px solid var(--dvw-border-soft);display:flex;flex-direction:column;align-items:center}.dvw-act{width:48px;height:48px;border:0;border-left:2px solid transparent;background:transparent;color:var(--dvw-text-3);font-size:22px;cursor:pointer}.dvw-act:hover,.dvw-act[data-active=true]{color:var(--dvw-text)}.dvw-act[data-active=true]{border-left-color:var(--dvw-accent)}.dvw-act.dsh{margin-top:auto}.dvw-side{grid-column:2;grid-row:1/3;min-width:0;width:100%;background:var(--dvw-surface-1);border-right:1px solid var(--dvw-border);display:flex;flex-direction:column}.dvw-side-resizer{grid-column:2;grid-row:1/3;justify-self:end;width:7px;height:100%;z-index:4;cursor:ew-resize;transform:translateX(3px);touch-action:none}.dvw-side-resizer:hover,.dvw-side-resizer:active{background:var(--dvw-accent)}.dvw-side-head{height:36px;display:flex;align-items:center;padding:0 12px;text-transform:uppercase;font-size:11px;letter-spacing:.4px}.dvw-toolbar{margin-left:auto;display:flex;gap:2px}.dvw-icon{border:0;background:transparent;color:var(--dvw-text-2);border-radius:4px;min-width:24px;height:24px;display:inline-grid;place-items:center;cursor:pointer}.dvw-icon:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-icon:disabled{opacity:.45;cursor:default}.dvw-file-picker{display:none}.dvw-tree,.dvw-results,.dvw-git{overflow:auto;flex:1}.dvw-tree[data-drop-target=true]{outline:1px dashed var(--dvw-accent);outline-offset:-3px}.dvw-tree-row{display:flex;align-items:center;height:24px;padding-right:6px;cursor:pointer;white-space:nowrap}.dvw-tree-row:hover{background:var(--dvw-hover)}.dvw-tree-row[data-selected=true],.dvw-tree-row[data-drop-target=true]{background:var(--dvw-active)}.dvw-chevron{width:16px;flex:none;text-align:center;color:var(--dvw-text-3)}.dvw-file-icon{width:18px;flex:none;color:var(--dvw-text-2)}.dvw-file-icon.folder{color:var(--dvw-accent)}.dvw-tree-name{overflow:hidden;text-overflow:ellipsis}.dvw-tree-rename,.dvw-tree-create-input{min-width:0;flex:1;height:20px;border:1px solid var(--dvw-accent);border-radius:0;background:var(--dvw-surface-1);color:var(--dvw-text);padding:0 3px;font:inherit;letter-spacing:0;outline:0}.dvw-tree-create-row{cursor:text}.dvw-tree-create-row:hover{background:transparent}.dvw-tree-create-input::placeholder{color:var(--dvw-text-3)}.dvw-tree-create-input[aria-invalid=true]{border-color:var(--dvw-error)}.dvw-tree-create-error{min-height:20px;padding-top:2px;padding-right:6px;padding-bottom:3px;color:var(--dvw-error);font-size:11px;line-height:15px;white-space:normal;overflow-wrap:anywhere}.dvw-tree-status{margin-left:auto;padding-left:6px;font-size:11px;font-weight:600;color:var(--dvw-warn)}.dvw-tree-status[data-status=M]{color:var(--dvw-warn)}.dvw-tree-status[data-status=A]{color:var(--dvw-success)}.dvw-tree-status[data-status=D]{color:var(--dvw-error)}.dvw-context-menu{position:fixed;z-index:40;min-width:148px;padding:4px;border:1px solid var(--dvw-border);border-radius:5px;background:var(--dvw-surface-3);box-shadow:0 6px 20px rgba(0,0,0,.3)}.dvw-context-menu button{width:100%;height:28px;border:0;border-radius:3px;background:transparent;color:var(--dvw-text);display:flex;align-items:center;gap:8px;padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-context-menu button:hover{background:var(--dvw-hover)}.dvw-context-menu .dvw-context-delete{color:var(--dvw-error)}
|
|
6317
6445
|
.dvw-main{grid-column:3;grid-row:1;display:flex;min-width:0;min-height:0;flex-direction:column;background:var(--dvw-surface-1)}.dvw-tabs{height:36px;background:var(--dvw-base);display:flex;overflow-x:auto}.dvw-tab{height:36px;min-width:110px;max-width:260px;border:0;border-right:1px solid var(--dvw-border-soft);background:var(--dvw-base);color:var(--dvw-text-2);padding:0 8px 0 12px;display:flex;align-items:center;gap:8px;cursor:pointer}.dvw-tab[data-active=true]{background:var(--dvw-surface-1);color:var(--dvw-text);border-top:1px solid var(--dvw-accent)}.dvw-tab-name{overflow:hidden;text-overflow:ellipsis;flex:1;text-align:left}.dvw-editor{position:relative;flex:1;min-height:0}.dvw-editor-toolbar{position:absolute;z-index:3;top:0;right:0;left:0;height:36px;display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:0 10px;border-bottom:1px solid var(--dvw-border-soft);background:var(--dvw-surface-1)}.dvw-editor-body{position:absolute;inset:0;min-height:0}.dvw-editor-body[data-toolbar=true]{top:36px}.dvw-mode-button{height:27px;padding:0 10px;display:flex;align-items:center;gap:6px;border:1px solid transparent;border-radius:5px;background:transparent;color:var(--dvw-text-2);cursor:pointer}.dvw-mode-button:hover{background:var(--dvw-hover)}.dvw-mode-button[data-active=true]{border-color:var(--dvw-border);background:var(--dvw-active);color:var(--dvw-text)}.dvw-empty{height:100%;display:grid;place-items:center;color:var(--dvw-text-3);text-align:center}.dvw-empty strong{font-size:24px;color:var(--dvw-text-2)}.dvw-message{padding:12px;color:var(--dvw-warn)}
|
|
6318
6446
|
.dvw-bottom{grid-column:3;grid-row:2;height:260px;min-height:120px;border-top:1px solid var(--dvw-border);background:var(--dvw-base);display:flex;flex-direction:column}.dvw-bottom-head{height:35px;display:flex;align-items:center;gap:14px;padding:0 12px}.dvw-bottom-title{border:0;border-bottom:1px solid var(--dvw-text);background:transparent;color:var(--dvw-text);height:35px}.dvw-bottom-body{flex:1;min-height:0}.dvw-status{grid-column:1/4;grid-row:3;background:var(--dvw-accent);color:#fff;display:flex;align-items:center;padding:0 8px;gap:18px;font-size:12px}.dvw-theme-control{position:relative;margin-left:auto}.dvw-theme-trigger{height:22px;min-width:112px;display:flex;align-items:center;gap:7px;padding:0 8px;border:0;border-radius:5px;background:color-mix(in srgb,#000 17%,transparent);color:#fff;cursor:pointer}.dvw-theme-trigger:hover{background:color-mix(in srgb,#000 27%,transparent)}.dvw-theme-orb{width:13px;height:13px;border:2px solid #fff;border-radius:50%;background:linear-gradient(90deg,#17181c 50%,#fff 50%)}.dvw-theme-orb.dark{background:#17181c}.dvw-theme-orb.light{background:#fff}.dvw-theme-menu{position:absolute;right:0;bottom:29px;width:224px;padding:6px;border:1px solid var(--dvw-border);border-radius:10px;background:var(--dvw-surface-3);box-shadow:0 10px 35px rgba(0,0,0,.28);color:var(--dvw-text)}.dvw-theme-menu button{width:100%;min-height:48px;border:0;border-radius:7px;background:transparent;color:inherit;display:grid;grid-template-columns:30px 1fr 20px;align-items:center;text-align:left;padding:6px;cursor:pointer}.dvw-theme-menu button:hover,.dvw-theme-menu button[aria-checked=true]{background:var(--dvw-hover)}.dvw-theme-menu strong,.dvw-theme-menu small{display:block}.dvw-theme-menu small{color:var(--dvw-text-3);margin-top:2px}.dvw-theme-swatch{width:22px;height:22px;border-radius:6px;border:1px solid var(--dvw-border);background:linear-gradient(135deg,#17181c 0 50%,#fff 50%)}.dvw-theme-swatch.dark{background:#17181c}.dvw-theme-swatch.light{background:#fff}
|
|
6319
6447
|
.dvw-search-form{padding:8px;display:grid;gap:6px}.dvw-input,.dvw-textarea,.dvw-select{width:100%;border:1px solid var(--dvw-border);background:var(--dvw-surface-2);color:var(--dvw-text);padding:5px 7px;outline:none}.dvw-input:focus,.dvw-textarea:focus,.dvw-select:focus{border-color:var(--dvw-accent)}.dvw-options{display:flex;align-items:center;gap:8px;font-size:11px}.dvw-result-file{padding:5px 8px;font-weight:600}.dvw-result{padding:4px 8px 4px 20px;cursor:pointer;display:flex;gap:8px}.dvw-result:hover{background:var(--dvw-hover)}.dvw-line{color:var(--dvw-text-3);min-width:30px;text-align:right}.dvw-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|