From a15fbe635adc26f4a03f54333617907708faae40 Mon Sep 17 00:00:00 2001 From: abchen Date: Thu, 14 Mar 2024 19:13:40 +0800 Subject: [PATCH 1/5] =?UTF-8?q?wip:=20=E5=A2=9E=E5=8A=A0mobx,mst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/bookmark-manager.json | 2 +- package.json | 2 + src/bootstrap.ts | 33 +- src/commands/code.ts | 176 ++++----- src/controllers/BookmarksController.ts | 248 +++++------- src/controllers/IController.ts | 3 +- .../UniversalBookmarkController.ts | 32 +- src/events.ts | 4 +- src/providers/BaseTreeProvider.ts | 8 +- src/providers/BookmarksTreeItem.ts | 15 +- src/providers/BookmarksTreeProvider.ts | 73 ++-- src/services/DecorationService.ts | 14 +- src/stores/BookmarkManagerConfig.ts | 14 + src/stores/DecorationOptions.ts | 76 ++++ src/stores/bookmark.ts | 373 ++++++++++++++++++ src/stores/index.ts | 1 + src/types/code.ts | 22 +- src/types/common.ts | 3 +- src/utils/bookmark.ts | 94 +++-- src/views/BookmarksTreeView.ts | 4 +- yarn.lock | 10 + 21 files changed, 810 insertions(+), 397 deletions(-) create mode 100644 src/stores/BookmarkManagerConfig.ts create mode 100644 src/stores/DecorationOptions.ts create mode 100644 src/stores/bookmark.ts create mode 100644 src/stores/index.ts diff --git a/.vscode/bookmark-manager.json b/.vscode/bookmark-manager.json index 2693aad..6562432 100644 --- a/.vscode/bookmark-manager.json +++ b/.vscode/bookmark-manager.json @@ -1 +1 @@ -{"version":"0.0.25","workspace":"bookmarks","updatedDate":"3/12/2024","content":[]} \ No newline at end of file +{"version":"0.0.26","workspace":"bookmarks","updatedDate":"3/14/2024","content":[{"type":"line","color":"default","selection":{"start":{"line":3,"character":0},"end":{"line":3,"character":55},"active":{"line":3,"character":55},"anchor":{"line":3,"character":0}},"fileUri":{"$mid":1,"fsPath":"d:\\projects\\myrepo\\bookmarks\\src\\types\\code.ts","_sep":1,"external":"file:///d%3A/projects/myrepo/bookmarks/src/types/code.ts","path":"/d:/projects/myrepo/bookmarks/src/types/code.ts","scheme":"file"},"languageId":"typescript","selectionContent":"export type BookmarkDecorationKey = string | 'default';","fileId":"d:\\projects\\myrepo\\bookmarks\\src\\types\\code.ts","fileName":"d:\\projects\\myrepo\\bookmarks\\src\\types\\code.ts","rangesOrOptions":{"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":55},"active":{"line":3,"character":55},"anchor":{"line":3,"character":0}},"hoverMessage":{},"renderOptions":{"after":{}}},"workspaceFolder":{"uri":{"$mid":1,"fsPath":"d:\\projects\\myrepo\\bookmarks","_sep":1,"external":"file:///d%3A/projects/myrepo/bookmarks","path":"/d:/projects/myrepo/bookmarks","scheme":"file"},"name":"bookmarks","index":0},"id":"f6316f9b-cd63-4210-9997-a2406b916b6c"}]} \ No newline at end of file diff --git a/package.json b/package.json index 2bc5eed..a3a8bf1 100644 --- a/package.json +++ b/package.json @@ -614,6 +614,8 @@ "@vscode/l10n": "^0.0.16", "@vscode/vsce": "^2.23.0", "lodash": "^4.17.21", + "mobx": "^6.12.0", + "mobx-state-tree": "^5.4.1", "uuid": "^9.0.1" }, "lint-staged": { diff --git a/src/bootstrap.ts b/src/bootstrap.ts index 43a05b3..39eace1 100644 --- a/src/bootstrap.ts +++ b/src/bootstrap.ts @@ -17,11 +17,15 @@ import {registerTelemetryLogger} from './utils'; import logger from './utils/logger'; import { + ServiceManager, initServiceManager, postInitController, } from './services/ServiceManager'; -let controllerManager: any = {}; +let controllerManager: { + bookmarks?: BookmarksController; + universal?: UniversalBookmarkController; +} = {}; /** * 注册所有的视图 @@ -55,13 +59,17 @@ function updateEverything() { updateTextEditorSelectionListener(); } -function initialController(context: ExtensionContext) { - controllerManager['bookmarks'] && controllerManager['bookmarks'].dispose(); - controllerManager['universal'] && controllerManager['universal'].dispose(); - const bookmarksController = new BookmarksController(context); - const universalController = new UniversalBookmarkController(context); - controllerManager['bookmarks'] = bookmarksController; - controllerManager['universal'] = universalController; +function initialController( + context: ExtensionContext, + serviceManager: ServiceManager, +) { + const bookmarksController = new BookmarksController(context, serviceManager); + const universalController = new UniversalBookmarkController( + context, + serviceManager, + ); + controllerManager.bookmarks = bookmarksController; + controllerManager.universal = universalController; } export default async function bootstrap(context: ExtensionContext) { @@ -72,9 +80,8 @@ export default async function bootstrap(context: ExtensionContext) { logger.log(`${EXTENSION_ID} is now active!`); - await initServiceManager(context, updateEverything); - - initialController(context); + const sm = await initServiceManager(context, updateEverything); + initialController(context, sm); postInitController(); registerAllTreeView(context); registerAllCommands(); @@ -82,9 +89,9 @@ export default async function bootstrap(context: ExtensionContext) { } export function resolveBookmarkController(): BookmarksController { - return controllerManager['bookmarks']; + return controllerManager.bookmarks!; } export function resolveUniversalController(): UniversalBookmarkController { - return controllerManager['universal']; + return controllerManager.universal!; } diff --git a/src/commands/code.ts b/src/commands/code.ts index b6d4e95..fbfda1c 100644 --- a/src/commands/code.ts +++ b/src/commands/code.ts @@ -23,17 +23,15 @@ import { } from '../constants'; import {registerCommand} from '../utils'; -import {BookmarkMeta, LineBookmarkContext} from '../types'; +import {LineBookmarkContext} from '../types'; import {resolveBookmarkController} from '../bootstrap'; -import BookmarksTreeItem from '../providers/BookmarksTreeItem'; +import BookmarkTreeItem from '../providers/BookmarksTreeItem'; import resolveServiceManager from '../services/ServiceManager'; import { checkIfBookmarksIsInCurrentEditor, chooseBookmarkColor, deleteBookmark, - editBookmarkDescription, - editBookmarkLabel, getBookmarkFromLineNumber, getBookmarksFromFileUri, getLineInfoStrFromBookmark, @@ -42,6 +40,7 @@ import { toggleBookmark, toggleBookmarksWithSelections, } from '../utils/bookmark'; +import {IBookmark} from '../stores/bookmark'; /** * 从`context`获取书签数据 @@ -49,17 +48,14 @@ import { * @param cb * @returns */ -function getBookmarkFromCtx( - context: LineBookmarkContext | BookmarksTreeItem | undefined, - cb?: () => void, -) { - let bookmark: BookmarkMeta | undefined; +function getBookmarkFromCtx(context: LineBookmarkContext, cb?: () => void) { + let bookmark: IBookmark | undefined; if ( context && 'contextValue' in context && context.contextValue === 'bookmark' ) { - bookmark = context.meta as BookmarkMeta; + bookmark = context.meta as IBookmark; } else { bookmark = getBookmarkFromLineNumber(); } @@ -78,16 +74,16 @@ function getBookmarkFromCtx( * @returns */ function getBookmarkColorFromCtx( - context: LineBookmarkContext | BookmarksTreeItem | undefined, + context: LineBookmarkContext | BookmarkTreeItem | undefined, cb?: () => void, ) { - let bookmark: BookmarkMeta | undefined; + let bookmark: IBookmark | undefined; if ( context && 'contextValue' in context && context.contextValue === 'color' ) { - bookmark = context.meta as BookmarkMeta; + bookmark = context.meta as IBookmark; } if (!bookmark && cb) { @@ -188,27 +184,20 @@ function clearAllBookmarks() { } /** * 通过命令行删除书签 + * - 从`command palette` 上调用删除操作, context 为undefined + * - 从 左侧通过gutter的菜单上下文调用删除操作, context 类型为 LineBookmarkContext + * - 从 文本编辑器中的菜单上下文调用删除操作, context 类型为 当前打开的文件的uri + * - 从树视图中调用删除操作, context 类型为 BookmarkTreeItem */ function deleteBookmarkCMD() { - registerCommand( - CMD_DELETE_BOOKMARK, - (context: LineBookmarkContext | BookmarksTreeItem) => { - const controller = resolveBookmarkController(); - if (!context || !controller) { - return; - } - // 从treeView中执行此命令 - if ('meta' in context && 'color' in context.meta) { - const _meta = context.meta as BookmarkMeta; - controller.remove(_meta.id); - return; - } - // 从`decoration`或者`command palette`那边删除调用此命令 - if (!('bookmarks' in context)) { - deleteBookmark(context as LineBookmarkContext); - } - }, - ); + registerCommand(CMD_DELETE_BOOKMARK, (context: LineBookmarkContext) => { + const controller = resolveBookmarkController(); + if (!controller) { + return; + } + + deleteBookmark(context); + }); } /** @@ -218,31 +207,29 @@ function deleteBookmarkCMD() { * - 如果不存在, 创建书签并追加label */ function editBookmark() { - registerCommand( - CMD_EDIT_LABEL, - async (context: LineBookmarkContext | BookmarksTreeItem | undefined) => { - let bookmark: BookmarkMeta | undefined = getBookmarkFromCtx(context); - - const label = await window.showInputBox({ - placeHolder: l10n.t('Type a label for your bookmarks'), - title: l10n.t( - 'Bookmark Label (Press `Enter` to confirm or press `Escape` to cancel)', - ), - value: bookmark?.label || '', + registerCommand(CMD_EDIT_LABEL, async (context: LineBookmarkContext) => { + let bookmark: IBookmark | undefined = getBookmarkFromCtx(context); + + const label = await window.showInputBox({ + placeHolder: l10n.t('Type a label for your bookmarks'), + title: l10n.t( + 'Bookmark Label (Press `Enter` to confirm or press `Escape` to cancel)', + ), + value: bookmark?.label || '', + }); + + if (!label) { + return; + } + if (!bookmark) { + toggleBookmark(context as LineBookmarkContext, { + label, + type: 'line', }); - if (!label) { - return; - } - if (!bookmark) { - toggleBookmark(context as LineBookmarkContext | undefined, { - label, - type: 'line', - }); - } else { - editBookmarkLabel(bookmark, label); - } - }, - ); + } else { + bookmark.updateLabel(label); + } + }); } /** @@ -289,8 +276,8 @@ function changeBookmarkColor() { // 改变书签颜色 registerCommand( CMD_CHANGE_BOOKMARK_COLOR, - async (ctx: LineBookmarkContext | BookmarksTreeItem | undefined) => { - let bookmark: BookmarkMeta | undefined = getBookmarkFromCtx(ctx); + async (ctx: LineBookmarkContext) => { + let bookmark: IBookmark | undefined = getBookmarkFromCtx(ctx); if (!bookmark) { window.showInformationMessage( l10n.t('Please select bookmark color'), @@ -307,8 +294,9 @@ function changeBookmarkColor() { if (!controller) { return; } - controller.update(bookmark.id, { - color: newColor, + bookmark.updateColor({ + ...bookmark.customColor, + name: newColor, }); }, ); @@ -318,8 +306,8 @@ function changeBookmarkColorName() { // 改变书签颜色 registerCommand( CMD_CHANGE_BOOKMARK_COLOR_NAME, - async (ctx: LineBookmarkContext | BookmarksTreeItem | undefined) => { - let bookmark: BookmarkMeta | undefined = getBookmarkColorFromCtx(ctx); + async (ctx: LineBookmarkContext) => { + let bookmark: IBookmark | undefined = getBookmarkColorFromCtx(ctx); if (!bookmark) { window.showInformationMessage( l10n.t('Please select bookmark color'), @@ -344,8 +332,9 @@ function changeBookmarkColorName() { if (!controller) { return; } - controller.updateGroupColorName(bookmark.color, { - color: newColorName, + bookmark.updateColor({ + ...bookmark.customColor, + name: newColorName, }); }, ); @@ -365,7 +354,9 @@ function clearAllBookmarksInCurrentFile() { controller.clearAllBookmarkInFile(args.meta.fileUri); } else { const activeEditor = window.activeTextEditor; - if (!activeEditor) {return;} + if (!activeEditor) { + return; + } if (checkIfBookmarksIsInCurrentEditor(activeEditor)) { controller.clearAllBookmarkInFile(activeEditor.document.uri); } @@ -377,33 +368,30 @@ function clearAllBookmarksInCurrentFile() { * 为书签增加备注信息 */ function addMoreMemo() { - registerCommand( - CMD_BOOKMARK_ADD_MORE_MEMO, - (ctx: LineBookmarkContext | BookmarksTreeItem | undefined) => { - let bookmark: BookmarkMeta | undefined = getBookmarkFromCtx(ctx); - if (!bookmark) { - window.showInformationMessage( - l10n.t('Please select the bookmark before proceeding.'), - {}, - ); - return; - } - window - .showInputBox({ - placeHolder: l10n.t('Type more info for your bookmarks'), - title: l10n.t( - 'Bookmark Label (Press `Enter` to confirm or press `Escape` to cancel)', - ), - }) - .then(description => { - if (!description) { - return; - } + registerCommand(CMD_BOOKMARK_ADD_MORE_MEMO, (ctx: LineBookmarkContext) => { + let bookmark: IBookmark | undefined = getBookmarkFromCtx(ctx); + if (!bookmark) { + window.showInformationMessage( + l10n.t('Please select the bookmark before proceeding.'), + {}, + ); + return; + } + window + .showInputBox({ + placeHolder: l10n.t('Type more info for your bookmarks'), + title: l10n.t( + 'Bookmark Label (Press `Enter` to confirm or press `Escape` to cancel)', + ), + }) + .then(description => { + if (!description) { + return; + } - editBookmarkDescription(bookmark!, description); - }); - }, - ); + bookmark!.updateDescription(description); + }); + }); } /** @@ -412,12 +400,12 @@ function addMoreMemo() { export function listBookmarksInCurrentFile() { registerCommand( 'listBookmarksInCurrentFile', - async (ctx: LineBookmarkContext | BookmarksTreeItem | undefined) => { + async (ctx: LineBookmarkContext) => { const editor = window.activeTextEditor; const controller = resolveBookmarkController(); const sm = resolveServiceManager(); - const bookmarkDS = controller.datastore; + const bookmarkDS = controller.store; if (!editor || !bookmarkDS) { return; } @@ -454,7 +442,7 @@ export function listBookmarksInCurrentFile() { placeHolder: l10n.t('Please select the bookmark you want to open'), canPickMany: false, ignoreFocusOut: false, - async onDidSelectItem(item: QuickPickItem & {meta: BookmarkMeta}) { + async onDidSelectItem(item: QuickPickItem & {meta: IBookmark}) { // @ts-ignore let bookmark = typeof item === 'object' ? item.meta : undefined; if (bookmark) { diff --git a/src/controllers/BookmarksController.ts b/src/controllers/BookmarksController.ts index 7c290e1..11f7406 100644 --- a/src/controllers/BookmarksController.ts +++ b/src/controllers/BookmarksController.ts @@ -4,7 +4,6 @@ import { ExtensionContext, FileSystemWatcher, Memento, - Selection, Uri, WorkspaceFolder, env, @@ -16,13 +15,11 @@ import path from 'node:path'; import fs from 'node:fs'; import {fileURLToPath} from 'node:url'; -import {IDisposable, generateUUID} from '../utils'; +import {IDisposable, log} from '../utils'; import {createHoverMessage, sortBookmarksByLineNumber} from '../utils/bookmark'; import { BookmarkColor, BookmarkManagerConfigure, - BookmarkMeta, - BookmarkStoreRootType, BookmarkStoreType, } from '../types'; import {EXTENSION_ID, EXTENSION_STORE_FILE_NAME} from '../constants'; @@ -34,9 +31,8 @@ import IController, { } from './IController'; import {registerExtensionCustomContextByKey} from '../context'; import ConfigService from '../services/ConfigService'; -import resolveServiceManager, { - ServiceManager, -} from '../services/ServiceManager'; +import {ServiceManager} from '../services/ServiceManager'; +import {BookmarksStore, IBookmark, IBookmarksStore} from '../stores/bookmark'; export type GroupedByFileType = BookmarkStoreType & { sortedIndex?: number; @@ -44,13 +40,13 @@ export type GroupedByFileType = BookmarkStoreType & { export type GroupedByColorType = { color: BookmarkColor; - bookmarks: BookmarkMeta[]; + bookmarks: IBookmark[]; sortedIndex?: number; }; export type GroupedByWorkspaceType = { workspace: WorkspaceFolder; - bookmarks: BookmarkMeta[]; + bookmarks: IBookmark[]; sortedIndex?: number; }; @@ -59,7 +55,7 @@ export default class BookmarksController implements IController { private _onDidChangeEvent = new EventEmitter(); - private _datastore!: BookmarkStoreRootType; + private _store!: IBookmarksStore; private _groupedByFile: GroupedByFileType[] = []; @@ -106,33 +102,33 @@ export default class BookmarksController implements IController { return this._context.workspaceState; } - public get datastore(): BookmarkStoreRootType | undefined { - return this._datastore; + public get store(): IBookmarksStore | undefined { + return this._store; } /** * 返回书签的总个数 */ public get totalCount(): number { - if (!this._datastore) { + if (!this._store) { return 0; } - return this._datastore.bookmarks.length; + return this._store.totalCount; } /** * 获取带有标签的书签 */ public get labeledCount(): number { - if (!this._datastore) { + if (!this._store) { return 0; } - return this._datastore.bookmarks.filter(it => it.label).length; + return this._store.labeledCount; } - constructor(context: ExtensionContext) { + constructor(context: ExtensionContext, serviceManager: ServiceManager) { this._context = context; - this._serviceManager = resolveServiceManager(); + this._serviceManager = serviceManager; this._configService = this._serviceManager.configService; this._configuration = this._configService.configuration; @@ -162,7 +158,7 @@ export default class BookmarksController implements IController { if (!ev.affectsConfiguration(`${EXTENSION_ID}.createJsonFile`)) { return; } - this._initialDatastore(); + this._initStore(); if (!this._configuration.createJsonFile) { this._watcher?.dispose(); } @@ -175,53 +171,29 @@ export default class BookmarksController implements IController { registerExtensionCustomContextByKey('code.view.groupView', this.groupView); - this._initialDatastore(); + this._initStore(); + this._initialWatcher(); } - private async _initialDatastore() { - let _datastore, _datastoreFromFile; - _datastoreFromFile = this._resolveDatastoreFromStoreFile() || { - bookmarks: [], - }; + private async _initStore() { + this._store = BookmarksStore.create(); + let store; + this._resolveDatastoreFromStoreFile(); + // 当从 `bookmark-manager.json`文件中读取, 直接刷新返回 if (this._configuration.createJsonFile) { - _datastore = _datastoreFromFile; - this._datastore = _datastore!; this.refresh(); } else { - _datastore = - _datastoreFromFile.bookmarks.length !== 0 - ? _datastoreFromFile - : this.workspaceState.get(EXTENSION_ID); - if (!_datastore) { - this._datastore = _datastoreFromFile; - this.save(this._datastore); - } else { - // 针对以前存在的书签, 进行扁平化成列表 - let _newDatastore: BookmarkStoreRootType = { - bookmarks: [], - }; - if (_datastore.data && _datastore.data.length) { - _newDatastore.bookmarks = this._flatToList(_datastore.data); - } else { - _newDatastore.bookmarks = ( - _datastore.data || - _datastore.bookmarks || - [] - ).map((it: any) => { - it.selection = new Selection( - it.selection.anchor, - it.selection.active, - ); - it.rangesOrOptions.hoverMessage = createHoverMessage( - it, - true, - true, - ); - return it; - }); + // 从state中读取数据 + store = this.workspaceState.get(EXTENSION_ID); + if (!store) { + store = this._store; + this.save(); + } else if (store.bookmarks && store.bookmarks.length) { + for (let bookmark of store.bookmarks) { + const _bookmark = this._store.createBookmark(bookmark); + this._store.add(_bookmark); } - this._datastore = _newDatastore; this.save(); } } @@ -245,13 +217,11 @@ export default class BookmarksController implements IController { '**/.vscode/bookmark-manager.json', ); this._watcher.onDidDelete(uri => { - this._datastore = { - bookmarks: [], - }; + this._store.clearAll(); this.save(); }); this._watcher.onDidChange(uri => { - this._datastore = this._resolveDatastoreFromStoreFile(); + this._resolveDatastoreFromStoreFile(); this._changeView(); this.refresh(); }); @@ -266,9 +236,6 @@ export default class BookmarksController implements IController { private _resolveDatastoreFromStoreFile() { let ws; const wsFolders = workspace.workspaceFolders || []; - const _datastore: BookmarkStoreRootType = { - bookmarks: [], - }; for (ws of wsFolders) { const storeFilePath = path.join( ws.uri.fsPath, @@ -279,24 +246,11 @@ export default class BookmarksController implements IController { JSON.parse(fs.readFileSync(storeFilePath).toString()) || {content: []} ).content; if (_bookmarks && _bookmarks.length) { - _datastore.bookmarks.push( - ..._bookmarks.map((it: any) => { - it.selection = new Selection( - it.selection.anchor, - it.selection.active, - ); - it.rangesOrOptions.hoverMessage = createHoverMessage( - it, - true, - true, - ); - return it; - }), - ); + this._store.addBookmarks(_bookmarks); } } } - return _datastore; + // return _datastore; } /** @@ -315,7 +269,7 @@ export default class BookmarksController implements IController { if (this.groupView === 'default') { this._groupedByFile = (this._getBookmarksGroupedByFile() || []).map( it => { - sortBookmarksByLineNumber(it.bookmarks); + it.bookmarks = sortBookmarksByLineNumber(it.bookmarks); return it; }, ); @@ -336,11 +290,11 @@ export default class BookmarksController implements IController { * @returns */ private _getBookmarksGroupedByColor() { - if (!this._datastore || !this._datastore.bookmarks.length) { + if (!this._store || !this._store.bookmarks.length) { return; } const groupedList: GroupedByColorType[] = []; - this._datastore.bookmarks.forEach(it => { + this._store.bookmarks.forEach(it => { const existed = groupedList.find(item => item.color === it.color); if (!existed) { groupedList.push({ @@ -359,12 +313,12 @@ export default class BookmarksController implements IController { * @returns */ private _getBookmarksGroupedByWorkspace() { - if (!this._datastore || !this._datastore.bookmarks.length) { + if (!this._store || !this._store.bookmarks.length) { return; } const grouped: GroupedByWorkspaceType[] = []; - this._datastore.bookmarks.forEach(it => { + this._store.bookmarks.forEach(it => { const existed = grouped.find( item => item.workspace.name === it.workspaceFolder?.name, ); @@ -384,75 +338,47 @@ export default class BookmarksController implements IController { this.sortedType = sortType; } - /** - * 将之前旧的数据转换成list - * @param arr - * @returns - */ - private _flatToList(arr: any[]) { - const newArr: any[] = []; - arr.forEach(store => { - const bookmarks = store.bookmarks.map((bookmark: any) => ({ - ...bookmark, - filename: store.filename, - fileId: store.id, - selection: new Selection( - bookmark.selection.anchor, - bookmark.selection.active, - ), - rangesOrOptions: { - ...bookmark.rangesOrOptions, - hoverMessage: createHoverMessage(bookmark, true, true), - }, - workspaceFolder: workspace.getWorkspaceFolder(store.fileUri), - })); - newArr.push(...bookmarks); - }); - return newArr; - } - - add(bookmark: Partial>) { + add(bookmark: Partial>) { // @ts-ignore - this._datastore.bookmarks.push({ - ...bookmark, - workspaceFolder: workspace.getWorkspaceFolder(bookmark.fileUri!), - id: generateUUID(), - }); + // this._store.bookmarks.push({ + // ...bookmark, + // workspaceFolder: workspace.getWorkspaceFolder(bookmark.fileUri!), + // }); + + const newBookmark = this._store.createBookmark(bookmark); + this._store.add(newBookmark); this.save(); } remove(id: string) { - const bookmarkIdx = this._datastore.bookmarks.findIndex(it => it.id === id); - if (bookmarkIdx === -1) { - return; + if (this._store.delete(id)) { + this.save(); } - this._datastore.bookmarks.splice(bookmarkIdx, 1); - this.save(); } - update(id: string, bookmarkDto: Partial>) { - let idx = this._datastore.bookmarks.findIndex(it => it.id === id); - if (idx === -1) { + update(id: string, bookmarkDto: Partial>) { + let existed = this._store.bookmarks.find(it => it.id === id); + if (!existed) { return; } - const existed = this._datastore.bookmarks[idx]; + const {rangesOrOptions, ...rest} = bookmarkDto; - this._datastore.bookmarks[idx] = { + existed.update({ ...existed, ...rest, rangesOrOptions: { - ...(existed.rangesOrOptions || {}), + ...existed.rangesOrOptions, ...rangesOrOptions, }, - } as BookmarkMeta; + }); this.save(); } updateGroupColorName( colorName: string, - bookmarkDto: Partial>, + bookmarkDto: Partial>, ) { - let sameColorBookmarks = this._datastore.bookmarks.filter( + let sameColorBookmarks = this._store.bookmarks.filter( it => it.color === colorName, ); const {rangesOrOptions, ...rest} = bookmarkDto; @@ -468,11 +394,11 @@ export default class BookmarksController implements IController { this.save(); } - getBookmarkStoreByFileUri(fileUri: Uri): BookmarkMeta[] { - if (!this._datastore) { + getBookmarkStoreByFileUri(fileUri: Uri): IBookmark[] { + if (!this._store) { return []; } - return this._datastore.bookmarks.filter(it => it.fileId === fileUri.fsPath); + return this._store.groupedByFile(fileUri); } /** @@ -492,16 +418,17 @@ export default class BookmarksController implements IController { * ] */ private _getBookmarksGroupedByFile() { - if (!this._datastore.bookmarks.length) { + if (!this._store.bookmarks.length) { return; } const groupedList: GroupedByFileType[] = []; - this._datastore.bookmarks.forEach(it => { + this._store.bookmarks.forEach(it => { const existed = groupedList.find(item => item.fileId === it.fileId); if (existed) { existed.bookmarks.push(it); - sortBookmarksByLineNumber(existed.bookmarks); } else { + const {fileId, fileName} = it; + groupedList.push({ fileId: it.fileId, // @ts-ignore @@ -511,13 +438,16 @@ export default class BookmarksController implements IController { }); } }); - return groupedList; + + return groupedList.map(it => ({ + ...it, + bookmarks: sortBookmarksByLineNumber(it.bookmarks), + })); } restore() { - this.save({ - bookmarks: [], - }); + this._store.clearAll(); + this.save(); } /** @@ -525,7 +455,7 @@ export default class BookmarksController implements IController { * 清除所有标签 */ clearAll() { - if (!this._datastore.bookmarks.length) { + if (!this._store.bookmarks.length) { return; } this.restore(); @@ -537,24 +467,22 @@ export default class BookmarksController implements IController { * @returns */ clearAllBookmarkInFile(fileUri: Uri) { - if (!this._datastore.bookmarks.length) { + if (!this._store.bookmarks.length) { return; } - this._datastore.bookmarks = this._datastore.bookmarks.filter( - it => it.fileId !== fileUri.fsPath, - ); + this._store.clearBookmarksByFile(fileUri.fsPath); this.save(); } - save(store?: BookmarkStoreRootType) { + save(store?: IBookmarksStore) { if (store) { - this._datastore = store; + this._store = store; } if (this._configuration.createJsonFile) { this._saveToDisk(); } else { - this.workspaceState.update(EXTENSION_ID, store || this._datastore); + this.workspaceState.update(EXTENSION_ID, store || this._store); } this._changeView(); this._fire(); @@ -565,7 +493,7 @@ export default class BookmarksController implements IController { * @param bookmark * @param label */ - editLabel(bookmark: BookmarkMeta, label: string) { + editLabel(bookmark: IBookmark, label: string) { bookmark.label = label; this.update(bookmark.id, { @@ -616,9 +544,15 @@ export default class BookmarksController implements IController { ? fileURLToPath(ws.uri.fsPath) : ws.uri.fsPath; + console.log( + !this._store.bookmarks.every( + it => it.workspaceFolder?.uri.fsPath === ws.uri.fsPath, + ), + ); + // 判断在对应的workspace文件夹中是否存在书签, 如果不存在, 不自动创建`bookmark-manager.json`文件 if ( - !this._datastore.bookmarks.every( + !this._store.bookmarks.every( it => it.workspaceFolder?.uri.fsPath === ws.uri.fsPath, ) ) { @@ -652,7 +586,7 @@ export default class BookmarksController implements IController { version: process.env.version, workspace: workspace.name, updatedDate: new Date().toLocaleDateString(), - content: this._datastore.bookmarks.filter( + content: this._store.bookmarks.filter( it => it.workspaceFolder?.uri.fsPath === workspace.uri.fsPath, ), }; @@ -673,7 +607,7 @@ export default class BookmarksController implements IController { } const ignoreContent = fs.readFileSync(ignoreFilePath, 'utf-8'); - const needWarning = this._needWarning && this.datastore?.bookmarks.length; + const needWarning = this._needWarning && this.store?.bookmarks.length; if ( !alwaysIgnore && @@ -692,7 +626,7 @@ export default class BookmarksController implements IController { return; } - if (!this._needWarning && this.datastore?.bookmarks.length) { + if (!this._needWarning && this.store?.bookmarks.length) { this._configService.updateGlobalValue('needWarning', true); this._needWarning = true; } @@ -709,7 +643,7 @@ export default class BookmarksController implements IController { } private _fire() { - if (!this._datastore) { + if (!this._store) { return; } this._onDidChangeEvent.fire(); diff --git a/src/controllers/IController.ts b/src/controllers/IController.ts index 972b21a..807ec31 100644 --- a/src/controllers/IController.ts +++ b/src/controllers/IController.ts @@ -1,6 +1,7 @@ import {Event, Disposable} from 'vscode'; import {BaseMeta, BookmarkStoreRootType} from '../types'; import {UniversalStoreType} from './UniversalBookmarkController'; +import {IBookmarksStore} from '../stores/bookmark'; /** * 视图查看方式 @@ -15,7 +16,7 @@ export type TreeViewSortedByType = 'linenumber' | 'custom' | 'time'; export type TreeGroupView = 'file' | 'color' | 'default' | 'workspace'; export default interface IController extends Disposable { - get datastore(): BookmarkStoreRootType | UniversalStoreType | undefined; + get store(): IBookmarksStore | UniversalStoreType | undefined; get totalCount(): number; diff --git a/src/controllers/UniversalBookmarkController.ts b/src/controllers/UniversalBookmarkController.ts index 85b09d4..459a289 100644 --- a/src/controllers/UniversalBookmarkController.ts +++ b/src/controllers/UniversalBookmarkController.ts @@ -6,9 +6,7 @@ import IController, { TreeGroupView, ViewType, } from './IController'; -import resolveServiceManager, { - ServiceManager, -} from '../services/ServiceManager'; +import {ServiceManager} from '../services/ServiceManager'; export const UNIVERSAL_STORE_KEY = 'bookmark-manager.universal'; export type UniversalBookmarkType = 'file' | 'link' | 'command' | 'code'; @@ -70,20 +68,20 @@ export default class UniversalBookmarkController implements IController { return this._context.globalState; } - get datastore(): UniversalStoreType | undefined { + get store(): UniversalStoreType | undefined { return this._datastore; } get totalCount(): number { - return this.datastore?.bookmarks.length || 0; + return this.store?.bookmarks.length || 0; } get labeledCount(): number { return 0; } - constructor(context: ExtensionContext) { + constructor(context: ExtensionContext, serviceManager: ServiceManager) { this._context = context; - this._serviceManager = resolveServiceManager(); + this._serviceManager = serviceManager; this._datastore = this._context.globalState.get(UNIVERSAL_STORE_KEY); if (!this._datastore) { @@ -117,43 +115,41 @@ export default class UniversalBookmarkController implements IController { add(bookmark: Omit) { const id = generateUUID(); - this.datastore!.bookmarks.push({ + this.store!.bookmarks.push({ id, ...bookmark, } as UniversalBookmarkMeta); this._save(); } remove(id: string) { - const idx = this.datastore?.bookmarks.findIndex(it => it.id === id); + const idx = this.store?.bookmarks.findIndex(it => it.id === id); if (idx === -1) { return; } - this.datastore!.bookmarks = this.datastore!.bookmarks.filter( - it => it.id !== id, - ); + this.store!.bookmarks = this.store!.bookmarks.filter(it => it.id !== id); this._save(); } update(id: string, bookmarkDto: Partial>) { - if (!this.datastore) { + if (!this.store) { return; } - const idx = this.datastore.bookmarks.findIndex(it => it.id === id); + const idx = this.store.bookmarks.findIndex(it => it.id === id); if (idx === -1) { return; } - const existed = this.datastore.bookmarks[idx]; - this.datastore.bookmarks[idx] = { + const existed = this.store.bookmarks[idx]; + this.store.bookmarks[idx] = { ...existed, ...bookmarkDto, } as UniversalBookmarkMeta; this._save(); } clearAll() { - if (!this.datastore) { + if (!this.store) { return; } - this.datastore.bookmarks = []; + this.store.bookmarks = []; this._save(); } save() { diff --git a/src/events.ts b/src/events.ts index 19c76cf..49d3a3d 100644 --- a/src/events.ts +++ b/src/events.ts @@ -11,10 +11,10 @@ import { getBookmarkFromLineNumber, updateBookmarksGroupByChangedLine, } from './utils/bookmark'; -import {BookmarkMeta} from './types'; import {registerExtensionCustomContextByKey} from './context'; import {resolveBookmarkController} from './bootstrap'; import resolveServiceManager from './services/ServiceManager'; +import {IBookmark} from './stores/bookmark'; let onDidChangeActiveTextEditor: Disposable | undefined; let onDidChangeVisibleTextEditors: Disposable | undefined; @@ -135,7 +135,7 @@ function updateLineBlame(editor: TextEditor, enableLineBlame: boolean) { } } -function buildLineBlameInfo(bookmark: BookmarkMeta) { +function buildLineBlameInfo(bookmark: IBookmark) { if (bookmark.label && bookmark.description) { return `${bookmark.label} - ${bookmark.description}`; } diff --git a/src/providers/BaseTreeProvider.ts b/src/providers/BaseTreeProvider.ts index 9738b72..d2cc76e 100644 --- a/src/providers/BaseTreeProvider.ts +++ b/src/providers/BaseTreeProvider.ts @@ -27,7 +27,7 @@ export default class BaseTreeProvider< private _serviceManager: ServiceManager; get datastore() { - return this._controller.datastore; + return this._controller.store; } get controller(): C { @@ -65,8 +65,10 @@ export default class BaseTreeProvider< // 当书签的数据发生变化时, 刷新 provider this._controller.onDidChangeEvent(() => { this.refresh(); - if (!this.controller.datastore) {return;} - const needClear = this.controller.datastore.bookmarks.length === 0; + if (!this.controller.store) { + return; + } + const needClear = this.controller.store.bookmarks.length === 0; this._serviceManager.decorationService.updateActiveEditorAllDecorations( needClear, ); diff --git a/src/providers/BookmarksTreeItem.ts b/src/providers/BookmarksTreeItem.ts index 68ddb6c..f91cf40 100644 --- a/src/providers/BookmarksTreeItem.ts +++ b/src/providers/BookmarksTreeItem.ts @@ -6,7 +6,7 @@ import { } from 'vscode'; import BaseTreeItem from './BaseTreeItem'; -import {BookmarkMeta, BookmarkStoreType} from '../types'; +import {BookmarkStoreType} from '../types'; import {getLineInfoStrFromBookmark} from '../utils'; import {CMD_GO_TO_SOURCE_LOCATION} from '../constants'; import { @@ -14,11 +14,12 @@ import { GroupedByWorkspaceType, } from '../controllers/BookmarksController'; import {ServiceManager} from '../services/ServiceManager'; +import {IBookmark} from '../stores/bookmark'; -export default class BookmarksTreeItem extends BaseTreeItem { +export default class BookmarkTreeItem extends BaseTreeItem { public meta: | BookmarkStoreType - | BookmarkMeta + | IBookmark | GroupedByColorType | GroupedByWorkspaceType; @@ -30,7 +31,7 @@ export default class BookmarksTreeItem extends BaseTreeItem { contextValue: string, meta: | BookmarkStoreType - | BookmarkMeta + | IBookmark | GroupedByColorType | GroupedByWorkspaceType, sm: ServiceManager, @@ -46,7 +47,7 @@ export default class BookmarksTreeItem extends BaseTreeItem { this.iconPath = ThemeIcon.Folder; this.resourceUri = (this.meta as GroupedByWorkspaceType).workspace.uri; } else if (this.contextValue === 'file') { - const _meta = this.meta as BookmarkMeta; + const _meta = this.meta as IBookmark; this._resolveFileOverview(); const filenameArr = _meta.fileName.split('\\'); this.label = filenameArr[filenameArr.length - 1]; @@ -74,7 +75,7 @@ export default class BookmarksTreeItem extends BaseTreeItem { const _meta = this.meta as GroupedByColorType; this.iconPath = (gutters[_meta.color] || gutters['default']).iconPath; } else if (this.contextValue === 'bookmark') { - const meta = this.meta as BookmarkMeta; + const meta = this.meta as IBookmark; this.iconPath = meta.label ? (tagGutters[meta.color] || tagGutters['default']).iconPath : (gutters[meta.color] || gutters['default']).iconPath; @@ -85,7 +86,7 @@ export default class BookmarksTreeItem extends BaseTreeItem { * 为书签创建 提示信息 */ private _createTooltips() { - const meta = this.meta as BookmarkMeta; + const meta = this.meta as IBookmark; const hoverMessage = meta.rangesOrOptions.hoverMessage as | MarkdownString | MarkdownString[] diff --git a/src/providers/BookmarksTreeProvider.ts b/src/providers/BookmarksTreeProvider.ts index 1bafb63..bae0490 100644 --- a/src/providers/BookmarksTreeProvider.ts +++ b/src/providers/BookmarksTreeProvider.ts @@ -1,12 +1,13 @@ -import BookmarksTreeItem from './BookmarksTreeItem'; +import BookmarkTreeItem from './BookmarksTreeItem'; import BaseTreeProvider from './BaseTreeProvider'; import {ProviderResult, Selection, TreeItemCollapsibleState} from 'vscode'; -import {BookmarkMeta, BookmarkStoreRootType, BookmarkStoreType} from '../types'; +import {BookmarkStoreRootType, BookmarkStoreType} from '../types'; import {resolveBookmarkController} from '../bootstrap'; import BookmarksController from '../controllers/BookmarksController'; +import {IBookmark} from '../stores/bookmark'; export class BookmarksTreeProvider extends BaseTreeProvider< - BookmarksTreeItem, + BookmarkTreeItem, BookmarksController > { constructor() { @@ -21,8 +22,8 @@ export class BookmarksTreeProvider extends BaseTreeProvider< * 显示列表数据展示格式 */ getChildren( - element?: BookmarksTreeItem | undefined, - ): ProviderResult { + element?: BookmarkTreeItem | undefined, + ): ProviderResult { if (this.controller.viewType === 'list') { return this.getChildrenByList(element); } @@ -42,14 +43,14 @@ export class BookmarksTreeProvider extends BaseTreeProvider< } } - getChildrenByFile(element?: BookmarksTreeItem | undefined) { + getChildrenByFile(element?: BookmarkTreeItem | undefined) { if (!element) { const bookmarkRootStoreArr = this.controller.groupedByFileBookmarks; const children = bookmarkRootStoreArr.map(it => { let label = this.isRelativePath ? this.getRelativePath(it.fileName) : it.fileName; - return new BookmarksTreeItem( + return new BookmarkTreeItem( label, TreeItemCollapsibleState.Collapsed, 'file', @@ -60,7 +61,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< return Promise.resolve(children); } - let children: BookmarksTreeItem[] = []; + let children: BookmarkTreeItem[] = []; try { children = (element.meta as BookmarkStoreType).bookmarks.map(it => { const selection = new Selection( @@ -68,7 +69,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< it.selection.active, ); - return new BookmarksTreeItem( + return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, 'bookmark', @@ -85,36 +86,36 @@ export class BookmarksTreeProvider extends BaseTreeProvider< } } - getChildrenByList(element?: BookmarksTreeItem | undefined) { + getChildrenByList(element?: BookmarkTreeItem | undefined) { if (!element) { - const children = ( - this.datastore as BookmarkStoreRootType - )?.bookmarks.map((it: BookmarkMeta) => { - const selection = new Selection( - it.selection.anchor, - it.selection.active, - ); + const children = (this.datastore as BookmarkStoreRootType)?.bookmarks.map( + (it: IBookmark) => { + const selection = new Selection( + it.selection.anchor, + it.selection.active, + ); - return new BookmarksTreeItem( - it.label || it.selectionContent || it.id, - TreeItemCollapsibleState.None, - 'bookmark', - { - ...it, - selection, - }, - this.serviceManager, - ); - }); + return new BookmarkTreeItem( + it.label || it.selectionContent || it.id, + TreeItemCollapsibleState.None, + 'bookmark', + { + ...it, + selection, + }, + this.serviceManager, + ); + }, + ); return Promise.resolve(children); } return Promise.resolve([]); } - getChildrenByColor(element?: BookmarksTreeItem | undefined) { + getChildrenByColor(element?: BookmarkTreeItem | undefined) { if (!element) { const store = this.controller.groupedByColorBookmarks; const children = store.map(it => { - return new BookmarksTreeItem( + return new BookmarkTreeItem( it.color, TreeItemCollapsibleState.Collapsed, 'color', @@ -125,7 +126,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< return Promise.resolve(children); } - let children: BookmarksTreeItem[] = []; + let children: BookmarkTreeItem[] = []; try { children = (element.meta as BookmarkStoreType).bookmarks.map(it => { const selection = new Selection( @@ -133,7 +134,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< it.selection.active, ); - return new BookmarksTreeItem( + return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, 'bookmark', @@ -150,11 +151,11 @@ export class BookmarksTreeProvider extends BaseTreeProvider< } } - getChildrenByWorkspace(element?: BookmarksTreeItem | undefined) { + getChildrenByWorkspace(element?: BookmarkTreeItem | undefined) { if (!element) { const store = this.controller.groupedByWorkspaceFolders; const children = store.map(it => { - return new BookmarksTreeItem( + return new BookmarkTreeItem( it.workspace.name, TreeItemCollapsibleState.Collapsed, 'workspace', @@ -165,7 +166,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< return Promise.resolve(children); } - let children: BookmarksTreeItem[] = []; + let children: BookmarkTreeItem[] = []; try { children = (element.meta as BookmarkStoreType).bookmarks.map(it => { const selection = new Selection( @@ -173,7 +174,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< it.selection.active, ); - return new BookmarksTreeItem( + return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, 'bookmark', diff --git a/src/services/DecorationService.ts b/src/services/DecorationService.ts index ce20601..c06a37d 100644 --- a/src/services/DecorationService.ts +++ b/src/services/DecorationService.ts @@ -6,17 +6,13 @@ import { l10n, window, } from 'vscode'; -import { - BookmarkColor, - BookmarkDecorationKey, - BookmarkMeta, - StringIndexType, -} from '../types'; +import {BookmarkColor, BookmarkDecorationKey, StringIndexType} from '../types'; import {IDisposable} from '../utils'; import resolveServiceManager, {ServiceManager} from './ServiceManager'; import {resolveBookmarkController} from '../bootstrap'; import BookmarksController from '../controllers/BookmarksController'; import logger from '../utils/logger'; +import {IBookmark} from '../stores/bookmark'; /** * 装饰器服务类 @@ -50,7 +46,7 @@ export default class DecorationService implements IDisposable { const configColors = configService.colors; const controller = resolveBookmarkController(); - const userColors = controller.datastore?.bookmarks.map(i => i.color) ?? []; + const userColors = controller.store?.bookmarks.map(i => i.color) ?? []; const allUsedColors = Array.from( new Set([...Object.keys(configColors), ...userColors]), ); @@ -178,7 +174,7 @@ export default class DecorationService implements IDisposable { * @param bookmarks * @returns */ - createRangeOrOptions(bookmarks: BookmarkMeta[]) { + createRangeOrOptions(bookmarks: IBookmark[]) { return bookmarks.map(bookmark => bookmark.rangesOrOptions); } @@ -191,7 +187,7 @@ export default class DecorationService implements IDisposable { editor: TextEditor, options: { color: BookmarkColor; - bookmarks: BookmarkMeta[]; + bookmarks: IBookmark[]; }, ) { try { diff --git a/src/stores/BookmarkManagerConfig.ts b/src/stores/BookmarkManagerConfig.ts new file mode 100644 index 0000000..5713e2a --- /dev/null +++ b/src/stores/BookmarkManagerConfig.ts @@ -0,0 +1,14 @@ +import {Instance, types} from 'mobx-state-tree'; + +const BookmarkManagerConfigureModel = types + .model('BookmarkManagerConfigureModel', {}) + .views(self => { + return {}; + }) + .actions(self => { + return {}; + }); + +export type BookmarkManagerConfigure = Instance< + typeof BookmarkManagerConfigureModel +>; diff --git a/src/stores/DecorationOptions.ts b/src/stores/DecorationOptions.ts new file mode 100644 index 0000000..280efa0 --- /dev/null +++ b/src/stores/DecorationOptions.ts @@ -0,0 +1,76 @@ +import {Instance, types} from 'mobx-state-tree'; +import {workspace} from 'vscode'; +import {EXTENSION_ID} from '../constants'; + +const CreateDecorationOptionsModel = types + .model('CreateDecorationOptionsModel', { + /** + * 是否在行号出现时指示图标 + */ + showGutterIcon: types.optional(types.boolean, true), + /** + * 是否在游标卡尺显示 gutter 图标所在位置, 默认颜色跟随书签选择的样式 + */ + showGutterInOverviewRuler: types.optional(types.boolean, false), + /** + * 是否显示书签样式 + */ + showTextDecoration: types.optional(types.boolean, false), + /** + * 是否使用默认样式 + */ + alwaysUseDefaultColor: types.optional(types.boolean, false), + /** + * 书签装饰器的字体样式 + */ + fontWeight: types.enumeration(['normal', 'bold', 'bolder', 'unset']), + /** + * 是否选择整行, 否则仅为存在文本字段的区域选择 + */ + wholeLine: types.optional(types.boolean, true), + /** + * 书签装饰器下划线的样式 + */ + textDecorationLine: types.optional(types.string, ''), + /** + * 书签装饰器样式 + */ + textDecorationStyle: types.optional(types.string, ''), + /** + * 书签装饰器的`tickness`样式 + */ + textDecorationThickness: types.optional(types.string, ''), + /** + * 高亮背景行 + */ + highlightBackground: types.optional(types.boolean, false), + /** + * 是否显示书签装饰器的外边框 + */ + showBorder: types.optional(types.boolean, false), + /** + * 书签装饰器的外边框样式 + */ + border: types.optional(types.string, ''), + /** + * 是否显示书签装饰器的轮廓 + */ + showOutline: types.optional(types.boolean, false), + /** + * 书签装饰器的轮廓样式 + */ + outline: types.optional(types.string, ''), + }) + .views(self => { + return {}; + }) + .actions(self => { + function afterCreate() { + const wsConfiguration = workspace.getConfiguration(EXTENSION_ID); + } + return {afterCreate}; + }); + +export type CreateDecorationOptions = Instance< + typeof CreateDecorationOptionsModel +>; diff --git a/src/stores/bookmark.ts b/src/stores/bookmark.ts new file mode 100644 index 0000000..a7ba40b --- /dev/null +++ b/src/stores/bookmark.ts @@ -0,0 +1,373 @@ +import {Instance, destroy, onSnapshot, types} from 'mobx-state-tree'; +import {DEFAULT_BOOKMARK_COLOR} from '../constants'; +import { + DecorationOptions, + Range, + Selection, + Uri, + WorkspaceFolder, +} from 'vscode'; +import {createHoverMessage, generateUUID} from '../utils'; +import {resolveBookmarkController} from '../bootstrap'; + +type SortedType = { + /** + * 表示文件/工作区间的排序索引 + */ + sortedIndex?: number; + /** + * 当按照文件/工作区分组的时, 书签的顺序索引 + */ + bookmarkSortedIndex?: number; +}; + +type MyUri = Uri & SortedType; + +type MyWorkspaceFolder = WorkspaceFolder & SortedType; + +type MyColor = { + name: string; +} & SortedType; + +type MyTag = SortedType & { + name: string; +}; + +const TagType = types.custom({ + name: 'MyTag', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value: MyTag) { + return value; + }, + isTargetType(value: MyTag | any): boolean { + return true; + }, + getValidationMessage(value: MyTag): string { + return ''; + }, +}); + +const MyUriType = types.custom({ + name: 'MyUri', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value: Uri) { + return value; + }, + isTargetType(value: Uri | any): boolean { + return true; + }, + getValidationMessage(value: Uri): string { + return ''; + }, +}); + +export type IMyUriType = Instance; + +const MyWorkspaceFolderType = types.custom< + MyWorkspaceFolder, + MyWorkspaceFolder +>({ + name: 'MyWorkspaceFolder', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); + +export type IMyWorkspaceFolderType = Instance; + +const RangType = types.custom({ + name: 'RangeType', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + if (!snapshot) {return 'Invalid rangesOrOptions';} + return ''; + }, +}); + +export type IRangeType = Instance; + +const DecorationOptionsType = types.custom< + DecorationOptions, + DecorationOptions +>({ + name: 'DecorationOptions', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); +export type IDecorationOptionsType = Instance; + +const MyColorType = types.custom({ + name: 'MyColor', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); + +export type IMyColorType = Instance; + +const MySelectionType = types.custom({ + name: 'Selection', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); + +export type IMySelectionType = Instance; + +export const Bookmark = types + .model('Boomkmark', { + id: types.string, + label: types.optional(types.string, ''), + description: types.optional(types.string, ''), + customColor: types.optional(MyColorType, { + name: DEFAULT_BOOKMARK_COLOR, + sortedIndex: -1, + bookmarkSortedIndex: -1, + }), + fileUri: MyUriType, + type: types.optional(types.enumeration(['line', 'selection']), 'line'), + selectionContent: types.optional(types.string, ''), + languageId: types.optional(types.string, 'javascript'), + workspaceFolder: types.maybeNull(MyWorkspaceFolderType), + rangesOrOptions: DecorationOptionsType, + createdAt: types.optional(types.Date, () => new Date()), + tag: types.optional(TagType, { + name: 'defaul', + sortedIndex: -1, + bookmarkSortedIndex: -1, + }), + }) + .views(self => { + return { + get fileId() { + return self.fileUri.fsPath; + }, + get fileName() { + return self.fileUri.fsPath; + }, + get color() { + return self.customColor.name; + }, + get selection() { + const {start, end} = self.rangesOrOptions.range; + return new Selection( + start.line, + start.character, + end.line, + end.character, + ); + }, + }; + }) + .actions(self => { + function update(bookmarkDto: Partial>) { + Object.keys(bookmarkDto).forEach(it => { + // @ts-ignore + if (bookmarkDto[it]) { + // @ts-ignore + self[it] = bookmarkDto[it]; + } + }); + } + function updateLabel(label: string) { + self.label = label; + } + function updateDescription(desc: string) { + self.description = desc; + } + + function updateRangesOrOptions(rangesOrOptions: IDecorationOptionsType) { + self.rangesOrOptions = rangesOrOptions; + } + + function updateColor(newColor: IMyColorType) { + self.customColor = newColor; + } + return { + update, + updateLabel, + updateDescription, + updateRangesOrOptions, + updateColor, + }; + }); + +export const BookmarksStore = types + .model('BookmarksStore', { + bookmarks: types.optional(types.array(Bookmark), []), + viewType: types.optional(types.enumeration(['tree', 'list']), 'tree'), + groupView: types.optional( + types.enumeration(['file', 'color', 'default', 'workspace']), + 'file', + ), + sortedType: types.optional( + types.enumeration(['linenumber', 'custom', 'time']), + 'linenumber', + ), + }) + .views(self => { + return { + groupedByFile(fileUri: Uri) { + const arr = []; + return self.bookmarks.filter( + it => it.fileUri.fsPath === fileUri.fsPath, + ); + }, + groupedByColor(color: IMyColorType) { + return self.bookmarks.filter(it => it.color === color.name); + }, + get totalCount() { + return self.bookmarks.length; + }, + get labeledCount() { + return self.bookmarks.filter(it => it.label.length).length; + }, + get colors() { + return self.bookmarks.map(it => it.color); + }, + }; + }) + .actions(self => { + function createBookmark(bookmark: any) { + let _bookmark; + const { + id, + label, + description, + type, + selectionContent, + languageId, + workspaceFolder, + rangesOrOptions, + createdAt, + fileUri, + } = bookmark; + + const customColor = bookmark.customColor + ? MyColorType.create({...bookmark.customColor}) + : MyColorType.create({ + name: bookmark.color, + sortedIndex: -1, + bookmarkSortedIndex: -1, + }); + rangesOrOptions.hoverMessage = createHoverMessage(bookmark, true, true); + _bookmark = Bookmark.create({ + id: id || generateUUID(), + label, + description, + customColor, + fileUri: MyUriType.create(fileUri), + type, + selectionContent, + languageId, + workspaceFolder: MyWorkspaceFolderType.create({...workspaceFolder}), + rangesOrOptions: DecorationOptionsType.create({ + ...rangesOrOptions, + }), + + createdAt, + }); + return _bookmark; + } + function add(bookmark: IBookmark) { + if (self.bookmarks.find(it => it.id === bookmark.id)) { + return; + } + self.bookmarks.push(bookmark); + } + return { + add, + addBookmarks(bookmarks: any[]) { + let _bookmark; + for (let bookmark of bookmarks) { + _bookmark = createBookmark(bookmark); + add(_bookmark); + } + }, + createBookmark, + delete(id: string) { + const idx = self.bookmarks.findIndex(it => it.id === id); + if (idx === -1) {return false;} + self.bookmarks.splice(idx, 1); + return true; + }, + update(id: string, dto: Partial) { + const bookmark = self.bookmarks.find(it => it.id === id); + if (!bookmark) { + return; + } + Object.keys(dto).forEach(key => { + // @ts-ignore + if (dto[key]) { + // @ts-ignore + bookmark[key] = dto[key]; + } + }); + }, + clearBookmarksByFile(fileName: string) { + const deleteItems = self.bookmarks.filter( + it => it.fileUri.fsPath === fileName, + ); + for (let item of deleteItems) { + self.bookmarks.remove(item); + } + }, + clearByColor(color: string) {}, + clearAll() { + self.bookmarks.clear(); + }, + }; + }); + +export type IBookmark = Instance; + +export type IBookmarksStore = Instance; diff --git a/src/stores/index.ts b/src/stores/index.ts new file mode 100644 index 0000000..40c651e --- /dev/null +++ b/src/stores/index.ts @@ -0,0 +1 @@ +export default function initialStore() {} diff --git a/src/types/code.ts b/src/types/code.ts index 12d26fa..987eae7 100644 --- a/src/types/code.ts +++ b/src/types/code.ts @@ -1,24 +1,8 @@ import {DecorationOptions, Selection, Uri, WorkspaceFolder} from 'vscode'; import {BaseMeta, BookmarkColor} from './common'; +import {IBookmark} from '../stores/bookmark'; export type BookmarkDecorationKey = string | 'default'; -export interface BookmarkMeta extends BaseMeta { - id: string; - fileId: string; - fileName: string; - fileUri: Uri; - type: 'line' | 'selection'; - color: BookmarkColor; - selection: Selection; - label?: string; - selectionContent?: string; - description?: string; - languageId?: string; - tag?: string; - workspaceFolder?: WorkspaceFolder; - rangesOrOptions: DecorationOptions; -} - /** * 根据文件名来分组 * ```json @@ -37,7 +21,7 @@ export type BookmarkStoreType = { fileId: string; fileUri: Uri; fileName: string; - bookmarks: BookmarkMeta[]; + bookmarks: IBookmark[]; }; /** @@ -50,5 +34,5 @@ export type BookmarkStoreType = { * ``` */ export type BookmarkStoreRootType = { - bookmarks: BookmarkMeta[]; + bookmarks: IBookmark[]; }; diff --git a/src/types/common.ts b/src/types/common.ts index 85d9025..5e7991f 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -1,4 +1,5 @@ import {Uri} from 'vscode'; +import BookmarkTreeItem from '../providers/BookmarksTreeItem'; export type StringIndexType = {[key: string]: T}; export type BookmarkColor = string | 'none'; @@ -7,11 +8,11 @@ export interface BaseMeta { id: string; label?: string; color: BookmarkColor; - sortedIndex?: number; } export type LineBookmarkContext = + | BookmarkTreeItem | Uri | {uri: Uri; lineNumber: number} | undefined; diff --git a/src/utils/bookmark.ts b/src/utils/bookmark.ts index e762f81..b432b75 100644 --- a/src/utils/bookmark.ts +++ b/src/utils/bookmark.ts @@ -14,10 +14,11 @@ import { TextDocumentChangeEvent, l10n, } from 'vscode'; -import {BookmarkMeta, LineBookmarkContext} from '../types'; +import {LineBookmarkContext} from '../types'; import {resolveBookmarkController} from '../bootstrap'; import resolveServiceManager from '../services/ServiceManager'; import {defaultColors} from '../constants/colors'; +import {IBookmark} from '../stores/bookmark'; const REGEXP_NEWLINE = /(\r\n)|(\n)/g; /** @@ -63,7 +64,7 @@ export function checkIfBookmarksIsInCurrentEditor(editor: TextEditor) { */ export function getBookmarkFromLineNumber( line?: number, -): BookmarkMeta | undefined { +): IBookmark | undefined { const editor = window.activeTextEditor; const controller = resolveBookmarkController(); if (!editor) { @@ -103,7 +104,7 @@ export function getBookmarkFromLineNumber( */ export function getBookmarksBelowChangedLine( line?: number, -): BookmarkMeta[] | undefined { +): IBookmark[] | undefined { const editor = window.activeTextEditor; const controller = resolveBookmarkController(); if (!editor) { @@ -150,7 +151,7 @@ export function highlightSelection( * 调转到对应的书签所在地,并进行高亮选区 * @param bookmark */ -export async function gotoSourceLocation(bookmark?: BookmarkMeta) { +export async function gotoSourceLocation(bookmark?: IBookmark) { if (!bookmark) { return; } @@ -216,7 +217,7 @@ export async function openDocumentAndGotoLocation(fileUri: Uri, range: Range) { * @param bookmark * @param memo */ -export function editBookmarkDescription(bookmark: BookmarkMeta, memo: string) { +export function editBookmarkDescription(bookmark: IBookmark, memo: string) { bookmark.description = memo; const controller = resolveBookmarkController(); controller.update(bookmark.id, { @@ -228,7 +229,7 @@ export function editBookmarkDescription(bookmark: BookmarkMeta, memo: string) { }); } -export function editBookmarkLabel(bookmark: BookmarkMeta, label: string) { +export function editBookmarkLabel(bookmark: IBookmark, label: string) { const controller = resolveBookmarkController(); controller.editLabel(bookmark, label); } @@ -251,7 +252,7 @@ export async function toggleBookmarksWithSelections(label: string) { * @returns */ export async function toggleBookmark( - context: LineBookmarkContext | undefined, + context: LineBookmarkContext, extra: { type: 'line' | 'selection'; label?: string; @@ -280,7 +281,7 @@ export async function toggleBookmark( return; } - const {type: bookmarkType, label, withColor = false} = extra; + const {type: bookmarkType, label = '', withColor = false} = extra; let range, selectionContent; const activeLine = editor.document.lineAt(selection.active.line); @@ -317,11 +318,16 @@ export async function toggleBookmark( } } const fileUri = editor.document.uri; - const bookmark: Omit = { + + const bookmark: any = { type: bookmarkType, label, - color: chosenColor, - selection: range, + customColor: { + name: chosenColor, + sortedIndex: -1, + bookmarkSortedIndex: -1, + }, + description: '', fileUri: editor.document.uri, languageId: editor.document.languageId, selectionContent, @@ -334,6 +340,7 @@ export async function toggleBookmark( after: {}, }, }, + workspaceFolder: workspace.getWorkspaceFolder(editor.document.uri!)!, }; bookmark.rangesOrOptions.hoverMessage = createHoverMessage( @@ -348,22 +355,38 @@ export async function toggleBookmark( * @param context * @returns */ -export function deleteBookmark(context: LineBookmarkContext) { +export function deleteBookmark(context?: LineBookmarkContext) { const editor = window.activeTextEditor; const controller = resolveBookmarkController(); - if (!context || !editor || !controller) { - return; + let _lineNumber = -1, + bookmark: IBookmark | undefined; + + // 从 `command palette` 中调用删除操作 + if (!context) { + if (!editor) {return;} + _lineNumber = editor.selection.active.line; + } else { + // 从打开的文本编辑器的菜单中调用 + if ('scheme' in context && context.scheme === 'file' && editor) { + _lineNumber = editor.selection.active.line; + } + + // 树视图中调用删除命令 + if ('meta' in context) { + bookmark = context.meta as IBookmark; + } + + // 从装饰器上调用 + if ('lineNumber' in context) { + _lineNumber = context.lineNumber - 1; + } } - // 获取当前行所在的`bookmark`信息 - const bookmark = getBookmarkFromLineNumber( - 'lineNumber' in context - ? context.lineNumber - 1 - : editor.selection.active.line, - ); - if (!bookmark) { - return; + if (_lineNumber !== -1) { + bookmark = getBookmarkFromLineNumber(_lineNumber); } + if (!bookmark) {return;} + controller.remove(bookmark.id); } @@ -402,7 +425,7 @@ export async function chooseBookmarkColor() { } const controller = resolveBookmarkController(); - const userColors = controller.datastore?.bookmarks.map(i => i.color) ?? []; + const userColors = controller.store!.colors; const allUsedColors = Array.from( new Set([...Object.keys(colors), ...userColors]), @@ -434,11 +457,11 @@ export async function quicklyJumpToBookmark() { const sm = resolveServiceManager(); const gutters = sm.gutterService.gutters; const tagGutters = sm.gutterService.tagGutters; - if (!controller || !controller.datastore) { + if (!controller || !controller.store) { return; } - const pickItems = controller.datastore.bookmarks.map(it => { + const pickItems = controller.store.bookmarks.map(it => { const iconPath = it.label ? (tagGutters[it.color] || tagGutters['default']).iconPath : (gutters[it.color] || (tagGutters['default'] as any)).iconPath; @@ -451,7 +474,8 @@ export async function quicklyJumpToBookmark() { iconPath: iconPath as any, meta: { ...it, - selection: new Selection(it.selection.anchor, it.selection.active), + // TODO:delete + // selection: new Selection(it.selection.anchor, it.selection.active), }, }; }); @@ -460,7 +484,7 @@ export async function quicklyJumpToBookmark() { placeHolder: l10n.t('Please select the bookmark you want to open'), canPickMany: false, ignoreFocusOut: false, - async onDidSelectItem(item: QuickPickItem & {meta: BookmarkMeta}) { + async onDidSelectItem(item: QuickPickItem & {meta: IBookmark}) { // @ts-ignore let bookmark = typeof item === 'object' ? item.meta : undefined; if (bookmark) { @@ -495,7 +519,7 @@ export async function quicklyJumpToBookmark() { * @returns */ export function createHoverMessage( - bookmark: Omit, + bookmark: Omit, showExtIcon: boolean = false, isRestore: boolean = false, ) { @@ -521,7 +545,7 @@ export function createHoverMessage( } function appendMarkdown( - bookmark: Omit, + bookmark: Omit, markdownString: MarkdownString, showExtIcon: boolean = false, ) { @@ -535,7 +559,7 @@ function appendMarkdown( } if (bookmark.selectionContent) { const code = resolveMarkdownLineNumber( - bookmark.selection, + bookmark.rangesOrOptions.range, bookmark.selectionContent, ); markdownString.appendCodeblock(code, bookmark.languageId || 'javascript'); @@ -762,7 +786,7 @@ export function updateLineBookmarkRangeWhenDocumentChange( * @param bookmark * @returns */ -export function getLineInfoFromBookmark(bookmark: BookmarkMeta) { +export function getLineInfoFromBookmark(bookmark: IBookmark) { const {start, end} = bookmark.selection; if (bookmark.type === 'line') { return { @@ -779,7 +803,7 @@ export function getLineInfoFromBookmark(bookmark: BookmarkMeta) { } } -export function getLineInfoStrFromBookmark(bookmark: BookmarkMeta) { +export function getLineInfoStrFromBookmark(bookmark: IBookmark) { const lineInfo = getLineInfoFromBookmark(bookmark); return bookmark.type === 'line' ? `Ln: ${lineInfo.line}` @@ -790,8 +814,10 @@ export function getLineInfoStrFromBookmark(bookmark: BookmarkMeta) { * 对书签进行按照行号排序 * @param bookmarks */ -export function sortBookmarksByLineNumber(bookmarks: BookmarkMeta[]) { - bookmarks.sort((a, b) => a.selection.start.line - b.selection.start.line); +export function sortBookmarksByLineNumber(bookmarks: IBookmark[]) { + return bookmarks.sort( + (a, b) => a.selection.start.line - b.selection.start.line, + ); } export function getBookmarksFromFileUri(uri: Uri) { diff --git a/src/views/BookmarksTreeView.ts b/src/views/BookmarksTreeView.ts index e9685f5..b5d59ae 100644 --- a/src/views/BookmarksTreeView.ts +++ b/src/views/BookmarksTreeView.ts @@ -1,11 +1,11 @@ import {EXTENSION_VIEW_ID} from '../constants'; -import BookmarksTreeItem from '../providers/BookmarksTreeItem'; +import BookmarkTreeItem from '../providers/BookmarksTreeItem'; import BaseTreeView, {TreeViewEnum} from './BaseTreeView'; import {BookmarksTreeProvider} from '../providers/BookmarksTreeProvider'; import BookmarksController from '../controllers/BookmarksController'; export class BookmarksTreeView extends BaseTreeView< - BookmarksTreeItem, + BookmarkTreeItem, BookmarksController > { type: TreeViewEnum = TreeViewEnum.CODE; diff --git a/yarn.lock b/yarn.lock index 30e6da8..8d3af0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2904,6 +2904,16 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== +mobx-state-tree@^5.4.1: + version "5.4.1" + resolved "https://registry.npmmirror.com/mobx-state-tree/-/mobx-state-tree-5.4.1.tgz#97182a1e2587db5ff7a2b5f11ac6971e50498aed" + integrity sha512-eEBmfeYzbNSbNsdM+T1pchuOykZXT50B7eCXgf0E0O/jad/cigu4heBB9RwxzzyD/QGrXBPVctKYLypVXNHt3Q== + +mobx@^6.12.0: + version "6.12.0" + resolved "https://registry.npmmirror.com/mobx/-/mobx-6.12.0.tgz#72b2685ca5af031aaa49e77a4d76ed67fcbf9135" + integrity sha512-Mn6CN6meXEnMa0a5u6a5+RKrqRedHBhZGd15AWLk9O6uFY4KYHzImdt8JI8WODo1bjTSRnwXhJox+FCUZhCKCQ== + mocha@^10.2.0: version "10.2.0" resolved "https://registry.npmmirror.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" From 57b7390707d326ee77182f59de5a8676e52a8afe Mon Sep 17 00:00:00 2001 From: abchen Date: Fri, 15 Mar 2024 11:30:25 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0mst,=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?mobx=E6=94=B9=E9=80=A0BookmarkController?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/bookmark-manager.json | 1 - package.json | 2 +- src/commands/code.ts | 6 +- src/controllers/BookmarksController.ts | 200 +++------------ src/events.ts | 21 +- src/providers/BookmarksTreeItem.ts | 31 ++- src/providers/BookmarksTreeProvider.ts | 77 +++--- src/stores/bookmark.ts | 234 +++++++++++++++--- ...{BookmarkManagerConfig.ts => configure.ts} | 0 src/types/code.ts | 6 +- src/utils/bookmark.ts | 69 ++---- 11 files changed, 324 insertions(+), 323 deletions(-) delete mode 100644 .vscode/bookmark-manager.json rename src/stores/{BookmarkManagerConfig.ts => configure.ts} (100%) diff --git a/.vscode/bookmark-manager.json b/.vscode/bookmark-manager.json deleted file mode 100644 index 6562432..0000000 --- a/.vscode/bookmark-manager.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"0.0.26","workspace":"bookmarks","updatedDate":"3/14/2024","content":[{"type":"line","color":"default","selection":{"start":{"line":3,"character":0},"end":{"line":3,"character":55},"active":{"line":3,"character":55},"anchor":{"line":3,"character":0}},"fileUri":{"$mid":1,"fsPath":"d:\\projects\\myrepo\\bookmarks\\src\\types\\code.ts","_sep":1,"external":"file:///d%3A/projects/myrepo/bookmarks/src/types/code.ts","path":"/d:/projects/myrepo/bookmarks/src/types/code.ts","scheme":"file"},"languageId":"typescript","selectionContent":"export type BookmarkDecorationKey = string | 'default';","fileId":"d:\\projects\\myrepo\\bookmarks\\src\\types\\code.ts","fileName":"d:\\projects\\myrepo\\bookmarks\\src\\types\\code.ts","rangesOrOptions":{"range":{"start":{"line":3,"character":0},"end":{"line":3,"character":55},"active":{"line":3,"character":55},"anchor":{"line":3,"character":0}},"hoverMessage":{},"renderOptions":{"after":{}}},"workspaceFolder":{"uri":{"$mid":1,"fsPath":"d:\\projects\\myrepo\\bookmarks","_sep":1,"external":"file:///d%3A/projects/myrepo/bookmarks","path":"/d:/projects/myrepo/bookmarks","scheme":"file"},"name":"bookmarks","index":0},"id":"f6316f9b-cd63-4210-9997-a2406b916b6c"}]} \ No newline at end of file diff --git a/package.json b/package.json index a3a8bf1..e7e9c29 100644 --- a/package.json +++ b/package.json @@ -492,7 +492,7 @@ }, { "command": "bookmark-manager.clearAllBookmarksInCurrentFile", - "when": "view == bookmark-manager && viewItem === file", + "when": "view == bookmark-manager && (viewItem === file || viewItem === workspace)", "group": "inline@2" }, { diff --git a/src/commands/code.ts b/src/commands/code.ts index fbfda1c..636e661 100644 --- a/src/commands/code.ts +++ b/src/commands/code.ts @@ -209,7 +209,6 @@ function deleteBookmarkCMD() { function editBookmark() { registerCommand(CMD_EDIT_LABEL, async (context: LineBookmarkContext) => { let bookmark: IBookmark | undefined = getBookmarkFromCtx(context); - const label = await window.showInputBox({ placeHolder: l10n.t('Type a label for your bookmarks'), title: l10n.t( @@ -217,12 +216,11 @@ function editBookmark() { ), value: bookmark?.label || '', }); - if (!label) { return; } if (!bookmark) { - toggleBookmark(context as LineBookmarkContext, { + toggleBookmark(context as LineBookmarkContext | undefined, { label, type: 'line', }); @@ -447,7 +445,7 @@ export function listBookmarksInCurrentFile() { let bookmark = typeof item === 'object' ? item.meta : undefined; if (bookmark) { const doc = await workspace.openTextDocument( - Uri.parse(bookmark.fileUri.path), + Uri.parse(bookmark.fileName), ); const editor = await window.showTextDocument(doc, { preview: true, diff --git a/src/controllers/BookmarksController.ts b/src/controllers/BookmarksController.ts index 11f7406..f0ad36d 100644 --- a/src/controllers/BookmarksController.ts +++ b/src/controllers/BookmarksController.ts @@ -15,13 +15,9 @@ import path from 'node:path'; import fs from 'node:fs'; import {fileURLToPath} from 'node:url'; -import {IDisposable, log} from '../utils'; -import {createHoverMessage, sortBookmarksByLineNumber} from '../utils/bookmark'; -import { - BookmarkColor, - BookmarkManagerConfigure, - BookmarkStoreType, -} from '../types'; +import {IDisposable} from '../utils'; +import {sortBookmarksByLineNumber} from '../utils/bookmark'; +import {BookmarkManagerConfigure} from '../types'; import {EXTENSION_ID, EXTENSION_STORE_FILE_NAME} from '../constants'; import IController, { @@ -32,23 +28,15 @@ import IController, { import {registerExtensionCustomContextByKey} from '../context'; import ConfigService from '../services/ConfigService'; import {ServiceManager} from '../services/ServiceManager'; -import {BookmarksStore, IBookmark, IBookmarksStore} from '../stores/bookmark'; - -export type GroupedByFileType = BookmarkStoreType & { - sortedIndex?: number; -}; - -export type GroupedByColorType = { - color: BookmarkColor; - bookmarks: IBookmark[]; - sortedIndex?: number; -}; - -export type GroupedByWorkspaceType = { - workspace: WorkspaceFolder; - bookmarks: IBookmark[]; - sortedIndex?: number; -}; +import { + BookmarksStore, + GroupedByColorType, + GroupedByFileType, + GroupedByWorkspaceType, + IBookmark, + IBookmarksStore, +} from '../stores/bookmark'; +import {IDisposer, onSnapshot} from 'mobx-state-tree'; export default class BookmarksController implements IController { private _context: ExtensionContext; @@ -84,6 +72,8 @@ export default class BookmarksController implements IController { */ private _needWarning: boolean = true; + private _storeDisposer: IDisposer | undefined; + public onDidChangeEvent: Event = this._onDidChangeEvent.event; public get groupedByFileBookmarks(): GroupedByFileType[] { @@ -178,25 +168,26 @@ export default class BookmarksController implements IController { private async _initStore() { this._store = BookmarksStore.create(); + let store; this._resolveDatastoreFromStoreFile(); // 当从 `bookmark-manager.json`文件中读取, 直接刷新返回 - if (this._configuration.createJsonFile) { - this.refresh(); - } else { + if (!this._configuration.createJsonFile) { // 从state中读取数据 store = this.workspaceState.get(EXTENSION_ID); if (!store) { store = this._store; - this.save(); } else if (store.bookmarks && store.bookmarks.length) { for (let bookmark of store.bookmarks) { const _bookmark = this._store.createBookmark(bookmark); this._store.add(_bookmark); } - this.save(); } } + + this._storeDisposer = onSnapshot(this._store, snapshot => { + this.save(); + }); this._changeView(); } @@ -218,7 +209,6 @@ export default class BookmarksController implements IController { ); this._watcher.onDidDelete(uri => { this._store.clearAll(); - this.save(); }); this._watcher.onDidChange(uri => { this._resolveDatastoreFromStoreFile(); @@ -250,7 +240,6 @@ export default class BookmarksController implements IController { } } } - // return _datastore; } /** @@ -259,28 +248,14 @@ export default class BookmarksController implements IController { private _changeView() { if (this.viewType === 'tree') { if (this.groupView === 'color') { - this._groupedByColor = (this._getBookmarksGroupedByColor() || []).map( - it => { - sortBookmarksByLineNumber(it.bookmarks); - return it; - }, - ); + this._groupedByColor = this._getBookmarksGroupedByColor(); } if (this.groupView === 'default') { - this._groupedByFile = (this._getBookmarksGroupedByFile() || []).map( - it => { - it.bookmarks = sortBookmarksByLineNumber(it.bookmarks); - return it; - }, - ); + this._groupedByFile = this._getBookmarksGroupedByFile(); } if (this.groupView === 'workspace') { - this._groupedByWorkspaceFolders = ( - this._getBookmarksGroupedByWorkspace() || [] - ).map(it => { - sortBookmarksByLineNumber(it.bookmarks); - return it; - }); + this._groupedByWorkspaceFolders = + this._getBookmarksGroupedByWorkspace(); } } } @@ -290,22 +265,10 @@ export default class BookmarksController implements IController { * @returns */ private _getBookmarksGroupedByColor() { - if (!this._store || !this._store.bookmarks.length) { - return; + if (!this._store) { + return []; } - const groupedList: GroupedByColorType[] = []; - this._store.bookmarks.forEach(it => { - const existed = groupedList.find(item => item.color === it.color); - if (!existed) { - groupedList.push({ - color: it.color, - bookmarks: [it], - }); - return; - } - existed.bookmarks.push(it); - }); - return groupedList; + return this._store.bookmarksGroupedByColor; } /** @@ -313,25 +276,11 @@ export default class BookmarksController implements IController { * @returns */ private _getBookmarksGroupedByWorkspace() { - if (!this._store || !this._store.bookmarks.length) { - return; + if (!this._store) { + return []; } - const grouped: GroupedByWorkspaceType[] = []; - this._store.bookmarks.forEach(it => { - const existed = grouped.find( - item => item.workspace.name === it.workspaceFolder?.name, - ); - if (!existed) { - grouped.push({ - workspace: it.workspaceFolder!, - bookmarks: [it], - }); - return; - } - existed.bookmarks.push(it); - }); - return grouped; + return this._store.bookmakrsGroupedByWorkspace; } changeSortType(sortType: TreeViewSortedByType): void { @@ -339,21 +288,12 @@ export default class BookmarksController implements IController { } add(bookmark: Partial>) { - // @ts-ignore - // this._store.bookmarks.push({ - // ...bookmark, - // workspaceFolder: workspace.getWorkspaceFolder(bookmark.fileUri!), - // }); - const newBookmark = this._store.createBookmark(bookmark); this._store.add(newBookmark); - this.save(); } remove(id: string) { - if (this._store.delete(id)) { - this.save(); - } + this._store.delete(id); } update(id: string, bookmarkDto: Partial>) { @@ -371,7 +311,6 @@ export default class BookmarksController implements IController { ...rangesOrOptions, }, }); - this.save(); } updateGroupColorName( @@ -391,14 +330,13 @@ export default class BookmarksController implements IController { }, }); } - this.save(); } getBookmarkStoreByFileUri(fileUri: Uri): IBookmark[] { if (!this._store) { return []; } - return this._store.groupedByFile(fileUri); + return this._store.getBookmarksByFileUri(fileUri); } /** @@ -418,36 +356,12 @@ export default class BookmarksController implements IController { * ] */ private _getBookmarksGroupedByFile() { - if (!this._store.bookmarks.length) { - return; - } - const groupedList: GroupedByFileType[] = []; - this._store.bookmarks.forEach(it => { - const existed = groupedList.find(item => item.fileId === it.fileId); - if (existed) { - existed.bookmarks.push(it); - } else { - const {fileId, fileName} = it; - - groupedList.push({ - fileId: it.fileId, - // @ts-ignore - fileName: it.fileName || it['filename'], - fileUri: it.fileUri, - bookmarks: [it], - }); - } - }); - - return groupedList.map(it => ({ - ...it, - bookmarks: sortBookmarksByLineNumber(it.bookmarks), - })); + if (!this._store) {return [];} + return this._store.bookmarksGroupedByFile; } restore() { this._store.clearAll(); - this.save(); } /** @@ -470,41 +384,19 @@ export default class BookmarksController implements IController { if (!this._store.bookmarks.length) { return; } - this._store.clearBookmarksByFile(fileUri.fsPath); - this.save(); + this._store.clearBookmarksByFile(fileUri); } - save(store?: IBookmarksStore) { - if (store) { - this._store = store; - } - + save() { if (this._configuration.createJsonFile) { this._saveToDisk(); } else { - this.workspaceState.update(EXTENSION_ID, store || this._store); + this.workspaceState.update(EXTENSION_ID, this._store); } this._changeView(); this._fire(); } - /** - * - * @param bookmark - * @param label - */ - editLabel(bookmark: IBookmark, label: string) { - bookmark.label = label; - - this.update(bookmark.id, { - label, - rangesOrOptions: { - ...bookmark.rangesOrOptions, - hoverMessage: createHoverMessage(bookmark, true, true), - }, - }); - } - refresh() { this._fire(); } @@ -544,21 +436,6 @@ export default class BookmarksController implements IController { ? fileURLToPath(ws.uri.fsPath) : ws.uri.fsPath; - console.log( - !this._store.bookmarks.every( - it => it.workspaceFolder?.uri.fsPath === ws.uri.fsPath, - ), - ); - - // 判断在对应的workspace文件夹中是否存在书签, 如果不存在, 不自动创建`bookmark-manager.json`文件 - if ( - !this._store.bookmarks.every( - it => it.workspaceFolder?.uri.fsPath === ws.uri.fsPath, - ) - ) { - continue; - } - const dotVscodeDir = path.join(workspacePath, '.vscode'); if (!fs.existsSync(dotVscodeDir)) { fs.mkdirSync(dotVscodeDir); @@ -587,7 +464,7 @@ export default class BookmarksController implements IController { workspace: workspace.name, updatedDate: new Date().toLocaleDateString(), content: this._store.bookmarks.filter( - it => it.workspaceFolder?.uri.fsPath === workspace.uri.fsPath, + it => it.wsFolder?.uri.fsPath === workspace.uri.fsPath, ), }; return JSON.stringify(content); @@ -640,6 +517,7 @@ export default class BookmarksController implements IController { } dispose(): void { this._disposables.filter(it => it).forEach(it => it.dispose()); + this._storeDisposer?.(); } private _fire() { diff --git a/src/events.ts b/src/events.ts index 49d3a3d..d07a95a 100644 --- a/src/events.ts +++ b/src/events.ts @@ -30,18 +30,12 @@ export function updateChangeActiveTextEditorListener() { onDidChangeActiveTextEditor?.dispose(); const sm = resolveServiceManager(); // 当打开多个editor group时,更新每个editor的中的decorations - const visibleTextEditors = window.visibleTextEditors; + let visibleTextEditors = window.visibleTextEditors; if (visibleTextEditors.length) { visibleTextEditors.forEach(editor => { sm.decorationService.updateDecorationsByEditor(editor); }); } - onDidChangeActiveTextEditor = window.onDidChangeActiveTextEditor(ev => { - if (!ev) { - return; - } - sm.decorationService.updateDecorationsByEditor(ev); - }); } /** @@ -151,7 +145,6 @@ function buildLineBlameInfo(bookmark: IBookmark) { export function updateBookmarkInfoWhenTextChangeListener() { onDidChangeTextDocumentDisposable?.dispose(); const controller = resolveBookmarkController(); - const sm = resolveServiceManager(); onDidChangeTextDocumentDisposable = workspace.onDidChangeTextDocument(e => { const {contentChanges, document} = e; // 代表存在文档发生变化 @@ -174,7 +167,6 @@ export function updateFilesRenameAndDeleteListeners() { onDidRenameFilesDisposable?.dispose(); onDidDeleteFilesDisposable?.dispose(); const controller = resolveBookmarkController(); - const sm = resolveServiceManager(); // 监听文件重命名, 同步修改书签的对应的文件信息 onDidRenameFilesDisposable = workspace.onDidRenameFiles(e => { const {files} = e; @@ -187,17 +179,10 @@ export function updateFilesRenameAndDeleteListeners() { if (!bookmarks.length) { continue; } - const filePathArr = file.newUri.path.split('/'); - bookmarks.map(it => { - return { - ...it, - fileId: file.newUri.fsPath, - fileUri: file.newUri, - fileName: filePathArr[filePathArr.length - 1], - }; + bookmarks.forEach(it => { + it.updateFileUri(file.newUri); }); } - controller.save(); }); // 监听文件删除 diff --git a/src/providers/BookmarksTreeItem.ts b/src/providers/BookmarksTreeItem.ts index f91cf40..3787b85 100644 --- a/src/providers/BookmarksTreeItem.ts +++ b/src/providers/BookmarksTreeItem.ts @@ -2,19 +2,21 @@ import { MarkdownString, ThemeIcon, TreeItemCollapsibleState, + Uri, l10n, + workspace, } from 'vscode'; import BaseTreeItem from './BaseTreeItem'; import {BookmarkStoreType} from '../types'; import {getLineInfoStrFromBookmark} from '../utils'; import {CMD_GO_TO_SOURCE_LOCATION} from '../constants'; +import {ServiceManager} from '../services/ServiceManager'; import { GroupedByColorType, GroupedByWorkspaceType, -} from '../controllers/BookmarksController'; -import {ServiceManager} from '../services/ServiceManager'; -import {IBookmark} from '../stores/bookmark'; + IBookmark, +} from '../stores/bookmark'; export default class BookmarkTreeItem extends BaseTreeItem { public meta: @@ -30,8 +32,8 @@ export default class BookmarkTreeItem extends BaseTreeItem { collapsibleState: TreeItemCollapsibleState, contextValue: string, meta: - | BookmarkStoreType | IBookmark + | BookmarkStoreType | GroupedByColorType | GroupedByWorkspaceType, sm: ServiceManager, @@ -43,15 +45,18 @@ export default class BookmarkTreeItem extends BaseTreeItem { if (this.contextValue === 'color') { this.label = label; } else if (this.contextValue === 'workspace') { + const meta = this.meta as GroupedByWorkspaceType; this.label = label; this.iconPath = ThemeIcon.Folder; - this.resourceUri = (this.meta as GroupedByWorkspaceType).workspace.uri; + if (workspace.workspaceFolders) { + this.resourceUri = meta.workspace.uri; + } } else if (this.contextValue === 'file') { - const _meta = this.meta as IBookmark; + const _meta = this.meta as BookmarkStoreType; this._resolveFileOverview(); - const filenameArr = _meta.fileName.split('\\'); - this.label = filenameArr[filenameArr.length - 1]; - this.description = label; + + this.label = _meta.fileName; + this.description = workspace.asRelativePath(_meta.fileId); } else { if (this._sm.configService.configuration.enableClick) { this.command = { @@ -69,16 +74,18 @@ export default class BookmarkTreeItem extends BaseTreeItem { const tagGutters = this._sm.gutterService.tagGutters; const gutters = this._sm.gutterService.gutters; if (this.contextValue === 'file') { + const meta = this.meta as BookmarkStoreType; this.iconPath = ThemeIcon.File; - this.resourceUri = (this.meta as BookmarkStoreType).fileUri; + this.resourceUri = Uri.parse(meta.fileName); } else if (this.contextValue === 'color') { const _meta = this.meta as GroupedByColorType; this.iconPath = (gutters[_meta.color] || gutters['default']).iconPath; } else if (this.contextValue === 'bookmark') { const meta = this.meta as IBookmark; + const color = meta.color || meta.customColor.name; this.iconPath = meta.label - ? (tagGutters[meta.color] || tagGutters['default']).iconPath - : (gutters[meta.color] || gutters['default']).iconPath; + ? (tagGutters[color] || tagGutters['default']).iconPath + : (gutters[color] || gutters['default']).iconPath; } } diff --git a/src/providers/BookmarksTreeProvider.ts b/src/providers/BookmarksTreeProvider.ts index bae0490..cd396c6 100644 --- a/src/providers/BookmarksTreeProvider.ts +++ b/src/providers/BookmarksTreeProvider.ts @@ -1,10 +1,10 @@ import BookmarkTreeItem from './BookmarksTreeItem'; import BaseTreeProvider from './BaseTreeProvider'; -import {ProviderResult, Selection, TreeItemCollapsibleState} from 'vscode'; +import {ProviderResult, TreeItemCollapsibleState} from 'vscode'; import {BookmarkStoreRootType, BookmarkStoreType} from '../types'; import {resolveBookmarkController} from '../bootstrap'; import BookmarksController from '../controllers/BookmarksController'; -import {IBookmark} from '../stores/bookmark'; +import {GroupedByWorkspaceType, IBookmark} from '../stores/bookmark'; export class BookmarksTreeProvider extends BaseTreeProvider< BookmarkTreeItem, @@ -64,19 +64,11 @@ export class BookmarksTreeProvider extends BaseTreeProvider< let children: BookmarkTreeItem[] = []; try { children = (element.meta as BookmarkStoreType).bookmarks.map(it => { - const selection = new Selection( - it.selection.anchor, - it.selection.active, - ); - return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, 'bookmark', - { - ...it, - selection, - }, + it, this.serviceManager, ); }); @@ -90,19 +82,11 @@ export class BookmarksTreeProvider extends BaseTreeProvider< if (!element) { const children = (this.datastore as BookmarkStoreRootType)?.bookmarks.map( (it: IBookmark) => { - const selection = new Selection( - it.selection.anchor, - it.selection.active, - ); - return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, 'bookmark', - { - ...it, - selection, - }, + it, this.serviceManager, ); }, @@ -129,19 +113,11 @@ export class BookmarksTreeProvider extends BaseTreeProvider< let children: BookmarkTreeItem[] = []; try { children = (element.meta as BookmarkStoreType).bookmarks.map(it => { - const selection = new Selection( - it.selection.anchor, - it.selection.active, - ); - return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, 'bookmark', - { - ...it, - selection, - }, + it, this.serviceManager, ); }); @@ -156,7 +132,7 @@ export class BookmarksTreeProvider extends BaseTreeProvider< const store = this.controller.groupedByWorkspaceFolders; const children = store.map(it => { return new BookmarkTreeItem( - it.workspace.name, + it.workspace.name!, TreeItemCollapsibleState.Collapsed, 'workspace', it, @@ -168,24 +144,29 @@ export class BookmarksTreeProvider extends BaseTreeProvider< } let children: BookmarkTreeItem[] = []; try { - children = (element.meta as BookmarkStoreType).bookmarks.map(it => { - const selection = new Selection( - it.selection.anchor, - it.selection.active, - ); - - return new BookmarkTreeItem( - it.label || it.selectionContent || it.id, - TreeItemCollapsibleState.None, - 'bookmark', - { - ...it, - selection, - }, - this.serviceManager, - ); - }); - return Promise.resolve(children); + if ('files' in element.meta) { + children = (element.meta as GroupedByWorkspaceType).files.map(it => { + return new BookmarkTreeItem( + it.fileId, + TreeItemCollapsibleState.Collapsed, + 'file', + it, + this.serviceManager, + ); + }); + return Promise.resolve(children); + } else { + children = (element.meta as BookmarkStoreType).bookmarks.map(it => { + return new BookmarkTreeItem( + it.label || it.selectionContent || it.id, + TreeItemCollapsibleState.None, + 'bookmark', + it, + this.serviceManager, + ); + }); + return Promise.resolve(children); + } } catch (error) { return Promise.resolve([]); } diff --git a/src/stores/bookmark.ts b/src/stores/bookmark.ts index a7ba40b..de50bfc 100644 --- a/src/stores/bookmark.ts +++ b/src/stores/bookmark.ts @@ -1,4 +1,4 @@ -import {Instance, destroy, onSnapshot, types} from 'mobx-state-tree'; +import {Instance, types} from 'mobx-state-tree'; import {DEFAULT_BOOKMARK_COLOR} from '../constants'; import { DecorationOptions, @@ -6,9 +6,14 @@ import { Selection, Uri, WorkspaceFolder, + workspace, } from 'vscode'; -import {createHoverMessage, generateUUID} from '../utils'; -import {resolveBookmarkController} from '../bootstrap'; +import { + createHoverMessage, + generateUUID, + sortBookmarksByLineNumber, +} from '../utils'; +import {BookmarkColor, BookmarkStoreType} from '../types'; type SortedType = { /** @@ -21,9 +26,24 @@ type SortedType = { bookmarkSortedIndex?: number; }; -type MyUri = Uri & SortedType; +type MyUri = { + /** + * 文件的相对路径 + */ + fsPath: string; +} & SortedType; + +type MyWorkspaceFolder = { + /** + * 公共文件夹名称 + */ + name: string; -type MyWorkspaceFolder = WorkspaceFolder & SortedType; + /** + * workspace index + */ + index: number; +} & SortedType; type MyColor = { name: string; @@ -33,6 +53,20 @@ type MyTag = SortedType & { name: string; }; +export type GroupedByFileType = BookmarkStoreType & { + sortedIndex?: number; +}; + +export type GroupedByColorType = { + color: BookmarkColor; + bookmarks: IBookmark[]; + sortedIndex?: number; +}; + +export type GroupedByWorkspaceType = { + workspace: Partial & SortedType; + files: BookmarkStoreType[]; +}; const TagType = types.custom({ name: 'MyTag', fromSnapshot(snapshot, env) { @@ -177,11 +211,11 @@ export const Bookmark = types type: types.optional(types.enumeration(['line', 'selection']), 'line'), selectionContent: types.optional(types.string, ''), languageId: types.optional(types.string, 'javascript'), - workspaceFolder: types.maybeNull(MyWorkspaceFolderType), + workspaceFolder: MyWorkspaceFolderType, rangesOrOptions: DecorationOptionsType, createdAt: types.optional(types.Date, () => new Date()), tag: types.optional(TagType, { - name: 'defaul', + name: 'default', sortedIndex: -1, bookmarkSortedIndex: -1, }), @@ -189,14 +223,27 @@ export const Bookmark = types .views(self => { return { get fileId() { - return self.fileUri.fsPath; + const ws = workspace.workspaceFolders?.find( + it => it.name === self.workspaceFolder.name, + ); + if (!ws) { + return self.fileUri.fsPath; + } + + return Uri.joinPath(ws.uri, self.fileUri.fsPath).fsPath; }, get fileName() { - return self.fileUri.fsPath; + const arr = self.fileUri.fsPath.split('/'); + return arr[arr.length - 1]; }, get color() { return self.customColor.name; }, + get wsFolder() { + return workspace.workspaceFolders?.find( + it => it.name === self.workspaceFolder.name, + ); + }, get selection() { const {start, end} = self.rangesOrOptions.range; return new Selection( @@ -218,25 +265,53 @@ export const Bookmark = types } }); } + function updateRangesOrOptionsHoverMessage() { + const rangesOrOptions = {...self.rangesOrOptions}; + rangesOrOptions.hoverMessage = createHoverMessage( + self as IBookmark, + true, + true, + ); + self.rangesOrOptions = rangesOrOptions; + } function updateLabel(label: string) { self.label = label; + updateRangesOrOptionsHoverMessage(); } function updateDescription(desc: string) { self.description = desc; + updateRangesOrOptionsHoverMessage(); } function updateRangesOrOptions(rangesOrOptions: IDecorationOptionsType) { self.rangesOrOptions = rangesOrOptions; + updateRangesOrOptionsHoverMessage(); } function updateColor(newColor: IMyColorType) { self.customColor = newColor; } + + function updateSelectionContent(content: string) { + self.selectionContent = content; + } + + function updateFileUri(uri: Uri) { + self.fileUri = { + fsPath: uri.fsPath, + sortedIndex: self.fileUri.sortedIndex, + bookmarkSortedIndex: self.fileUri.bookmarkSortedIndex, + }; + } + return { update, updateLabel, updateDescription, updateRangesOrOptions, + updateRangesOrOptionsHoverMessage, + updateSelectionContent, + updateFileUri, updateColor, }; }); @@ -256,14 +331,108 @@ export const BookmarksStore = types }) .views(self => { return { - groupedByFile(fileUri: Uri) { - const arr = []; - return self.bookmarks.filter( - it => it.fileUri.fsPath === fileUri.fsPath, - ); + getBookmarksByFileUri(fileUri: Uri) { + return self.bookmarks.filter(it => it.fileId === fileUri.fsPath); }, - groupedByColor(color: IMyColorType) { - return self.bookmarks.filter(it => it.color === color.name); + get bookmarksGroupedByFile() { + if (!self.bookmarks.length) {return [];} + const grouped: GroupedByFileType[] = []; + self.bookmarks.forEach(it => { + const existed = grouped.find(item => item.fileId === it.fileId); + if (existed) { + existed.bookmarks.push(it); + } else { + grouped.push({ + fileId: it.fileId, + // @ts-ignore + fileName: it.fileName || it['filename'], + fileUri: it.fileUri, + bookmarks: [it], + }); + } + }); + return grouped.map(it => ({ + ...it, + bookmarks: sortBookmarksByLineNumber(it.bookmarks), + })); + }, + get bookmarksGroupedByColor() { + const grouped: GroupedByColorType[] = []; + self.bookmarks.forEach(it => { + const existed = grouped.find(item => item.color === it.color); + if (!existed) { + grouped.push({ + color: it.color, + bookmarks: [it], + }); + return; + } + existed.bookmarks.push(it); + }); + return grouped.map(it => ({ + ...it, + bookmarks: sortBookmarksByLineNumber(it.bookmarks), + })); + }, + + /** + * { + * workspace: MyWorkspaceFolder + * files:[ + * { + * fileId: string, + * bookmarks: [ + * + * ] + * } + * ] + * + * } + */ + get bookmakrsGroupedByWorkspace() { + const grouped: GroupedByWorkspaceType[] = []; + self.bookmarks.forEach(it => { + const existed = grouped.find( + item => item.workspace.name === it.workspaceFolder?.name, + ); + + if (!existed) { + grouped.push({ + workspace: {...it.workspaceFolder, ...it.wsFolder}, + files: [ + { + bookmarks: [it], + fileId: it.fileId, + fileName: it.fileName, + fileUri: it.fileUri, + }, + ], + }); + return; + } + const existedFile = existed.files.find( + file => file.fileId === it.fileId, + ); + if (!existedFile) { + existed.files.push({ + fileId: it.fileId, + fileName: it.fileName, + fileUri: it.fileUri, + bookmarks: [it], + }); + return; + } + existedFile.bookmarks.push(it); + }); + return grouped.map(it => { + it.files = it.files.map(file => { + return { + ...file, + bookmarks: sortBookmarksByLineNumber(file.bookmarks), + }; + }); + return it; + }); }, get totalCount() { return self.bookmarks.length; @@ -272,7 +441,7 @@ export const BookmarksStore = types return self.bookmarks.filter(it => it.label.length).length; }, get colors() { - return self.bookmarks.map(it => it.color); + return self.bookmarks.map(it => it.color || it.customColor.name); }, }; }) @@ -293,27 +462,33 @@ export const BookmarksStore = types } = bookmark; const customColor = bookmark.customColor - ? MyColorType.create({...bookmark.customColor}) - : MyColorType.create({ - name: bookmark.color, + ? bookmark.customColor + : { + name: bookmark.color || 'default', sortedIndex: -1, bookmarkSortedIndex: -1, - }); + }; rangesOrOptions.hoverMessage = createHoverMessage(bookmark, true, true); _bookmark = Bookmark.create({ id: id || generateUUID(), label, description, customColor, - fileUri: MyUriType.create(fileUri), + fileUri: { + sortedIndex: fileUri.sortedIndex || -1, + bookmarkSortedIndex: fileUri.bookmarkSortedIndex || -1, + fsPath: workspace.asRelativePath(fileUri.fsPath, false), + }, type, selectionContent, languageId, - workspaceFolder: MyWorkspaceFolderType.create({...workspaceFolder}), - rangesOrOptions: DecorationOptionsType.create({ - ...rangesOrOptions, - }), - + workspaceFolder: { + sortedIndex: workspaceFolder.sortedIndex || -1, + bookmarkSortedIndex: workspaceFolder.bookmarkSortedIndex || -1, + name: workspaceFolder.name, + index: workspaceFolder.index, + }, + rangesOrOptions: rangesOrOptions, createdAt, }); return _bookmark; @@ -325,6 +500,7 @@ export const BookmarksStore = types self.bookmarks.push(bookmark); } return { + afterCreate() {}, add, addBookmarks(bookmarks: any[]) { let _bookmark; @@ -353,9 +529,9 @@ export const BookmarksStore = types } }); }, - clearBookmarksByFile(fileName: string) { + clearBookmarksByFile(fileUri: Uri) { const deleteItems = self.bookmarks.filter( - it => it.fileUri.fsPath === fileName, + it => it.fileId === fileUri.fsPath, ); for (let item of deleteItems) { self.bookmarks.remove(item); diff --git a/src/stores/BookmarkManagerConfig.ts b/src/stores/configure.ts similarity index 100% rename from src/stores/BookmarkManagerConfig.ts rename to src/stores/configure.ts diff --git a/src/types/code.ts b/src/types/code.ts index 987eae7..0056085 100644 --- a/src/types/code.ts +++ b/src/types/code.ts @@ -1,6 +1,4 @@ -import {DecorationOptions, Selection, Uri, WorkspaceFolder} from 'vscode'; -import {BaseMeta, BookmarkColor} from './common'; -import {IBookmark} from '../stores/bookmark'; +import {IBookmark, IMyUriType} from '../stores/bookmark'; export type BookmarkDecorationKey = string | 'default'; /** @@ -19,7 +17,7 @@ export type BookmarkStoreType = { * fileUri.fsPath */ fileId: string; - fileUri: Uri; + fileUri: IMyUriType; fileName: string; bookmarks: IBookmark[]; }; diff --git a/src/utils/bookmark.ts b/src/utils/bookmark.ts index b432b75..98c8bde 100644 --- a/src/utils/bookmark.ts +++ b/src/utils/bookmark.ts @@ -19,6 +19,7 @@ import {resolveBookmarkController} from '../bootstrap'; import resolveServiceManager from '../services/ServiceManager'; import {defaultColors} from '../constants/colors'; import {IBookmark} from '../stores/bookmark'; +import logger from './logger'; const REGEXP_NEWLINE = /(\r\n)|(\n)/g; /** @@ -156,11 +157,16 @@ export async function gotoSourceLocation(bookmark?: IBookmark) { return; } const activeEditor = window.activeTextEditor; - const {fileUri, rangesOrOptions, selection} = bookmark; + const {fileId, rangesOrOptions, selection} = bookmark; const range = selection || rangesOrOptions?.range; + const openedUri = Uri.from({ + scheme: 'file', + path: fileId, + }); + if (!range) { - const doc = await workspace.openTextDocument(Uri.parse(fileUri.path)); + const doc = await workspace.openTextDocument(openedUri); if (!doc) { return; @@ -170,7 +176,7 @@ export async function gotoSourceLocation(bookmark?: IBookmark) { } if (activeEditor) { - if (activeEditor.document.uri.fsPath === fileUri.fsPath) { + if (activeEditor.document.uri.fsPath === fileId) { activeEditor.revealRange(range); const {start, end} = range; highlightSelection( @@ -180,10 +186,10 @@ export async function gotoSourceLocation(bookmark?: IBookmark) { new Position(end.line, end.character), ); } else { - openDocumentAndGotoLocation(fileUri, range); + openDocumentAndGotoLocation(openedUri, range); } } else { - openDocumentAndGotoLocation(fileUri, range); + openDocumentAndGotoLocation(openedUri, range); } } @@ -194,7 +200,7 @@ export async function gotoSourceLocation(bookmark?: IBookmark) { * @returns */ export async function openDocumentAndGotoLocation(fileUri: Uri, range: Range) { - const doc = await workspace.openTextDocument(Uri.parse(fileUri.path)); + const doc = await workspace.openTextDocument(fileUri); if (!doc) { return; @@ -212,28 +218,6 @@ export async function openDocumentAndGotoLocation(fileUri: Uri, range: Range) { ); } -/** - * 编辑对应书签的描述 - * @param bookmark - * @param memo - */ -export function editBookmarkDescription(bookmark: IBookmark, memo: string) { - bookmark.description = memo; - const controller = resolveBookmarkController(); - controller.update(bookmark.id, { - description: memo, - rangesOrOptions: { - ...bookmark.rangesOrOptions, - hoverMessage: createHoverMessage(bookmark, true, true), - }, - }); -} - -export function editBookmarkLabel(bookmark: IBookmark, label: string) { - const controller = resolveBookmarkController(); - controller.editLabel(bookmark, label); -} - /** * 开启选择区域的书签,并包含标签 * @param label @@ -317,6 +301,7 @@ export async function toggleBookmark( return; } } + const fileUri = editor.document.uri; const bookmark: any = { @@ -348,6 +333,7 @@ export async function toggleBookmark( true, true, ); + controller.add(bookmark); } /** @@ -472,11 +458,7 @@ export async function quicklyJumpToBookmark() { description: getLineInfoStrFromBookmark(it), detail: it.fileName, iconPath: iconPath as any, - meta: { - ...it, - // TODO:delete - // selection: new Selection(it.selection.anchor, it.selection.active), - }, + meta: it, }; }); const chosenBookmarks = await window.showQuickPick(pickItems, { @@ -489,7 +471,10 @@ export async function quicklyJumpToBookmark() { let bookmark = typeof item === 'object' ? item.meta : undefined; if (bookmark) { const doc = await workspace.openTextDocument( - Uri.parse(bookmark.fileUri.path), + Uri.from({ + scheme: 'file', + path: item.meta.fileId, + }), ); const editor = await window.showTextDocument(doc, { preview: true, @@ -760,22 +745,16 @@ export function updateBookmarksGroupByChangedLine( * @param dto */ export function updateLineBookmarkRangeWhenDocumentChange( - bookmark: any, - dto: any, + bookmark: IBookmark, + dto: Partial, ) { - const controller = resolveBookmarkController(); const {selection, selectionContent, ...rest} = dto; - if (selectionContent) { - bookmark.selectionContent = selectionContent; - } - // 更新当前行的书签信息 - controller.update(bookmark.id, { - selection, + bookmark.update({ selectionContent, - ...(rest || {}), + type: rest.type, rangesOrOptions: { ...bookmark.rangesOrOptions, - range: selection, + range: selection as Range, hoverMessage: createHoverMessage(bookmark, true, true), }, }); From 954e0efc5c8d147e7a87420c996ad712f8d6118f Mon Sep 17 00:00:00 2001 From: abchen Date: Fri, 15 Mar 2024 19:11:30 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat:=E4=BD=BF=E7=94=A8mst=E6=94=B9?= =?UTF-8?q?=E9=80=A0=E6=8F=92=E4=BB=B6=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/neat-planets-roll.md | 5 + src/bootstrap.ts | 18 +- src/commands/code.ts | 13 +- src/controllers/BookmarksController.ts | 36 +-- src/controllers/IController.ts | 4 +- src/events.ts | 6 + src/providers/BaseTreeProvider.ts | 9 +- src/providers/BookmarksTreeItem.ts | 43 ++-- src/providers/BookmarksTreeProvider.ts | 104 +++++---- src/providers/UniversalTreeProvider.ts | 2 +- src/services/ConfigService.ts | 143 +++--------- src/services/DecorationService.ts | 5 +- src/services/GutterService.ts | 2 +- src/services/index.ts | 6 + src/stores/bookmark.ts | 217 +++--------------- src/stores/configure.ts | 149 +++++++++++- src/stores/custom.ts | 171 ++++++++++++++ .../{DecorationOptions.ts => decoration.ts} | 39 +++- src/stores/index.ts | 5 +- src/types/code.ts | 8 +- src/types/common.ts | 2 +- src/types/configuration.ts | 101 -------- src/types/index.ts | 1 - src/utils/bookmark.ts | 9 +- src/utils/logger.ts | 8 +- src/views/BaseTreeView.ts | 20 +- 26 files changed, 587 insertions(+), 539 deletions(-) create mode 100644 .changeset/neat-planets-roll.md create mode 100644 src/services/index.ts create mode 100644 src/stores/custom.ts rename src/stores/{DecorationOptions.ts => decoration.ts} (55%) delete mode 100644 src/types/configuration.ts diff --git a/.changeset/neat-planets-roll.md b/.changeset/neat-planets-roll.md new file mode 100644 index 0000000..c0e20fd --- /dev/null +++ b/.changeset/neat-planets-roll.md @@ -0,0 +1,5 @@ +--- +'bookmark-manager': patch +--- + +增加mst, 使用mobx改造BookmarkController diff --git a/src/bootstrap.ts b/src/bootstrap.ts index 39eace1..16dbdf3 100644 --- a/src/bootstrap.ts +++ b/src/bootstrap.ts @@ -79,13 +79,17 @@ export default async function bootstrap(context: ExtensionContext) { context.subscriptions.push(registerTelemetryLogger()); logger.log(`${EXTENSION_ID} is now active!`); - - const sm = await initServiceManager(context, updateEverything); - initialController(context, sm); - postInitController(); - registerAllTreeView(context); - registerAllCommands(); - updateEverything(); + try { + const sm = await initServiceManager(context, updateEverything); + initialController(context, sm); + postInitController(); + registerAllTreeView(context); + registerAllCommands(); + updateEverything(); + } catch (error) { + console.error(error); + logger.error(error); + } } export function resolveBookmarkController(): BookmarksController { diff --git a/src/commands/code.ts b/src/commands/code.ts index 636e661..3e44436 100644 --- a/src/commands/code.ts +++ b/src/commands/code.ts @@ -235,7 +235,13 @@ function editBookmark() { */ function goToBookmark() { registerCommand(CMD_GO_TO_SOURCE_LOCATION, args => { - gotoSourceLocation(args.meta || args); + const sm = resolveServiceManager(); + const {enableClick} = sm.configService.configuration; + + // 表示点击TreeView中的定位图标进入此方法, 反之为单击书签跳转到书签位置 + if (args.meta || (args && enableClick)) { + gotoSourceLocation(args.meta || args); + } }); } @@ -270,8 +276,10 @@ function quickPreviewOrJumpToBookmark() { }); } +/** + * 改变书签颜色 + */ function changeBookmarkColor() { - // 改变书签颜色 registerCommand( CMD_CHANGE_BOOKMARK_COLOR, async (ctx: LineBookmarkContext) => { @@ -301,7 +309,6 @@ function changeBookmarkColor() { } function changeBookmarkColorName() { - // 改变书签颜色 registerCommand( CMD_CHANGE_BOOKMARK_COLOR_NAME, async (ctx: LineBookmarkContext) => { diff --git a/src/controllers/BookmarksController.ts b/src/controllers/BookmarksController.ts index f0ad36d..842687b 100644 --- a/src/controllers/BookmarksController.ts +++ b/src/controllers/BookmarksController.ts @@ -1,3 +1,5 @@ +import path from 'node:path'; +import fs from 'node:fs'; import { Event, EventEmitter, @@ -11,13 +13,10 @@ import { window, workspace, } from 'vscode'; -import path from 'node:path'; -import fs from 'node:fs'; +import {IDisposer, destroy, onSnapshot} from 'mobx-state-tree'; import {fileURLToPath} from 'node:url'; import {IDisposable} from '../utils'; -import {sortBookmarksByLineNumber} from '../utils/bookmark'; -import {BookmarkManagerConfigure} from '../types'; import {EXTENSION_ID, EXTENSION_STORE_FILE_NAME} from '../constants'; import IController, { @@ -30,13 +29,14 @@ import ConfigService from '../services/ConfigService'; import {ServiceManager} from '../services/ServiceManager'; import { BookmarksStore, - GroupedByColorType, - GroupedByFileType, - GroupedByWorkspaceType, + BookmarksGroupedByColorType, + BookmarksGroupedByFileWithSortType, + BookmarksGroupedByWorkspaceType, IBookmark, IBookmarksStore, } from '../stores/bookmark'; -import {IDisposer, onSnapshot} from 'mobx-state-tree'; + +import {IBookmarkManagerConfigure} from '../stores/configure'; export default class BookmarksController implements IController { private _context: ExtensionContext; @@ -45,11 +45,11 @@ export default class BookmarksController implements IController { private _store!: IBookmarksStore; - private _groupedByFile: GroupedByFileType[] = []; + private _groupedByFile: BookmarksGroupedByFileWithSortType[] = []; - private _groupedByColor: GroupedByColorType[] = []; + private _groupedByColor: BookmarksGroupedByColorType[] = []; - private _groupedByWorkspaceFolders: GroupedByWorkspaceType[] = []; + private _groupedByWorkspaceFolders: BookmarksGroupedByWorkspaceType[] = []; public viewType: ViewType = 'tree'; @@ -61,7 +61,7 @@ export default class BookmarksController implements IController { private _watcher: FileSystemWatcher | undefined; - private _configuration: BookmarkManagerConfigure; + private _configuration: IBookmarkManagerConfigure; private _configService: ConfigService; @@ -76,15 +76,15 @@ export default class BookmarksController implements IController { public onDidChangeEvent: Event = this._onDidChangeEvent.event; - public get groupedByFileBookmarks(): GroupedByFileType[] { + public get groupedByFileBookmarks(): BookmarksGroupedByFileWithSortType[] { return this._groupedByFile; } - public get groupedByColorBookmarks(): GroupedByColorType[] { + public get groupedByColorBookmarks(): BookmarksGroupedByColorType[] { return this._groupedByColor; } - public get groupedByWorkspaceFolders(): GroupedByWorkspaceType[] { + public get groupedByWorkspaceFolders(): BookmarksGroupedByWorkspaceType[] { return this._groupedByWorkspaceFolders; } @@ -121,7 +121,6 @@ export default class BookmarksController implements IController { this._serviceManager = serviceManager; this._configService = this._serviceManager.configService; this._configuration = this._configService.configuration; - this._initial(); } @@ -356,7 +355,9 @@ export default class BookmarksController implements IController { * ] */ private _getBookmarksGroupedByFile() { - if (!this._store) {return [];} + if (!this._store) { + return []; + } return this._store.bookmarksGroupedByFile; } @@ -518,6 +519,7 @@ export default class BookmarksController implements IController { dispose(): void { this._disposables.filter(it => it).forEach(it => it.dispose()); this._storeDisposer?.(); + destroy(this._store); } private _fire() { diff --git a/src/controllers/IController.ts b/src/controllers/IController.ts index 807ec31..41d5830 100644 --- a/src/controllers/IController.ts +++ b/src/controllers/IController.ts @@ -1,7 +1,7 @@ import {Event, Disposable} from 'vscode'; -import {BaseMeta, BookmarkStoreRootType} from '../types'; +import {BaseMeta} from '../types'; import {UniversalStoreType} from './UniversalBookmarkController'; -import {IBookmarksStore} from '../stores/bookmark'; +import {IBookmarksStore} from '../stores'; /** * 视图查看方式 diff --git a/src/events.ts b/src/events.ts index d07a95a..b1612bc 100644 --- a/src/events.ts +++ b/src/events.ts @@ -36,6 +36,12 @@ export function updateChangeActiveTextEditorListener() { sm.decorationService.updateDecorationsByEditor(editor); }); } + // onDidChangeActiveTextEditor = window.onDidChangeActiveTextEditor(ev => { + // if (!ev) { + // return; + // } + // sm.decorationService.updateDecorationsByEditor(ev); + // }); } /** diff --git a/src/providers/BaseTreeProvider.ts b/src/providers/BaseTreeProvider.ts index d2cc76e..9408bc2 100644 --- a/src/providers/BaseTreeProvider.ts +++ b/src/providers/BaseTreeProvider.ts @@ -6,12 +6,12 @@ import { TreeItem, } from 'vscode'; import BaseTreeItem from './BaseTreeItem'; -import {BookmarkManagerConfigure} from '../types'; import {getRelativePath} from '../utils'; import IController from '../controllers/IController'; import resolveServiceManager, { ServiceManager, } from '../services/ServiceManager'; +import {IBookmarkManagerConfigure} from '../stores'; export default class BaseTreeProvider< T extends BaseTreeItem, @@ -20,7 +20,7 @@ export default class BaseTreeProvider< { private _onDidChangeEvent = new EventEmitter(); - private _extensionConfiguration: BookmarkManagerConfigure | undefined; + private _extensionConfiguration: IBookmarkManagerConfigure | undefined; private _controller: C; @@ -55,10 +55,11 @@ export default class BaseTreeProvider< this._serviceManager = resolveServiceManager(); this._extensionConfiguration = this.configService.configuration; - // 监听插件的配置变化 + // 监听插件的配置变化, 同时刷新TreeView this.configService?.onExtensionConfigChange( - (config: BookmarkManagerConfigure) => { + (config: IBookmarkManagerConfigure) => { this._extensionConfiguration = config; + this.refresh(); }, ); diff --git a/src/providers/BookmarksTreeItem.ts b/src/providers/BookmarksTreeItem.ts index 3787b85..b8d5c33 100644 --- a/src/providers/BookmarksTreeItem.ts +++ b/src/providers/BookmarksTreeItem.ts @@ -8,22 +8,22 @@ import { } from 'vscode'; import BaseTreeItem from './BaseTreeItem'; -import {BookmarkStoreType} from '../types'; +import {BookmarksGroupedByFileType} from '../types'; import {getLineInfoStrFromBookmark} from '../utils'; import {CMD_GO_TO_SOURCE_LOCATION} from '../constants'; import {ServiceManager} from '../services/ServiceManager'; import { - GroupedByColorType, - GroupedByWorkspaceType, + BookmarksGroupedByColorType, + BookmarksGroupedByWorkspaceType, IBookmark, -} from '../stores/bookmark'; +} from '../stores'; export default class BookmarkTreeItem extends BaseTreeItem { public meta: - | BookmarkStoreType | IBookmark - | GroupedByColorType - | GroupedByWorkspaceType; + | BookmarksGroupedByFileType + | BookmarksGroupedByColorType + | BookmarksGroupedByWorkspaceType; private _sm: ServiceManager; @@ -33,9 +33,9 @@ export default class BookmarkTreeItem extends BaseTreeItem { contextValue: string, meta: | IBookmark - | BookmarkStoreType - | GroupedByColorType - | GroupedByWorkspaceType, + | BookmarksGroupedByFileType + | BookmarksGroupedByColorType + | BookmarksGroupedByWorkspaceType, sm: ServiceManager, ) { super(label, collapsibleState, contextValue); @@ -45,26 +45,23 @@ export default class BookmarkTreeItem extends BaseTreeItem { if (this.contextValue === 'color') { this.label = label; } else if (this.contextValue === 'workspace') { - const meta = this.meta as GroupedByWorkspaceType; + const meta = this.meta as BookmarksGroupedByWorkspaceType; this.label = label; this.iconPath = ThemeIcon.Folder; if (workspace.workspaceFolders) { this.resourceUri = meta.workspace.uri; } } else if (this.contextValue === 'file') { - const _meta = this.meta as BookmarkStoreType; + const _meta = this.meta as BookmarksGroupedByFileType; this._resolveFileOverview(); - this.label = _meta.fileName; this.description = workspace.asRelativePath(_meta.fileId); } else { - if (this._sm.configService.configuration.enableClick) { - this.command = { - title: l10n.t('Jump to bookmark position'), - command: `bookmark-manager.${CMD_GO_TO_SOURCE_LOCATION}`, - arguments: [this.meta], - }; - } + this.command = { + title: l10n.t('Jump to bookmark position'), + command: `bookmark-manager.${CMD_GO_TO_SOURCE_LOCATION}`, + arguments: [this.meta], + }; this._createTooltips(); } this._resolveIconPath(); @@ -74,11 +71,11 @@ export default class BookmarkTreeItem extends BaseTreeItem { const tagGutters = this._sm.gutterService.tagGutters; const gutters = this._sm.gutterService.gutters; if (this.contextValue === 'file') { - const meta = this.meta as BookmarkStoreType; + const meta = this.meta as BookmarksGroupedByFileType; this.iconPath = ThemeIcon.File; this.resourceUri = Uri.parse(meta.fileName); } else if (this.contextValue === 'color') { - const _meta = this.meta as GroupedByColorType; + const _meta = this.meta as BookmarksGroupedByColorType; this.iconPath = (gutters[_meta.color] || gutters['default']).iconPath; } else if (this.contextValue === 'bookmark') { const meta = this.meta as IBookmark; @@ -111,7 +108,7 @@ export default class BookmarkTreeItem extends BaseTreeItem { const hoverMessage = new MarkdownString(`### ${this.label}`, true); hoverMessage.supportHtml = true; hoverMessage.supportThemeIcons = true; - const {bookmarks} = this.meta as BookmarkStoreType; + const {bookmarks} = this.meta as BookmarksGroupedByFileType; let item, markdownStr; let idx = 0; for (item of bookmarks) { diff --git a/src/providers/BookmarksTreeProvider.ts b/src/providers/BookmarksTreeProvider.ts index cd396c6..9fb4748 100644 --- a/src/providers/BookmarksTreeProvider.ts +++ b/src/providers/BookmarksTreeProvider.ts @@ -1,10 +1,10 @@ import BookmarkTreeItem from './BookmarksTreeItem'; import BaseTreeProvider from './BaseTreeProvider'; import {ProviderResult, TreeItemCollapsibleState} from 'vscode'; -import {BookmarkStoreRootType, BookmarkStoreType} from '../types'; +import {BookmarkGroupByListType, BookmarksGroupedByFileType} from '../types'; import {resolveBookmarkController} from '../bootstrap'; import BookmarksController from '../controllers/BookmarksController'; -import {GroupedByWorkspaceType, IBookmark} from '../stores/bookmark'; +import {BookmarksGroupedByWorkspaceType, IBookmark} from '../stores/bookmark'; export class BookmarksTreeProvider extends BaseTreeProvider< BookmarkTreeItem, @@ -63,25 +63,8 @@ export class BookmarksTreeProvider extends BaseTreeProvider< } let children: BookmarkTreeItem[] = []; try { - children = (element.meta as BookmarkStoreType).bookmarks.map(it => { - return new BookmarkTreeItem( - it.label || it.selectionContent || it.id, - TreeItemCollapsibleState.None, - 'bookmark', - it, - this.serviceManager, - ); - }); - return Promise.resolve(children); - } catch (error) { - return Promise.resolve([]); - } - } - - getChildrenByList(element?: BookmarkTreeItem | undefined) { - if (!element) { - const children = (this.datastore as BookmarkStoreRootType)?.bookmarks.map( - (it: IBookmark) => { + children = (element.meta as BookmarksGroupedByFileType).bookmarks.map( + it => { return new BookmarkTreeItem( it.label || it.selectionContent || it.id, TreeItemCollapsibleState.None, @@ -92,6 +75,25 @@ export class BookmarksTreeProvider extends BaseTreeProvider< }, ); return Promise.resolve(children); + } catch (error) { + return Promise.resolve([]); + } + } + + getChildrenByList(element?: BookmarkTreeItem | undefined) { + if (!element) { + const children = ( + this.datastore as BookmarkGroupByListType + )?.bookmarks.map((it: IBookmark) => { + return new BookmarkTreeItem( + it.label || it.selectionContent || it.id, + TreeItemCollapsibleState.None, + 'bookmark', + it, + this.serviceManager, + ); + }); + return Promise.resolve(children); } return Promise.resolve([]); } @@ -112,15 +114,17 @@ export class BookmarksTreeProvider extends BaseTreeProvider< } let children: BookmarkTreeItem[] = []; try { - children = (element.meta as BookmarkStoreType).bookmarks.map(it => { - return new BookmarkTreeItem( - it.label || it.selectionContent || it.id, - TreeItemCollapsibleState.None, - 'bookmark', - it, - this.serviceManager, - ); - }); + children = (element.meta as BookmarksGroupedByFileType).bookmarks.map( + it => { + return new BookmarkTreeItem( + it.label || it.selectionContent || it.id, + TreeItemCollapsibleState.None, + 'bookmark', + it, + this.serviceManager, + ); + }, + ); return Promise.resolve(children); } catch (error) { return Promise.resolve([]); @@ -145,26 +149,30 @@ export class BookmarksTreeProvider extends BaseTreeProvider< let children: BookmarkTreeItem[] = []; try { if ('files' in element.meta) { - children = (element.meta as GroupedByWorkspaceType).files.map(it => { - return new BookmarkTreeItem( - it.fileId, - TreeItemCollapsibleState.Collapsed, - 'file', - it, - this.serviceManager, - ); - }); + children = (element.meta as BookmarksGroupedByWorkspaceType).files.map( + it => { + return new BookmarkTreeItem( + it.fileId, + TreeItemCollapsibleState.Collapsed, + 'file', + it, + this.serviceManager, + ); + }, + ); return Promise.resolve(children); } else { - children = (element.meta as BookmarkStoreType).bookmarks.map(it => { - return new BookmarkTreeItem( - it.label || it.selectionContent || it.id, - TreeItemCollapsibleState.None, - 'bookmark', - it, - this.serviceManager, - ); - }); + children = (element.meta as BookmarksGroupedByFileType).bookmarks.map( + it => { + return new BookmarkTreeItem( + it.label || it.selectionContent || it.id, + TreeItemCollapsibleState.None, + 'bookmark', + it, + this.serviceManager, + ); + }, + ); return Promise.resolve(children); } } catch (error) { diff --git a/src/providers/UniversalTreeProvider.ts b/src/providers/UniversalTreeProvider.ts index 9b28fd4..d50ca63 100644 --- a/src/providers/UniversalTreeProvider.ts +++ b/src/providers/UniversalTreeProvider.ts @@ -1,4 +1,4 @@ -import {ProviderResult, Selection, TreeItemCollapsibleState} from 'vscode'; +import {ProviderResult, TreeItemCollapsibleState} from 'vscode'; import {resolveUniversalController} from '../bootstrap'; import BaseTreeProvider from './BaseTreeProvider'; import {UniversalTreeItem} from './UniversalTreeItem'; diff --git a/src/services/ConfigService.ts b/src/services/ConfigService.ts index 2112e77..0d5c4f0 100644 --- a/src/services/ConfigService.ts +++ b/src/services/ConfigService.ts @@ -3,42 +3,40 @@ import { Disposable, Event, EventEmitter, - WorkspaceConfiguration, commands, workspace, } from 'vscode'; -import { - BookmarkManagerConfigure, - CreateDecorationOptions, - StringIndexType, -} from '../types'; -import {DEFAULT_BOOKMARK_COLOR, EXTENSION_ID} from '../constants'; +import {EXTENSION_ID} from '../constants'; import {registerExtensionCustomContextByKey} from '../context'; import {ServiceManager} from './ServiceManager'; -import {defaultColors} from '../constants/colors'; +import { + IBookmarkManagerConfigure, + IRootConfigureModel, + RootConfigureModel, +} from '../stores/configure'; +import {ICreateDecorationOptions} from '../stores/decoration'; +import {StringIndexType} from '../types'; +import {destroy} from 'mobx-state-tree'; /** * 插件的用户配置,以及全局配置, 并监听配置的改动 */ export default class ConfigService implements Disposable { private _onDecorationConfigChangeEvent = - new EventEmitter(); + new EventEmitter(); private _onExtensionConfigChangeEvent = - new EventEmitter(); + new EventEmitter(); private _onDidChangeConfigurationEvent: EventEmitter = new EventEmitter(); - private _configuration: BookmarkManagerConfigure | undefined; - - private _wsConfiguration: WorkspaceConfiguration | undefined; - private _decorationConfiguration: CreateDecorationOptions | undefined; - - private _colors: StringIndexType = {}; + private _configuration: IBookmarkManagerConfigure | undefined; - private _customColors: StringIndexType = {}; + private _decorationConfiguration: ICreateDecorationOptions | undefined; private _serviceManager: ServiceManager; + + private _store!: IRootConfigureModel; onDidChangeConfiguration: Event = this._onDidChangeConfigurationEvent.event; @@ -47,11 +45,16 @@ export default class ConfigService implements Disposable { onExtensionConfigChange = this._onExtensionConfigChangeEvent.event; get colors() { - return this._colors; + const _colors = {} as StringIndexType; + this._store.configure!.colors.forEach((value, key) => { + // @ts-ignore + _colors[key as string] = value; + }); + return _colors; } get customColors() { - return this._customColors; + return this._store.configure!.customColor; } get configuration() { @@ -61,9 +64,6 @@ export default class ConfigService implements Disposable { return this._configuration; } - get workspaceConfiguration() { - return this._wsConfiguration; - } get decorationConfiguration() { if (!this._decorationConfiguration) { this._decorationConfiguration = this._getCreateDecorationOptions(); @@ -73,13 +73,15 @@ export default class ConfigService implements Disposable { constructor(sm: ServiceManager) { this._serviceManager = sm; - this._resolveWorkspaceConfiguration(); + + this._initStore(); workspace.onDidChangeConfiguration(ev => { if (!ev.affectsConfiguration(EXTENSION_ID)) { return; } - this._resolveWorkspaceConfiguration(); + // 需要手动刷新配置中的数据 + this._store.refresh(); this._init(); this.fire(ev); }); @@ -87,16 +89,14 @@ export default class ConfigService implements Disposable { this._init(); } - private _resolveWorkspaceConfiguration() { - this._wsConfiguration = workspace.getConfiguration(EXTENSION_ID); - } - private _init() { this._configuration = this._getExtensionConfiguration(); this._registerContextKey(); - this.resolveAllColors(true); } + private _initStore() { + this._store = RootConfigureModel.create(); + } /** * 将用户配置的内容注册到`context`中 */ @@ -109,28 +109,8 @@ export default class ConfigService implements Disposable { * 获取用户自定义的书签装饰器配置 * @returns 返回一个书签装饰的配置 */ - private _getCreateDecorationOptions(): CreateDecorationOptions { - const configuration = this._wsConfiguration!; - return { - showGutterIcon: configuration.get('showGutterIcon') || false, - showGutterInOverviewRuler: - configuration.get('showGutterInOverviewRuler') || false, - alwaysUseDefaultColor: - configuration.get('alwaysUseDefaultColor') || false, - showTextDecoration: configuration.get('showTextDecoration'), - fontWeight: configuration.get('fontWeight') || 'bold', - wholeLine: configuration.get('wholeLine') || false, - textDecorationLine: - configuration.get('textDecorationLine') || 'underline', - textDecorationStyle: configuration.get('textDecorationStyle') || 'wavy', - textDecorationThickness: - configuration.get('textDecorationThickness') || 'auto', - highlightBackground: configuration.get('highlightBackground') || false, - showBorder: configuration.get('showBorder') || false, - border: configuration.get('border') || '1px solid', - showOutline: configuration.get('showOutline') || false, - outline: configuration.get('outline') || '1px solid', - } as CreateDecorationOptions; + private _getCreateDecorationOptions(): ICreateDecorationOptions { + return this._store.decoration!; } /** @@ -139,30 +119,15 @@ export default class ConfigService implements Disposable { * - 额外配置 * @returns */ - private _getExtensionConfiguration(): BookmarkManagerConfigure { - const configuration = this._wsConfiguration!; - const createDecoration = this._getCreateDecorationOptions(); - return { - ...createDecoration, - colors: this._colors, - lineBlame: configuration.get('lineBlame') || false, - relativePath: configuration.get('relativePath') || false, - defaultBookmarkIconColor: configuration.get('defaultBookmarkIconColor'), - enableClick: configuration.get('enableClick') || false, - createJsonFile: configuration.get('createJsonFile') || false, - useBuiltInColors: configuration.get('useBuiltInColors') || false, - alwaysIgnore: configuration.get('alwaysIgnore') || false, - autoSwitchSingleToMultiWhenLineWrapping: - configuration.get('autoSwitchSingleToMultiWithLineWrap') || false, - }; + private _getExtensionConfiguration(): IBookmarkManagerConfigure { + return this._store.configure!; } /** * 注册插件自定义上下文 */ private _registerExtensionCustomContext() { - const _configuration = - this._configuration || this._getExtensionConfiguration(); + const _configuration = this._getExtensionConfiguration(); Object.entries(_configuration).forEach(([key, value]) => { if (typeof value !== 'boolean') { return; @@ -172,45 +137,6 @@ export default class ConfigService implements Disposable { registerExtensionCustomContextByKey('toggleBookmarkWithSelection', false); } - resolveAllColors(isRestore: boolean = false) { - if (!isRestore && Object.keys(this._colors).length) { - return this._colors; - } - - this._colors = {} as StringIndexType; - const config = this._wsConfiguration!; - - this.resolveCustomColors(); - - Object.entries(this._customColors).forEach(([key, value]) => { - if (typeof value === 'string') { - this._colors[key] = value; - } - }); - - Object.entries(defaultColors).filter(([key, color]) => { - this._colors[key] = color; - }); - - this._colors['default'] = - config.get('defaultBookmarkIconColor') || DEFAULT_BOOKMARK_COLOR; - - return this._colors; - } - - /** - * 处理用户自定义的颜色(标签)配置 - */ - resolveCustomColors() { - const config = this._wsConfiguration!; - this._customColors = {} as StringIndexType; - Object.entries(config.get('colors') as object).filter(([key, value]) => { - if (typeof value === 'string') { - this._customColors[key] = value; - } - }); - } - /** * 获取插件全局配置 * @param key @@ -250,5 +176,6 @@ export default class ConfigService implements Disposable { this._onDidChangeConfigurationEvent.dispose(); this._onDecorationConfigChangeEvent.dispose(); this._onExtensionConfigChangeEvent.dispose(); + destroy(this._store); } } diff --git a/src/services/DecorationService.ts b/src/services/DecorationService.ts index c06a37d..161888c 100644 --- a/src/services/DecorationService.ts +++ b/src/services/DecorationService.ts @@ -13,6 +13,7 @@ import {resolveBookmarkController} from '../bootstrap'; import BookmarksController from '../controllers/BookmarksController'; import logger from '../utils/logger'; import {IBookmark} from '../stores/bookmark'; +import {DEFAULT_BOOKMARK_COLOR} from '../constants'; /** * 装饰器服务类 @@ -111,7 +112,7 @@ export default class DecorationService implements IDisposable { } if (alwaysUseDefaultColor) { - color = colors.default; + color = colors['default']; } const decorationGutterIconPath = _showGutterIcon @@ -138,7 +139,7 @@ export default class DecorationService implements IDisposable { backgroundColor: highlightBackground ? color : '', textDecoration: showTextDecoration ? this.buildTextDecoration({ - color, + color: color || DEFAULT_BOOKMARK_COLOR, textDecorationLine, textDecorationStyle, textDecorationThickness, diff --git a/src/services/GutterService.ts b/src/services/GutterService.ts index b97adf6..8c91f10 100644 --- a/src/services/GutterService.ts +++ b/src/services/GutterService.ts @@ -41,7 +41,7 @@ export default class GutterService implements Disposable { private _initial() { const configService = this._sm.configService; const colors = configService.colors; - Object.entries(colors).forEach(([key, value]) => { + Object.entries(colors).forEach(([key, value]: [string, string]) => { this._gutters[key] = { color: value, iconPath: svgToUri(createBookmarkIcon(value || DEFAULT_BOOKMARK_COLOR)), diff --git a/src/services/index.ts b/src/services/index.ts new file mode 100644 index 0000000..271836b --- /dev/null +++ b/src/services/index.ts @@ -0,0 +1,6 @@ +export * from './ServiceManager'; +export * from './ConfigService'; +export * from './GitService'; +export * from './GutterService'; +export * from './StatusbarService'; +export * from './WorkspaceService'; diff --git a/src/stores/bookmark.ts b/src/stores/bookmark.ts index de50bfc..1451643 100644 --- a/src/stores/bookmark.ts +++ b/src/stores/bookmark.ts @@ -1,201 +1,36 @@ import {Instance, types} from 'mobx-state-tree'; import {DEFAULT_BOOKMARK_COLOR} from '../constants'; -import { - DecorationOptions, - Range, - Selection, - Uri, - WorkspaceFolder, - workspace, -} from 'vscode'; +import {Selection, Uri, WorkspaceFolder, workspace} from 'vscode'; import { createHoverMessage, generateUUID, sortBookmarksByLineNumber, } from '../utils'; -import {BookmarkColor, BookmarkStoreType} from '../types'; - -type SortedType = { - /** - * 表示文件/工作区间的排序索引 - */ - sortedIndex?: number; - /** - * 当按照文件/工作区分组的时, 书签的顺序索引 - */ - bookmarkSortedIndex?: number; -}; - -type MyUri = { - /** - * 文件的相对路径 - */ - fsPath: string; -} & SortedType; - -type MyWorkspaceFolder = { - /** - * 公共文件夹名称 - */ - name: string; - - /** - * workspace index - */ - index: number; -} & SortedType; - -type MyColor = { - name: string; -} & SortedType; - -type MyTag = SortedType & { - name: string; -}; - -export type GroupedByFileType = BookmarkStoreType & { - sortedIndex?: number; -}; - -export type GroupedByColorType = { +import {BookmarkColor, BookmarksGroupedByFileType} from '../types'; +import { + SortedType, + MyColorType, + MyUriType, + MyWorkspaceFolderType, + DecorationOptionsType, + TagType, + IDecorationOptionsType, + IMyColorType, +} from './custom'; + +export type BookmarksGroupedByFileWithSortType = BookmarksGroupedByFileType & + SortedType; + +export type BookmarksGroupedByColorType = { color: BookmarkColor; bookmarks: IBookmark[]; sortedIndex?: number; }; -export type GroupedByWorkspaceType = { +export type BookmarksGroupedByWorkspaceType = { workspace: Partial & SortedType; - files: BookmarkStoreType[]; + files: BookmarksGroupedByFileType[]; }; -const TagType = types.custom({ - name: 'MyTag', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value: MyTag) { - return value; - }, - isTargetType(value: MyTag | any): boolean { - return true; - }, - getValidationMessage(value: MyTag): string { - return ''; - }, -}); - -const MyUriType = types.custom({ - name: 'MyUri', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value: Uri) { - return value; - }, - isTargetType(value: Uri | any): boolean { - return true; - }, - getValidationMessage(value: Uri): string { - return ''; - }, -}); - -export type IMyUriType = Instance; - -const MyWorkspaceFolderType = types.custom< - MyWorkspaceFolder, - MyWorkspaceFolder ->({ - name: 'MyWorkspaceFolder', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value) { - return value; - }, - isTargetType(value) { - return true; - }, - getValidationMessage(snapshot) { - return ''; - }, -}); - -export type IMyWorkspaceFolderType = Instance; - -const RangType = types.custom({ - name: 'RangeType', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value) { - return value; - }, - isTargetType(value) { - return true; - }, - getValidationMessage(snapshot) { - if (!snapshot) {return 'Invalid rangesOrOptions';} - return ''; - }, -}); - -export type IRangeType = Instance; - -const DecorationOptionsType = types.custom< - DecorationOptions, - DecorationOptions ->({ - name: 'DecorationOptions', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value) { - return value; - }, - isTargetType(value) { - return true; - }, - getValidationMessage(snapshot) { - return ''; - }, -}); -export type IDecorationOptionsType = Instance; - -const MyColorType = types.custom({ - name: 'MyColor', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value) { - return value; - }, - isTargetType(value) { - return true; - }, - getValidationMessage(snapshot) { - return ''; - }, -}); - -export type IMyColorType = Instance; - -const MySelectionType = types.custom({ - name: 'Selection', - fromSnapshot(snapshot, env) { - return snapshot; - }, - toSnapshot(value) { - return value; - }, - isTargetType(value) { - return true; - }, - getValidationMessage(snapshot) { - return ''; - }, -}); - -export type IMySelectionType = Instance; export const Bookmark = types .model('Boomkmark', { @@ -335,8 +170,10 @@ export const BookmarksStore = types return self.bookmarks.filter(it => it.fileId === fileUri.fsPath); }, get bookmarksGroupedByFile() { - if (!self.bookmarks.length) {return [];} - const grouped: GroupedByFileType[] = []; + if (!self.bookmarks.length) { + return []; + } + const grouped: BookmarksGroupedByFileWithSortType[] = []; self.bookmarks.forEach(it => { const existed = grouped.find(item => item.fileId === it.fileId); if (existed) { @@ -357,7 +194,7 @@ export const BookmarksStore = types })); }, get bookmarksGroupedByColor() { - const grouped: GroupedByColorType[] = []; + const grouped: BookmarksGroupedByColorType[] = []; self.bookmarks.forEach(it => { const existed = grouped.find(item => item.color === it.color); if (!existed) { @@ -390,7 +227,7 @@ export const BookmarksStore = types * } */ get bookmakrsGroupedByWorkspace() { - const grouped: GroupedByWorkspaceType[] = []; + const grouped: BookmarksGroupedByWorkspaceType[] = []; self.bookmarks.forEach(it => { const existed = grouped.find( item => item.workspace.name === it.workspaceFolder?.name, @@ -512,7 +349,9 @@ export const BookmarksStore = types createBookmark, delete(id: string) { const idx = self.bookmarks.findIndex(it => it.id === id); - if (idx === -1) {return false;} + if (idx === -1) { + return false; + } self.bookmarks.splice(idx, 1); return true; }, diff --git a/src/stores/configure.ts b/src/stores/configure.ts index 5713e2a..04c57d5 100644 --- a/src/stores/configure.ts +++ b/src/stores/configure.ts @@ -1,14 +1,151 @@ -import {Instance, types} from 'mobx-state-tree'; +import {Instance, applySnapshot, cast, types} from 'mobx-state-tree'; +import {WorkspaceConfiguration, workspace} from 'vscode'; +import {DEFAULT_BOOKMARK_COLOR, EXTENSION_ID} from '../constants'; +import {defaultColors} from '../constants/colors'; +import {CreateDecorationOptionsModel} from './decoration'; -const BookmarkManagerConfigureModel = types - .model('BookmarkManagerConfigureModel', {}) +export type StringIndexType = {[key: string]: T}; + +export const BookmarkManagerConfigureModel = types + .model('BookmarkManagerConfigureModel', { + /** + * 配置书签的颜色 + */ + colors: types.map(types.string), + /** + * 是否开启lineBlame 功能 + */ + lineBlame: types.optional(types.boolean, false), + /** + * 是否在树视图中显示相对路径 + */ + relativePath: types.optional(types.boolean, false), + /** + * 允许单击书签跳转到书签所在位置 + */ + enableClick: types.optional(types.boolean, false), + /** + * 设置默认书签颜色 + */ + defaultBookmarkIconColor: types.optional(types.string, ''), + /** + * 是否在`.vscode`文件中创建`bookmark-manager.json` + * 建议将`bookmark-manager.json`添加到.gitignore,避免提交到代码仓库中,引起不必要的麻烦 + */ + createJsonFile: types.optional(types.boolean, false), + /** + * 使用内置的颜色 + */ + useBuiltInColors: types.optional(types.boolean, false), + /** + * 是否将`bookmark-manager.json`文件追加到`.gitIgnore` 文件中 + */ + alwaysIgnore: types.optional(types.boolean, false), + /** + * 自动将单行书签切换为多行书签 + */ + autoSwitchSingleToMultiWhenLineWrapping: types.optional( + types.boolean, + false, + ), + }) .views(self => { - return {}; + const configuration = workspace.getConfiguration(EXTENSION_ID); + return { + get customColor() { + const _customColors: StringIndexType = {}; + Object.entries(configuration.get('colors') as object).filter( + ([key, value]) => { + if (typeof value === 'string') { + _customColors[key] = value; + } + }, + ); + return _customColors; + }, + }; + }) + .actions(self => { + function resolveCustomColors(configuration: WorkspaceConfiguration) { + const _customColors: StringIndexType = {}; + Object.entries(configuration.get('colors') as object).filter( + ([key, value]) => { + if (typeof value === 'string') { + _customColors[key] = value; + } + }, + ); + return _customColors; + } + + function resolveColors(configuration: WorkspaceConfiguration) { + const _colors = {} as any; + const customColors = resolveCustomColors(configuration); + Object.entries(customColors).forEach(([key, value]) => { + if (typeof value === 'string') { + _colors[key] = value; + } + }); + + Object.entries(defaultColors).filter(([key, color]) => { + _colors[key] = color; + }); + _colors['default'] = + configuration.get('defaultBookmarkIconColor') || DEFAULT_BOOKMARK_COLOR; + if ((self as IBookmarkManagerConfigure).updateColors) { + (self as IBookmarkManagerConfigure).updateColors(_colors); + } + } + function resolveConfiguration() { + const configuration = workspace.getConfiguration(EXTENSION_ID); + resolveColors(configuration); + self.lineBlame = configuration.get('lineBlame') || false; + self.relativePath = configuration.get('relativePath') || false; + self.defaultBookmarkIconColor = + configuration.get('defaultBookmarkIconColor') || DEFAULT_BOOKMARK_COLOR; + self.enableClick = configuration.get('enableClick') || false; + self.createJsonFile = configuration.get('createJsonFile') || false; + self.useBuiltInColors = configuration.get('useBuiltInColors') || false; + self.alwaysIgnore = configuration.get('alwaysIgnore') || false; + self.autoSwitchSingleToMultiWhenLineWrapping = + configuration.get('autoSwitchSingleToMultiWithLineWrap') || false; + } + return { + updateColors(colors: StringIndexType) { + self.colors.clear(); + Object.keys(colors).forEach(it => { + self.colors.set(it, colors[it]); + }); + }, + afterCreate() { + resolveConfiguration(); + }, + afterAttach() {}, + resolveConfiguration, + }; + }); +export const RootConfigureModel = types + .model('RootConfigureMode', { + decoration: types.maybeNull(CreateDecorationOptionsModel), + configure: types.maybeNull(BookmarkManagerConfigureModel), }) .actions(self => { - return {}; + return { + afterCreate() { + self.decoration = CreateDecorationOptionsModel.create(); + self.configure = BookmarkManagerConfigureModel.create({ + colors: {}, + }); + }, + refresh() { + self.decoration?.resolveDecorationOptions(); + self.configure?.resolveConfiguration(); + }, + }; }); -export type BookmarkManagerConfigure = Instance< +export type IBookmarkManagerConfigure = Instance< typeof BookmarkManagerConfigureModel >; + +export type IRootConfigureModel = Instance; diff --git a/src/stores/custom.ts b/src/stores/custom.ts new file mode 100644 index 0000000..bf66223 --- /dev/null +++ b/src/stores/custom.ts @@ -0,0 +1,171 @@ +import {Instance, types} from 'mobx-state-tree'; +import {Uri, Range, DecorationOptions, Selection} from 'vscode'; + +export type SortedType = { + /** + * 表示文件/工作区间的排序索引 + */ + sortedIndex?: number; + /** + * 当按照文件/工作区分组的时, 书签的顺序索引 + */ + bookmarkSortedIndex?: number; +}; + +export type MyUri = { + /** + * 文件的相对路径 + */ + fsPath: string; +} & SortedType; + +export type MyWorkspaceFolder = { + /** + * 公共文件夹名称 + */ + name: string; + + /** + * workspace index + */ + index: number; +} & SortedType; + +export type MyColor = { + name: string; +} & SortedType; + +export type MyTag = SortedType & { + name: string; +}; +export const TagType = types.custom({ + name: 'MyTag', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value: MyTag) { + return value; + }, + isTargetType(value: MyTag | any): boolean { + return true; + }, + getValidationMessage(value: MyTag): string { + return ''; + }, +}); + +export const MyUriType = types.custom({ + name: 'MyUri', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value: Uri) { + return value; + }, + isTargetType(value: Uri | any): boolean { + return true; + }, + getValidationMessage(value: Uri): string { + return ''; + }, +}); + +export type IMyUriType = Instance; + +export const MyWorkspaceFolderType = types.custom< + MyWorkspaceFolder, + MyWorkspaceFolder +>({ + name: 'MyWorkspaceFolder', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); + +export type IMyWorkspaceFolderType = Instance; + +export const RangType = types.custom({ + name: 'RangeType', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + if (!snapshot) { + return 'Invalid rangesOrOptions'; + } + return ''; + }, +}); + +export type IRangeType = Instance; + +export const DecorationOptionsType = types.custom< + DecorationOptions, + DecorationOptions +>({ + name: 'DecorationOptions', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); +export type IDecorationOptionsType = Instance; + +export const MyColorType = types.custom({ + name: 'MyColor', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); + +export type IMyColorType = Instance; + +export const MySelectionType = types.custom({ + name: 'Selection', + fromSnapshot(snapshot, env) { + return snapshot; + }, + toSnapshot(value) { + return value; + }, + isTargetType(value) { + return true; + }, + getValidationMessage(snapshot) { + return ''; + }, +}); + +export type IMySelectionType = Instance; diff --git a/src/stores/DecorationOptions.ts b/src/stores/decoration.ts similarity index 55% rename from src/stores/DecorationOptions.ts rename to src/stores/decoration.ts index 280efa0..deb00be 100644 --- a/src/stores/DecorationOptions.ts +++ b/src/stores/decoration.ts @@ -1,8 +1,8 @@ -import {Instance, types} from 'mobx-state-tree'; import {workspace} from 'vscode'; +import {Instance, types} from 'mobx-state-tree'; import {EXTENSION_ID} from '../constants'; -const CreateDecorationOptionsModel = types +export const CreateDecorationOptionsModel = types .model('CreateDecorationOptionsModel', { /** * 是否在行号出现时指示图标 @@ -23,7 +23,10 @@ const CreateDecorationOptionsModel = types /** * 书签装饰器的字体样式 */ - fontWeight: types.enumeration(['normal', 'bold', 'bolder', 'unset']), + fontWeight: types.optional( + types.enumeration(['normal', 'bold', 'bolder', 'unset']), + 'bold', + ), /** * 是否选择整行, 否则仅为存在文本字段的区域选择 */ @@ -65,12 +68,36 @@ const CreateDecorationOptionsModel = types return {}; }) .actions(self => { + function resolveDecorationOptions() { + const configuration = workspace.getConfiguration(EXTENSION_ID); + self.showGutterIcon = configuration.get('showGutterIcon') || false; + self.showGutterInOverviewRuler = + configuration.get('showGutterInOverviewRuler') || false; + self.alwaysUseDefaultColor = + configuration.get('alwaysUseDefaultColor') || false; + self.showTextDecoration = configuration.get('showTextDecoration') || true; + self.fontWeight = configuration.get('fontWeight') || 'bold'; + self.wholeLine = configuration.get('wholeLine') || false; + self.textDecorationLine = + configuration.get('textDecorationLine') || 'underline'; + self.textDecorationStyle = + configuration.get('textDecorationStyle') || 'wavy'; + self.textDecorationThickness = + configuration.get('textDecorationThickness') || 'auto'; + self.highlightBackground = + configuration.get('highlightBackground') || false; + self.showBorder = configuration.get('showBorder') || false; + self.border = configuration.get('border') || '1px solid'; + self.showOutline = configuration.get('showOutline') || false; + self.outline = configuration.get('outline') || '1px solid'; + } + function afterCreate() { - const wsConfiguration = workspace.getConfiguration(EXTENSION_ID); + resolveDecorationOptions(); } - return {afterCreate}; + return {afterCreate, resolveDecorationOptions}; }); -export type CreateDecorationOptions = Instance< +export type ICreateDecorationOptions = Instance< typeof CreateDecorationOptionsModel >; diff --git a/src/stores/index.ts b/src/stores/index.ts index 40c651e..2e7c913 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -1 +1,4 @@ -export default function initialStore() {} +export * from './bookmark'; +export * from './configure'; +export * from './decoration'; +export * from './custom'; diff --git a/src/types/code.ts b/src/types/code.ts index 0056085..d67bb25 100644 --- a/src/types/code.ts +++ b/src/types/code.ts @@ -1,4 +1,4 @@ -import {IBookmark, IMyUriType} from '../stores/bookmark'; +import {IBookmark, IMyUriType} from '../stores'; export type BookmarkDecorationKey = string | 'default'; /** @@ -12,9 +12,9 @@ export type BookmarkDecorationKey = string | 'default'; * } * ``` */ -export type BookmarkStoreType = { +export type BookmarksGroupedByFileType = { /** - * fileUri.fsPath + * 文件路径名 */ fileId: string; fileUri: IMyUriType; @@ -31,6 +31,6 @@ export type BookmarkStoreType = { * } * ``` */ -export type BookmarkStoreRootType = { +export type BookmarkGroupByListType = { bookmarks: IBookmark[]; }; diff --git a/src/types/common.ts b/src/types/common.ts index 5e7991f..1fad333 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -12,7 +12,7 @@ export interface BaseMeta { } export type LineBookmarkContext = - | BookmarkTreeItem | Uri | {uri: Uri; lineNumber: number} + | BookmarkTreeItem | undefined; diff --git a/src/types/configuration.ts b/src/types/configuration.ts deleted file mode 100644 index b449d17..0000000 --- a/src/types/configuration.ts +++ /dev/null @@ -1,101 +0,0 @@ -import {StringIndexType} from './common'; - -export interface CreateDecorationOptions { - /** - * 是否在行号出现时指示图标 - */ - showGutterIcon: boolean; - /** - * 是否在游标卡尺显示 gutter 图标所在位置, 默认颜色跟随书签选择的样式 - */ - showGutterInOverviewRuler: boolean; - /** - * 是否显示书签样式 - */ - showTextDecoration?: boolean; - /** - * 是否使用默认样式 - */ - alwaysUseDefaultColor?: boolean; - /** - * 书签装饰器的字体样式 - */ - fontWeight: 'normal' | 'bold' | 'bolder' | 'unset'; - /** - * 是否选择整行, 否则仅为存在文本字段的区域选择 - */ - wholeLine: boolean; - - /** - * 书签装饰器下划线的样式 - */ - textDecorationLine: string; - /** - * 书签装饰器样式 - */ - textDecorationStyle: string; - /** - * 书签装饰器的`tickness`样式 - */ - textDecorationThickness: string; - /** - * 高亮背景行 - */ - highlightBackground: boolean; - /** - * 是否显示书签装饰器的外边框 - */ - showBorder: boolean; - /** - * 书签装饰器的外边框样式 - */ - border: string; - /** - * 是否显示书签装饰器的轮廓 - */ - showOutline: boolean; - /** - * 书签装饰器的轮廓样式 - */ - outline: string; -} - -export type BookmarkManagerConfigure = CreateDecorationOptions & { - /** - * 配置书签的颜色 - */ - colors: StringIndexType; - /** - * 是否开启lineBlame 功能 - */ - lineBlame: boolean; - /** - * 是否在树视图中显示相对路径 - */ - relativePath: boolean; - /** - * 允许单击书签跳转到书签所在位置 - */ - enableClick: boolean; - /** - * 设置默认书签颜色 - */ - defaultBookmarkIconColor?: string; - /** - * 是否在`.vscode`文件中创建`bookmark-manager.json` - * 建议将`bookmark-manager.json`添加到.gitignore,避免提交到代码仓库中,引起不必要的麻烦 - */ - createJsonFile: boolean; - /** - * 使用内置的颜色 - */ - useBuiltInColors: boolean; - /** - * 是否将`bookmark-manager.json`文件追加到`.gitIgnore` 文件中 - */ - alwaysIgnore: boolean; - /** - * 自动将单行书签切换为多行书签 - */ - autoSwitchSingleToMultiWhenLineWrapping: boolean; -}; diff --git a/src/types/index.ts b/src/types/index.ts index 1b45e0f..2d11c40 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,3 @@ export * from './common'; export * from './code'; export * from './universal'; -export * from './configuration'; diff --git a/src/utils/bookmark.ts b/src/utils/bookmark.ts index 98c8bde..07d70df 100644 --- a/src/utils/bookmark.ts +++ b/src/utils/bookmark.ts @@ -19,7 +19,6 @@ import {resolveBookmarkController} from '../bootstrap'; import resolveServiceManager from '../services/ServiceManager'; import {defaultColors} from '../constants/colors'; import {IBookmark} from '../stores/bookmark'; -import logger from './logger'; const REGEXP_NEWLINE = /(\r\n)|(\n)/g; /** @@ -349,7 +348,9 @@ export function deleteBookmark(context?: LineBookmarkContext) { // 从 `command palette` 中调用删除操作 if (!context) { - if (!editor) {return;} + if (!editor) { + return; + } _lineNumber = editor.selection.active.line; } else { // 从打开的文本编辑器的菜单中调用 @@ -371,7 +372,9 @@ export function deleteBookmark(context?: LineBookmarkContext) { if (_lineNumber !== -1) { bookmark = getBookmarkFromLineNumber(_lineNumber); } - if (!bookmark) {return;} + if (!bookmark) { + return; + } controller.remove(bookmark.id); } diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 7c452b6..0a7a339 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -62,28 +62,28 @@ export function resolveLoggerChannel() { return logger; } -export function info(msg: string) { +export function info(msg: any) { logger.output.info('>', msg); logger.telemetry.logUsage('info', { info: msg, }); } -export function warn(msg: string) { +export function warn(msg: any) { logger.output.warn('>', msg); logger.telemetry.logUsage('warn', { info: msg, }); } -export function error(msg: string) { +export function error(msg: any) { logger.output.error('>', msg); logger.telemetry.logError('error', { info: msg, }); } -export function log(msg: string) { +export function log(msg: any) { logger.output.info('>', msg); logger.telemetry.logUsage('log', { info: msg, diff --git a/src/views/BaseTreeView.ts b/src/views/BaseTreeView.ts index 2a4edd7..36ed78c 100644 --- a/src/views/BaseTreeView.ts +++ b/src/views/BaseTreeView.ts @@ -6,6 +6,7 @@ import IController from '../controllers/IController'; import resolveServiceManager, { ServiceManager, } from '../services/ServiceManager'; +import {IBookmark} from '../stores'; export enum TreeViewEnum { BASE = 0, UNIVERSAL, @@ -82,9 +83,10 @@ export default class BaseTreeView draggedSource.meta.bookmarks.length && draggedSource.meta.color !== target.meta.color ) { - for (let item of draggedSource.meta.bookmarks) { - self._controller.update(item.id, { - color: target.meta.color, + for (let bookmark of draggedSource.meta.bookmarks) { + (bookmark as IBookmark).updateColor({ + ...bookmark.customColor, + name: target.meta.color, }); } return; @@ -92,8 +94,10 @@ export default class BaseTreeView // 不同树的之间拖拽 if (draggedSource.meta.color !== target.meta.color) { - self._controller.update(draggedSource.meta.id, { - color: target.meta.color, + const bookmark = draggedSource.meta as IBookmark; + bookmark.updateColor({ + ...bookmark.customColor, + name: target.meta.color, }); return; } @@ -105,7 +109,9 @@ export default class BaseTreeView // groupView 为default, workspace 以及 file情况下, 第二级 支持拖拽排序, 第一级支持拖拽排序 const sourceContextValue = draggedSource.contextValue; const targetContextValue = target.contextValue; - if (!sourceContextValue || !targetContextValue) {return;} + if (!sourceContextValue || !targetContextValue) { + return; + } if ( targetContextValue === 'bookmark' && @@ -115,7 +121,7 @@ export default class BaseTreeView } // 1. 对于顶层级进行拖拽, 顶层进行排序 - //2. 第二层级中 进行排序 + // 2. 第二层级中 进行排序 console.log(draggedSource, target); } }, From 2db8f8814758deb9c20965c4279ab4a21f6f59d1 Mon Sep 17 00:00:00 2001 From: abchen Date: Fri, 15 Mar 2024 20:05:28 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat:=E4=BC=98=E5=8C=96BookmarkController?= =?UTF-8?q?=E4=BB=A3=E7=A0=81,=E5=90=8C=E6=97=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=8A=E6=AC=A1=E6=8F=90=E4=BA=A4=E4=BA=A7=E7=94=9F=E7=9A=84?= =?UTF-8?q?BUG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/proud-pears-study.md | 5 ++ src/controllers/BookmarksController.ts | 76 +++++++++---------- src/controllers/IController.ts | 27 +++---- .../UniversalBookmarkController.ts | 24 +++--- src/stores/bookmark.ts | 75 +++++++++++++++++- src/types/common.ts | 19 +++++ 6 files changed, 153 insertions(+), 73 deletions(-) create mode 100644 .changeset/proud-pears-study.md diff --git a/.changeset/proud-pears-study.md b/.changeset/proud-pears-study.md new file mode 100644 index 0000000..025fe95 --- /dev/null +++ b/.changeset/proud-pears-study.md @@ -0,0 +1,5 @@ +--- +'bookmark-manager': patch +--- + +feat:使用mst改造插件配置 diff --git a/src/controllers/BookmarksController.ts b/src/controllers/BookmarksController.ts index 842687b..e50998d 100644 --- a/src/controllers/BookmarksController.ts +++ b/src/controllers/BookmarksController.ts @@ -17,14 +17,12 @@ import {IDisposer, destroy, onSnapshot} from 'mobx-state-tree'; import {fileURLToPath} from 'node:url'; import {IDisposable} from '../utils'; -import {EXTENSION_ID, EXTENSION_STORE_FILE_NAME} from '../constants'; - -import IController, { - TreeViewSortedByType, - TreeGroupView, - ViewType, -} from './IController'; -import {registerExtensionCustomContextByKey} from '../context'; +import { + EXTENSION_ID, + EXTENSION_STORE_FILE_NAME, + EXTENSION_STORE_PATH, +} from '../constants'; + import ConfigService from '../services/ConfigService'; import {ServiceManager} from '../services/ServiceManager'; import { @@ -37,6 +35,8 @@ import { } from '../stores/bookmark'; import {IBookmarkManagerConfigure} from '../stores/configure'; +import {TreeViewType, TreeViewGroupType, TreeViewSortedType} from '../types'; +import IController from './IController'; export default class BookmarksController implements IController { private _context: ExtensionContext; @@ -51,11 +51,11 @@ export default class BookmarksController implements IController { private _groupedByWorkspaceFolders: BookmarksGroupedByWorkspaceType[] = []; - public viewType: ViewType = 'tree'; + public viewType: TreeViewType = 'tree'; - public groupView: TreeGroupView = 'default'; + public groupView: TreeViewGroupType = 'default'; - public sortedType: TreeViewSortedByType = 'linenumber'; + public sortedType: TreeViewSortedType = 'linenumber'; private _disposables: IDisposable[] = []; @@ -129,15 +129,6 @@ export default class BookmarksController implements IController { '_needWarning', true, ); - this.viewType = this._configService.getGlobalValue('code.viewType', 'tree'); - this.groupView = this._configService.getGlobalValue( - 'code.groupView', - 'file', - ); - - if (!workspace.workspaceFolders || workspace.workspaceFolders!.length < 2) { - this.groupView = 'default'; - } this._configService.onExtensionConfigChange(configuration => { this._configuration = configuration; @@ -153,13 +144,6 @@ export default class BookmarksController implements IController { } }); - registerExtensionCustomContextByKey( - 'code.viewAsTree', - this.viewType === 'tree', - ); - - registerExtensionCustomContextByKey('code.view.groupView', this.groupView); - this._initStore(); this._initialWatcher(); @@ -168,6 +152,17 @@ export default class BookmarksController implements IController { private async _initStore() { this._store = BookmarksStore.create(); + this.viewType = this._store.viewType as TreeViewType; + this.groupView = this._store.groupView as TreeViewGroupType; + this.sortedType = this._store.sortedType as TreeViewSortedType; + + if ( + (!workspace.workspaceFolders || workspace.workspaceFolders!.length < 2) && + this.groupView !== 'default' + ) { + this._store.updateGroupView('default'); + } + let store; this._resolveDatastoreFromStoreFile(); // 当从 `bookmark-manager.json`文件中读取, 直接刷新返回 @@ -185,6 +180,10 @@ export default class BookmarksController implements IController { } this._storeDisposer = onSnapshot(this._store, snapshot => { + // 更新对应的配置数据 + this.viewType = this._store.viewType as TreeViewType; + this.groupView = this._store.groupView as TreeViewGroupType; + this.sortedType = this._store.sortedType as TreeViewSortedType; this.save(); }); this._changeView(); @@ -228,7 +227,7 @@ export default class BookmarksController implements IController { for (ws of wsFolders) { const storeFilePath = path.join( ws.uri.fsPath, - './.vscode/bookmark-manager.json', + `./${EXTENSION_STORE_PATH}`, ); if (fs.existsSync(storeFilePath)) { const _bookmarks = ( @@ -282,10 +281,6 @@ export default class BookmarksController implements IController { return this._store.bookmakrsGroupedByWorkspace; } - changeSortType(sortType: TreeViewSortedByType): void { - this.sortedType = sortType; - } - add(bookmark: Partial>) { const newBookmark = this._store.createBookmark(bookmark); this._store.add(newBookmark); @@ -402,21 +397,18 @@ export default class BookmarksController implements IController { this._fire(); } - changeViewType(viewType: ViewType) { - this.viewType = viewType; - this._configService.updateGlobalValue('code.viewType', viewType); + changeSortType(sortType: TreeViewSortedType): void { + this._store.updateSortedType(sortType); + } - registerExtensionCustomContextByKey( - 'code.viewAsTree', - this.viewType === 'tree', - ); + changeViewType(viewType: TreeViewType) { + this._store.udpateViewType(viewType); this._changeView(); this._fire(); } - changeGroupView(groupType: TreeGroupView) { - this.groupView = groupType; - this._configService.updateGlobalValue('code.groupView', groupType); + changeGroupView(groupType: TreeViewGroupType) { + this._store.updateGroupView(groupType); this._changeView(); this._fire(); } diff --git a/src/controllers/IController.ts b/src/controllers/IController.ts index 41d5830..cc1e544 100644 --- a/src/controllers/IController.ts +++ b/src/controllers/IController.ts @@ -1,20 +1,13 @@ import {Event, Disposable} from 'vscode'; -import {BaseMeta} from '../types'; +import { + BaseMeta, + TreeViewGroupType, + TreeViewSortedType, + TreeViewType, +} from '../types'; import {UniversalStoreType} from './UniversalBookmarkController'; import {IBookmarksStore} from '../stores'; -/** - * 视图查看方式 - */ -export type ViewType = 'tree' | 'list'; - -/** - * 视图排序方式 - */ -export type TreeViewSortedByType = 'linenumber' | 'custom' | 'time'; - -export type TreeGroupView = 'file' | 'color' | 'default' | 'workspace'; - export default interface IController extends Disposable { get store(): IBookmarksStore | UniversalStoreType | undefined; @@ -22,9 +15,9 @@ export default interface IController extends Disposable { get labeledCount(): number; - get viewType(): ViewType; + get viewType(): TreeViewType; - get groupView(): TreeGroupView; + get groupView(): TreeViewGroupType; onDidChangeEvent: Event; @@ -38,7 +31,7 @@ export default interface IController extends Disposable { clearAll(): void; refresh(): void; - changeViewType(viewType: ViewType): void; + changeViewType(viewType: TreeViewType): void; - changeSortType(sortType: TreeViewSortedByType): void; + changeSortType(sortType: TreeViewSortedType): void; } diff --git a/src/controllers/UniversalBookmarkController.ts b/src/controllers/UniversalBookmarkController.ts index 459a289..45b97cd 100644 --- a/src/controllers/UniversalBookmarkController.ts +++ b/src/controllers/UniversalBookmarkController.ts @@ -1,11 +1,13 @@ import {Event, EventEmitter, ExtensionContext, Uri} from 'vscode'; -import {BaseMeta, BookmarkColor} from '../types'; +import { + BaseMeta, + BookmarkColor, + TreeViewGroupType, + TreeViewSortedType, + TreeViewType, +} from '../types'; import {generateUUID} from '../utils'; -import IController, { - TreeViewSortedByType, - TreeGroupView, - ViewType, -} from './IController'; +import IController from './IController'; import {ServiceManager} from '../services/ServiceManager'; export const UNIVERSAL_STORE_KEY = 'bookmark-manager.universal'; export type UniversalBookmarkType = 'file' | 'link' | 'command' | 'code'; @@ -61,7 +63,7 @@ export default class UniversalBookmarkController implements IController { private _onDidChangeEvent: EventEmitter = new EventEmitter(); private _serviceManager: ServiceManager; - public sortedType: Omit = 'linenumber'; + public sortedType: Omit = 'linenumber'; public onDidChangeEvent: Event = this._onDidChangeEvent.event; get globalState() { @@ -94,10 +96,10 @@ export default class UniversalBookmarkController implements IController { } this._initial(); } - get viewType(): ViewType { + get viewType(): TreeViewType { return 'list'; } - get groupView(): TreeGroupView { + get groupView(): TreeViewGroupType { return 'default'; } @@ -172,9 +174,9 @@ export default class UniversalBookmarkController implements IController { refresh() { this._onDidChangeEvent.fire(); } - changeViewType(viewType: ViewType): void {} + changeViewType(viewType: TreeViewType): void {} - changeSortType(sortType: TreeViewSortedByType): void { + changeSortType(sortType: TreeViewSortedType): void { this.sortedType = sortType; } } diff --git a/src/stores/bookmark.ts b/src/stores/bookmark.ts index 1451643..8370298 100644 --- a/src/stores/bookmark.ts +++ b/src/stores/bookmark.ts @@ -6,7 +6,13 @@ import { generateUUID, sortBookmarksByLineNumber, } from '../utils'; -import {BookmarkColor, BookmarksGroupedByFileType} from '../types'; +import { + BookmarkColor, + BookmarksGroupedByFileType, + TreeViewGroupType, + TreeViewSortedType, + TreeViewType, +} from '../types'; import { SortedType, MyColorType, @@ -17,6 +23,8 @@ import { IDecorationOptionsType, IMyColorType, } from './custom'; +import resolveServiceManager from '../services/ServiceManager'; +import {registerExtensionCustomContextByKey} from '../context'; export type BookmarksGroupedByFileWithSortType = BookmarksGroupedByFileType & SortedType; @@ -160,7 +168,7 @@ export const BookmarksStore = types 'file', ), sortedType: types.optional( - types.enumeration(['linenumber', 'custom', 'time']), + types.enumeration(['linenumber', 'custom', 'createdTime', 'updatedTime']), 'linenumber', ), }) @@ -336,8 +344,39 @@ export const BookmarksStore = types } self.bookmarks.push(bookmark); } + return { - afterCreate() {}, + afterCreate() { + const sm = resolveServiceManager(); + self.viewType = sm.configService.getGlobalValue( + 'code.viewType', + 'tree', + ); + self.groupView = sm.configService.getGlobalValue( + 'code.groupView', + 'file', + ); + self.sortedType = sm.configService.getGlobalValue( + 'code.sortedType', + 'createdTime', + ); + + // 注册对应的上下文 + registerExtensionCustomContextByKey( + 'code.viewAsTree', + self.viewType === 'tree', + ); + + registerExtensionCustomContextByKey( + 'code.view.groupView', + self.groupView, + ); + + registerExtensionCustomContextByKey( + 'code.view.sortedType', + self.sortedType, + ); + }, add, addBookmarks(bookmarks: any[]) { let _bookmark; @@ -368,6 +407,36 @@ export const BookmarksStore = types } }); }, + udpateViewType(viewType: TreeViewType) { + if (self.viewType === viewType) { + return; + } + const sm = resolveServiceManager(); + sm.configService.updateGlobalValue('code.viewType', viewType); + registerExtensionCustomContextByKey( + 'code.viewAsTree', + viewType === 'tree', + ); + self.viewType = viewType; + }, + updateGroupView(groupView: TreeViewGroupType) { + if (self.groupView === groupView) { + return; + } + const sm = resolveServiceManager(); + sm.configService.updateGlobalValue('code.groupView', groupView); + registerExtensionCustomContextByKey('code.view.groupView', groupView); + self.groupView = groupView; + }, + updateSortedType(sortedType: TreeViewSortedType) { + if (self.sortedType === sortedType) { + return; + } + const sm = resolveServiceManager(); + sm.configService.updateGlobalValue('code.sortedType', sortedType); + registerExtensionCustomContextByKey('code.view.sortedType', sortedType); + self.sortedType = sortedType; + }, clearBookmarksByFile(fileUri: Uri) { const deleteItems = self.bookmarks.filter( it => it.fileId === fileUri.fsPath, diff --git a/src/types/common.ts b/src/types/common.ts index 1fad333..2bdf21a 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -16,3 +16,22 @@ export type LineBookmarkContext = | {uri: Uri; lineNumber: number} | BookmarkTreeItem | undefined; + +/** + * 视图查看方式 + */ +export type TreeViewType = 'tree' | 'list'; + +/** + * 视图排序方式 + */ +export type TreeViewSortedType = + | 'linenumber' + | 'custom' + | 'createdTime' + | 'updatedTime'; + +/** + * 视图分组方式 + */ +export type TreeViewGroupType = 'file' | 'color' | 'default' | 'workspace'; From af8c240decbf650b0475b3a65ef187f6fafac4c3 Mon Sep 17 00:00:00 2001 From: abchen Date: Fri, 15 Mar 2024 20:06:30 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/neat-planets-roll.md | 5 ----- .changeset/proud-pears-study.md | 5 ----- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) delete mode 100644 .changeset/neat-planets-roll.md delete mode 100644 .changeset/proud-pears-study.md diff --git a/.changeset/neat-planets-roll.md b/.changeset/neat-planets-roll.md deleted file mode 100644 index c0e20fd..0000000 --- a/.changeset/neat-planets-roll.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'bookmark-manager': patch ---- - -增加mst, 使用mobx改造BookmarkController diff --git a/.changeset/proud-pears-study.md b/.changeset/proud-pears-study.md deleted file mode 100644 index 025fe95..0000000 --- a/.changeset/proud-pears-study.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'bookmark-manager': patch ---- - -feat:使用mst改造插件配置 diff --git a/CHANGELOG.md b/CHANGELOG.md index b4fbfbe..a3d7f9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## 0.0.27 + +### Patch Changes + +- 954e0ef: 增加mst, 使用mobx改造BookmarkController +- 2db8f88: feat:使用mst改造插件配置 +- feat:优化BookmarkController代码,同时修复上次提交产生的BUG + ## 0.0.26 ### Patch Changes diff --git a/package.json b/package.json index e7e9c29..e3a88e1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bookmark-manager", "displayName": "Bookmark Manager (BM)", "description": "Simple and easy to use bookmark manager", - "version": "0.0.26", + "version": "0.0.27", "engines": { "vscode": "^1.82.0" },