Skip to content

Commit 3816e6f

Browse files
committed
feat: 增加刷新反向引用信息的功能
1 parent 7f48fa4 commit 3816e6f

File tree

3 files changed

+198
-112
lines changed

3 files changed

+198
-112
lines changed

app/src/core/service/dataManageService/textNodeSmartTools.tsx

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import { Dialog } from "@/components/ui/dialog";
2-
import { loadAllServicesBeforeInit } from "@/core/loadAllServices";
32
import { Project } from "@/core/Project";
4-
import { RecentFileManager } from "@/core/service/dataFileService/RecentFileManager";
53
import { Edge } from "@/core/stage/stageObject/association/Edge";
64
import { LineEdge } from "@/core/stage/stageObject/association/LineEdge";
75
import { CollisionBox } from "@/core/stage/stageObject/collisionBox/collisionBox";
86
import { ReferenceBlockNode } from "@/core/stage/stageObject/entity/ReferenceBlockNode";
97
import { TextNode } from "@/core/stage/stageObject/entity/TextNode";
108
import { DetailsManager } from "@/core/stage/stageObject/tools/entityDetailsManager";
11-
import { PathString } from "@/utils/pathString";
129
import { averageColors, Color, Vector } from "@graphif/data-structures";
1310
import { Rectangle } from "@graphif/shapes";
1411
import { toast } from "sonner";
@@ -545,62 +542,6 @@ export namespace TextNodeSmartTools {
545542

546543
project.stageManager.add(referenceBlock);
547544
project.stageManager.delete(selectedNode); // TODO: 直接删除原有节点有隐患
548-
549-
// 更新被引用文件的reference.msgpack
550-
const currentFileName = PathString.getFileNameFromPath(project.uri.path);
551-
if (!currentFileName) return;
552-
553-
try {
554-
// 根据文件名查找被引用文件
555-
const recentFiles = await RecentFileManager.getRecentFiles();
556-
const referencedFile = recentFiles.find(
557-
(file) =>
558-
PathString.getFileNameFromPath(file.uri.path) === fileName ||
559-
PathString.getFileNameFromPath(file.uri.fsPath) === fileName,
560-
);
561-
if (!referencedFile) return;
562-
563-
// 创建被引用文件的Project实例
564-
const referencedProject = new Project(referencedFile.uri);
565-
566-
// 初始化项目
567-
loadAllServicesBeforeInit(referencedProject);
568-
await referencedProject.init();
569-
570-
// 更新引用
571-
if (sectionName) {
572-
// 引用特定Section的情况
573-
if (!referencedProject.references.sections[sectionName]) {
574-
referencedProject.references.sections[sectionName] = [];
575-
}
576-
577-
// 确保数组中没有重复的文件名
578-
const index = referencedProject.references.sections[sectionName].indexOf(currentFileName);
579-
if (index === -1) {
580-
referencedProject.references.sections[sectionName].push(currentFileName);
581-
// 保存更新
582-
await referencedProject.save();
583-
}
584-
} else {
585-
// 引用整个文件的情况
586-
if (!referencedProject.references.files) {
587-
referencedProject.references.files = [];
588-
}
589-
590-
// 确保数组中没有重复的文件名
591-
const index = referencedProject.references.files.indexOf(currentFileName);
592-
if (index === -1) {
593-
referencedProject.references.files.push(currentFileName);
594-
// 保存更新
595-
await referencedProject.save();
596-
}
597-
}
598-
599-
// 关闭项目
600-
await referencedProject.dispose();
601-
// TODO: 存在隐患,欠考虑如果引用已经被当前软件打开的情况。
602-
} catch (error) {
603-
toast.error("Failed to update reference:" + String(error));
604-
}
545+
await project.referenceManager.insertRefDataToSourcePrgFile(fileName, sectionName);
605546
}
606547
}

