mirror of
https://github.com/EthanMarti/infio-copilot.git
synced 2026-05-13 11:02:32 +00:00
添加对 CodeMirror 的支持,更新相关依赖版本,并在样式中增加 JSON 视图的样式。新增 JSON 视图类型并实现打开配置文件的功能,更新国际化文本以支持配置文件操作。
This commit is contained in:
168
src/BaseFileView.tsx
Normal file
168
src/BaseFileView.tsx
Normal file
@@ -0,0 +1,168 @@
|
||||
import { EditorState, Extension } from "@codemirror/state";
|
||||
import { EditorView, ViewUpdate } from "@codemirror/view";
|
||||
import { TFile, TextFileView, WorkspaceLeaf } from "obsidian";
|
||||
|
||||
import InfioPlugin from './main';
|
||||
|
||||
export default abstract class BaseView extends TextFileView {
|
||||
public plugin: InfioPlugin;
|
||||
protected cmEditor: EditorView;
|
||||
protected editorEl: HTMLElement;
|
||||
protected state: { filePath?: string } | null = null;
|
||||
protected isEditorLoaded: boolean = false;
|
||||
protected currentFilePath: string | null = null;
|
||||
|
||||
protected constructor(leaf: WorkspaceLeaf, plugin: InfioPlugin) {
|
||||
super(leaf);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
onload(): void {
|
||||
super.onload();
|
||||
this.editorEl = this.contentEl.createDiv("datafile-source-view mod-cm6");
|
||||
|
||||
this.cmEditor = new EditorView({
|
||||
state: this.createDefaultEditorState(),
|
||||
parent: this.editorEl,
|
||||
});
|
||||
|
||||
this.app.workspace.trigger("codemirror", this.cmEditor);
|
||||
this.isEditorLoaded = true;
|
||||
|
||||
// Load file content if state contains filePath and editor is now loaded
|
||||
if (this.state?.filePath) {
|
||||
this.loadFileFromPath(this.state.filePath);
|
||||
}
|
||||
}
|
||||
|
||||
async setState(state: { filePath?: string }): Promise<void> {
|
||||
this.state = state;
|
||||
// If filePath is provided and editor is loaded, load the file immediately
|
||||
if (state.filePath && this.isEditorLoaded) {
|
||||
await this.loadFileFromPath(state.filePath);
|
||||
}
|
||||
}
|
||||
|
||||
getState(): { filePath?: string } {
|
||||
return { filePath: this.currentFilePath };
|
||||
}
|
||||
|
||||
private async loadFileFromPath(filePath: string): Promise<void> {
|
||||
// Store the current file path for saving
|
||||
this.currentFilePath = filePath;
|
||||
|
||||
// Try to get the file from vault first (for regular files)
|
||||
const file = this.app.vault.getAbstractFileByPath(filePath);
|
||||
|
||||
if (file && file instanceof TFile) {
|
||||
// Regular file in vault
|
||||
this.file = file;
|
||||
await this.onLoadFile(file);
|
||||
} else {
|
||||
// File not in vault (hidden directory), read directly from filesystem
|
||||
console.log('File not in vault, reading directly from filesystem');
|
||||
await this.loadFileFromFilesystem(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
private async loadFileFromFilesystem(filePath: string): Promise<void> {
|
||||
try {
|
||||
// Use vault adapter to read file directly from filesystem
|
||||
const content = await this.app.vault.adapter.read(filePath);
|
||||
this.setViewData(content, true);
|
||||
} catch (error) {
|
||||
console.error('Failed to load file from filesystem:', error);
|
||||
// If file doesn't exist, create it with empty content
|
||||
this.setViewData('{}', true);
|
||||
}
|
||||
}
|
||||
|
||||
async onLoadFile(file: TFile): Promise<void> {
|
||||
try {
|
||||
const content = await this.app.vault.read(file);
|
||||
this.setViewData(content, true);
|
||||
} catch (error) {
|
||||
console.error('Failed to load file content:', error);
|
||||
}
|
||||
}
|
||||
|
||||
getViewData(): string {
|
||||
return this.cmEditor.state.doc.toString();
|
||||
}
|
||||
|
||||
setViewData(data: string, clear: boolean): void {
|
||||
if (clear) {
|
||||
this.cmEditor.dispatch({ changes: { from: 0, to: this.cmEditor.state.doc.length, insert: data } });
|
||||
} else {
|
||||
this.cmEditor.dispatch({ changes: { from: 0, to: this.cmEditor.state.doc.length, insert: data } });
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.setViewData('', true);
|
||||
}
|
||||
|
||||
async save(clear?: boolean): Promise<void> {
|
||||
const content = this.getViewData();
|
||||
|
||||
if (this.file) {
|
||||
// Regular file in vault
|
||||
await this.app.vault.modify(this.file, content);
|
||||
} else if (this.currentFilePath) {
|
||||
// File in hidden directory, save directly to filesystem
|
||||
await this.app.vault.adapter.write(this.currentFilePath, content);
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// gets the title of the document
|
||||
getDisplayText(): string {
|
||||
if (this.file) {
|
||||
return this.file.basename;
|
||||
}
|
||||
if (this.currentFilePath) {
|
||||
return this.currentFilePath.split('/').pop() || "JSON File";
|
||||
}
|
||||
if (this.state?.filePath) {
|
||||
return this.state.filePath.split('/').pop() || "JSON File";
|
||||
}
|
||||
return "NOFILE";
|
||||
}
|
||||
|
||||
onClose(): Promise<void> {
|
||||
return super.onClose();
|
||||
}
|
||||
|
||||
async reload(): Promise<void> {
|
||||
await this.save(false);
|
||||
|
||||
const data = this.getViewData();
|
||||
this.cmEditor.setState(this.createDefaultEditorState());
|
||||
this.setViewData(data, false);
|
||||
}
|
||||
|
||||
protected onEditorUpdate(update: ViewUpdate): void {
|
||||
if (update.docChanged) {
|
||||
this.requestSave();
|
||||
}
|
||||
}
|
||||
|
||||
abstract getViewType(): string;
|
||||
|
||||
protected abstract getEditorExtensions(): Extension[];
|
||||
|
||||
private createDefaultEditorState(): EditorState {
|
||||
return EditorState.create({
|
||||
extensions: [...this.getCommonEditorExtensions(), ...this.getEditorExtensions()]
|
||||
});
|
||||
}
|
||||
|
||||
private getCommonEditorExtensions(): Extension[] {
|
||||
const extensions: Extension[] = [];
|
||||
extensions.push(EditorView.lineWrapping);
|
||||
return extensions;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user