monaco-editor11 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/css.worker-C7FogG4G.js +93 -0
- package/dist/assets/editor.worker-iXcRX1Tq.js +26 -0
- package/dist/assets/html.worker-C8VxctEJ.js +470 -0
- package/dist/assets/json.worker-CMC9kgPL.js +58 -0
- package/dist/assets/ts.worker-CtTJ3hNN.js +67731 -0
- package/dist/index.d.ts +0 -6
- package/dist/monaco-editor11.es.js +49 -78
- package/dist/monaco-editor11.umd.js +1 -50
- package/dist/monaco.d.ts +8 -0
- package/dist/workers/common/initialize.js +16 -0
- package/dist/workers/common/workers.js +141 -0
- package/dist/workers/editor/common/abstractSyntaxTokenBackend.js +128 -0
- package/dist/workers/editor/common/abstractText.js +89 -0
- package/dist/workers/editor/common/ast.js +485 -0
- package/dist/workers/editor/common/autoIndent.js +390 -0
- package/dist/workers/editor/common/beforeEditPositionMapper.js +110 -0
- package/dist/workers/editor/common/bracketPairsImpl.js +717 -0
- package/dist/workers/editor/common/bracketPairsTree.js +343 -0
- package/dist/workers/editor/common/brackets.js +108 -0
- package/dist/workers/editor/common/characterClassifier.js +59 -0
- package/dist/workers/editor/common/characterPair.js +40 -0
- package/dist/workers/editor/common/colorizedBracketPairsDecorationProvider.js +97 -0
- package/dist/workers/editor/common/columnRange.js +35 -0
- package/dist/workers/editor/common/combineTextEditInfos.js +124 -0
- package/dist/workers/editor/common/common.js +20 -0
- package/dist/workers/editor/common/computeMovedLines.js +249 -0
- package/dist/workers/editor/common/concat23Trees.js +192 -0
- package/dist/workers/editor/common/contiguousMultilineTokens.js +32 -0
- package/dist/workers/editor/common/contiguousMultilineTokensBuilder.js +23 -0
- package/dist/workers/editor/common/contiguousTokensEditing.js +128 -0
- package/dist/workers/editor/common/contiguousTokensStore.js +207 -0
- package/dist/workers/editor/common/coordinatesConverter.js +51 -0
- package/dist/workers/editor/common/cursor.js +899 -0
- package/dist/workers/editor/common/cursorAtomicMoveOperations.js +145 -0
- package/dist/workers/editor/common/cursorCollection.js +194 -0
- package/dist/workers/editor/common/cursorColumnSelection.js +93 -0
- package/dist/workers/editor/common/cursorColumns.js +112 -0
- package/dist/workers/editor/common/cursorCommon.js +250 -0
- package/dist/workers/editor/common/cursorContext.js +15 -0
- package/dist/workers/editor/common/cursorDeleteOperations.js +231 -0
- package/dist/workers/editor/common/cursorMoveCommands.js +676 -0
- package/dist/workers/editor/common/cursorMoveOperations.js +290 -0
- package/dist/workers/editor/common/cursorTypeEditOperations.js +968 -0
- package/dist/workers/editor/common/cursorTypeOperations.js +173 -0
- package/dist/workers/editor/common/cursorUtils.js +75 -0
- package/dist/workers/editor/common/cursorWordOperations.js +720 -0
- package/dist/workers/editor/common/defaultDocumentColorsComputer.js +138 -0
- package/dist/workers/editor/common/defaultLinesDiffComputer.js +188 -0
- package/dist/workers/editor/common/diffAlgorithm.js +139 -0
- package/dist/workers/editor/common/diffEditor.js +38 -0
- package/dist/workers/editor/common/dynamicProgrammingDiffing.js +101 -0
- package/dist/workers/editor/common/edit.js +183 -0
- package/dist/workers/editor/common/editOperation.js +36 -0
- package/dist/workers/editor/common/editStack.js +363 -0
- package/dist/workers/editor/common/editorAction.js +26 -0
- package/dist/workers/editor/common/editorBaseApi.js +43 -0
- package/dist/workers/editor/common/editorColorRegistry.js +102 -0
- package/dist/workers/editor/common/editorCommon.js +13 -0
- package/dist/workers/editor/common/editorConfigurationSchema.js +338 -0
- package/dist/workers/editor/common/editorContextKeys.js +84 -0
- package/dist/workers/editor/common/editorFeatures.js +17 -0
- package/dist/workers/editor/common/editorOptions.js +3440 -0
- package/dist/workers/editor/common/editorTheme.js +23 -0
- package/dist/workers/editor/common/editorWebWorker.js +299 -0
- package/dist/workers/editor/common/editorWorker.js +9 -0
- package/dist/workers/editor/common/editorWorkerHost.js +15 -0
- package/dist/workers/editor/common/editorZoom.js +26 -0
- package/dist/workers/editor/common/electricCharacter.js +55 -0
- package/dist/workers/editor/common/encodedTokenAttributes.js +79 -0
- package/dist/workers/editor/common/enterAction.js +53 -0
- package/dist/workers/editor/common/eolCounter.js +44 -0
- package/dist/workers/editor/common/findSectionHeaders.js +128 -0
- package/dist/workers/editor/common/fixBrackets.js +67 -0
- package/dist/workers/editor/common/fixedArray.js +70 -0
- package/dist/workers/editor/common/fontInfo.js +172 -0
- package/dist/workers/editor/common/fontInfoFromSettings.js +29 -0
- package/dist/workers/editor/common/getIconClasses.js +106 -0
- package/dist/workers/editor/common/getPositionOffsetTransformerFromTextModel.js +24 -0
- package/dist/workers/editor/common/glyphLanesModel.js +61 -0
- package/dist/workers/editor/common/guidesTextModelPart.js +405 -0
- package/dist/workers/editor/common/heuristicSequenceOptimizations.js +374 -0
- package/dist/workers/editor/common/indentRules.js +63 -0
- package/dist/workers/editor/common/indentation.js +39 -0
- package/dist/workers/editor/common/indentationGuesser.js +178 -0
- package/dist/workers/editor/common/indentationLineProcessor.js +193 -0
- package/dist/workers/editor/common/inlineDecorations.js +26 -0
- package/dist/workers/editor/common/inplaceReplaceSupport.js +87 -0
- package/dist/workers/editor/common/inputMode.js +22 -0
- package/dist/workers/editor/common/intervalTree.js +1002 -0
- package/dist/workers/editor/common/language.js +9 -0
- package/dist/workers/editor/common/languageBracketsConfiguration.js +133 -0
- package/dist/workers/editor/common/languageConfiguration.js +138 -0
- package/dist/workers/editor/common/languageConfigurationRegistry.js +361 -0
- package/dist/workers/editor/common/languageFeatureDebounce.js +137 -0
- package/dist/workers/editor/common/languageFeatureRegistry.js +180 -0
- package/dist/workers/editor/common/languageFeatures.js +9 -0
- package/dist/workers/editor/common/languageFeaturesService.js +47 -0
- package/dist/workers/editor/common/languageSelector.js +112 -0
- package/dist/workers/editor/common/languageService.js +92 -0
- package/dist/workers/editor/common/languages.js +522 -0
- package/dist/workers/editor/common/languagesAssociations.js +193 -0
- package/dist/workers/editor/common/languagesRegistry.js +237 -0
- package/dist/workers/editor/common/legacyLinesDiffComputer.js +468 -0
- package/dist/workers/editor/common/length.js +129 -0
- package/dist/workers/editor/common/lineDecorations.js +208 -0
- package/dist/workers/editor/common/lineEdit.js +75 -0
- package/dist/workers/editor/common/lineHeights.js +370 -0
- package/dist/workers/editor/common/linePart.js +25 -0
- package/dist/workers/editor/common/lineRange.js +312 -0
- package/dist/workers/editor/common/lineSequence.js +36 -0
- package/dist/workers/editor/common/lineTokens.js +405 -0
- package/dist/workers/editor/common/linesDiffComputer.js +29 -0
- package/dist/workers/editor/common/linesDiffComputers.js +13 -0
- package/dist/workers/editor/common/linesLayout.js +765 -0
- package/dist/workers/editor/common/linesSliceCharSequence.js +205 -0
- package/dist/workers/editor/common/linkComputer.js +269 -0
- package/dist/workers/editor/common/markerDecorations.js +9 -0
- package/dist/workers/editor/common/markerDecorationsService.js +248 -0
- package/dist/workers/editor/common/minimapTokensColorTracker.js +58 -0
- package/dist/workers/editor/common/mirrorTextModel.js +117 -0
- package/dist/workers/editor/common/model.js +9 -0
- package/dist/workers/editor/common/modelLineProjection.js +350 -0
- package/dist/workers/editor/common/modelLineProjectionData.js +297 -0
- package/dist/workers/editor/common/modelService.js +413 -0
- package/dist/workers/editor/common/modesRegistry.js +75 -0
- package/dist/workers/editor/common/monospaceLineBreaksComputer.js +473 -0
- package/dist/workers/editor/common/myersDiffAlgorithm.js +159 -0
- package/dist/workers/editor/common/nodeReader.js +127 -0
- package/dist/workers/editor/common/nullTokenize.js +29 -0
- package/dist/workers/editor/common/offsetRange.js +225 -0
- package/dist/workers/editor/common/onEnter.js +109 -0
- package/dist/workers/editor/common/oneCursor.js +117 -0
- package/dist/workers/editor/common/overviewZoneManager.js +176 -0
- package/dist/workers/editor/common/parser.js +121 -0
- package/dist/workers/editor/common/pieceTreeBase.js +1473 -0
- package/dist/workers/editor/common/pieceTreeTextBuffer.js +461 -0
- package/dist/workers/editor/common/pieceTreeTextBufferBuilder.js +140 -0
- package/dist/workers/editor/common/point.js +50 -0
- package/dist/workers/editor/common/position.js +142 -0
- package/dist/workers/editor/common/positionToOffset.js +17 -0
- package/dist/workers/editor/common/positionToOffsetImpl.js +98 -0
- package/dist/workers/editor/common/prefixSumComputer.js +226 -0
- package/dist/workers/editor/common/range.js +421 -0
- package/dist/workers/editor/common/rangeMapping.js +229 -0
- package/dist/workers/editor/common/rangeSingleLine.js +17 -0
- package/dist/workers/editor/common/rbTreeBase.js +362 -0
- package/dist/workers/editor/common/rect.js +163 -0
- package/dist/workers/editor/common/replaceCommand.js +158 -0
- package/dist/workers/editor/common/resolverService.js +5 -0
- package/dist/workers/editor/common/rgba.js +35 -0
- package/dist/workers/editor/common/richEditBrackets.js +356 -0
- package/dist/workers/editor/common/selection.js +145 -0
- package/dist/workers/editor/common/semanticTokensDto.js +82 -0
- package/dist/workers/editor/common/semanticTokensProviderStyling.js +263 -0
- package/dist/workers/editor/common/semanticTokensStyling.js +9 -0
- package/dist/workers/editor/common/semanticTokensStylingService.js +47 -0
- package/dist/workers/editor/common/shiftCommand.js +241 -0
- package/dist/workers/editor/common/smallImmutableSet.js +108 -0
- package/dist/workers/editor/common/sparseMultilineTokens.js +548 -0
- package/dist/workers/editor/common/sparseTokensStore.js +210 -0
- package/dist/workers/editor/common/standaloneEnums.js +1017 -0
- package/dist/workers/editor/common/standaloneStrings.js +42 -0
- package/dist/workers/editor/common/stringBuilder.js +122 -0
- package/dist/workers/editor/common/stringEdit.js +165 -0
- package/dist/workers/editor/common/supports.js +58 -0
- package/dist/workers/editor/common/surroundSelectionCommand.js +44 -0
- package/dist/workers/editor/common/textChange.js +248 -0
- package/dist/workers/editor/common/textEdit.js +269 -0
- package/dist/workers/editor/common/textLength.js +87 -0
- package/dist/workers/editor/common/textModel.js +2031 -0
- package/dist/workers/editor/common/textModelBracketPairs.js +45 -0
- package/dist/workers/editor/common/textModelDefaults.js +18 -0
- package/dist/workers/editor/common/textModelEditSource.js +166 -0
- package/dist/workers/editor/common/textModelEvents.js +216 -0
- package/dist/workers/editor/common/textModelGuides.js +40 -0
- package/dist/workers/editor/common/textModelPart.js +23 -0
- package/dist/workers/editor/common/textModelSearch.js +455 -0
- package/dist/workers/editor/common/textModelStringEdit.js +11 -0
- package/dist/workers/editor/common/textModelSync.impl.js +307 -0
- package/dist/workers/editor/common/textModelText.js +26 -0
- package/dist/workers/editor/common/textModelTokens.js +436 -0
- package/dist/workers/editor/common/textResourceConfiguration.js +6 -0
- package/dist/workers/editor/common/textToHtmlTokenizer.js +139 -0
- package/dist/workers/editor/common/tokenStore.js +407 -0
- package/dist/workers/editor/common/tokenWithTextArray.js +73 -0
- package/dist/workers/editor/common/tokenization.js +287 -0
- package/dist/workers/editor/common/tokenizationRegistry.js +123 -0
- package/dist/workers/editor/common/tokenizationTextModelPart.js +275 -0
- package/dist/workers/editor/common/tokenizer.js +301 -0
- package/dist/workers/editor/common/tokenizerSyntaxTokenBackend.js +261 -0
- package/dist/workers/editor/common/treeSitterLibraryService.js +9 -0
- package/dist/workers/editor/common/treeSitterSyntaxTokenBackend.js +167 -0
- package/dist/workers/editor/common/treeSitterThemeService.js +9 -0
- package/dist/workers/editor/common/treeSitterTokenizationImpl.js +713 -0
- package/dist/workers/editor/common/treeSitterTree.js +395 -0
- package/dist/workers/editor/common/treeViewsDnd.js +24 -0
- package/dist/workers/editor/common/treeViewsDndService.js +12 -0
- package/dist/workers/editor/common/trimTrailingWhitespaceCommand.js +98 -0
- package/dist/workers/editor/common/unicodeTextModelHighlighter.js +188 -0
- package/dist/workers/editor/common/utils.js +62 -0
- package/dist/workers/editor/common/viewContext.js +22 -0
- package/dist/workers/editor/common/viewEventHandler.js +186 -0
- package/dist/workers/editor/common/viewEvents.js +180 -0
- package/dist/workers/editor/common/viewLayout.js +368 -0
- package/dist/workers/editor/common/viewLineRenderer.js +948 -0
- package/dist/workers/editor/common/viewLinesViewportData.js +30 -0
- package/dist/workers/editor/common/viewModel.js +98 -0
- package/dist/workers/editor/common/viewModelDecoration.js +55 -0
- package/dist/workers/editor/common/viewModelDecorations.js +132 -0
- package/dist/workers/editor/common/viewModelEventDispatcher.js +398 -0
- package/dist/workers/editor/common/viewModelImpl.js +1163 -0
- package/dist/workers/editor/common/viewModelLines.js +938 -0
- package/dist/workers/editor/common/wordCharacterClassifier.js +87 -0
- package/dist/workers/editor/common/wordHelper.js +127 -0
- package/dist/workers/editor/editor.worker.js +11 -0
- package/dist/workers/language/css.worker.js +8 -0
- package/dist/workers/language/cssMode.js +198 -0
- package/dist/workers/language/cssWorker.js +183 -0
- package/dist/workers/language/html.worker.js +8 -0
- package/dist/workers/language/htmlMode.js +213 -0
- package/dist/workers/language/htmlWorker.js +126 -0
- package/dist/workers/language/json.worker.js +8 -0
- package/dist/workers/language/jsonMode.js +224 -0
- package/dist/workers/language/jsonWorker.js +187 -0
- package/dist/workers/language/languageFeatures.js +1009 -0
- package/dist/workers/language/lib.index.js +103 -0
- package/dist/workers/language/lib.js +1107 -0
- package/dist/workers/language/lspLanguageFeatures.js +716 -0
- package/dist/workers/language/monaco.contribution.js +144 -0
- package/dist/workers/language/tokenization.js +189 -0
- package/dist/workers/language/ts.worker.js +14 -0
- package/dist/workers/language/tsMode.js +212 -0
- package/dist/workers/language/tsWorker.js +352 -0
- package/dist/workers/language/typescriptServices.js +210154 -0
- package/dist/workers/language/typescriptServicesMetadata.js +3 -0
- package/dist/workers/language/workerManager.js +65 -0
- package/package.json +3 -2
|
@@ -0,0 +1,899 @@
|
|
|
1
|
+
import { onUnexpectedError } from '../../../base/common/errors.js';
|
|
2
|
+
import { nextCharLength, commonPrefixLength, commonSuffixLength } from '../../../base/common/strings.js';
|
|
3
|
+
import { CursorCollection } from './cursorCollection.js';
|
|
4
|
+
import { CursorState, EditOperationResult } from '../cursorCommon.js';
|
|
5
|
+
import { CursorContext } from './cursorContext.js';
|
|
6
|
+
import { DeleteOperations } from './cursorDeleteOperations.js';
|
|
7
|
+
import { TypeOperations, CompositionOutcome } from './cursorTypeOperations.js';
|
|
8
|
+
import { BaseTypeWithAutoClosingCommand } from './cursorTypeEditOperations.js';
|
|
9
|
+
import { Range } from '../core/range.js';
|
|
10
|
+
import { Selection } from '../core/selection.js';
|
|
11
|
+
import { ModelInjectedTextChangedEvent } from '../textModelEvents.js';
|
|
12
|
+
import { ViewRevealRangeRequestEvent, ViewCursorStateChangedEvent } from '../viewEvents.js';
|
|
13
|
+
import { Disposable, dispose } from '../../../base/common/lifecycle.js';
|
|
14
|
+
import { CursorStateChangedEvent } from '../viewModelEventDispatcher.js';
|
|
15
|
+
import { EditSources } from '../textModelEditSource.js';
|
|
16
|
+
|
|
17
|
+
/*---------------------------------------------------------------------------------------------
|
|
18
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
19
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
20
|
+
*--------------------------------------------------------------------------------------------*/
|
|
21
|
+
class CursorsController extends Disposable {
|
|
22
|
+
constructor(model, viewModel, coordinatesConverter, cursorConfig) {
|
|
23
|
+
super();
|
|
24
|
+
this._model = model;
|
|
25
|
+
this._knownModelVersionId = this._model.getVersionId();
|
|
26
|
+
this._viewModel = viewModel;
|
|
27
|
+
this._coordinatesConverter = coordinatesConverter;
|
|
28
|
+
this.context = new CursorContext(this._model, this._viewModel, this._coordinatesConverter, cursorConfig);
|
|
29
|
+
this._cursors = new CursorCollection(this.context);
|
|
30
|
+
this._hasFocus = false;
|
|
31
|
+
this._isHandling = false;
|
|
32
|
+
this._compositionState = null;
|
|
33
|
+
this._columnSelectData = null;
|
|
34
|
+
this._autoClosedActions = [];
|
|
35
|
+
this._prevEditOperationType = 0 /* EditOperationType.Other */;
|
|
36
|
+
}
|
|
37
|
+
dispose() {
|
|
38
|
+
this._cursors.dispose();
|
|
39
|
+
this._autoClosedActions = dispose(this._autoClosedActions);
|
|
40
|
+
super.dispose();
|
|
41
|
+
}
|
|
42
|
+
updateConfiguration(cursorConfig) {
|
|
43
|
+
this.context = new CursorContext(this._model, this._viewModel, this._coordinatesConverter, cursorConfig);
|
|
44
|
+
this._cursors.updateContext(this.context);
|
|
45
|
+
}
|
|
46
|
+
onLineMappingChanged(eventsCollector) {
|
|
47
|
+
if (this._knownModelVersionId !== this._model.getVersionId()) {
|
|
48
|
+
// There are model change events that I didn't yet receive.
|
|
49
|
+
//
|
|
50
|
+
// This can happen when editing the model, and the view model receives the change events first,
|
|
51
|
+
// and the view model emits line mapping changed events, all before the cursor gets a chance to
|
|
52
|
+
// recover from markers.
|
|
53
|
+
//
|
|
54
|
+
// The model change listener above will be called soon and we'll ensure a valid cursor state there.
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Ensure valid state
|
|
58
|
+
this.setStates(eventsCollector, 'viewModel', 0 /* CursorChangeReason.NotSet */, this.getCursorStates());
|
|
59
|
+
}
|
|
60
|
+
setHasFocus(hasFocus) {
|
|
61
|
+
this._hasFocus = hasFocus;
|
|
62
|
+
}
|
|
63
|
+
_validateAutoClosedActions() {
|
|
64
|
+
if (this._autoClosedActions.length > 0) {
|
|
65
|
+
const selections = this._cursors.getSelections();
|
|
66
|
+
for (let i = 0; i < this._autoClosedActions.length; i++) {
|
|
67
|
+
const autoClosedAction = this._autoClosedActions[i];
|
|
68
|
+
if (!autoClosedAction.isValid(selections)) {
|
|
69
|
+
autoClosedAction.dispose();
|
|
70
|
+
this._autoClosedActions.splice(i, 1);
|
|
71
|
+
i--;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ------ some getters/setters
|
|
77
|
+
getPrimaryCursorState() {
|
|
78
|
+
return this._cursors.getPrimaryCursor();
|
|
79
|
+
}
|
|
80
|
+
getLastAddedCursorIndex() {
|
|
81
|
+
return this._cursors.getLastAddedCursorIndex();
|
|
82
|
+
}
|
|
83
|
+
getCursorStates() {
|
|
84
|
+
return this._cursors.getAll();
|
|
85
|
+
}
|
|
86
|
+
setStates(eventsCollector, source, reason, states) {
|
|
87
|
+
let reachedMaxCursorCount = false;
|
|
88
|
+
const multiCursorLimit = this.context.cursorConfig.multiCursorLimit;
|
|
89
|
+
if (states !== null && states.length > multiCursorLimit) {
|
|
90
|
+
states = states.slice(0, multiCursorLimit);
|
|
91
|
+
reachedMaxCursorCount = true;
|
|
92
|
+
}
|
|
93
|
+
const oldState = CursorModelState.from(this._model, this);
|
|
94
|
+
this._cursors.setStates(states);
|
|
95
|
+
this._cursors.normalize();
|
|
96
|
+
this._columnSelectData = null;
|
|
97
|
+
this._validateAutoClosedActions();
|
|
98
|
+
return this._emitStateChangedIfNecessary(eventsCollector, source, reason, oldState, reachedMaxCursorCount);
|
|
99
|
+
}
|
|
100
|
+
setCursorColumnSelectData(columnSelectData) {
|
|
101
|
+
this._columnSelectData = columnSelectData;
|
|
102
|
+
}
|
|
103
|
+
revealAll(eventsCollector, source, minimalReveal, verticalType, revealHorizontal, scrollType) {
|
|
104
|
+
const viewPositions = this._cursors.getViewPositions();
|
|
105
|
+
let revealViewRange = null;
|
|
106
|
+
let revealViewSelections = null;
|
|
107
|
+
if (viewPositions.length > 1) {
|
|
108
|
+
revealViewSelections = this._cursors.getViewSelections();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
revealViewRange = Range.fromPositions(viewPositions[0], viewPositions[0]);
|
|
112
|
+
}
|
|
113
|
+
eventsCollector.emitViewEvent(new ViewRevealRangeRequestEvent(source, minimalReveal, revealViewRange, revealViewSelections, verticalType, revealHorizontal, scrollType));
|
|
114
|
+
}
|
|
115
|
+
revealPrimary(eventsCollector, source, minimalReveal, verticalType, revealHorizontal, scrollType) {
|
|
116
|
+
const primaryCursor = this._cursors.getPrimaryCursor();
|
|
117
|
+
const revealViewSelections = [primaryCursor.viewState.selection];
|
|
118
|
+
eventsCollector.emitViewEvent(new ViewRevealRangeRequestEvent(source, minimalReveal, null, revealViewSelections, verticalType, revealHorizontal, scrollType));
|
|
119
|
+
}
|
|
120
|
+
saveState() {
|
|
121
|
+
const result = [];
|
|
122
|
+
const selections = this._cursors.getSelections();
|
|
123
|
+
for (let i = 0, len = selections.length; i < len; i++) {
|
|
124
|
+
const selection = selections[i];
|
|
125
|
+
result.push({
|
|
126
|
+
inSelectionMode: !selection.isEmpty(),
|
|
127
|
+
selectionStart: {
|
|
128
|
+
lineNumber: selection.selectionStartLineNumber,
|
|
129
|
+
column: selection.selectionStartColumn,
|
|
130
|
+
},
|
|
131
|
+
position: {
|
|
132
|
+
lineNumber: selection.positionLineNumber,
|
|
133
|
+
column: selection.positionColumn,
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
restoreState(eventsCollector, states) {
|
|
140
|
+
const desiredSelections = [];
|
|
141
|
+
for (let i = 0, len = states.length; i < len; i++) {
|
|
142
|
+
const state = states[i];
|
|
143
|
+
let positionLineNumber = 1;
|
|
144
|
+
let positionColumn = 1;
|
|
145
|
+
// Avoid missing properties on the literal
|
|
146
|
+
if (state.position && state.position.lineNumber) {
|
|
147
|
+
positionLineNumber = state.position.lineNumber;
|
|
148
|
+
}
|
|
149
|
+
if (state.position && state.position.column) {
|
|
150
|
+
positionColumn = state.position.column;
|
|
151
|
+
}
|
|
152
|
+
let selectionStartLineNumber = positionLineNumber;
|
|
153
|
+
let selectionStartColumn = positionColumn;
|
|
154
|
+
// Avoid missing properties on the literal
|
|
155
|
+
if (state.selectionStart && state.selectionStart.lineNumber) {
|
|
156
|
+
selectionStartLineNumber = state.selectionStart.lineNumber;
|
|
157
|
+
}
|
|
158
|
+
if (state.selectionStart && state.selectionStart.column) {
|
|
159
|
+
selectionStartColumn = state.selectionStart.column;
|
|
160
|
+
}
|
|
161
|
+
desiredSelections.push({
|
|
162
|
+
selectionStartLineNumber: selectionStartLineNumber,
|
|
163
|
+
selectionStartColumn: selectionStartColumn,
|
|
164
|
+
positionLineNumber: positionLineNumber,
|
|
165
|
+
positionColumn: positionColumn
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
this.setStates(eventsCollector, 'restoreState', 0 /* CursorChangeReason.NotSet */, CursorState.fromModelSelections(desiredSelections));
|
|
169
|
+
this.revealAll(eventsCollector, 'restoreState', false, 0 /* VerticalRevealType.Simple */, true, 1 /* editorCommon.ScrollType.Immediate */);
|
|
170
|
+
}
|
|
171
|
+
onModelContentChanged(eventsCollector, event) {
|
|
172
|
+
if (event instanceof ModelInjectedTextChangedEvent) {
|
|
173
|
+
// If injected texts change, the view positions of all cursors need to be updated.
|
|
174
|
+
if (this._isHandling) {
|
|
175
|
+
// The view positions will be updated when handling finishes
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// setStates might remove markers, which could trigger a decoration change.
|
|
179
|
+
// If there are injected text decorations for that line, `onModelContentChanged` is emitted again
|
|
180
|
+
// and an endless recursion happens.
|
|
181
|
+
// _isHandling prevents that.
|
|
182
|
+
this._isHandling = true;
|
|
183
|
+
try {
|
|
184
|
+
this.setStates(eventsCollector, 'modelChange', 0 /* CursorChangeReason.NotSet */, this.getCursorStates());
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
this._isHandling = false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const e = event.rawContentChangedEvent;
|
|
192
|
+
this._knownModelVersionId = e.versionId;
|
|
193
|
+
if (this._isHandling) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const hadFlushEvent = e.containsEvent(1 /* RawContentChangedType.Flush */);
|
|
197
|
+
this._prevEditOperationType = 0 /* EditOperationType.Other */;
|
|
198
|
+
if (hadFlushEvent) {
|
|
199
|
+
// a model.setValue() was called
|
|
200
|
+
this._cursors.dispose();
|
|
201
|
+
this._cursors = new CursorCollection(this.context);
|
|
202
|
+
this._validateAutoClosedActions();
|
|
203
|
+
this._emitStateChangedIfNecessary(eventsCollector, 'model', 1 /* CursorChangeReason.ContentFlush */, null, false);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
if (this._hasFocus && e.resultingSelection && e.resultingSelection.length > 0) {
|
|
207
|
+
const cursorState = CursorState.fromModelSelections(e.resultingSelection);
|
|
208
|
+
if (this.setStates(eventsCollector, 'modelChange', e.isUndoing ? 5 /* CursorChangeReason.Undo */ : e.isRedoing ? 6 /* CursorChangeReason.Redo */ : 2 /* CursorChangeReason.RecoverFromMarkers */, cursorState)) {
|
|
209
|
+
this.revealAll(eventsCollector, 'modelChange', false, 0 /* VerticalRevealType.Simple */, true, 0 /* editorCommon.ScrollType.Smooth */);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
const selectionsFromMarkers = this._cursors.readSelectionFromMarkers();
|
|
214
|
+
this.setStates(eventsCollector, 'modelChange', 2 /* CursorChangeReason.RecoverFromMarkers */, CursorState.fromModelSelections(selectionsFromMarkers));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
getSelection() {
|
|
220
|
+
return this._cursors.getPrimaryCursor().modelState.selection;
|
|
221
|
+
}
|
|
222
|
+
getTopMostViewPosition() {
|
|
223
|
+
return this._cursors.getTopMostViewPosition();
|
|
224
|
+
}
|
|
225
|
+
getBottomMostViewPosition() {
|
|
226
|
+
return this._cursors.getBottomMostViewPosition();
|
|
227
|
+
}
|
|
228
|
+
getCursorColumnSelectData() {
|
|
229
|
+
if (this._columnSelectData) {
|
|
230
|
+
return this._columnSelectData;
|
|
231
|
+
}
|
|
232
|
+
const primaryCursor = this._cursors.getPrimaryCursor();
|
|
233
|
+
const viewSelectionStart = primaryCursor.viewState.selectionStart.getStartPosition();
|
|
234
|
+
const viewPosition = primaryCursor.viewState.position;
|
|
235
|
+
return {
|
|
236
|
+
isReal: false,
|
|
237
|
+
fromViewLineNumber: viewSelectionStart.lineNumber,
|
|
238
|
+
fromViewVisualColumn: this.context.cursorConfig.visibleColumnFromColumn(this._viewModel, viewSelectionStart),
|
|
239
|
+
toViewLineNumber: viewPosition.lineNumber,
|
|
240
|
+
toViewVisualColumn: this.context.cursorConfig.visibleColumnFromColumn(this._viewModel, viewPosition),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
getSelections() {
|
|
244
|
+
return this._cursors.getSelections();
|
|
245
|
+
}
|
|
246
|
+
setSelections(eventsCollector, source, selections, reason) {
|
|
247
|
+
this.setStates(eventsCollector, source, reason, CursorState.fromModelSelections(selections));
|
|
248
|
+
}
|
|
249
|
+
getPrevEditOperationType() {
|
|
250
|
+
return this._prevEditOperationType;
|
|
251
|
+
}
|
|
252
|
+
setPrevEditOperationType(type) {
|
|
253
|
+
this._prevEditOperationType = type;
|
|
254
|
+
}
|
|
255
|
+
// ------ auxiliary handling logic
|
|
256
|
+
_pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges) {
|
|
257
|
+
const autoClosedCharactersDeltaDecorations = [];
|
|
258
|
+
const autoClosedEnclosingDeltaDecorations = [];
|
|
259
|
+
for (let i = 0, len = autoClosedCharactersRanges.length; i < len; i++) {
|
|
260
|
+
autoClosedCharactersDeltaDecorations.push({
|
|
261
|
+
range: autoClosedCharactersRanges[i],
|
|
262
|
+
options: {
|
|
263
|
+
description: 'auto-closed-character',
|
|
264
|
+
inlineClassName: 'auto-closed-character',
|
|
265
|
+
stickiness: 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
autoClosedEnclosingDeltaDecorations.push({
|
|
269
|
+
range: autoClosedEnclosingRanges[i],
|
|
270
|
+
options: {
|
|
271
|
+
description: 'auto-closed-enclosing',
|
|
272
|
+
stickiness: 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersDeltaDecorations);
|
|
277
|
+
const autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingDeltaDecorations);
|
|
278
|
+
this._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations));
|
|
279
|
+
}
|
|
280
|
+
_executeEditOperation(opResult, editReason) {
|
|
281
|
+
if (!opResult) {
|
|
282
|
+
// Nothing to execute
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (opResult.shouldPushStackElementBefore) {
|
|
286
|
+
this._model.pushStackElement();
|
|
287
|
+
}
|
|
288
|
+
const result = CommandExecutor.executeCommands(this._model, this._cursors.getSelections(), opResult.commands, editReason);
|
|
289
|
+
if (result) {
|
|
290
|
+
// The commands were applied correctly
|
|
291
|
+
this._interpretCommandResult(result);
|
|
292
|
+
// Check for auto-closing closed characters
|
|
293
|
+
const autoClosedCharactersRanges = [];
|
|
294
|
+
const autoClosedEnclosingRanges = [];
|
|
295
|
+
for (let i = 0; i < opResult.commands.length; i++) {
|
|
296
|
+
const command = opResult.commands[i];
|
|
297
|
+
if (command instanceof BaseTypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) {
|
|
298
|
+
autoClosedCharactersRanges.push(command.closeCharacterRange);
|
|
299
|
+
autoClosedEnclosingRanges.push(command.enclosingRange);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (autoClosedCharactersRanges.length > 0) {
|
|
303
|
+
this._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);
|
|
304
|
+
}
|
|
305
|
+
this._prevEditOperationType = opResult.type;
|
|
306
|
+
}
|
|
307
|
+
if (opResult.shouldPushStackElementAfter) {
|
|
308
|
+
this._model.pushStackElement();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
_interpretCommandResult(cursorState) {
|
|
312
|
+
if (!cursorState || cursorState.length === 0) {
|
|
313
|
+
cursorState = this._cursors.readSelectionFromMarkers();
|
|
314
|
+
}
|
|
315
|
+
this._columnSelectData = null;
|
|
316
|
+
this._cursors.setSelections(cursorState);
|
|
317
|
+
this._cursors.normalize();
|
|
318
|
+
}
|
|
319
|
+
// -----------------------------------------------------------------------------------------------------------
|
|
320
|
+
// ----- emitting events
|
|
321
|
+
_emitStateChangedIfNecessary(eventsCollector, source, reason, oldState, reachedMaxCursorCount) {
|
|
322
|
+
const newState = CursorModelState.from(this._model, this);
|
|
323
|
+
if (newState.equals(oldState)) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
const selections = this._cursors.getSelections();
|
|
327
|
+
const viewSelections = this._cursors.getViewSelections();
|
|
328
|
+
// Let the view get the event first.
|
|
329
|
+
eventsCollector.emitViewEvent(new ViewCursorStateChangedEvent(viewSelections, selections, reason));
|
|
330
|
+
// Only after the view has been notified, let the rest of the world know...
|
|
331
|
+
if (!oldState
|
|
332
|
+
|| oldState.cursorState.length !== newState.cursorState.length
|
|
333
|
+
|| newState.cursorState.some((newCursorState, i) => !newCursorState.modelState.equals(oldState.cursorState[i].modelState))) {
|
|
334
|
+
const oldSelections = oldState ? oldState.cursorState.map(s => s.modelState.selection) : null;
|
|
335
|
+
const oldModelVersionId = oldState ? oldState.modelVersionId : 0;
|
|
336
|
+
eventsCollector.emitOutgoingEvent(new CursorStateChangedEvent(oldSelections, selections, oldModelVersionId, newState.modelVersionId, source || 'keyboard', reason, reachedMaxCursorCount));
|
|
337
|
+
}
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
// -----------------------------------------------------------------------------------------------------------
|
|
341
|
+
// ----- handlers beyond this point
|
|
342
|
+
_findAutoClosingPairs(edits) {
|
|
343
|
+
if (!edits.length) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const indices = [];
|
|
347
|
+
for (let i = 0, len = edits.length; i < len; i++) {
|
|
348
|
+
const edit = edits[i];
|
|
349
|
+
if (!edit.text || edit.text.indexOf('\n') >= 0) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
const m = edit.text.match(/([)\]}>'"`])([^)\]}>'"`]*)$/);
|
|
353
|
+
if (!m) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
const closeChar = m[1];
|
|
357
|
+
const autoClosingPairsCandidates = this.context.cursorConfig.autoClosingPairs.autoClosingPairsCloseSingleChar.get(closeChar);
|
|
358
|
+
if (!autoClosingPairsCandidates || autoClosingPairsCandidates.length !== 1) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
const openChar = autoClosingPairsCandidates[0].open;
|
|
362
|
+
const closeCharIndex = edit.text.length - m[2].length - 1;
|
|
363
|
+
const openCharIndex = edit.text.lastIndexOf(openChar, closeCharIndex - 1);
|
|
364
|
+
if (openCharIndex === -1) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
indices.push([openCharIndex, closeCharIndex]);
|
|
368
|
+
}
|
|
369
|
+
return indices;
|
|
370
|
+
}
|
|
371
|
+
executeEdits(eventsCollector, source, edits, cursorStateComputer, reason) {
|
|
372
|
+
let autoClosingIndices = null;
|
|
373
|
+
if (source === 'snippet') {
|
|
374
|
+
autoClosingIndices = this._findAutoClosingPairs(edits);
|
|
375
|
+
}
|
|
376
|
+
if (autoClosingIndices) {
|
|
377
|
+
edits[0]._isTracked = true;
|
|
378
|
+
}
|
|
379
|
+
const autoClosedCharactersRanges = [];
|
|
380
|
+
const autoClosedEnclosingRanges = [];
|
|
381
|
+
const selections = this._model.pushEditOperations(this.getSelections(), edits, (undoEdits) => {
|
|
382
|
+
if (autoClosingIndices) {
|
|
383
|
+
for (let i = 0, len = autoClosingIndices.length; i < len; i++) {
|
|
384
|
+
const [openCharInnerIndex, closeCharInnerIndex] = autoClosingIndices[i];
|
|
385
|
+
const undoEdit = undoEdits[i];
|
|
386
|
+
const lineNumber = undoEdit.range.startLineNumber;
|
|
387
|
+
const openCharIndex = undoEdit.range.startColumn - 1 + openCharInnerIndex;
|
|
388
|
+
const closeCharIndex = undoEdit.range.startColumn - 1 + closeCharInnerIndex;
|
|
389
|
+
autoClosedCharactersRanges.push(new Range(lineNumber, closeCharIndex + 1, lineNumber, closeCharIndex + 2));
|
|
390
|
+
autoClosedEnclosingRanges.push(new Range(lineNumber, openCharIndex + 1, lineNumber, closeCharIndex + 2));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
const selections = cursorStateComputer(undoEdits);
|
|
394
|
+
if (selections) {
|
|
395
|
+
// Don't recover the selection from markers because
|
|
396
|
+
// we know what it should be.
|
|
397
|
+
this._isHandling = true;
|
|
398
|
+
}
|
|
399
|
+
return selections;
|
|
400
|
+
}, undefined, reason);
|
|
401
|
+
if (selections) {
|
|
402
|
+
this._isHandling = false;
|
|
403
|
+
this.setSelections(eventsCollector, source, selections, 0 /* CursorChangeReason.NotSet */);
|
|
404
|
+
}
|
|
405
|
+
if (autoClosedCharactersRanges.length > 0) {
|
|
406
|
+
this._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
_executeEdit(callback, eventsCollector, source, cursorChangeReason = 0 /* CursorChangeReason.NotSet */) {
|
|
410
|
+
if (this.context.cursorConfig.readOnly) {
|
|
411
|
+
// we cannot edit when read only...
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const oldState = CursorModelState.from(this._model, this);
|
|
415
|
+
this._cursors.stopTrackingSelections();
|
|
416
|
+
this._isHandling = true;
|
|
417
|
+
try {
|
|
418
|
+
this._cursors.ensureValidState();
|
|
419
|
+
callback();
|
|
420
|
+
}
|
|
421
|
+
catch (err) {
|
|
422
|
+
onUnexpectedError(err);
|
|
423
|
+
}
|
|
424
|
+
this._isHandling = false;
|
|
425
|
+
this._cursors.startTrackingSelections();
|
|
426
|
+
this._validateAutoClosedActions();
|
|
427
|
+
if (this._emitStateChangedIfNecessary(eventsCollector, source, cursorChangeReason, oldState, false)) {
|
|
428
|
+
this.revealAll(eventsCollector, source, false, 0 /* VerticalRevealType.Simple */, true, 0 /* editorCommon.ScrollType.Smooth */);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
getAutoClosedCharacters() {
|
|
432
|
+
return AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);
|
|
433
|
+
}
|
|
434
|
+
startComposition(eventsCollector) {
|
|
435
|
+
this._compositionState = new CompositionState(this._model, this.getSelections());
|
|
436
|
+
}
|
|
437
|
+
endComposition(eventsCollector, source) {
|
|
438
|
+
const reason = EditSources.cursor({ kind: 'compositionEnd', detailedSource: source });
|
|
439
|
+
const compositionOutcome = this._compositionState ? this._compositionState.deduceOutcome(this._model, this.getSelections()) : null;
|
|
440
|
+
this._compositionState = null;
|
|
441
|
+
this._executeEdit(() => {
|
|
442
|
+
if (source === 'keyboard') {
|
|
443
|
+
// composition finishes, let's check if we need to auto complete if necessary.
|
|
444
|
+
this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, compositionOutcome, this.getSelections(), this.getAutoClosedCharacters()), reason);
|
|
445
|
+
}
|
|
446
|
+
}, eventsCollector, source);
|
|
447
|
+
}
|
|
448
|
+
type(eventsCollector, text, source) {
|
|
449
|
+
const reason = EditSources.cursor({ kind: 'type', detailedSource: source });
|
|
450
|
+
this._executeEdit(() => {
|
|
451
|
+
if (source === 'keyboard') {
|
|
452
|
+
// If this event is coming straight from the keyboard, look for electric characters and enter
|
|
453
|
+
const len = text.length;
|
|
454
|
+
let offset = 0;
|
|
455
|
+
while (offset < len) {
|
|
456
|
+
const charLength = nextCharLength(text, offset);
|
|
457
|
+
const chr = text.substr(offset, charLength);
|
|
458
|
+
// Here we must interpret each typed character individually
|
|
459
|
+
this._executeEditOperation(TypeOperations.typeWithInterceptors(!!this._compositionState, this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), this.getAutoClosedCharacters(), chr), reason);
|
|
460
|
+
offset += charLength;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
this._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text), reason);
|
|
465
|
+
}
|
|
466
|
+
}, eventsCollector, source);
|
|
467
|
+
}
|
|
468
|
+
compositionType(eventsCollector, text, replacePrevCharCnt, replaceNextCharCnt, positionDelta, source) {
|
|
469
|
+
const reason = EditSources.cursor({ kind: 'compositionType', detailedSource: source });
|
|
470
|
+
if (text.length === 0 && replacePrevCharCnt === 0 && replaceNextCharCnt === 0) {
|
|
471
|
+
// this edit is a no-op
|
|
472
|
+
if (positionDelta !== 0) {
|
|
473
|
+
// but it still wants to move the cursor
|
|
474
|
+
const newSelections = this.getSelections().map(selection => {
|
|
475
|
+
const position = selection.getPosition();
|
|
476
|
+
return new Selection(position.lineNumber, position.column + positionDelta, position.lineNumber, position.column + positionDelta);
|
|
477
|
+
});
|
|
478
|
+
this.setSelections(eventsCollector, source, newSelections, 0 /* CursorChangeReason.NotSet */);
|
|
479
|
+
}
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
this._executeEdit(() => {
|
|
483
|
+
this._executeEditOperation(TypeOperations.compositionType(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text, replacePrevCharCnt, replaceNextCharCnt, positionDelta), reason);
|
|
484
|
+
}, eventsCollector, source);
|
|
485
|
+
}
|
|
486
|
+
paste(eventsCollector, text, pasteOnNewLine, multicursorText, source) {
|
|
487
|
+
const reason = EditSources.cursor({ kind: 'paste', detailedSource: source });
|
|
488
|
+
this._executeEdit(() => {
|
|
489
|
+
this._executeEditOperation(TypeOperations.paste(this.context.cursorConfig, this._model, this.getSelections(), text, pasteOnNewLine, multicursorText || []), reason);
|
|
490
|
+
}, eventsCollector, source, 4 /* CursorChangeReason.Paste */);
|
|
491
|
+
}
|
|
492
|
+
cut(eventsCollector, source) {
|
|
493
|
+
const reason = EditSources.cursor({ kind: 'cut', detailedSource: source });
|
|
494
|
+
this._executeEdit(() => {
|
|
495
|
+
this._executeEditOperation(DeleteOperations.cut(this.context.cursorConfig, this._model, this.getSelections()), reason);
|
|
496
|
+
}, eventsCollector, source);
|
|
497
|
+
}
|
|
498
|
+
executeCommand(eventsCollector, command, source) {
|
|
499
|
+
const reason = EditSources.cursor({ kind: 'executeCommand', detailedSource: source });
|
|
500
|
+
this._executeEdit(() => {
|
|
501
|
+
this._cursors.killSecondaryCursors();
|
|
502
|
+
this._executeEditOperation(new EditOperationResult(0 /* EditOperationType.Other */, [command], {
|
|
503
|
+
shouldPushStackElementBefore: false,
|
|
504
|
+
shouldPushStackElementAfter: false
|
|
505
|
+
}), reason);
|
|
506
|
+
}, eventsCollector, source);
|
|
507
|
+
}
|
|
508
|
+
executeCommands(eventsCollector, commands, source) {
|
|
509
|
+
const reason = EditSources.cursor({ kind: 'executeCommands', detailedSource: source });
|
|
510
|
+
this._executeEdit(() => {
|
|
511
|
+
this._executeEditOperation(new EditOperationResult(0 /* EditOperationType.Other */, commands, {
|
|
512
|
+
shouldPushStackElementBefore: false,
|
|
513
|
+
shouldPushStackElementAfter: false
|
|
514
|
+
}), reason);
|
|
515
|
+
}, eventsCollector, source);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* A snapshot of the cursor and the model state
|
|
520
|
+
*/
|
|
521
|
+
class CursorModelState {
|
|
522
|
+
static from(model, cursor) {
|
|
523
|
+
return new CursorModelState(model.getVersionId(), cursor.getCursorStates());
|
|
524
|
+
}
|
|
525
|
+
constructor(modelVersionId, cursorState) {
|
|
526
|
+
this.modelVersionId = modelVersionId;
|
|
527
|
+
this.cursorState = cursorState;
|
|
528
|
+
}
|
|
529
|
+
equals(other) {
|
|
530
|
+
if (!other) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
if (this.modelVersionId !== other.modelVersionId) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
if (this.cursorState.length !== other.cursorState.length) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
for (let i = 0, len = this.cursorState.length; i < len; i++) {
|
|
540
|
+
if (!this.cursorState[i].equals(other.cursorState[i])) {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
class AutoClosedAction {
|
|
548
|
+
static getAllAutoClosedCharacters(autoClosedActions) {
|
|
549
|
+
let autoClosedCharacters = [];
|
|
550
|
+
for (const autoClosedAction of autoClosedActions) {
|
|
551
|
+
autoClosedCharacters = autoClosedCharacters.concat(autoClosedAction.getAutoClosedCharactersRanges());
|
|
552
|
+
}
|
|
553
|
+
return autoClosedCharacters;
|
|
554
|
+
}
|
|
555
|
+
constructor(model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations) {
|
|
556
|
+
this._model = model;
|
|
557
|
+
this._autoClosedCharactersDecorations = autoClosedCharactersDecorations;
|
|
558
|
+
this._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations;
|
|
559
|
+
}
|
|
560
|
+
dispose() {
|
|
561
|
+
this._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []);
|
|
562
|
+
this._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []);
|
|
563
|
+
}
|
|
564
|
+
getAutoClosedCharactersRanges() {
|
|
565
|
+
const result = [];
|
|
566
|
+
for (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) {
|
|
567
|
+
const decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]);
|
|
568
|
+
if (decorationRange) {
|
|
569
|
+
result.push(decorationRange);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return result;
|
|
573
|
+
}
|
|
574
|
+
isValid(selections) {
|
|
575
|
+
const enclosingRanges = [];
|
|
576
|
+
for (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) {
|
|
577
|
+
const decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]);
|
|
578
|
+
if (decorationRange) {
|
|
579
|
+
enclosingRanges.push(decorationRange);
|
|
580
|
+
if (decorationRange.startLineNumber !== decorationRange.endLineNumber) {
|
|
581
|
+
// Stop tracking if the range becomes multiline...
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
enclosingRanges.sort(Range.compareRangesUsingStarts);
|
|
587
|
+
selections.sort(Range.compareRangesUsingStarts);
|
|
588
|
+
for (let i = 0; i < selections.length; i++) {
|
|
589
|
+
if (i >= enclosingRanges.length) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
if (!enclosingRanges[i].strictContainsRange(selections[i])) {
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
class CommandExecutor {
|
|
600
|
+
static executeCommands(model, selectionsBefore, commands, editReason = EditSources.unknown({ name: 'executeCommands' })) {
|
|
601
|
+
const ctx = {
|
|
602
|
+
model: model,
|
|
603
|
+
selectionsBefore: selectionsBefore,
|
|
604
|
+
trackedRanges: [],
|
|
605
|
+
trackedRangesDirection: []
|
|
606
|
+
};
|
|
607
|
+
const result = this._innerExecuteCommands(ctx, commands, editReason);
|
|
608
|
+
for (let i = 0, len = ctx.trackedRanges.length; i < len; i++) {
|
|
609
|
+
ctx.model._setTrackedRange(ctx.trackedRanges[i], null, 0 /* TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges */);
|
|
610
|
+
}
|
|
611
|
+
return result;
|
|
612
|
+
}
|
|
613
|
+
static _innerExecuteCommands(ctx, commands, editReason) {
|
|
614
|
+
if (this._arrayIsEmpty(commands)) {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
const commandsData = this._getEditOperations(ctx, commands);
|
|
618
|
+
if (commandsData.operations.length === 0) {
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
const rawOperations = commandsData.operations;
|
|
622
|
+
const loserCursorsMap = this._getLoserCursorMap(rawOperations);
|
|
623
|
+
if (loserCursorsMap.hasOwnProperty('0')) {
|
|
624
|
+
// These commands are very messed up
|
|
625
|
+
console.warn('Ignoring commands');
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
// Remove operations belonging to losing cursors
|
|
629
|
+
const filteredOperations = [];
|
|
630
|
+
for (let i = 0, len = rawOperations.length; i < len; i++) {
|
|
631
|
+
if (!loserCursorsMap.hasOwnProperty(rawOperations[i].identifier.major.toString())) {
|
|
632
|
+
filteredOperations.push(rawOperations[i]);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// TODO@Alex: find a better way to do this.
|
|
636
|
+
// give the hint that edit operations are tracked to the model
|
|
637
|
+
if (commandsData.hadTrackedEditOperation && filteredOperations.length > 0) {
|
|
638
|
+
filteredOperations[0]._isTracked = true;
|
|
639
|
+
}
|
|
640
|
+
let selectionsAfter = ctx.model.pushEditOperations(ctx.selectionsBefore, filteredOperations, (inverseEditOperations) => {
|
|
641
|
+
const groupedInverseEditOperations = [];
|
|
642
|
+
for (let i = 0; i < ctx.selectionsBefore.length; i++) {
|
|
643
|
+
groupedInverseEditOperations[i] = [];
|
|
644
|
+
}
|
|
645
|
+
for (const op of inverseEditOperations) {
|
|
646
|
+
if (!op.identifier) {
|
|
647
|
+
// perhaps auto whitespace trim edits
|
|
648
|
+
continue;
|
|
649
|
+
}
|
|
650
|
+
groupedInverseEditOperations[op.identifier.major].push(op);
|
|
651
|
+
}
|
|
652
|
+
const minorBasedSorter = (a, b) => {
|
|
653
|
+
return a.identifier.minor - b.identifier.minor;
|
|
654
|
+
};
|
|
655
|
+
const cursorSelections = [];
|
|
656
|
+
for (let i = 0; i < ctx.selectionsBefore.length; i++) {
|
|
657
|
+
if (groupedInverseEditOperations[i].length > 0) {
|
|
658
|
+
groupedInverseEditOperations[i].sort(minorBasedSorter);
|
|
659
|
+
cursorSelections[i] = commands[i].computeCursorState(ctx.model, {
|
|
660
|
+
getInverseEditOperations: () => {
|
|
661
|
+
return groupedInverseEditOperations[i];
|
|
662
|
+
},
|
|
663
|
+
getTrackedSelection: (id) => {
|
|
664
|
+
const idx = parseInt(id, 10);
|
|
665
|
+
const range = ctx.model._getTrackedRange(ctx.trackedRanges[idx]);
|
|
666
|
+
if (ctx.trackedRangesDirection[idx] === 0 /* SelectionDirection.LTR */) {
|
|
667
|
+
return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);
|
|
668
|
+
}
|
|
669
|
+
return new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
cursorSelections[i] = ctx.selectionsBefore[i];
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return cursorSelections;
|
|
678
|
+
}, undefined, editReason);
|
|
679
|
+
if (!selectionsAfter) {
|
|
680
|
+
selectionsAfter = ctx.selectionsBefore;
|
|
681
|
+
}
|
|
682
|
+
// Extract losing cursors
|
|
683
|
+
const losingCursors = [];
|
|
684
|
+
for (const losingCursorIndex in loserCursorsMap) {
|
|
685
|
+
if (loserCursorsMap.hasOwnProperty(losingCursorIndex)) {
|
|
686
|
+
losingCursors.push(parseInt(losingCursorIndex, 10));
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// Sort losing cursors descending
|
|
690
|
+
losingCursors.sort((a, b) => {
|
|
691
|
+
return b - a;
|
|
692
|
+
});
|
|
693
|
+
// Remove losing cursors
|
|
694
|
+
for (const losingCursor of losingCursors) {
|
|
695
|
+
selectionsAfter.splice(losingCursor, 1);
|
|
696
|
+
}
|
|
697
|
+
return selectionsAfter;
|
|
698
|
+
}
|
|
699
|
+
static _arrayIsEmpty(commands) {
|
|
700
|
+
for (let i = 0, len = commands.length; i < len; i++) {
|
|
701
|
+
if (commands[i]) {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
return true;
|
|
706
|
+
}
|
|
707
|
+
static _getEditOperations(ctx, commands) {
|
|
708
|
+
let operations = [];
|
|
709
|
+
let hadTrackedEditOperation = false;
|
|
710
|
+
for (let i = 0, len = commands.length; i < len; i++) {
|
|
711
|
+
const command = commands[i];
|
|
712
|
+
if (command) {
|
|
713
|
+
const r = this._getEditOperationsFromCommand(ctx, i, command);
|
|
714
|
+
operations = operations.concat(r.operations);
|
|
715
|
+
hadTrackedEditOperation = hadTrackedEditOperation || r.hadTrackedEditOperation;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return {
|
|
719
|
+
operations: operations,
|
|
720
|
+
hadTrackedEditOperation: hadTrackedEditOperation
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
static _getEditOperationsFromCommand(ctx, majorIdentifier, command) {
|
|
724
|
+
// This method acts as a transaction, if the command fails
|
|
725
|
+
// everything it has done is ignored
|
|
726
|
+
const operations = [];
|
|
727
|
+
let operationMinor = 0;
|
|
728
|
+
const addEditOperation = (range, text, forceMoveMarkers = false) => {
|
|
729
|
+
if (Range.isEmpty(range) && text === '') {
|
|
730
|
+
// This command wants to add a no-op => no thank you
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
operations.push({
|
|
734
|
+
identifier: {
|
|
735
|
+
major: majorIdentifier,
|
|
736
|
+
minor: operationMinor++
|
|
737
|
+
},
|
|
738
|
+
range: range,
|
|
739
|
+
text: text,
|
|
740
|
+
forceMoveMarkers: forceMoveMarkers,
|
|
741
|
+
isAutoWhitespaceEdit: command.insertsAutoWhitespace
|
|
742
|
+
});
|
|
743
|
+
};
|
|
744
|
+
let hadTrackedEditOperation = false;
|
|
745
|
+
const addTrackedEditOperation = (selection, text, forceMoveMarkers) => {
|
|
746
|
+
hadTrackedEditOperation = true;
|
|
747
|
+
addEditOperation(selection, text, forceMoveMarkers);
|
|
748
|
+
};
|
|
749
|
+
const trackSelection = (_selection, trackPreviousOnEmpty) => {
|
|
750
|
+
const selection = Selection.liftSelection(_selection);
|
|
751
|
+
let stickiness;
|
|
752
|
+
if (selection.isEmpty()) {
|
|
753
|
+
if (typeof trackPreviousOnEmpty === 'boolean') {
|
|
754
|
+
if (trackPreviousOnEmpty) {
|
|
755
|
+
stickiness = 2 /* TrackedRangeStickiness.GrowsOnlyWhenTypingBefore */;
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
stickiness = 3 /* TrackedRangeStickiness.GrowsOnlyWhenTypingAfter */;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
// Try to lock it with surrounding text
|
|
763
|
+
const maxLineColumn = ctx.model.getLineMaxColumn(selection.startLineNumber);
|
|
764
|
+
if (selection.startColumn === maxLineColumn) {
|
|
765
|
+
stickiness = 2 /* TrackedRangeStickiness.GrowsOnlyWhenTypingBefore */;
|
|
766
|
+
}
|
|
767
|
+
else {
|
|
768
|
+
stickiness = 3 /* TrackedRangeStickiness.GrowsOnlyWhenTypingAfter */;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
stickiness = 1 /* TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */;
|
|
774
|
+
}
|
|
775
|
+
const l = ctx.trackedRanges.length;
|
|
776
|
+
const id = ctx.model._setTrackedRange(null, selection, stickiness);
|
|
777
|
+
ctx.trackedRanges[l] = id;
|
|
778
|
+
ctx.trackedRangesDirection[l] = selection.getDirection();
|
|
779
|
+
return l.toString();
|
|
780
|
+
};
|
|
781
|
+
const editOperationBuilder = {
|
|
782
|
+
addEditOperation: addEditOperation,
|
|
783
|
+
addTrackedEditOperation: addTrackedEditOperation,
|
|
784
|
+
trackSelection: trackSelection
|
|
785
|
+
};
|
|
786
|
+
try {
|
|
787
|
+
command.getEditOperations(ctx.model, editOperationBuilder);
|
|
788
|
+
}
|
|
789
|
+
catch (e) {
|
|
790
|
+
// TODO@Alex use notification service if this should be user facing
|
|
791
|
+
// e.friendlyMessage = nls.localize('corrupt.commands', "Unexpected exception while executing command.");
|
|
792
|
+
onUnexpectedError(e);
|
|
793
|
+
return {
|
|
794
|
+
operations: [],
|
|
795
|
+
hadTrackedEditOperation: false
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
return {
|
|
799
|
+
operations: operations,
|
|
800
|
+
hadTrackedEditOperation: hadTrackedEditOperation
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
static _getLoserCursorMap(operations) {
|
|
804
|
+
// This is destructive on the array
|
|
805
|
+
operations = operations.slice(0);
|
|
806
|
+
// Sort operations with last one first
|
|
807
|
+
operations.sort((a, b) => {
|
|
808
|
+
// Note the minus!
|
|
809
|
+
return -(Range.compareRangesUsingEnds(a.range, b.range));
|
|
810
|
+
});
|
|
811
|
+
// Operations can not overlap!
|
|
812
|
+
const loserCursorsMap = {};
|
|
813
|
+
for (let i = 1; i < operations.length; i++) {
|
|
814
|
+
const previousOp = operations[i - 1];
|
|
815
|
+
const currentOp = operations[i];
|
|
816
|
+
if (Range.getStartPosition(previousOp.range).isBefore(Range.getEndPosition(currentOp.range))) {
|
|
817
|
+
let loserMajor;
|
|
818
|
+
if (previousOp.identifier.major > currentOp.identifier.major) {
|
|
819
|
+
// previousOp loses the battle
|
|
820
|
+
loserMajor = previousOp.identifier.major;
|
|
821
|
+
}
|
|
822
|
+
else {
|
|
823
|
+
loserMajor = currentOp.identifier.major;
|
|
824
|
+
}
|
|
825
|
+
loserCursorsMap[loserMajor.toString()] = true;
|
|
826
|
+
for (let j = 0; j < operations.length; j++) {
|
|
827
|
+
if (operations[j].identifier.major === loserMajor) {
|
|
828
|
+
operations.splice(j, 1);
|
|
829
|
+
if (j < i) {
|
|
830
|
+
i--;
|
|
831
|
+
}
|
|
832
|
+
j--;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (i > 0) {
|
|
836
|
+
i--;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return loserCursorsMap;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
class CompositionLineState {
|
|
844
|
+
constructor(text, lineNumber, startSelectionOffset, endSelectionOffset) {
|
|
845
|
+
this.text = text;
|
|
846
|
+
this.lineNumber = lineNumber;
|
|
847
|
+
this.startSelectionOffset = startSelectionOffset;
|
|
848
|
+
this.endSelectionOffset = endSelectionOffset;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
class CompositionState {
|
|
852
|
+
static _capture(textModel, selections) {
|
|
853
|
+
const result = [];
|
|
854
|
+
for (const selection of selections) {
|
|
855
|
+
if (selection.startLineNumber !== selection.endLineNumber) {
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
const lineNumber = selection.startLineNumber;
|
|
859
|
+
result.push(new CompositionLineState(textModel.getLineContent(lineNumber), lineNumber, selection.startColumn - 1, selection.endColumn - 1));
|
|
860
|
+
}
|
|
861
|
+
return result;
|
|
862
|
+
}
|
|
863
|
+
constructor(textModel, selections) {
|
|
864
|
+
this._original = CompositionState._capture(textModel, selections);
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Returns the inserted text during this composition.
|
|
868
|
+
* If the composition resulted in existing text being changed (i.e. not a pure insertion) it returns null.
|
|
869
|
+
*/
|
|
870
|
+
deduceOutcome(textModel, selections) {
|
|
871
|
+
if (!this._original) {
|
|
872
|
+
return null;
|
|
873
|
+
}
|
|
874
|
+
const current = CompositionState._capture(textModel, selections);
|
|
875
|
+
if (!current) {
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
if (this._original.length !== current.length) {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
const result = [];
|
|
882
|
+
for (let i = 0, len = this._original.length; i < len; i++) {
|
|
883
|
+
result.push(CompositionState._deduceOutcome(this._original[i], current[i]));
|
|
884
|
+
}
|
|
885
|
+
return result;
|
|
886
|
+
}
|
|
887
|
+
static _deduceOutcome(original, current) {
|
|
888
|
+
const commonPrefix = Math.min(original.startSelectionOffset, current.startSelectionOffset, commonPrefixLength(original.text, current.text));
|
|
889
|
+
const commonSuffix = Math.min(original.text.length - original.endSelectionOffset, current.text.length - current.endSelectionOffset, commonSuffixLength(original.text, current.text));
|
|
890
|
+
const deletedText = original.text.substring(commonPrefix, original.text.length - commonSuffix);
|
|
891
|
+
const insertedTextStartOffset = commonPrefix;
|
|
892
|
+
const insertedTextEndOffset = current.text.length - commonSuffix;
|
|
893
|
+
const insertedText = current.text.substring(insertedTextStartOffset, insertedTextEndOffset);
|
|
894
|
+
const insertedTextRange = new Range(current.lineNumber, insertedTextStartOffset + 1, current.lineNumber, insertedTextEndOffset + 1);
|
|
895
|
+
return new CompositionOutcome(deletedText, original.startSelectionOffset - commonPrefix, original.endSelectionOffset - commonPrefix, insertedText, current.startSelectionOffset - commonPrefix, current.endSelectionOffset - commonPrefix, insertedTextRange);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
export { CommandExecutor, CursorsController };
|