diff --git a/src/events.ts b/src/events.ts index b0dc44c..06b85b5 100644 --- a/src/events.ts +++ b/src/events.ts @@ -16,7 +16,7 @@ import {resolveBookmarkController} from './bootstrap'; import resolveServiceManager from './services/ServiceManager'; import {IBookmark} from './stores/bookmark'; -let onDidChangeActiveTextEditor: Disposable | undefined; +// let onDidChangeActiveTextEditor: Disposable | undefined; let onDidChangeVisibleTextEditors: Disposable | undefined; let onDidSaveTextDocumentDisposable: Disposable | undefined; let onDidCursorChangeDisposable: Disposable | undefined; @@ -27,20 +27,20 @@ let onDidDeleteFilesDisposable: Disposable | undefined; let onDidTextSelectionDisposable: Disposable | undefined; export function updateChangeActiveTextEditorListener() { - onDidChangeActiveTextEditor?.dispose(); + // onDidChangeActiveTextEditor?.dispose(); const sm = resolveServiceManager(); // 当打开多个editor group时,更新每个editor的中的decorations let visibleTextEditors = window.visibleTextEditors; if (visibleTextEditors.length) { visibleTextEditors.forEach(editor => { - sm.decorationService.updateDecorationsByEditor(editor); + sm.decorationService.updateDecorationsByEditor(editor, true); }); } // onDidChangeActiveTextEditor = window.onDidChangeActiveTextEditor(ev => { // if (!ev) { // return; // } - // sm.decorationService.updateDecorationsByEditor(ev); + // sm.decorationService.updateDecorationsByEditor(ev, true); // }); } @@ -227,7 +227,7 @@ export function updateTextEditorSelectionListener() { } export function disableAllEvents() { - onDidChangeActiveTextEditor?.dispose(); + // onDidChangeActiveTextEditor?.dispose(); onDidChangeBreakpoints?.dispose(); onDidCursorChangeDisposable?.dispose(); onDidSaveTextDocumentDisposable?.dispose(); diff --git a/src/providers/BookmarksTreeItem.ts b/src/providers/BookmarksTreeItem.ts index a04d64e..39bb5dd 100644 --- a/src/providers/BookmarksTreeItem.ts +++ b/src/providers/BookmarksTreeItem.ts @@ -79,15 +79,16 @@ export default class BookmarkTreeItem extends BaseTreeItem { this._resolveIconPath(); } - private _resolveIconPath() { + private async _resolveIconPath() { if (this.contextValue === BookmarkTreeItemCtxValueEnum.FILE) { const meta = this.meta as BookmarksGroupedByFileType; this.iconPath = ThemeIcon.File; this.resourceUri = Uri.parse(meta.fileName); } else if (this.contextValue === BookmarkTreeItemCtxValueEnum.COLOR) { const _meta = this.meta as BookmarksGroupedByColorType; + // TODO: 使用默认的图标 - this.iconPath = _meta.color; + this.iconPath = await this._sm.iconsService.getDotIcon(_meta.color); } else if (this.contextValue === BookmarkTreeItemCtxValueEnum.BOOKMARK) { const meta = this.meta as IBookmark; const color = meta.color; diff --git a/src/services/DecorationService.ts b/src/services/DecorationService.ts index 2d0277e..730f0e2 100644 --- a/src/services/DecorationService.ts +++ b/src/services/DecorationService.ts @@ -1,23 +1,29 @@ -import {TextEditor, window} from 'vscode'; +import { + DecorationRangeBehavior, + l10n, + OverviewRulerLane, + TextEditor, + TextEditorDecorationType, + window, +} from 'vscode'; import {ServiceManager} from './ServiceManager'; import {resolveBookmarkController} from '../bootstrap'; import BookmarksController from '../controllers/BookmarksController'; -import {IBookmark} from '../stores/bookmark'; +import {Bookmark, IBookmark} from '../stores/bookmark'; import {BaseService} from './BaseService'; +import {DEFAULT_BOOKMARK_COLOR} from '../constants'; +import {Instance} from 'mobx-state-tree'; /** * 装饰器服务类 */ export default class DecorationService extends BaseService { + private _decorations: Map; constructor(sm: ServiceManager) { super(DecorationService.name, sm); - } - - setupAllDecorations() { - // this.restoreAllDecorations(); + this._decorations = new Map(); this.sm.configService.onDidChangeConfiguration(() => { - // this.restoreAllDecorations(); - // this.updateActiveEditorAllDecorations(); + this.updateActiveEditorAllDecorations(true); }); } @@ -43,12 +49,14 @@ export default class DecorationService extends BaseService { editor: TextEditor, options: { bookmarks: IBookmark[]; + clear: boolean; }, ) { try { - const {bookmarks} = options; options.bookmarks.forEach(it => { - editor.setDecorations(it.textDecoration, [it.prettierRangesOrOptions]); + editor.setDecorations(this.getTextDecoration(it, options.clear), [ + it.prettierRangesOrOptions, + ]); }); } catch (error) { this._logger.error(error); @@ -71,7 +79,8 @@ export default class DecorationService extends BaseService { const bookmarks = controller.getBookmarkStoreByFileUri(editor.document.uri); this.updateDecoration(editor, { - bookmarks: clear ? [] : bookmarks, + bookmarks, + clear, }); } @@ -94,13 +103,123 @@ export default class DecorationService extends BaseService { * dispose 所有的装饰器 */ disposeAllDecorations() { - const controller = resolveBookmarkController() as BookmarksController; - if (!controller) { + this._decorations.forEach(it => it.dispose()); + } + + createTextDecoration(bookmark: IBookmark) { + let color = bookmark.plainColor || DEFAULT_BOOKMARK_COLOR; + + const { + fontWeight, + showTextDecoration, + showGutterIcon, + showGutterInOverviewRuler, + alwaysUseDefaultColor, + wholeLine, + textDecorationLine, + textDecorationStyle, + textDecorationThickness, + highlightBackground, + showBorder, + border, + showOutline, + outline, + } = this.configure.decoration; + + let overviewRulerColor; + let overviewRulerLane: OverviewRulerLane | undefined = undefined; + if (showGutterInOverviewRuler) { + overviewRulerColor = bookmark.plainColor; + overviewRulerLane = OverviewRulerLane.Center; + } else { + overviewRulerColor = undefined; + } + + let _showGutterIcon = showGutterIcon; + + if (!(showGutterIcon || showGutterInOverviewRuler || showTextDecoration)) { + window.showInformationMessage( + l10n.t( + `'showGutterIcon', 'showGutterInOverviewRuler', 'showTextDecoration' not available at the same time this is only 'false'`, + ), + ); + _showGutterIcon = true; + } + + if (alwaysUseDefaultColor) { + color = + this.store.colors.find(it => it.label === 'default')?.value || + DEFAULT_BOOKMARK_COLOR; + } + + let rangeBehavior = DecorationRangeBehavior.ClosedClosed; + + const decoration = window.createTextEditorDecorationType({ + isWholeLine: wholeLine, + borderRadius: '2px', + borderColor: color, + outlineColor: color, + fontWeight, + overviewRulerLane, + overviewRulerColor, + rangeBehavior, + gutterIconPath: bookmark.iconPath, + gutterIconSize: 'auto', + border: showBorder ? border : '', + outline: showOutline ? outline : '', + backgroundColor: highlightBackground ? color : '', + textDecoration: showTextDecoration + ? `${textDecorationLine} ${textDecorationStyle} ${textDecorationThickness} ${color}` + : '', + }); + + this._decorations.set(bookmark.id, decoration); + + return decoration; + } + + updateTextDecoration(bookmark: Instance) { + const editor = window.visibleTextEditors.find( + it => it.document.uri.fsPath === bookmark.fileId, + ); + if (!editor) { return; } - controller.disposeAllBookmarkTextDecorations(); + const prevTextDecoration = this._decorations.get(bookmark.id); + if (prevTextDecoration) { + editor.setDecorations(prevTextDecoration, []); + prevTextDecoration.dispose(); + this._decorations.delete(bookmark.id); + } + const newTextDecoration = this.getTextDecoration(bookmark); + return newTextDecoration; } + getTextDecoration(bookmark: IBookmark, clear: boolean = false) { + const textDecoration = this._decorations.get(bookmark.id); + if (!textDecoration) { + return this.createTextDecoration(bookmark); + } else if (clear) { + return this.updateTextDecoration(bookmark); + } + return textDecoration; + } + + removeTextDecoration(bookmark: IBookmark) { + const textDecoration = this._decorations.get(bookmark.id); + if (!textDecoration) { + return; + } + const editor = window.visibleTextEditors.find( + it => it.document.uri.fsPath === bookmark.fileId, + ); + if (editor) { + editor.setDecorations(textDecoration, []); + } + + this._decorations.delete(bookmark.id); + textDecoration.dispose(); + } dispose(): void { this.disposeAllDecorations(); } diff --git a/src/services/IconsService.ts b/src/services/IconsService.ts index 24225c5..d1671c6 100644 --- a/src/services/IconsService.ts +++ b/src/services/IconsService.ts @@ -7,6 +7,8 @@ import { import {IconifyIconsType} from '../types/icon'; import {BaseService} from './BaseService'; import {applySnapshot, IDisposer, onSnapshot} from 'mobx-state-tree'; +import {Uri} from 'vscode'; +import {escapeColor} from '../utils'; /** * @zh 装饰器和树上的图标服务类 @@ -63,9 +65,7 @@ export class IconsService extends BaseService { return; } - if ( - !this.store.icons.find(it => it.prefix === prefix && it.name === name) - ) { + if (!this.store.icons.find(it => it.id === prefixWithName)) { const response = await this.download( `${iconfiy_public_url}/${prefix}.json?icons=${name}`, ); @@ -144,6 +144,34 @@ export class IconsService extends BaseService { } } + async getIconUri(name: string, colorLabel: string = 'default') { + let icon = this.store.icons.find(it => it.id === name); + + if (!icon) { + await this.downloadIcon(name); + icon = this.store.icons.find(it => it.id === name); + } + + let color = + this.store.colors.find(it => it.label === colorLabel)?.value || + this.configure.configure.defaultBookmarkIconColor; + + color = color.startsWith('#') ? escapeColor(color) : color; + + const body = icon?.body.replace(/fill="(\w.*?)"/gi, `fill="${color}"`); + + return Uri.parse( + `data:image/svg+xml;utf8,${body}`, + ); + } + + async getDotIcon(colorLabel: string) { + return this.getIconUri( + this.configure.configure.defaultBookmarkIcon, + colorLabel, + ); + } + dispose(): void { this._snapshotDisposer(); this._snapshotDisposer2(); diff --git a/src/stores/bookmark-store.ts b/src/stores/bookmark-store.ts index dc55484..01bf449 100644 --- a/src/stores/bookmark-store.ts +++ b/src/stores/bookmark-store.ts @@ -533,6 +533,7 @@ export const BookmarksStore = types } for (let bookmark of bookmarks) { + bookmark.removeTextDecoration(); self.bookmarks.remove(bookmark); } } @@ -542,6 +543,7 @@ export const BookmarksStore = types if (idx === -1) { return false; } + self.bookmarks[idx].removeTextDecoration(); self.bookmarks.splice(idx, 1); return true; } @@ -578,6 +580,7 @@ export const BookmarksStore = types it => it.fileId === fileUri.fsPath, ); for (let item of deleteItems) { + item.removeTextDecoration(); self.bookmarks.remove(item); } } @@ -585,6 +588,7 @@ export const BookmarksStore = types function clearBookmarksByColor(color: string) { const bookmarks = self.bookmarks.filter(it => it.color === color); for (let bookmark of bookmarks) { + bookmark.removeTextDecoration(); self.bookmarks.remove(bookmark); } } @@ -599,6 +603,7 @@ export const BookmarksStore = types const delGroups = self.groups.filter(it => it.workspace === wsName); for (let bookmark of delBookmarks) { + bookmark.removeTextDecoration(); self.bookmarks.remove(bookmark); } @@ -606,6 +611,7 @@ export const BookmarksStore = types self.groups.remove(group); } } else { + self.bookmarks.forEach(it => it.removeTextDecoration()); self.bookmarks.clear(); } if (self.groups.find(it => it.id !== DEFAULT_BOOKMARK_GROUP_ID)) { diff --git a/src/stores/bookmark.ts b/src/stores/bookmark.ts index 11379bc..899f11f 100644 --- a/src/stores/bookmark.ts +++ b/src/stores/bookmark.ts @@ -1,12 +1,4 @@ -import {BookmarkGroup} from './bookmark-group'; -import { - getEnv, - getParent, - getRoot, - Instance, - SnapshotIn, - types, -} from 'mobx-state-tree'; +import {Instance, SnapshotIn, types} from 'mobx-state-tree'; import { default_bookmark_color, DEFAULT_BOOKMARK_COLOR, @@ -33,7 +25,6 @@ import { } from './custom'; import {DEFAULT_BOOKMARK_GROUP_ID} from '../constants/bookmark'; import {ServiceManager} from '../services'; -import {BookmarksStore} from './bookmark-store'; import {resolveBookmarkController} from '../bootstrap'; export type BookmarksGroupedByColorType = { @@ -215,7 +206,13 @@ export const Bookmark = types ? defaultLabeledBookmarkIcon : defaultBookmarkIcon; - const icon = icons.find(it => it.id === iconId); + let icon = icons.find(it => it.id === iconId); + if (!icon) { + icon = + self.label.length || self.description.length + ? icons.find(it => it.id === defaultLabeledBookmarkIcon) + : icons.find(it => it.id === defaultBookmarkIcon); + } const body = icon?.body.replace( /fill="currentColor"/gi, @@ -230,84 +227,6 @@ export const Bookmark = types const controller = resolveBookmarkController(); return controller.store.groups.find(it => it.id === self.groupId); }, - - /** - * @zh 书签的装饰器 - */ - get textDecoration() { - const {store, configure} = ServiceManager.instance; - let color = - (self as Instance).plainColor || - DEFAULT_BOOKMARK_COLOR; - - const { - fontWeight, - showTextDecoration, - showGutterIcon, - showGutterInOverviewRuler, - alwaysUseDefaultColor, - wholeLine, - textDecorationLine, - textDecorationStyle, - textDecorationThickness, - highlightBackground, - showBorder, - border, - showOutline, - outline, - } = configure.decoration!; - - let overviewRulerColor; - let overviewRulerLane: OverviewRulerLane | undefined = undefined; - if (showGutterInOverviewRuler) { - overviewRulerColor = self.color; - overviewRulerLane = OverviewRulerLane.Center; - } else { - overviewRulerColor = undefined; - } - - let _showGutterIcon = showGutterIcon; - - if ( - !(showGutterIcon || showGutterInOverviewRuler || showTextDecoration) - ) { - window.showInformationMessage( - l10n.t( - `'showGutterIcon', 'showGutterInOverviewRuler', 'showTextDecoration' not available at the same time this is only 'false'`, - ), - ); - _showGutterIcon = true; - } - - if (alwaysUseDefaultColor) { - color = - store.colors.find(it => it.label === 'default')?.value || - DEFAULT_BOOKMARK_COLOR; - } - - let rangeBehavior = DecorationRangeBehavior.ClosedClosed; - - const decoration = window.createTextEditorDecorationType({ - isWholeLine: wholeLine, - borderRadius: '2px', - borderColor: color, - outlineColor: color, - fontWeight, - overviewRulerLane, - overviewRulerColor, - rangeBehavior, - gutterIconPath: (self as Instance).iconPath, - gutterIconSize: 'auto', - border: showBorder ? border : '', - outline: showOutline ? outline : '', - backgroundColor: highlightBackground ? color : '', - textDecoration: showTextDecoration - ? `${textDecorationLine} ${textDecorationStyle} ${textDecorationThickness} ${color}` - : '', - }); - - return decoration; - }, }; }) .actions(self => { @@ -318,6 +237,12 @@ export const Bookmark = types self[key] = value; } + function updateTextDecoration() { + ServiceManager.instance.decorationService.updateTextDecoration( + self as Instance, + ); + } + function update(dto: Partial>) { Object.keys(dto).forEach(key => { // @ts-ignore @@ -327,22 +252,26 @@ export const Bookmark = types function updateLabel(label: string) { self.label = label; + updateTextDecoration(); } function updateDescription(desc: string) { self.description = desc; + updateTextDecoration(); } function updateColor(newColor: string) { self.color = ServiceManager.instance.store.colors.find(it => it.label === newColor) ?.label || 'default'; + updateTextDecoration(); } function updateFileUri(uri: Uri) { self.fileUri = { fsPath: uri.fsPath, }; + updateTextDecoration(); } function changeGroupId(id: string) { @@ -384,20 +313,7 @@ export const Bookmark = types self.sortedInfo.update(key, value); } } - function afterCreate() { - const editors = window.visibleTextEditors; - if (!editors.length) { - return; - } - for (const editor of editors) { - if (editor.document.uri.fsPath !== self.fileId) { - continue; - } - editor.setDecorations(self.textDecoration, [ - self.prettierRangesOrOptions, - ]); - } - } + function afterCreate() {} /** * @zh 当书签创建时调用 渲染装饰器 */ @@ -417,8 +333,11 @@ export const Bookmark = types updateColorSortedIndex, updateWorkspaceSortedIndex, updateFileSortedIndex, - disposeTextDecoration() { - self.textDecoration.dispose(); + updateTextDecoration, + removeTextDecoration() { + ServiceManager.instance.decorationService.removeTextDecoration( + self as Instance, + ); }, }; });