app/src/core/stage/stageManager/concreteMethods/StageReferenceManager.tsx

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { onOpenFile } from "@/core/service/GlobalMenu";
88
import { ReferenceBlockNode } from "../../stageObject/entity/ReferenceBlockNode";
99
import { RectangleLittleNoteEffect } from "@/core/service/feedbackService/effectEngine/concrete/RectangleLittleNoteEffect";
1010
import { SectionReferencePanel } from "@/sub/ReferencesWindow";
11+
import { loadAllServicesBeforeInit } from "@/core/loadAllServices";
1112

1213
interface parserResult {
1314
/**
@@ -32,6 +33,12 @@ interface parserResult {
3233
export class ReferenceManager {
3334
constructor(private readonly project: Project) {}
3435

36+
/**
37+
* 保险检查函数
38+
* 解析用户在文本节点中输入的引用格式文本,防止直接退出编辑模式后触发转换,导致引用块内容被错误解析
39+
* @param text 引用块文本
40+
* @returns
41+
*/
3542
public static referenceBlockTextParser(text: string): parserResult {
3643
if (!text.startsWith("[[") || !text.endsWith("]]")) {
3744
return {
@@ -103,6 +110,136 @@ export class ReferenceManager {
103110
}
104111
}
105112

113+
/**
114+
* 更新当前项目的引用信息
115+
* (清理无效的引用)
116+
*/
117+
public async updateCurrentProjectReference() {
118+
const recentFiles = await RecentFileManager.getRecentFiles();
119+
120+
// 遍历当前项目的每一个被引用的Section框
121+
for (const sectionName in this.project.references.sections) {
122+
const fileNameList = this.project.references.sections[sectionName];
123+
const fileNameListNew = [];
124+
for (const fileName of fileNameList) {
125+
const file = recentFiles.find(
126+
(file) =>
127+
PathString.getFileNameFromPath(file.uri.path) === fileName ||
128+
PathString.getFileNameFromPath(file.uri.fsPath) === fileName,
129+
);
130+
if (file) {
131+
// 即使文件存在,也要打开看一看引用块是否在那个文件中。
132+
const thatProject = new Project(file.uri);
133+
loadAllServicesBeforeInit(thatProject);
134+
await thatProject.init();
135+
if (this.checkReferenceBlockInProject(thatProject, fileName, sectionName)) {
136+
fileNameListNew.push(fileName);
137+
}
138+
thatProject.dispose();
139+
}
140+
}
141+
if (fileNameListNew.length === 0) {
142+
// 直接把这个章节从引用列表中删除
143+
delete this.project.references.sections[sectionName];
144+
} else {
145+
this.project.references.sections[sectionName] = fileNameListNew;
146+
}
147+
}
148+
149+
// 遍历每一个直接引用自己整个文件的文件
150+
const fileNameListNew = [];
151+
for (const fileName of this.project.references.files) {
152+
const file = recentFiles.find(
153+
(file) =>
154+
PathString.getFileNameFromPath(file.uri.path) === fileName ||
155+
PathString.getFileNameFromPath(file.uri.fsPath) === fileName,
156+
);
157+
if (file) {
158+
// 即使文件存在,也要打开看一看引用块是否在那个文件中。
159+
const thatProject = new Project(file.uri);
160+
loadAllServicesBeforeInit(thatProject);
161+
await thatProject.init();
162+
if (this.checkReferenceBlockInProject(thatProject, fileName, "")) {
163+
fileNameListNew.push(fileName);
164+
}
165+
thatProject.dispose();
166+
}
167+
}
168+
this.project.references.files = fileNameListNew;
169+
}
170+
171+
public checkReferenceBlockInProject(project: Project, fileName: string, sectionName: string) {
172+
const referenceBlocks = project.stage
173+
.filter((object) => object instanceof ReferenceBlockNode)
174+
.filter(
175+
(referenceBlockNode) =>
176+
referenceBlockNode.fileName === fileName && referenceBlockNode.sectionName === sectionName,
177+
);
178+
if (referenceBlocks.length > 0) {
179+
return true;
180+
}
181+
return false;
182+
}
183+
184+
public async insertRefDataToSourcePrgFile(fileName: string, sectionName: string) {
185+
// 更新被引用文件的reference.msgpack
186+
const currentFileName = PathString.getFileNameFromPath(this.project.uri.path);
187+
if (!currentFileName) return;
188+
189+
try {
190+
// 根据文件名查找被引用文件
191+
const recentFiles = await RecentFileManager.getRecentFiles();
192+
const referencedFile = recentFiles.find(
193+
(file) =>
194+
PathString.getFileNameFromPath(file.uri.path) === fileName ||
195+
PathString.getFileNameFromPath(file.uri.fsPath) === fileName,
196+
);
197+
if (!referencedFile) return;
198+
199+
// 创建被引用文件的Project实例
200+
const referencedProject = new Project(referencedFile.uri);
201+
202+
// 初始化项目
203+
loadAllServicesBeforeInit(referencedProject);
204+
await referencedProject.init();
205+
206+
// 更新引用
207+
if (sectionName) {
208+
// 引用特定Section的情况
209+
if (!referencedProject.references.sections[sectionName]) {
210+
referencedProject.references.sections[sectionName] = [];
211+
}
212+
213+
// 确保数组中没有重复的文件名
214+
const index = referencedProject.references.sections[sectionName].indexOf(currentFileName);
215+
if (index === -1) {
216+
referencedProject.references.sections[sectionName].push(currentFileName);
217+
// 保存更新
218+
await referencedProject.save();
219+
}
220+
} else {
221+
// 引用整个文件的情况
222+
if (!referencedProject.references.files) {
223+
referencedProject.references.files = [];
224+
}
225+
226+
// 确保数组中没有重复的文件名
227+
const index = referencedProject.references.files.indexOf(currentFileName);
228+
if (index === -1) {
229+
referencedProject.references.files.push(currentFileName);
230+
// 保存更新
231+
await referencedProject.save();
232+
}
233+
}
234+
235+
// 关闭项目
236+
await referencedProject.dispose();
237+
// TODO: 存在隐患,欠考虑如果引用已经被当前软件打开的情况。
238+
} catch (error) {
239+
toast.error("更新reference.msgpack失败:" + String(error));
240+
}
241+
}
242+
106243
/**
107244
* 从源头 跳转到引用位置
108245
* @param section

app/src/sub/ReferencesWindow.tsx

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ export default function ReferencesWindow(props: { currentProjectFileName: string
1515
if (!project) return <></>;
1616

1717
const [references, setReferences] = useState(project.references);
18+
const [isUpdating, setIsUpdating] = useState(false);
1819

19-
function refresh() {
20+
async function refresh() {
21+
setIsUpdating(true);
22+
await project?.referenceManager.updateCurrentProjectReference();
2023
setReferences({ ...project!.references });
21-
// 现在这个刷新作用很小,不能检测已经失效的引用
24+
setIsUpdating(false);
2225
}
2326

2427
useEffect(() => {
25-
refresh();
28+
setReferences({ ...project!.references });
2629
}, []);
2730

2831
return (
@@ -33,60 +36,65 @@ export default function ReferencesWindow(props: { currentProjectFileName: string
3336
刷新
3437
</Button>
3538
</div>
36-
37-
{/* 引用信息展示 */}
38-
<div className="flex-1 overflow-y-auto">
39-
<div className="mb-4">
40-
<h3 className="mb-2 text-lg font-semibold">直接引用{currentProjectFileName}的文件</h3>
41-
{references.files.length === 0 ? (
42-
<p className="text-muted-foreground text-sm">当前项目中没有引用{currentProjectFileName}的文件</p>
43-
) : (
44-
<div className="space-y-1">
45-
{references.files.map((filePath) => {
46-
const fileName = PathString.getFileNameFromPath(filePath);
47-
return (
48-
<div
49-
key={filePath}
50-
className="text-select-option-text flex cursor-pointer items-center gap-2 rounded p-1 text-sm *:cursor-pointer hover:ring"
51-
onClick={() => project.referenceManager.jumpToReferenceLocation(fileName, "")}
52-
>
53-
<span className="font-medium">{fileName}</span>
54-
<span className="text-muted-foreground text-xs">{filePath}</span>
55-
</div>
56-
);
57-
})}
58-
</div>
59-
)}
60-
</div>
61-
62-
<div>
63-
<h3 className="mb-2 text-lg font-semibold">引用此文件中一些Section框的文件</h3>
64-
{Object.keys(references.sections).length === 0 ? (
65-
<p className="text-muted-foreground text-sm">{currentProjectFileName}中没有被引用的Section</p>
66-
) : (
67-
<div className="space-y-3">
68-
{Object.entries(references.sections).map(([referencedSectionName, sections]) => (
69-
<div key={referencedSectionName}>
70-
<div className="text-select-option-text rounded p-1 font-medium">{referencedSectionName}</div>
71-
<div className="my-1 ml-4 space-y-1">
72-
{sections.map((fileName) => (
39+
{isUpdating ? (
40+
<div className="text-muted-foreground text-sm">正在刷新中...</div>
41+
) : (
42+
<>
43+
{/* 引用信息展示 */}
44+
<div className="flex-1 overflow-y-auto">
45+
<div className="mb-4">
46+
<h3 className="mb-2 text-lg font-semibold">直接引用{currentProjectFileName}的文件</h3>
47+
{references.files.length === 0 ? (
48+
<p className="text-muted-foreground text-sm">当前项目中没有引用{currentProjectFileName}的文件</p>
49+
) : (
50+
<div className="space-y-1">
51+
{references.files.map((filePath) => {
52+
const fileName = PathString.getFileNameFromPath(filePath);
53+
return (
7354
<div
74-
onClick={() =>
75-
project.referenceManager.jumpToReferenceLocation(fileName, referencedSectionName)
76-
}
77-
key={fileName}
78-
className="border-muted text-select-option-text cursor-pointer rounded border-l-2 p-1 pl-2 text-sm hover:ring"
55+
key={filePath}
56+
className="text-select-option-text flex cursor-pointer items-center gap-2 rounded p-1 text-sm *:cursor-pointer hover:ring"
57+
onClick={() => project.referenceManager.jumpToReferenceLocation(fileName, "")}
7958
>
80-
{fileName}
59+
<span className="font-medium">{fileName}</span>
60+
<span className="text-muted-foreground text-xs">{filePath}</span>
8161
</div>
82-
))}
83-
</div>
62+
);
63+
})}
8464
</div>
85-
))}
65+
)}
8666
</div>
87-
)}
88-
</div>
89-
</div>
67+
68+
<div>
69+
<h3 className="mb-2 text-lg font-semibold">引用此文件中一些Section框的文件</h3>
70+
{Object.keys(references.sections).length === 0 ? (
71+
<p className="text-muted-foreground text-sm">{currentProjectFileName}中没有被引用的Section</p>
72+
) : (
73+
<div className="space-y-3">
74+
{Object.entries(references.sections).map(([referencedSectionName, sections]) => (
75+
<div key={referencedSectionName}>
76+
<div className="text-select-option-text rounded p-1 font-medium">{referencedSectionName}</div>
77+
<div className="my-1 ml-4 space-y-1">
78+
{sections.map((fileName) => (
79+
<div
80+
onClick={() =>
81+
project.referenceManager.jumpToReferenceLocation(fileName, referencedSectionName)
82+
}
83+
key={fileName}
84+
className="border-muted text-select-option-text cursor-pointer rounded border-l-2 p-1 pl-2 text-sm hover:ring"
85+
>
86+
{fileName}
87+
</div>
88+
))}
89+
</div>
90+
</div>
91+
))}
92+
</div>
93+
)}
94+
</div>
95+
</div>
96+
</>
97+
)}
9098
</div>
9199
);
92100
}

0 commit comments

Comments
 (0)