import { Autowired, Injectable } from '@opensumi/di'; import { Emitter, IDisposable, MaybeNull, URI, arrays } from '@opensumi/ide-core-browser'; import { IEditor } from '../../common'; import { IBreadCrumbPart, IBreadCrumbProvider, IBreadCrumbService } from '../types'; import { DefaultBreadCrumbProvider } from './default'; const { addElement } = arrays; @Injectable() export class BreadCrumbServiceImpl implements IBreadCrumbService { private providers: IBreadCrumbProvider[] = []; private _onDidUpdateBreadCrumbResults = new Emitter<{ uri: URI; editor: MaybeNull }>(); public readonly onDidUpdateBreadCrumbResults = this._onDidUpdateBreadCrumbResults.event; // editor-id / uriString private crumbResults: Map, Map> = new Map(); @Autowired() defaultBreadCrumbProvider: DefaultBreadCrumbProvider; constructor() { this.registerBreadCrumbProvider(this.defaultBreadCrumbProvider); } registerBreadCrumbProvider(provider: IBreadCrumbProvider): IDisposable { const disposer = addElement(this.providers, provider); provider.onDidUpdateBreadCrumb((uri: URI) => { this.crumbResults.forEach((crumbResults, editor) => { if (crumbResults.has(uri.toString())) { this.getBreadCrumbs(uri, editor); } }); }); return disposer; } getBreadCrumbs(uri: URI, editor: MaybeNull): IBreadCrumbPart[] | undefined { const editorCrumbResults = this.getEditorCrumbResults(editor); for (const provider of this.providers) { if (provider.handlesUri(uri)) { const lastCrumb = editorCrumbResults.get(uri.toString()); const newCrumb = provider.provideBreadCrumbForUri(uri, editor); if (!isBreadCrumbArrayEqual(lastCrumb, newCrumb)) { editorCrumbResults.set(uri.toString(), newCrumb); this._onDidUpdateBreadCrumbResults.fire({ editor, uri }); } break; } } return editorCrumbResults.get(uri.toString()); } getEditorCrumbResults(editor: MaybeNull): Map { if (!this.crumbResults.has(editor)) { this.crumbResults.set(editor, new Map()); if (editor) { // todo IEditor 应该也暴露 onDispose editor.monacoEditor.onDidDispose(() => { this.crumbResults.delete(editor); }); } } return this.crumbResults.get(editor)!; } disposeCrumb(uri: URI) { // this.crumbResults.delete(uri.toString()); } } function isBreadCrumbArrayEqual(p1: IBreadCrumbPart[] | undefined, p2: IBreadCrumbPart[] | undefined): boolean { if (!p1 && !p2) { return true; } else if (!p1 || !p2) { return false; } else { if (p1.length !== p2.length) { return false; } for (let i = 0; i < p1.length; i++) { if (!isBreadCrumbEqual(p1[i], p2[i])) { return false; } } return true; } } function isBreadCrumbEqual(p1: IBreadCrumbPart, p2: IBreadCrumbPart): boolean { return p1.name === p2.name; }