From 2f1478bcb9fb354d6cc2cf3b9ed06eec8c355ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 3 Jul 2024 18:08:52 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=91=E5=90=AC=E7=89=A9=E7=BC=96=E5=8F=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/editorTable/editorTable.ts | 76 +++++++++++++++++++++++++--------- src/editorTable/treeView.ts | 44 ++++++++++++++------ 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/editorTable/editorTable.ts b/src/editorTable/editorTable.ts index e17f430..19624ad 100644 --- a/src/editorTable/editorTable.ts +++ b/src/editorTable/editorTable.ts @@ -2,6 +2,7 @@ import { Table } from "../constants"; import { env } from "../env"; import * as vscode from "vscode"; import * as y3 from 'y3-helper'; +import { throttle } from "../utility/decorators"; type ObjectShape = { "name": string | number, @@ -70,18 +71,26 @@ async function loadObject(tableName: Table.NameCN, key: number) { } } -function getFileID(uri: vscode.Uri): number|undefined { - if (!uri.path.toLowerCase().endsWith('.json')) { +function getFileID(fileName: string): number|undefined { + if (!fileName.toLowerCase().endsWith('.json')) { return; } - let id = parseInt(uri.path.slice(0, -5)); + let idStr = fileName.slice(0, -5).split('/').pop(); + if (!idStr) { + return; + } + // 确保只有数字 + if (!/^\d+$/.test(idStr)) { + return; + } + let id = parseInt(idStr); if (isNaN(id)) { return; } return id; } -class EditorTable extends vscode.Disposable { +export class EditorTable extends vscode.Disposable { public uri; public nameEN; private _objectCache: { [key: number]: EditorObject | null | undefined } = {}; @@ -121,29 +130,59 @@ class EditorTable extends vscode.Disposable { if (type !== vscode.FileType.File) { continue; } - if (!name.toLowerCase().endsWith('.json')) { - continue; - } - let id = parseInt(name.slice(0, -5)); - if (isNaN(id)) { + let id = getFileID(name); + if (id === undefined) { continue; } this._listCache.push(id); } + this._listCache.sort(); } + this.resortList(); return this._listCache; } public fetchList() { + this.resortList(); return this._listCache; } + private _listActions: ['create' | 'delete', number][] = []; + private resortList() { + if (this._listActions.length === 0) { + return; + } + let map: { [key: number]: boolean } = {}; + let list: number[] = []; + for (const id of this._listCache!) { + map[id] = true; + } + for (const [action, id] of this._listActions) { + if (action === 'create') { + map[id] = true; + } else { + delete map[id]; + } + } + this._listActions.length = 0; + for (const id in map) { + list.push(Number(id)); + } + list.sort(); + this._listCache = list; + } + + @throttle(200) + private callOnDidChange() { + this._onDidChange.fire(); + } + private _onDidChange: vscode.EventEmitter = new vscode.EventEmitter(); private initWatcher() { this.watcher = vscode.workspace.createFileSystemWatcher(new vscode.RelativePattern(this.uri, '*.json')); this.watcher.onDidChange((fileUri) => { - let id = getFileID(fileUri); + let id = getFileID(fileUri.path); if (id === undefined) { return; } @@ -151,33 +190,30 @@ class EditorTable extends vscode.Disposable { return; } this._objectCache[id] = undefined; - this._onDidChange.fire(); + this.callOnDidChange(); }); this.watcher.onDidCreate((fileUri) => { - let id = getFileID(fileUri); + let id = getFileID(fileUri.path); if (id === undefined) { return; } if (!this._listCache) { return; } - this._listCache.push(id); - this._onDidChange.fire(); + this._listActions.push(['create', id]); + this.callOnDidChange(); }); this.watcher.onDidDelete((fileUri) => { - let id = getFileID(fileUri); + let id = getFileID(fileUri.path); if (id === undefined) { return; } if (!this._listCache) { return; } - let index = this._listCache.indexOf(id); - if (index !== -1) { - this._listCache.splice(index, 1); - } this._objectCache[id] = undefined; - this._onDidChange.fire(); + this._listActions.push(['delete', id]); + this.callOnDidChange(); }); } diff --git a/src/editorTable/treeView.ts b/src/editorTable/treeView.ts index 4d6f52c..794240c 100644 --- a/src/editorTable/treeView.ts +++ b/src/editorTable/treeView.ts @@ -13,6 +13,8 @@ class FileNode extends vscode.TreeItem { public key: number, ) { super(`加载中...(${key})`); + + this.id = `${tableName}/${key}`; } public update(): void | Promise { @@ -39,24 +41,25 @@ class FileNode extends vscode.TreeItem { class DirNode extends vscode.TreeItem { readonly contextValue = 'directory'; readonly collapsibleState = vscode.TreeItemCollapsibleState.Collapsed; + readonly table: editorTable.EditorTable; constructor( public tableName: Table.NameCN, ) { super(`${tableName}(加载中...)`); - let table = editorTable.open(tableName); - this.resourceUri = table.uri; + this.table = editorTable.open(tableName); + this.resourceUri = this.table.uri; + this.id = tableName; } public update(): void | Promise { - let table = editorTable.open(this.tableName); - let list = table.fetchList(); + let list = this.table.fetchList(); if (list) { this.label = `${this.tableName}(${list.length})`; return; } else { return new Promise(async resolve => { - await table.getList(); + await this.table.getList(); resolve(); }); } @@ -75,13 +78,30 @@ class DirNode extends vscode.TreeItem { type TreeNode = FileNode | DirNode; -class TreeViewProvider implements vscode.TreeDataProvider { - private async getRoot(): Promise { - let nodes: DirNode[] = []; +class TreeViewProvider extends vscode.Disposable implements vscode.TreeDataProvider { + constructor() { + super(() => { + this.disposables.forEach(d => d.dispose()); + }); + } + + private dirNodes?: DirNode[]; + private disposables: vscode.Disposable[] = []; + + private getRoot(): DirNode[] { + if (this.dirNodes) { + return this.dirNodes; + } + this.dirNodes = []; for (const nameCN in Table.name.fromCN) { - nodes.push(new DirNode(nameCN as Table.NameCN)); + let dirNode = new DirNode(nameCN as Table.NameCN); + this.dirNodes.push(dirNode); + + this.disposables.push(dirNode.table.onDidChange(() => { + this.refresh(dirNode); + })); } - return nodes; + return this.dirNodes; } public async getChildren(node?: TreeNode | undefined) { @@ -89,7 +109,7 @@ class TreeViewProvider implements vscode.TreeDataProvider { return; } if (node === undefined) { - return await this.getRoot(); + return this.getRoot(); } else if(node instanceof DirNode) { return await node.getChildren(); } else { @@ -122,7 +142,7 @@ class TreeView extends vscode.Disposable { super(() => { this.disposables.forEach(d => d.dispose()); }); - this.provider = new TreeViewProvider(); + this.disposables.push(this.provider = new TreeViewProvider()); this.disposables.push(this.treeView = vscode.window.createTreeView('y3-helper.editorTableView', { treeDataProvider: this.provider,