| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { once } from '../../../../base/common/functional.js';
- import { DisposableStore, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
- import { withNullAsUndefined } from '../../../../base/common/types.js';
- import { getCodeEditor, isDiffEditor } from '../../../browser/editorBrowser.js';
- import { OverviewRulerLane } from '../../../common/model.js';
- import { overviewRulerRangeHighlight } from '../../../common/core/editorColorRegistry.js';
- import { themeColorFromId } from '../../../../platform/theme/common/themeService.js';
- /**
- * A reusable quick access provider for the editor with support
- * for adding decorations for navigating in the currently active file
- * (for example "Go to line", "Go to symbol").
- */
- export class AbstractEditorNavigationQuickAccessProvider {
- constructor(options) {
- this.options = options;
- //#endregion
- //#region Decorations Utils
- this.rangeHighlightDecorationId = undefined;
- }
- //#region Provider methods
- provide(picker, token) {
- var _a;
- const disposables = new DisposableStore();
- // Apply options if any
- picker.canAcceptInBackground = !!((_a = this.options) === null || _a === void 0 ? void 0 : _a.canAcceptInBackground);
- // Disable filtering & sorting, we control the results
- picker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;
- // Provide based on current active editor
- const pickerDisposable = disposables.add(new MutableDisposable());
- pickerDisposable.value = this.doProvide(picker, token);
- // Re-create whenever the active editor changes
- disposables.add(this.onDidActiveTextEditorControlChange(() => {
- // Clear old
- pickerDisposable.value = undefined;
- // Add new
- pickerDisposable.value = this.doProvide(picker, token);
- }));
- return disposables;
- }
- doProvide(picker, token) {
- const disposables = new DisposableStore();
- // With text control
- const editor = this.activeTextEditorControl;
- if (editor && this.canProvideWithTextEditor(editor)) {
- const context = { editor };
- // Restore any view state if this picker was closed
- // without actually going to a line
- const codeEditor = getCodeEditor(editor);
- if (codeEditor) {
- // Remember view state and update it when the cursor position
- // changes even later because it could be that the user has
- // configured quick access to remain open when focus is lost and
- // we always want to restore the current location.
- let lastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());
- disposables.add(codeEditor.onDidChangeCursorPosition(() => {
- lastKnownEditorViewState = withNullAsUndefined(editor.saveViewState());
- }));
- context.restoreViewState = () => {
- if (lastKnownEditorViewState && editor === this.activeTextEditorControl) {
- editor.restoreViewState(lastKnownEditorViewState);
- }
- };
- disposables.add(once(token.onCancellationRequested)(() => { var _a; return (_a = context.restoreViewState) === null || _a === void 0 ? void 0 : _a.call(context); }));
- }
- // Clean up decorations on dispose
- disposables.add(toDisposable(() => this.clearDecorations(editor)));
- // Ask subclass for entries
- disposables.add(this.provideWithTextEditor(context, picker, token));
- }
- // Without text control
- else {
- disposables.add(this.provideWithoutTextEditor(picker, token));
- }
- return disposables;
- }
- /**
- * Subclasses to implement if they can operate on the text editor.
- */
- canProvideWithTextEditor(editor) {
- return true;
- }
- gotoLocation({ editor }, options) {
- editor.setSelection(options.range);
- editor.revealRangeInCenter(options.range, 0 /* ScrollType.Smooth */);
- if (!options.preserveFocus) {
- editor.focus();
- }
- }
- getModel(editor) {
- var _a;
- return isDiffEditor(editor) ?
- (_a = editor.getModel()) === null || _a === void 0 ? void 0 : _a.modified :
- editor.getModel();
- }
- addDecorations(editor, range) {
- editor.changeDecorations(changeAccessor => {
- // Reset old decorations if any
- const deleteDecorations = [];
- if (this.rangeHighlightDecorationId) {
- deleteDecorations.push(this.rangeHighlightDecorationId.overviewRulerDecorationId);
- deleteDecorations.push(this.rangeHighlightDecorationId.rangeHighlightId);
- this.rangeHighlightDecorationId = undefined;
- }
- // Add new decorations for the range
- const newDecorations = [
- // highlight the entire line on the range
- {
- range,
- options: {
- description: 'quick-access-range-highlight',
- className: 'rangeHighlight',
- isWholeLine: true
- }
- },
- // also add overview ruler highlight
- {
- range,
- options: {
- description: 'quick-access-range-highlight-overview',
- overviewRuler: {
- color: themeColorFromId(overviewRulerRangeHighlight),
- position: OverviewRulerLane.Full
- }
- }
- }
- ];
- const [rangeHighlightId, overviewRulerDecorationId] = changeAccessor.deltaDecorations(deleteDecorations, newDecorations);
- this.rangeHighlightDecorationId = { rangeHighlightId, overviewRulerDecorationId };
- });
- }
- clearDecorations(editor) {
- const rangeHighlightDecorationId = this.rangeHighlightDecorationId;
- if (rangeHighlightDecorationId) {
- editor.changeDecorations(changeAccessor => {
- changeAccessor.deltaDecorations([
- rangeHighlightDecorationId.overviewRulerDecorationId,
- rangeHighlightDecorationId.rangeHighlightId
- ], []);
- });
- this.rangeHighlightDecorationId = undefined;
- }
- }
- }
|