cache loaded var

This commit is contained in:
codetypes committed 2025-03-19 08:23:27 +08:00
1 parent d9dbf15d30
commit 4fb851c8cc
5 files changed
+136 -78

No files matched your search

+3 -2
View File
@@ -1,9 +1,10 @@
{ {
"name": "def-core", "name": "declare-core",
"desc": "", "desc": "",
"firstid": 1, "firstid": 1,
"export": true, "export": true,
"import": [], "import": [],
"group": [],
"declvar": [ "declvar": [
{ {
"name": "context", "name": "context",
@@ -18,4 +19,4 @@
"id": 1, "id": 1,
"name": "Sequence" "name": "Sequence"
} }
} }
+16 -26
View File
@@ -23,7 +23,6 @@ import {
} from "../contexts/workspace-context"; } from "../contexts/workspace-context";
import { ImportDef, isExprType, NodeModel, TreeGraphData, TreeModel, VarDef } from "../misc/b3type"; import { ImportDef, isExprType, NodeModel, TreeGraphData, TreeModel, VarDef } from "../misc/b3type";
import * as b3util from "../misc/b3util"; import * as b3util from "../misc/b3util";
import { loadSubtreeVarDef, loadVarDef } from "../misc/b3util";
import { message } from "../misc/hooks"; import { message } from "../misc/hooks";
import i18n from "../misc/i18n"; import i18n from "../misc/i18n";
import { Hotkey, isMacos, useKeyDown } from "../misc/keys"; import { Hotkey, isMacos, useKeyDown } from "../misc/keys";
@@ -48,13 +47,6 @@ interface FilterOption {
isFocused: boolean; isFocused: boolean;
} }
const collectVarDefs = (editor: EditorStore) => {
const vars: VarDef[] = editor.declvar.slice();
loadVarDef(editor.import).forEach((v) => vars.push(v));
loadSubtreeVarDef(editor.root).forEach((v) => vars.push(v));
return vars;
};
const createTreeData = (node: NodeModel, parent?: string) => { const createTreeData = (node: NodeModel, parent?: string) => {
return b3util.createTreeData(node, parent, calcTreeDataSize); return b3util.createTreeData(node, parent, calcTreeDataSize);
}; };
@@ -78,9 +70,9 @@ const isTreeUpdated = (editor: EditorStore, editTree: EditTree) => {
return true; return true;
} }
let max = Math.max(editor.declvar.length, editTree.data.declvar.length); let max = Math.max(editor.declare.declvar.length, editTree.data.declvar.length);
for (let i = 0; i < max; i++) { for (let i = 0; i < max; i++) {
const v1: VarDef | undefined = editor.declvar[i]; const v1: VarDef | undefined = editor.declare.declvar[i];
const v2: VarDef | undefined = editTree.data.declvar[i]; const v2: VarDef | undefined = editTree.data.declvar[i];
if (v1?.name !== v2?.name || v1?.desc !== v2?.desc) { if (v1?.name !== v2?.name || v1?.desc !== v2?.desc) {
return true; return true;
@@ -94,9 +86,9 @@ const isTreeUpdated = (editor: EditorStore, editTree: EditTree) => {
} }
} }
max = Math.max(editor.import.length, editTree.data.import.length); max = Math.max(editor.declare.import.length, editTree.data.import.length);
for (let i = 0; i < max; i++) { for (let i = 0; i < max; i++) {
const v1: ImportDef | undefined = editor.import[i]; const v1: ImportDef | undefined = editor.declare.import[i];
const v2: ImportDef | undefined = editTree.data.import[i]; const v2: ImportDef | undefined = editTree.data.import[i];
if (v1?.path !== v2?.path) { if (v1?.path !== v2?.path) {
return true; return true;
@@ -210,16 +202,17 @@ const createMenu = () => {
export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, ...props }) => { export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, ...props }) => {
const workspace = useWorkspace( const workspace = useWorkspace(
useShallow((state) => ({ useShallow((state) => ({
refresh: state.refresh,
editing: state.editing, editing: state.editing,
editingNode: state.editingNode,
editingTree: state.editingTree,
nodeDefs: state.nodeDefs,
onEditingNode: state.onEditingNode, onEditingNode: state.onEditingNode,
onEditingTree: state.onEditingTree, onEditingTree: state.onEditingTree,
open: state.open, open: state.open,
workdir: state.workdir,
relative: state.relative, relative: state.relative,
updateFileMeta: state.updateFileMeta, updateFileMeta: state.updateFileMeta,
nodeDefs: state.nodeDefs, workdir: state.workdir,
editingTree: state.editingTree,
editingNode: state.editingNode,
})) }))
); );
@@ -544,14 +537,13 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
editor.data.export = editTree.data.export !== false; editor.data.export = editTree.data.export !== false;
editor.data.group = editTree.data.group || []; editor.data.group = editTree.data.group || [];
editor.data.firstid = editTree.data.firstid ?? 1; editor.data.firstid = editTree.data.firstid ?? 1;
editor.declvar = editTree.data.declvar || []; editor.declare.declvar = editTree.data.declvar || [];
editor.import = editTree.data.import || []; editor.declare.import = editTree.data.import || [];
editor.data.import = editor.import.map((v) => v.path).sort(); editor.data.import = editor.declare.import.map((v) => v.path).sort();
editor.data.declvar = editor.declvar editor.data.declvar = editor.declare.declvar
.map((v) => ({ ...v })) .map((v) => ({ ...v }))
.sort((a, b) => a.name.localeCompare(b.name)); .sort((a, b) => a.name.localeCompare(b.name));
b3util.updateUsingGroups(editor.data.group); workspace.refresh(editor.path);
b3util.updateUsingVars(collectVarDefs(editor));
pushHistory(); pushHistory();
refresh(); refresh();
onChange(); onChange();
@@ -744,8 +736,8 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
const data = JSON.parse(str) as TreeModel; const data = JSON.parse(str) as TreeModel;
editor.data = data; editor.data = data;
editor.root = createTreeData(data.root); editor.root = createTreeData(data.root);
editor.import = data.import.map((v) => ({ path: v, vars: [] })); editor.declare.import = data.import.map((v) => ({ path: v, vars: [], depends: [] }));
editor.declvar = data.declvar.map((v) => ({ ...v })); editor.declare.declvar = data.declvar.map((v) => ({ ...v }));
editor.autoId = b3util.refreshTreeDataId(editor.root, editor.data.firstid); editor.autoId = b3util.refreshTreeDataId(editor.root, editor.data.firstid);
editor.graph.changeData(editor.root); editor.graph.changeData(editor.root);
editor.graph.layout(); editor.graph.layout();
@@ -1263,8 +1255,6 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
useEffect(() => { useEffect(() => {
if (workspace.editing === editor) { if (workspace.editing === editor) {
checkSubtree(); checkSubtree();
b3util.updateUsingGroups(editor.data.group);
b3util.updateUsingVars(collectVarDefs(editor));
} }
}, [workspace.editing]); }, [workspace.editing]);
+44 -10
View File
@@ -7,7 +7,6 @@ import { create } from "zustand";
import { NodeDef } from "../behavior3/src/behavior3"; import { NodeDef } from "../behavior3/src/behavior3";
import { ImportDef, NodeModel, TreeGraphData, TreeModel, VarDef } from "../misc/b3type"; import { ImportDef, NodeModel, TreeGraphData, TreeModel, VarDef } from "../misc/b3type";
import * as b3util from "../misc/b3util"; import * as b3util from "../misc/b3util";
import { loadSubtreeVarDef } from "../misc/b3util";
import { message } from "../misc/hooks"; import { message } from "../misc/hooks";
import i18n from "../misc/i18n"; import i18n from "../misc/i18n";
import Path from "../misc/path"; import Path from "../misc/path";
@@ -47,8 +46,11 @@ export class EditorStore {
data: TreeModel; data: TreeModel;
root: TreeGraphData; root: TreeGraphData;
import: ImportDef[]; declare: {
declvar: VarDef[]; import: ImportDef[];
subtree: ImportDef[];
declvar: VarDef[];
};
autoId: number = 1; autoId: number = 1;
dragSrcId?: string; dragSrcId?: string;
@@ -76,8 +78,11 @@ export class EditorStore {
this.data.name = Path.basenameWithoutExt(path); this.data.name = Path.basenameWithoutExt(path);
this.root = b3util.createTreeData(this.data.root); this.root = b3util.createTreeData(this.data.root);
this.modifiedTime = fs.statSync(path).mtimeMs; this.modifiedTime = fs.statSync(path).mtimeMs;
this.import = this.data.import.map((v) => ({ path: v, vars: [] })); this.declare = {
this.declvar = this.data.declvar.map((v) => ({ ...v })); import: this.data.import.map((v) => ({ path: v, vars: [], depends: [] })),
subtree: [],
declvar: this.data.declvar.map((v) => ({ ...v })),
};
this.autoId = b3util.refreshTreeDataId(this.root, this.data.firstid); this.autoId = b3util.refreshTreeDataId(this.root, this.data.firstid);
this.historyStack.push( this.historyStack.push(
JSON.stringify( JSON.stringify(
@@ -166,6 +171,7 @@ export type WorkspaceStore = {
close: (path: string) => void; close: (path: string) => void;
find: (path: string) => EditorStore | undefined; find: (path: string) => EditorStore | undefined;
relative: (path: string) => string; relative: (path: string) => string;
refresh: (path: string) => void;
save: () => void; save: () => void;
saveAs: () => void; saveAs: () => void;
@@ -526,6 +532,26 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
return Path.relative(workspace.workdir, path).replaceAll(Path.sep, "/"); return Path.relative(workspace.workdir, path).replaceAll(Path.sep, "/");
}, },
refresh: (path: string) => {
const workspace = get();
const editor = workspace.editors.find((v) => v.path === path);
if (!editor) {
return;
}
const vars: Set<VarDef> = new Set(editor.declare.declvar.slice());
editor.declare.subtree = b3util.findSubtrees(editor.root).map((v) => ({
path: v,
vars: [],
depends: [],
}));
b3util.loadVarDef(editor.declare.import).forEach((v) => vars.add(v));
b3util.loadVarDef(editor.declare.subtree).forEach((v) => {
vars.add(v);
});
b3util.updateUsingGroups(editor.data.group);
b3util.updateUsingVars(Array.from(vars));
},
save: () => { save: () => {
const workspace = get(); const workspace = get();
saveFile(workspace.editing); saveFile(workspace.editing);
@@ -560,7 +586,9 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
} else { } else {
const fullpath = Path.posixPath(`${workspace.workdir}/${filename}`); const fullpath = Path.posixPath(`${workspace.workdir}/${filename}`);
const editor = workspace.find(fullpath); const editor = workspace.find(fullpath);
if (editor && editor.modifiedTime + 500 < fs.statSync(fullpath).mtimeMs) { const modified = fs.statSync(fullpath).mtimeMs;
b3util.files[Path.posixPath(filename)] = modified;
if (editor && editor.modifiedTime + 500 < modified) {
if (editor.unsave) { if (editor.unsave) {
editor.alertReload = true; editor.alertReload = true;
set({ modifiedTime: Date.now() }); set({ modifiedTime: Date.now() });
@@ -595,7 +623,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
let fileMeta = allFiles.get(path); let fileMeta = allFiles.get(path);
if (!fileMeta) { if (!fileMeta) {
fileMeta = { path: fileNode.path }; fileMeta = { path: fileNode.path };
allFiles.set(fileNode.path, fileMeta); allFiles.set(path, fileMeta);
} else { } else {
fileMeta.path = fileNode.path; fileMeta.path = fileNode.path;
} }
@@ -610,8 +638,11 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
}; };
collect(data); collect(data);
allFiles.forEach((file, key) => { allFiles.forEach((file, key) => {
const modified = fs.statSync(file.path).mtimeMs;
b3util.files[key] = modified;
if (!file.exists) { if (!file.exists) {
allFiles.delete(key); allFiles.delete(key);
delete b3util.files[key];
updated = true; updated = true;
} }
}); });
@@ -653,13 +684,16 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
if (workspace.editing) { if (workspace.editing) {
workspace.editing.editNode = null; workspace.editing.editNode = null;
} }
workspace.refresh(editor.path);
set({ set({
editingTree: { editingTree: {
data: { data: {
...editor.data, ...editor.data,
import: editor.import, import: editor.declare.import,
declvar: editor.declvar, declvar: editor.declare.declvar,
subtree: loadSubtreeVarDef(editor.root), subtree: editor.declare.subtree
.map((def) => def.vars)
.reduce((acc, v) => [...acc, ...v], []),
}, },
}, },
editingNodeDef: null, editingNodeDef: null,
+5 -1
View File
@@ -43,8 +43,12 @@ export interface GroupDef {
export interface ImportDef { export interface ImportDef {
path: string; path: string;
date?: number; modified?: number;
vars: VarDef[]; vars: VarDef[];
depends: {
path: string;
modified: number;
}[];
} }
export interface TreeModel { export interface TreeModel {
+68 -39
View File
@@ -28,7 +28,9 @@ export let nodeDefs: NodeDefs = new NodeDefs();
export let groupDefs: string[] = []; export let groupDefs: string[] = [];
export let usingGroups: Record<string, boolean> = {}; export let usingGroups: Record<string, boolean> = {};
export let usingVars: Record<string, VarDef> | null = null; export let usingVars: Record<string, VarDef> | null = null;
export const files: Record<string, number> = {};
const parsedVarDefs: Record<string, ImportDef> = {};
const parsedExprs: Record<string, string[]> = {}; const parsedExprs: Record<string, string[]> = {};
let workdir: string = ""; let workdir: string = "";
let alertError: (msg: string, duration?: number) => void = () => {}; let alertError: (msg: string, duration?: number) => void = () => {};
@@ -73,6 +75,18 @@ export const updateUsingVars = (vars: VarDef[]) => {
} }
}; };
export const parseExpr = (expr: string) => {
if (parsedExprs[expr]) {
return parsedExprs[expr];
}
const result = expr
.split(/[^a-zA-Z0-9_.]/)
.map((v) => v.split(".")[0])
.filter((v) => isValidVariableName(v));
parsedExprs[expr] = result;
return result;
};
export const isValidVariableName = (name: string) => { export const isValidVariableName = (name: string) => {
return /^[a-zA-Z_]/.test(name); return /^[a-zA-Z_]/.test(name);
}; };
@@ -716,67 +730,82 @@ export const isTreeFile = (path: string) => {
}; };
export const loadVarDef = (list: ImportDef[]) => { export const loadVarDef = (list: ImportDef[]) => {
const all: Set<VarDef> = new Set();
for (const entry of list) { for (const entry of list) {
// TODO: check file date if (!files[entry.path]) {
// TODO: use cache console.warn(`file not found:${workdir}/${entry.path}`);
if (entry.vars.length) {
entry.vars.forEach((v) => all.add(v));
continue; continue;
} }
const filter: Map<string, boolean> = new Map();
const vars: VarDef[] = []; let changed = false;
if (!entry.modified || files[entry.path] > entry.modified) {
changed = true;
}
if (!changed) {
changed = entry.depends.some((v) => files[v.path] && files[v.path] > v.modified);
}
if (!changed) {
continue;
}
entry.vars = [];
entry.depends = [];
entry.modified = files[entry.path];
const vars: Set<VarDef> = new Set();
const depends: Set<string> = new Set();
const load = (path: string) => { const load = (path: string) => {
if (filter.has(path)) { if (parsingStack.includes(path)) {
return; return;
} }
filter.set(path, true);
const parsedEntry: ImportDef | undefined = parsedVarDefs[path];
if (parsedEntry && files[path] === parsedEntry.modified) {
parsedEntry.depends.forEach((v) => depends.add(v.path));
parsedEntry.vars.forEach((v) => vars.add(v));
return;
}
parsingStack.push(path);
try { try {
const model: TreeModel = readTree(`${workdir}/${path}`); const model: TreeModel = readTree(`${workdir}/${path}`);
model.declvar.forEach((v) => vars.push(v)); model.declvar.forEach((v) => vars.add(v));
model.import.forEach((v) => load(v)); model.import.forEach((v) => {
load(v);
depends.add(v);
});
console.log(`load var: ${path}`);
} catch (e) { } catch (e) {
alertError(`parsing error: ${path}`); alertError(`parsing error: ${path}`);
} }
parsingStack.pop();
}; };
load(entry.path); load(entry.path);
filter.clear(); entry.vars = Array.from(vars).sort((a, b) => a.name.localeCompare(b.name));
entry.vars = vars entry.depends = Array.from(depends).map((v) => ({ path: v, modified: files[v] }));
.filter((v) => { parsedVarDefs[entry.path] = {
if (!filter.has(v.name)) { path: entry.path,
filter.set(v.name, true); vars: entry.vars.map((v) => ({ name: v.name, desc: v.desc })),
return true; depends: entry.depends.slice(),
} modified: entry.modified,
return false; };
})
.sort((a, b) => a.name.localeCompare(b.name));
entry.vars.forEach((v) => all.add(v));
} }
const all: Set<VarDef> = new Set();
list.forEach((entry) => entry.vars.forEach((v) => all.add(v)));
return Array.from(all); return Array.from(all);
}; };
export const loadSubtreeVarDef = (data: TreeGraphData) => { export const findSubtrees = (data: TreeGraphData) => {
const list: ImportDef[] = []; const list: string[] = [];
const traverse = (v: TreeGraphData) => { const traverse = (v: TreeGraphData) => {
if (v.path) { if (v.path) {
list.push({ path: v.path, vars: [] }); list.push(v.path);
} }
if (v.children) { if (v.children) {
v.children.forEach(traverse); v.children.forEach((child) => traverse(child));
} }
}; };
traverse(data); traverse(data);
return loadVarDef(list); return list;
};
export const parseExpr = (expr: string) => {
if (parsedExprs[expr]) {
return parsedExprs[expr];
}
const result = expr
.split(/[^a-zA-Z0-9_.]/)
.map((v) => v.split(".")[0])
.filter((v) => isValidVariableName(v));
parsedExprs[expr] = result;
return result;
}; };