store open files in history
This commit is contained in:
1 parent
5fb19c5c08
commit
3b1091cf87
8 files changed
+119
-62
No files matched your search
+1
-22
@@ -109,7 +109,6 @@ if (!app.requestSingleInstanceLock()) {
|
||||
|
||||
interface Workspace {
|
||||
projectPath?: string;
|
||||
files: { path: string; active: boolean }[];
|
||||
window: BrowserWindow;
|
||||
}
|
||||
|
||||
@@ -244,27 +243,7 @@ ipcMain.handle("open-win", (e, arg) => {
|
||||
ipcMain.handle("ready-to-show", (e) => {
|
||||
const workspace = windows.find((v) => v.window.webContents.id === e.sender.id);
|
||||
if (workspace && workspace.projectPath) {
|
||||
workspace.window.webContents.send("open-project", workspace.projectPath, workspace.files);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle("open-file", (e, path: string) => {
|
||||
const workspace = windows.find((v) => v.window.webContents.id === e.sender.id);
|
||||
if (workspace) {
|
||||
const entry = workspace.files.find((v) => v.path === path);
|
||||
workspace.files.forEach((v) => (v.active = false));
|
||||
if (entry) {
|
||||
entry.active = true;
|
||||
} else {
|
||||
workspace.files.push({ path, active: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle("close-file", (e, path: string) => {
|
||||
const workspace = windows.find((v) => v.window.webContents.id === e.sender.id);
|
||||
if (workspace) {
|
||||
workspace.files = workspace.files.filter((v) => v.path !== path);
|
||||
workspace.window.webContents.send("open-project", workspace.projectPath);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ export const Editor: FC<EditorProps> = ({ onChange, data: editor, ...props }) =>
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
e.stopPropagation();
|
||||
editor.dispatch(hotkeyMap[key]);
|
||||
editor.dispatch?.(hotkeyMap[key]);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -153,7 +153,7 @@ export const Editor: FC<EditorProps> = ({ onChange, data: editor, ...props }) =>
|
||||
return;
|
||||
}
|
||||
e.stopPropagation();
|
||||
editor.dispatch(hotkeyMap[key]);
|
||||
editor.dispatch?.(hotkeyMap[key]);
|
||||
});
|
||||
|
||||
const searchInputRef = useRef<InputRef>(null);
|
||||
@@ -493,7 +493,7 @@ export const Editor: FC<EditorProps> = ({ onChange, data: editor, ...props }) =>
|
||||
)}
|
||||
|
||||
<Dropdown
|
||||
menu={{ items: menuItems, onClick: (info) => editor.dispatch(info.key as EditEvent) }}
|
||||
menu={{ items: menuItems, onClick: (info) => editor.dispatch?.(info.key as EditEvent) }}
|
||||
trigger={["contextMenu"]}
|
||||
>
|
||||
<div tabIndex={-1} style={{ width: "100%", height: "100%" }} ref={graphRef} />
|
||||
|
||||
@@ -105,11 +105,11 @@ const renameFile = (oldPath: string, newPath: string) => {
|
||||
for (const editor of workspace.editors) {
|
||||
if (isDirectory) {
|
||||
if (editor.path.startsWith(oldPath)) {
|
||||
editor.dispatch("rename", editor.path.replace(oldPath, newPath));
|
||||
editor.dispatch?.("rename", editor.path.replace(oldPath, newPath));
|
||||
}
|
||||
} else {
|
||||
if (editor.path === oldPath) {
|
||||
editor.dispatch("rename", newPath);
|
||||
editor.dispatch?.("rename", newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,12 +406,12 @@ const doMoveFile = (path: string, newPath: string) => {
|
||||
fs.renameSync(path, newPath);
|
||||
for (const editor of workspace.editors) {
|
||||
if (editor.path.startsWith(path)) {
|
||||
editor.dispatch("rename", destDir + "/" + Path.basename(editor.path));
|
||||
editor.dispatch?.("rename", destDir + "/" + Path.basename(editor.path));
|
||||
}
|
||||
console.log("editor move", editor.path === newPath, editor.path, newPath);
|
||||
if (editor.path.startsWith(newPath)) {
|
||||
console.log("editor reload", editor.path === newPath, editor.path, newPath);
|
||||
editor.dispatch("refresh");
|
||||
editor.dispatch?.("refresh");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ const VarDeclItem: FC<VarItemProps> = ({ name, onChange, onRemove, disabled, ...
|
||||
borderTop: "1px solid #3d506c",
|
||||
borderBottom: "1px solid #3d506c",
|
||||
}}
|
||||
onClick={() => value.name && editing?.dispatch("clickVar", value.name)}
|
||||
onClick={() => value.name && editing?.dispatch?.("clickVar", value.name)}
|
||||
>
|
||||
<AimOutlined />
|
||||
<span style={{ marginLeft: 4 }}>{value?.count ?? 0}</span>
|
||||
@@ -254,7 +254,7 @@ const TreeInspector: FC = () => {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const finish = (values: any) => {
|
||||
workspace.editing?.dispatch("updateTree", {
|
||||
workspace.editing?.dispatch?.("updateTree", {
|
||||
name: values.name,
|
||||
desc: values.desc,
|
||||
export: values.export,
|
||||
@@ -812,7 +812,7 @@ const NodeInspector: FC = () => {
|
||||
data.output = [];
|
||||
}
|
||||
|
||||
workspace.editing?.dispatch("updateNode", {
|
||||
workspace.editing?.dispatch?.("updateNode", {
|
||||
data: data,
|
||||
} as EditNode);
|
||||
};
|
||||
@@ -1500,7 +1500,7 @@ const NodeInspector: FC = () => {
|
||||
type="primary"
|
||||
style={{ width: "100%" }}
|
||||
icon={<EditOutlined />}
|
||||
onClick={() => workspace.editing?.dispatch("editSubtree")}
|
||||
onClick={() => workspace.editing?.dispatch?.("editSubtree")}
|
||||
>
|
||||
{t("editSubtree")}
|
||||
</Button>
|
||||
|
||||
@@ -29,8 +29,8 @@ const getFocusedWebContents = () => {
|
||||
return BrowserWindow.getFocusedWindow()?.webContents;
|
||||
};
|
||||
|
||||
ipcRenderer.on("open-project", (_, dir, files) => {
|
||||
useWorkspace.getState().init(dir, files);
|
||||
ipcRenderer.on("open-project", (_, dir) => {
|
||||
useWorkspace.getState().init(dir);
|
||||
});
|
||||
|
||||
ipcRenderer.on("refresh-app-men", () => {
|
||||
|
||||
@@ -80,12 +80,12 @@ export const Workspace: FC = () => {
|
||||
|
||||
useKeyDown(Hotkey.SearchNode, keysRef, (event) => {
|
||||
event.preventDefault();
|
||||
workspace.editing?.dispatch("searchNode");
|
||||
workspace.editing?.dispatch?.("searchNode");
|
||||
});
|
||||
|
||||
useKeyDown(Hotkey.JumpNode, keysRef, (event) => {
|
||||
event.preventDefault();
|
||||
workspace.editing?.dispatch("jumpNode");
|
||||
workspace.editing?.dispatch?.("jumpNode");
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -118,7 +118,7 @@ export const Workspace: FC = () => {
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
editor.alertReload = false;
|
||||
editor.dispatch("reload");
|
||||
editor.dispatch?.("reload");
|
||||
alert.destroy();
|
||||
keysRef.current?.focus();
|
||||
setShowingAlert(false);
|
||||
@@ -164,7 +164,7 @@ export const Workspace: FC = () => {
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
editor.dispatch("save");
|
||||
editor.dispatch?.("save");
|
||||
workspace.close(editor.path);
|
||||
alert.destroy();
|
||||
keysRef.current?.focus();
|
||||
@@ -232,7 +232,7 @@ export const Workspace: FC = () => {
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
unsaves.forEach((editor) => editor.dispatch("save"));
|
||||
unsaves.forEach((editor) => editor.dispatch?.("save"));
|
||||
alert.destroy();
|
||||
window.close();
|
||||
setShowingAlert(false);
|
||||
|
||||
@@ -7,10 +7,21 @@ import { useWorkspace } from "./workspace-context";
|
||||
|
||||
const settingPath = app.getPath("userData") + "/settings.json";
|
||||
|
||||
export type OpenEditor = {
|
||||
path: string;
|
||||
active: boolean;
|
||||
};
|
||||
|
||||
export type ProjectSetting = {
|
||||
path: string;
|
||||
buildDir: string;
|
||||
editors: OpenEditor[];
|
||||
};
|
||||
|
||||
export type SettingModel = {
|
||||
recent: string[];
|
||||
buildDir: string;
|
||||
layout: NodeLayout;
|
||||
projects: ProjectSetting[];
|
||||
};
|
||||
|
||||
export type SettingStore = {
|
||||
@@ -20,8 +31,12 @@ export type SettingStore = {
|
||||
save: () => void;
|
||||
appendRecent: (path: string) => void;
|
||||
removeRecent: (path: string) => void;
|
||||
setBuildDir: (dir: string) => void;
|
||||
setLayout: (layout: "compact" | "normal") => void;
|
||||
setBuildDir: (project: string, dir: string) => void;
|
||||
getBuildDir: (project: string) => string;
|
||||
openEditor: (project: string, path: string) => void;
|
||||
closeEditor: (project: string, path: string) => void;
|
||||
getEditors: (project: string) => OpenEditor[];
|
||||
};
|
||||
|
||||
export const useSetting = create<SettingStore>((set, get) => ({
|
||||
@@ -29,22 +44,25 @@ export const useSetting = create<SettingStore>((set, get) => ({
|
||||
recent: [],
|
||||
buildDir: "",
|
||||
layout: "compact",
|
||||
checkExpr: true,
|
||||
projects: [],
|
||||
},
|
||||
load: () => {
|
||||
try {
|
||||
if (fs.existsSync(settingPath)) {
|
||||
const settings = readJson(settingPath) as SettingModel;
|
||||
settings.layout = settings.layout || "compact";
|
||||
settings.projects = settings.projects || [];
|
||||
set({ data: settings });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
|
||||
save: () => {
|
||||
writeJson(settingPath, get().data);
|
||||
},
|
||||
|
||||
appendRecent: (path: string) => {
|
||||
const { data, save } = get();
|
||||
const recent = data.recent.filter((v) => v !== path);
|
||||
@@ -52,21 +70,75 @@ export const useSetting = create<SettingStore>((set, get) => ({
|
||||
set({ data: { ...data, recent } });
|
||||
save();
|
||||
},
|
||||
|
||||
removeRecent: (path: string) => {
|
||||
const { data, save } = get();
|
||||
const recent = data.recent.filter((v) => v !== path);
|
||||
set({ data: { ...data, recent } });
|
||||
save();
|
||||
},
|
||||
setBuildDir: (dir: string) => {
|
||||
const { data, save } = get();
|
||||
set({ data: { ...data, buildDir: dir } });
|
||||
save();
|
||||
},
|
||||
|
||||
setLayout: (layout: "compact" | "normal") => {
|
||||
const { data, save } = get();
|
||||
set({ data: { ...data, layout } });
|
||||
save();
|
||||
useWorkspace.getState().editing?.dispatch("refresh");
|
||||
useWorkspace.getState().editing?.dispatch?.("refresh");
|
||||
},
|
||||
|
||||
setBuildDir: (projectPath: string, dir: string) => {
|
||||
const { data, save } = get();
|
||||
let project = data.projects.find((v) => v.path === projectPath);
|
||||
if (!project) {
|
||||
project = {
|
||||
path: projectPath,
|
||||
buildDir: "",
|
||||
editors: [],
|
||||
};
|
||||
}
|
||||
project.buildDir = dir;
|
||||
set({ data: { ...data, projects: data.projects } });
|
||||
save();
|
||||
},
|
||||
|
||||
getBuildDir: (project: string) => {
|
||||
const { data } = get();
|
||||
return data.projects.find((v) => v.path === project)?.buildDir ?? "";
|
||||
},
|
||||
|
||||
openEditor: (projectPath: string, filePath: string) => {
|
||||
const { data, save } = get();
|
||||
let project = data.projects.find((v) => v.path === projectPath);
|
||||
if (!project) {
|
||||
project = {
|
||||
path: projectPath,
|
||||
buildDir: "",
|
||||
editors: [],
|
||||
};
|
||||
data.projects.push(project);
|
||||
}
|
||||
const editor = project.editors.find((v) => v.path === filePath);
|
||||
project.editors.forEach((v) => (v.active = false));
|
||||
if (editor) {
|
||||
editor.active = true;
|
||||
} else {
|
||||
project.editors.push({ path: filePath, active: true });
|
||||
}
|
||||
set({ data: { ...data, projects: data.projects } });
|
||||
save();
|
||||
},
|
||||
|
||||
closeEditor: (project: string, path: string) => {
|
||||
const { data, save } = get();
|
||||
const projectSetting = data.projects.find((v) => v.path === project);
|
||||
if (projectSetting) {
|
||||
projectSetting.editors = projectSetting.editors.filter((v) => v.path !== path);
|
||||
}
|
||||
set({ data: { ...data, projects: data.projects } });
|
||||
save();
|
||||
},
|
||||
|
||||
getEditors: (project: string) => {
|
||||
const { data } = get();
|
||||
return data.projects.find((v) => v.path === project)?.editors ?? [];
|
||||
},
|
||||
}));
|
||||
@@ -47,7 +47,7 @@ export class EditorStore {
|
||||
alertReload: boolean = false;
|
||||
focusId?: string | null;
|
||||
|
||||
dispatch!: (event: EditEvent, data?: unknown) => void;
|
||||
dispatch?: (event: EditEvent, data?: unknown) => void;
|
||||
|
||||
constructor(path: string) {
|
||||
this.path = path;
|
||||
@@ -113,7 +113,7 @@ export interface WorkspaceModel {
|
||||
}
|
||||
|
||||
export type WorkspaceStore = {
|
||||
init: (project: string, files?: { path: string; active: boolean }[]) => void;
|
||||
init: (project: string) => void;
|
||||
createProject: () => void;
|
||||
openProject: (project?: string) => void;
|
||||
batchProject: () => void;
|
||||
@@ -212,7 +212,7 @@ const loadFileTree = (workdir: string, filename: string) => {
|
||||
|
||||
const saveFile = (editor?: EditorStore) => {
|
||||
if (editor?.changed) {
|
||||
editor.dispatch("save");
|
||||
editor.dispatch?.("save");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -225,8 +225,9 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
path: "",
|
||||
settings: {},
|
||||
|
||||
init: (path, files) => {
|
||||
init: (path) => {
|
||||
const workspace = get();
|
||||
const files = useSetting.getState().getEditors(path);
|
||||
if (!workspace.workdir) {
|
||||
try {
|
||||
workspace.workdir = Path.dirname(path).replaceAll(Path.sep, "/");
|
||||
@@ -236,9 +237,10 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
workspace.loadNodeDefs();
|
||||
workspace.watch();
|
||||
useSetting.getState().appendRecent(path);
|
||||
if (files?.length) {
|
||||
if (files.length) {
|
||||
for (const entry of files) {
|
||||
try {
|
||||
entry.path = Path.posixPath(entry.path);
|
||||
const editor = new EditorStore(entry.path);
|
||||
workspace.editors.push(editor);
|
||||
if (entry.active) {
|
||||
@@ -271,7 +273,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
});
|
||||
b3util.setCheckExpr(checkExpr);
|
||||
saveWorkspace();
|
||||
useWorkspace.getState().editing?.dispatch("refresh");
|
||||
get().editing?.dispatch?.("refresh");
|
||||
},
|
||||
|
||||
setupBuildScript: () => {
|
||||
@@ -365,17 +367,18 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
|
||||
buildProject: async () => {
|
||||
const workspace = get();
|
||||
const setting = useSetting.getState();
|
||||
if (workspace.path) {
|
||||
if (!buildDir) {
|
||||
buildDir = dialog.showOpenDialogSync({
|
||||
properties: ["openDirectory", "createDirectory"],
|
||||
defaultPath: useSetting.getState().data.buildDir,
|
||||
defaultPath: setting.getBuildDir(workspace.path),
|
||||
})?.[0];
|
||||
}
|
||||
}
|
||||
if (buildDir) {
|
||||
for (const editor of workspace.editors) {
|
||||
editor.dispatch("save");
|
||||
editor.dispatch?.("save");
|
||||
}
|
||||
const debug = console.debug;
|
||||
console.debug = () => {};
|
||||
@@ -386,7 +389,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
} else {
|
||||
message.success(i18n.t("buildCompleted"));
|
||||
}
|
||||
useSetting.getState().setBuildDir(buildDir);
|
||||
setting.setBuildDir(workspace.path, buildDir);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
message.error(i18n.t("buildFailed"));
|
||||
@@ -511,6 +514,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
|
||||
edit: (path, focusId) => {
|
||||
const workspace = get();
|
||||
const setting = useSetting.getState();
|
||||
const editor = workspace.editors.find((v) => v.path === path);
|
||||
if (editor) {
|
||||
editor.focusId = focusId;
|
||||
@@ -519,11 +523,11 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
if (editor) {
|
||||
workspace.onEditingTree(editor);
|
||||
}
|
||||
ipcRenderer.invoke("open-file", path);
|
||||
},
|
||||
|
||||
close: (path) => {
|
||||
const workspace = get();
|
||||
const setting = useSetting.getState();
|
||||
const idx = workspace.editors.findIndex((v) => v.path === path);
|
||||
const editors = workspace.editors.filter((v) => v.path !== path);
|
||||
const editor = workspace.editors.find((v) => v.path === path);
|
||||
@@ -538,7 +542,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
set({ editingNode: undefined, editingTree: undefined });
|
||||
}
|
||||
set({ editing: editting, editors: editors });
|
||||
ipcRenderer.invoke("close-file", path);
|
||||
setting.closeEditor(workspace.path, path);
|
||||
},
|
||||
|
||||
find: (path) => {
|
||||
@@ -605,7 +609,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
editor.alertReload = true;
|
||||
set({ modifiedTime: Date.now() });
|
||||
} else {
|
||||
editor.dispatch("reload");
|
||||
editor.dispatch?.("reload");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -674,7 +678,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
const workspace = get();
|
||||
b3util.initWorkdir(workspace.workdir, message.error.bind(message));
|
||||
set({ nodeDefs: b3util.nodeDefs, groupDefs: b3util.groupDefs });
|
||||
workspace.editing?.dispatch("refresh");
|
||||
workspace.editing?.dispatch?.("refresh");
|
||||
},
|
||||
|
||||
// node edit
|
||||
@@ -689,7 +693,9 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
||||
// tree edit
|
||||
onEditingTree: (editor) => {
|
||||
const workspace = get();
|
||||
const setting = useSetting.getState();
|
||||
workspace.refresh(editor.path);
|
||||
setting.openEditor(workspace.path, editor.path);
|
||||
set({
|
||||
editingTree: {
|
||||
...editor.data,
|
||||
|
||||
Reference in new issue
Block a user