123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { Disposable, DisposableStore, toDisposable } from '../../../base/common/lifecycle.js';
- import { getCodeEditor } from '../../browser/editorBrowser.js';
- import { AbstractEditorNavigationQuickAccessProvider } from './editorNavigationQuickAccess.js';
- import { localize } from '../../../nls.js';
- export class AbstractGotoLineQuickAccessProvider extends AbstractEditorNavigationQuickAccessProvider {
- constructor() {
- super({ canAcceptInBackground: true });
- }
- provideWithoutTextEditor(picker) {
- const label = localize('cannotRunGotoLine', "Open a text editor first to go to a line.");
- picker.items = [{ label }];
- picker.ariaLabel = label;
- return Disposable.None;
- }
- provideWithTextEditor(context, picker, token) {
- const editor = context.editor;
- const disposables = new DisposableStore();
- // Goto line once picked
- disposables.add(picker.onDidAccept(event => {
- const [item] = picker.selectedItems;
- if (item) {
- if (!this.isValidLineNumber(editor, item.lineNumber)) {
- return;
- }
- this.gotoLocation(context, { range: this.toRange(item.lineNumber, item.column), keyMods: picker.keyMods, preserveFocus: event.inBackground });
- if (!event.inBackground) {
- picker.hide();
- }
- }
- }));
- // React to picker changes
- const updatePickerAndEditor = () => {
- const position = this.parsePosition(editor, picker.value.trim().substr(AbstractGotoLineQuickAccessProvider.PREFIX.length));
- const label = this.getPickLabel(editor, position.lineNumber, position.column);
- // Picker
- picker.items = [{
- lineNumber: position.lineNumber,
- column: position.column,
- label
- }];
- // ARIA Label
- picker.ariaLabel = label;
- // Clear decorations for invalid range
- if (!this.isValidLineNumber(editor, position.lineNumber)) {
- this.clearDecorations(editor);
- return;
- }
- // Reveal
- const range = this.toRange(position.lineNumber, position.column);
- editor.revealRangeInCenter(range, 0 /* Smooth */);
- // Decorate
- this.addDecorations(editor, range);
- };
- updatePickerAndEditor();
- disposables.add(picker.onDidChangeValue(() => updatePickerAndEditor()));
- // Adjust line number visibility as needed
- const codeEditor = getCodeEditor(editor);
- if (codeEditor) {
- const options = codeEditor.getOptions();
- const lineNumbers = options.get(59 /* lineNumbers */);
- if (lineNumbers.renderType === 2 /* Relative */) {
- codeEditor.updateOptions({ lineNumbers: 'on' });
- disposables.add(toDisposable(() => codeEditor.updateOptions({ lineNumbers: 'relative' })));
- }
- }
- return disposables;
- }
- toRange(lineNumber = 1, column = 1) {
- return {
- startLineNumber: lineNumber,
- startColumn: column,
- endLineNumber: lineNumber,
- endColumn: column
- };
- }
- parsePosition(editor, value) {
- // Support line-col formats of `line,col`, `line:col`, `line#col`
- const numbers = value.split(/,|:|#/).map(part => parseInt(part, 10)).filter(part => !isNaN(part));
- const endLine = this.lineCount(editor) + 1;
- return {
- lineNumber: numbers[0] > 0 ? numbers[0] : endLine + numbers[0],
- column: numbers[1]
- };
- }
- getPickLabel(editor, lineNumber, column) {
- // Location valid: indicate this as picker label
- if (this.isValidLineNumber(editor, lineNumber)) {
- if (this.isValidColumn(editor, lineNumber, column)) {
- return localize('gotoLineColumnLabel', "Go to line {0} and character {1}.", lineNumber, column);
- }
- return localize('gotoLineLabel', "Go to line {0}.", lineNumber);
- }
- // Location invalid: show generic label
- const position = editor.getPosition() || { lineNumber: 1, column: 1 };
- const lineCount = this.lineCount(editor);
- if (lineCount > 1) {
- return localize('gotoLineLabelEmptyWithLimit', "Current Line: {0}, Character: {1}. Type a line number between 1 and {2} to navigate to.", position.lineNumber, position.column, lineCount);
- }
- return localize('gotoLineLabelEmpty', "Current Line: {0}, Character: {1}. Type a line number to navigate to.", position.lineNumber, position.column);
- }
- isValidLineNumber(editor, lineNumber) {
- if (!lineNumber || typeof lineNumber !== 'number') {
- return false;
- }
- return lineNumber > 0 && lineNumber <= this.lineCount(editor);
- }
- isValidColumn(editor, lineNumber, column) {
- if (!column || typeof column !== 'number') {
- return false;
- }
- const model = this.getModel(editor);
- if (!model) {
- return false;
- }
- const positionCandidate = { lineNumber, column };
- return model.validatePosition(positionCandidate).equals(positionCandidate);
- }
- lineCount(editor) {
- var _a, _b;
- return (_b = (_a = this.getModel(editor)) === null || _a === void 0 ? void 0 : _a.getLineCount()) !== null && _b !== void 0 ? _b : 0;
- }
- }
- AbstractGotoLineQuickAccessProvider.PREFIX = ':';
|