/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { Position } from './core/position.js'; import { Range } from './core/range.js'; import { Selection } from './core/selection.js'; import { createScopedLineTokens } from './languages/supports.js'; import { CursorColumns } from './core/cursorColumns.js'; import { normalizeIndentation } from './core/indentation.js'; const autoCloseAlways = () => true; const autoCloseNever = () => false; const autoCloseBeforeWhitespace = (chr) => (chr === ' ' || chr === '\t'); export class CursorConfiguration { constructor(languageId, modelOptions, configuration, languageConfigurationService) { this.languageConfigurationService = languageConfigurationService; this._cursorMoveConfigurationBrand = undefined; this._languageId = languageId; const options = configuration.options; const layoutInfo = options.get(133 /* EditorOption.layoutInfo */); this.readOnly = options.get(83 /* EditorOption.readOnly */); this.tabSize = modelOptions.tabSize; this.indentSize = modelOptions.indentSize; this.insertSpaces = modelOptions.insertSpaces; this.stickyTabStops = options.get(106 /* EditorOption.stickyTabStops */); this.lineHeight = options.get(61 /* EditorOption.lineHeight */); this.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2); this.useTabStops = options.get(118 /* EditorOption.useTabStops */); this.wordSeparators = options.get(119 /* EditorOption.wordSeparators */); this.emptySelectionClipboard = options.get(33 /* EditorOption.emptySelectionClipboard */); this.copyWithSyntaxHighlighting = options.get(21 /* EditorOption.copyWithSyntaxHighlighting */); this.multiCursorMergeOverlapping = options.get(71 /* EditorOption.multiCursorMergeOverlapping */); this.multiCursorPaste = options.get(73 /* EditorOption.multiCursorPaste */); this.autoClosingBrackets = options.get(5 /* EditorOption.autoClosingBrackets */); this.autoClosingQuotes = options.get(8 /* EditorOption.autoClosingQuotes */); this.autoClosingDelete = options.get(6 /* EditorOption.autoClosingDelete */); this.autoClosingOvertype = options.get(7 /* EditorOption.autoClosingOvertype */); this.autoSurround = options.get(11 /* EditorOption.autoSurround */); this.autoIndent = options.get(9 /* EditorOption.autoIndent */); this.surroundingPairs = {}; this._electricChars = null; this.shouldAutoCloseBefore = { quote: this._getShouldAutoClose(languageId, this.autoClosingQuotes), bracket: this._getShouldAutoClose(languageId, this.autoClosingBrackets) }; this.autoClosingPairs = this.languageConfigurationService.getLanguageConfiguration(languageId).getAutoClosingPairs(); const surroundingPairs = this.languageConfigurationService.getLanguageConfiguration(languageId).getSurroundingPairs(); if (surroundingPairs) { for (const pair of surroundingPairs) { this.surroundingPairs[pair.open] = pair.close; } } } static shouldRecreate(e) { return (e.hasChanged(133 /* EditorOption.layoutInfo */) || e.hasChanged(119 /* EditorOption.wordSeparators */) || e.hasChanged(33 /* EditorOption.emptySelectionClipboard */) || e.hasChanged(71 /* EditorOption.multiCursorMergeOverlapping */) || e.hasChanged(73 /* EditorOption.multiCursorPaste */) || e.hasChanged(5 /* EditorOption.autoClosingBrackets */) || e.hasChanged(8 /* EditorOption.autoClosingQuotes */) || e.hasChanged(6 /* EditorOption.autoClosingDelete */) || e.hasChanged(7 /* EditorOption.autoClosingOvertype */) || e.hasChanged(11 /* EditorOption.autoSurround */) || e.hasChanged(118 /* EditorOption.useTabStops */) || e.hasChanged(61 /* EditorOption.lineHeight */) || e.hasChanged(83 /* EditorOption.readOnly */)); } get electricChars() { var _a; if (!this._electricChars) { this._electricChars = {}; const electricChars = (_a = this.languageConfigurationService.getLanguageConfiguration(this._languageId).electricCharacter) === null || _a === void 0 ? void 0 : _a.getElectricCharacters(); if (electricChars) { for (const char of electricChars) { this._electricChars[char] = true; } } } return this._electricChars; } /** * Should return opening bracket type to match indentation with */ onElectricCharacter(character, context, column) { const scopedLineTokens = createScopedLineTokens(context, column - 1); const electricCharacterSupport = this.languageConfigurationService.getLanguageConfiguration(scopedLineTokens.languageId).electricCharacter; if (!electricCharacterSupport) { return null; } return electricCharacterSupport.onElectricCharacter(character, scopedLineTokens, column - scopedLineTokens.firstCharOffset); } normalizeIndentation(str) { return normalizeIndentation(str, this.indentSize, this.insertSpaces); } _getShouldAutoClose(languageId, autoCloseConfig) { switch (autoCloseConfig) { case 'beforeWhitespace': return autoCloseBeforeWhitespace; case 'languageDefined': return this._getLanguageDefinedShouldAutoClose(languageId); case 'always': return autoCloseAlways; case 'never': return autoCloseNever; } } _getLanguageDefinedShouldAutoClose(languageId) { const autoCloseBeforeSet = this.languageConfigurationService.getLanguageConfiguration(languageId).getAutoCloseBeforeSet(); return c => autoCloseBeforeSet.indexOf(c) !== -1; } /** * Returns a visible column from a column. * @see {@link CursorColumns} */ visibleColumnFromColumn(model, position) { return CursorColumns.visibleColumnFromColumn(model.getLineContent(position.lineNumber), position.column, this.tabSize); } /** * Returns a visible column from a column. * @see {@link CursorColumns} */ columnFromVisibleColumn(model, lineNumber, visibleColumn) { const result = CursorColumns.columnFromVisibleColumn(model.getLineContent(lineNumber), visibleColumn, this.tabSize); const minColumn = model.getLineMinColumn(lineNumber); if (result < minColumn) { return minColumn; } const maxColumn = model.getLineMaxColumn(lineNumber); if (result > maxColumn) { return maxColumn; } return result; } } export class CursorState { constructor(modelState, viewState) { this._cursorStateBrand = undefined; this.modelState = modelState; this.viewState = viewState; } static fromModelState(modelState) { return new PartialModelCursorState(modelState); } static fromViewState(viewState) { return new PartialViewCursorState(viewState); } static fromModelSelection(modelSelection) { const selection = Selection.liftSelection(modelSelection); const modelState = new SingleCursorState(Range.fromPositions(selection.getSelectionStart()), 0, selection.getPosition(), 0); return CursorState.fromModelState(modelState); } static fromModelSelections(modelSelections) { const states = []; for (let i = 0, len = modelSelections.length; i < len; i++) { states[i] = this.fromModelSelection(modelSelections[i]); } return states; } equals(other) { return (this.viewState.equals(other.viewState) && this.modelState.equals(other.modelState)); } } export class PartialModelCursorState { constructor(modelState) { this.modelState = modelState; this.viewState = null; } } export class PartialViewCursorState { constructor(viewState) { this.modelState = null; this.viewState = viewState; } } /** * Represents the cursor state on either the model or on the view model. */ export class SingleCursorState { constructor(selectionStart, selectionStartLeftoverVisibleColumns, position, leftoverVisibleColumns) { this._singleCursorStateBrand = undefined; this.selectionStart = selectionStart; this.selectionStartLeftoverVisibleColumns = selectionStartLeftoverVisibleColumns; this.position = position; this.leftoverVisibleColumns = leftoverVisibleColumns; this.selection = SingleCursorState._computeSelection(this.selectionStart, this.position); } equals(other) { return (this.selectionStartLeftoverVisibleColumns === other.selectionStartLeftoverVisibleColumns && this.leftoverVisibleColumns === other.leftoverVisibleColumns && this.position.equals(other.position) && this.selectionStart.equalsRange(other.selectionStart)); } hasSelection() { return (!this.selection.isEmpty() || !this.selectionStart.isEmpty()); } move(inSelectionMode, lineNumber, column, leftoverVisibleColumns) { if (inSelectionMode) { // move just position return new SingleCursorState(this.selectionStart, this.selectionStartLeftoverVisibleColumns, new Position(lineNumber, column), leftoverVisibleColumns); } else { // move everything return new SingleCursorState(new Range(lineNumber, column, lineNumber, column), leftoverVisibleColumns, new Position(lineNumber, column), leftoverVisibleColumns); } } static _computeSelection(selectionStart, position) { if (selectionStart.isEmpty() || !position.isBeforeOrEqual(selectionStart.getStartPosition())) { return Selection.fromPositions(selectionStart.getStartPosition(), position); } else { return Selection.fromPositions(selectionStart.getEndPosition(), position); } } } export class EditOperationResult { constructor(type, commands, opts) { this._editOperationResultBrand = undefined; this.type = type; this.commands = commands; this.shouldPushStackElementBefore = opts.shouldPushStackElementBefore; this.shouldPushStackElementAfter = opts.shouldPushStackElementAfter; } } export function isQuote(ch) { return (ch === '\'' || ch === '"' || ch === '`'); }